Memory & Knowledge Graph
Query the character's persistent memory system to retrieve facts, relationships, and conversation history across sessions.
Overview
Estuary characters remember things about users across conversations. The memory system stores facts, relationships, and context as a knowledge graph. The SDK provides a MemoryClient accessible via client.memory that lets you query this data through the REST API.
Memory is scoped to a specific character-player pair -- each player has their own memory with each character.
For more details on how memory works, see the Memory System platform documentation.
Authentication
The MemoryClient authenticates using the same API key configured on the EstuaryClient. It becomes available after connect():
async with EstuaryClient(config) as client:
await client.connect()
# client.memory is now ready to use
facts = await client.memory.get_core_facts()
The memory API uses REST endpoints, not the WebSocket connection. However, client.memory requires connect() first because the character and player IDs are confirmed during the session handshake.
Listing Memories
Retrieve a paginated list of memories with optional filtering:
result = await client.memory.get_memories(
status="active",
limit=20,
offset=0,
)
print(f"Total memories: {result.total}")
for memory in result.memories:
print(f"[{memory.memory_type}] {memory.content}")
Filter Options
| Option | Type | Description |
|---|---|---|
memory_type | str | Filter by memory type |
status | str | Filter by status (e.g., "active") |
limit | int | Max results to return (default: 50) |
offset | int | Pagination offset |
sort_by | str | Deprecated. Accepted for backward compatibility, but no longer sent and has no effect. |
sort_order | str | Deprecated. Accepted for backward compatibility, but no longer sent and has no effect. |
:::note Sorting arguments are ignored
sort_by and sort_order remain in the signature so existing code keeps working, but the SDK no longer puts them on the wire: the memories list endpoint never applied them. Pass them if you like, the result is the same list either way.
:::
Core Facts
Core facts are high-confidence, stable pieces of information the character has learned about the player -- things like their name, preferences, or important details:
result = await client.memory.get_core_facts()
for fact in result.core_facts:
print(f"{fact.fact_key}: {fact.fact_value}")
Knowledge Graph
The knowledge graph represents memories as a network of entities and relationships:
graph = await client.memory.get_graph(
include_entities=True,
include_character_memories=True,
)
print("Nodes:", len(graph.nodes))
print("Edges:", len(graph.edges))
print("Stats:", graph.stats)
Graph Options
| Option | Type | Default | Description |
|---|---|---|---|
include_entities | bool | None | Include entity nodes in the graph |
include_character_memories | bool | None | Include the character's own memories |
Searching Memories
Search across all memories using natural language:
results = await client.memory.search("likes pizza", limit=5)
print(f"Found {results.total} results for \"{results.query}\"")
for result in results.results:
print(f"{result.similarity:.2f}: {result.content} (id: {result.memory_id})")
Search uses semantic similarity, so the query does not need to match the stored text exactly. limit accepts 1 to 50 and defaults to 10 when omitted.
Each hit carries three fields: memory_id, similarity, and content. The hit does not include the full memory record, so use get_memories() if you need the rest of its fields.
:::info Search requires a current SDK version
Memory search works from this release onward. Earlier versions of the SDK sent the query in a form the API does not accept, so search() could never return results. Upgrade with pip install --upgrade estuary-sdk if your calls are failing.
:::
See Search Memories in the REST API reference for the underlying request and response shape.
Timeline
View memories organized chronologically:
timeline = await client.memory.get_timeline(group_by="week")
print(f"Total memories: {timeline.total_memories}")
for group in timeline.timeline:
print(f"{group.date}: {len(group.memories)} memories")
Timeline Options
| Option | Type | Description |
|---|---|---|
start_date | str | ISO date string for range start |
end_date | str | ISO date string for range end |
group_by | str | "day", "week", or "month" |
Statistics
Get aggregate statistics about the character's memory for this player:
stats = await client.memory.get_stats()
print(f"Active: {stats.total_active}, Core facts: {stats.core_facts}")
print(f"By type: {stats.by_type}")
Deleting Memories
Delete all memories for this player-character pair:
result = await client.memory.delete_all(confirm=True)
print(f"Deleted {result.deleted_count} memories")
This is irreversible. The confirm=True parameter is a safety guard.
Example: Memory Dashboard
import asyncio
from estuary_sdk import EstuaryClient, EstuaryConfig
config = EstuaryConfig(
server_url="https://api.estuary-ai.com",
api_key="est_your_api_key",
character_id="your-character-uuid",
player_id="user-123",
)
async def main():
async with EstuaryClient(config) as client:
await client.connect()
# Fetch everything concurrently
facts, graph, stats, timeline = await asyncio.gather(
client.memory.get_core_facts(),
client.memory.get_graph(include_entities=True),
client.memory.get_stats(),
client.memory.get_timeline(group_by="week"),
)
print("=== Core Facts ===")
for fact in facts.core_facts:
print(f" {fact.fact_key}: {fact.fact_value}")
print("\n=== Knowledge Graph ===")
print(f" {len(graph.nodes)} nodes, {len(graph.edges)} edges")
print("\n=== Stats ===")
print(f" Active: {stats.total_active}, Core facts: {stats.core_facts}")
print("\n=== Timeline ===")
for group in timeline.timeline:
print(f" {group.date}: {len(group.memories)} memories")
asyncio.run(main())
Real-Time Memory Events
If you want to be notified when new memories are extracted during a conversation, enable realtime_memory in your config:
config = EstuaryConfig(
server_url="https://api.estuary-ai.com",
api_key="est_your_api_key",
character_id="your-character-uuid",
player_id="user-123",
realtime_memory=True,
)
async with EstuaryClient(config) as client:
async def on_memory_updated(event):
print(f"Extracted {event.memories_extracted} memories, {event.facts_extracted} facts")
for memory in event.new_memories:
print(f" [{memory.memory_type}] {memory.content} (confidence: {memory.confidence})")
client.on("memory_updated", on_memory_updated)
await client.connect()
The memory_updated event fires after each bot response when the server finishes extracting memories from the conversation turn.
Real-time memory events are useful for building UIs that show the user what the character has learned, or for triggering application logic based on extracted facts.
Next Steps
- API Reference: Data Models -- Memory type definitions
- Memory System (Platform) -- How memory works under the hood