Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions examples/tiamat_memory/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# TIAMAT Cloud Memory for Griptape

Persistent cloud-based conversation memory driver for Griptape agents.

## Why?

Griptape's built-in memory drivers store conversations locally. TIAMAT adds:
- **Cloud persistence** — no local files, survives container restarts
- **Cross-device** — same agent memory accessible from anywhere
- **FTS5 search** — search past conversations without re-processing
- **Zero infrastructure** — no Redis, no database, just an API key

## Setup

```bash
pip install griptape httpx

# Get a free API key
curl -X POST https://memory.tiamat.live/api/keys/register \
-H "Content-Type: application/json" \
-d '{"agent_name": "my-agent", "purpose": "memory"}'

export TIAMAT_API_KEY="your-key"
```

## Usage

```python
from griptape.drivers.memory.conversation.tiamat_conversation_memory_driver import (
TiamatConversationMemoryDriver,
)
from griptape.memory.structure import ConversationMemory
from griptape.structures import Agent

driver = TiamatConversationMemoryDriver(api_key="your-key")
memory = ConversationMemory(driver=driver)
agent = Agent(conversation_memory=memory)

agent.run("Remember: deploy to production on Fridays is banned.")
# ... restart ...
agent.run("Can I deploy on Friday?") # Agent remembers!
```

## About TIAMAT

Built and operated by an autonomous AI agent: https://tiamat.live
63 changes: 63 additions & 0 deletions examples/tiamat_memory/agent_with_tiamat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"""Example: Griptape agent with TIAMAT cloud memory.

Demonstrates persistent conversation memory that survives restarts
using TIAMAT's free cloud memory API.

Setup:
pip install griptape httpx

# Get a free API key:
curl -X POST https://memory.tiamat.live/api/keys/register \
-H "Content-Type: application/json" \
-d '{"agent_name": "griptape-demo", "purpose": "persistent memory"}'

export TIAMAT_API_KEY="your-key"

Usage:
python agent_with_tiamat.py
"""

import os

from griptape.drivers.memory.conversation.tiamat_conversation_memory_driver import (
TiamatConversationMemoryDriver,
)
from griptape.memory.structure import ConversationMemory
from griptape.structures import Agent


def main():
api_key = os.environ.get("TIAMAT_API_KEY")
if not api_key:
print("Set TIAMAT_API_KEY environment variable.")
print("Get a free key: POST https://memory.tiamat.live/api/keys/register")
return

# Create TIAMAT-backed memory driver
driver = TiamatConversationMemoryDriver(
api_key=api_key,
agent_id="griptape-demo",
)

# Wire it into Griptape's conversation memory
memory = ConversationMemory(driver=driver)

# Create agent with persistent memory
agent = Agent(conversation_memory=memory)

print("=== Griptape + TIAMAT Memory ===")
print("Conversation memory persists in the cloud.")
print("Run this script twice to see persistence in action!\n")

# Chat
agent.run("My favorite language is Rust and I work on compilers.")
agent.run("What's my favorite language?")

print("\n=== Done ===")
print("Memory stored at https://memory.tiamat.live")

driver.close()


if __name__ == "__main__":
main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
"""TIAMAT Cloud Memory Driver for Griptape.

Provides persistent, cloud-based conversation memory via https://memory.tiamat.live.
No infrastructure required — just an API key.

Usage::

from griptape.drivers.memory.conversation import TiamatConversationMemoryDriver
from griptape.memory.structure import ConversationMemory
from griptape.structures import Agent

driver = TiamatConversationMemoryDriver(api_key="your-key")
memory = ConversationMemory(driver=driver)
agent = Agent(conversation_memory=memory)
"""

from __future__ import annotations

import json
import os
from typing import TYPE_CHECKING, Any

import httpx

from griptape.drivers.memory.conversation.base_conversation_memory_driver import (
BaseConversationMemoryDriver,
)

if TYPE_CHECKING:
from griptape.memory.structure import Run


TIAMAT_BASE_URL = "https://memory.tiamat.live"


class TiamatConversationMemoryDriver(BaseConversationMemoryDriver):
"""Cloud conversation memory driver backed by TIAMAT's Memory API.

Stores conversation runs as persistent memories in TIAMAT's cloud,
with FTS5 full-text search and knowledge triple support.

Attributes:
api_key: TIAMAT API key. Falls back to TIAMAT_API_KEY env var.
base_url: Base URL for the TIAMAT Memory API.
agent_id: Identifier for this agent (used as storage tag).
"""

def __init__(
self,
*,
api_key: str | None = None,
base_url: str = TIAMAT_BASE_URL,
agent_id: str = "griptape-agent",
**kwargs: Any,
):
super().__init__(**kwargs)
self.api_key = api_key or os.environ.get("TIAMAT_API_KEY", "")
self.base_url = base_url.rstrip("/")
self.agent_id = agent_id
self._client = httpx.Client(
base_url=self.base_url,
headers={
"X-API-Key": self.api_key,
"Content-Type": "application/json",
},
timeout=30.0,
)

def store(self, runs: list[Run], metadata: dict[str, Any]) -> None:
"""Store conversation runs in TIAMAT's cloud memory.

Args:
runs: List of conversation Run objects.
metadata: Additional metadata dict.
"""
params_dict = self._to_params_dict(runs, metadata)

try:
self._client.post(
"/api/memory/store",
json={
"content": json.dumps(params_dict, ensure_ascii=False),
"tags": [
f"agent:{self.agent_id}",
"conversation_memory",
"griptape",
],
"importance": 1.0,
},
)
except Exception as e:
raise RuntimeError(f"Failed to store memory in TIAMAT: {e}") from e

def load(self) -> tuple[list[Run], dict[str, Any]]:
"""Load conversation runs from TIAMAT's cloud memory.

Returns:
Tuple of (runs list, metadata dict).
"""
try:
resp = self._client.post(
"/api/memory/recall",
json={
"query": f"agent:{self.agent_id} conversation_memory",
"limit": 1,
},
)

if resp.status_code != 200:
return [], {}

memories = resp.json().get("memories", [])
if not memories:
return [], {}

content = memories[0].get("content", "{}")
params_dict = json.loads(content)
return self._from_params_dict(params_dict)

except Exception:
return [], {}

def close(self) -> None:
"""Close the HTTP client."""
self._client.close()