From 095c6ccb1fa80eb70922f22ba4418bd3d8c4b23e Mon Sep 17 00:00:00 2001 From: TIAMAT Date: Sun, 22 Feb 2026 03:40:10 +0000 Subject: [PATCH] feat: add TIAMAT cloud conversation memory driver Adds TiamatConversationMemoryDriver that provides persistent, cloud-based conversation memory for Griptape agents via https://memory.tiamat.live. Features: - Cloud persistence - no local files, survives container restarts - Cross-device agent memory accessible from anywhere - FTS5 full-text search across conversation history - Zero infrastructure - no Redis or database required - Implements BaseConversationMemoryDriver interface Includes: - griptape/drivers/memory/conversation/tiamat_conversation_memory_driver.py - examples/tiamat_memory/agent_with_tiamat.py - Usage example - examples/tiamat_memory/README.md - Documentation --- examples/tiamat_memory/README.md | 46 +++++++ examples/tiamat_memory/agent_with_tiamat.py | 63 +++++++++ .../tiamat_conversation_memory_driver.py | 125 ++++++++++++++++++ 3 files changed, 234 insertions(+) create mode 100644 examples/tiamat_memory/README.md create mode 100644 examples/tiamat_memory/agent_with_tiamat.py create mode 100644 griptape/drivers/memory/conversation/tiamat_conversation_memory_driver.py diff --git a/examples/tiamat_memory/README.md b/examples/tiamat_memory/README.md new file mode 100644 index 000000000..126172432 --- /dev/null +++ b/examples/tiamat_memory/README.md @@ -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 diff --git a/examples/tiamat_memory/agent_with_tiamat.py b/examples/tiamat_memory/agent_with_tiamat.py new file mode 100644 index 000000000..b97aac964 --- /dev/null +++ b/examples/tiamat_memory/agent_with_tiamat.py @@ -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() diff --git a/griptape/drivers/memory/conversation/tiamat_conversation_memory_driver.py b/griptape/drivers/memory/conversation/tiamat_conversation_memory_driver.py new file mode 100644 index 000000000..6ede9ec88 --- /dev/null +++ b/griptape/drivers/memory/conversation/tiamat_conversation_memory_driver.py @@ -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()