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. No additional setup is required:
const client = new EstuaryClient({
serverUrl: 'https://api.estuary-ai.com',
apiKey: 'est_your_api_key',
characterId: 'your-character-uuid',
playerId: 'user-123',
});
// client.memory is ready to use immediately -- no need to call connect() first
const facts = await client.memory.getCoreFacts();
The memory API uses REST endpoints, not the WebSocket connection. You can query memory without calling client.connect().
Every memory request carries your API key plus an X-Estuary-Client: estuary-ts-sdk/<version> header identifying the SDK and its version (see Client identification). The header goes on REST requests only, never on the WebSocket connection.
Reads need a key with the memories:read scope and edits need memories:write. A key that lacks the scope a call needs gets a 403, surfaced as described in Error Handling.
Listing Memories
Retrieve a paginated list of memories with optional filtering:
const result = await client.memory.getMemories({
status: 'active',
limit: 20,
offset: 0,
});
console.log(`Total memories: ${result.total}`);
for (const memory of result.memories) {
console.log(memory);
}
Filter Options
| Option | Type | Description |
|---|---|---|
memoryType | string | Filter by memory type |
status | string | Filter by status (e.g., 'active') |
limit | number | Max results to return |
offset | number | Pagination offset |
sortBy | string | Deprecated. Accepted for compatibility, but ignored: it is no longer sent and no route ever honored it |
sortOrder | string | Deprecated. Accepted for compatibility, but ignored: it is no longer sent and no route ever honored it |
Memories come back in the server's default order. Sort client side if you need a specific order.
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:
const result = await client.memory.getCoreFacts();
for (const fact of result.coreFacts) {
console.log(fact);
}
Knowledge Graph
The knowledge graph represents memories as a network of entities and relationships:
const graph = await client.memory.getGraph({
includeEntities: true,
includeCharacterMemories: true,
});
console.log('Nodes:', graph.nodes.length);
console.log('Edges:', graph.edges.length);
console.log('Stats:', graph.stats);
Graph Options
| Option | Type | Default | Description |
|---|---|---|---|
includeEntities | boolean | false | Include entity nodes in the graph |
includeCharacterMemories | boolean | false | Include the character's own memories |
Searching Memories
Search across all memories using natural language:
// Optional second argument: result limit, 1 to 50 (server default 10)
const results = await client.memory.search('likes pizza', 5);
console.log(`Found ${results.total} results for "${results.query}"`);
for (const result of results.results) {
console.log(`[${result.similarity.toFixed(2)}] ${result.content} (${result.memoryId})`);
}
Search uses semantic similarity, so the query does not need to match the stored text exactly.
Each hit is a MemorySearchResult with three fields: memoryId, similarity, and content. It is not a full memory object, so if you need the other fields, match memoryId against the results of getMemories().
:::note Search works from this release onward
Earlier SDK versions sent the search request in a form the server rejected, so search() could never return results. Upgrade to the current version to use it. For the request and response shapes, see Search Memories in the REST reference.
:::
Timeline
View memories organized chronologically:
const timeline = await client.memory.getTimeline({
groupBy: 'week',
});
console.log(`Total memories: ${timeline.totalMemories}`);
for (const group of timeline.timeline) {
console.log(`${group.date}: ${group.memories.length} memories`);
}
Timeline Options
| Option | Type | Description |
|---|---|---|
startDate | string | ISO date string for range start |
endDate | string | ISO date string for range end |
groupBy | string | 'day', 'week', or 'month' |
Statistics
Get aggregate statistics about the character's memory for this player:
const stats = await client.memory.getStats();
console.log(stats);
Example: Memory Dashboard
import { EstuaryClient } from '@estuary-ai/sdk';
const client = new EstuaryClient({
serverUrl: 'https://api.estuary-ai.com',
apiKey: 'est_your_api_key',
characterId: 'your-character-uuid',
playerId: 'user-123',
});
async function showMemoryDashboard() {
// Fetch everything in parallel
const [facts, graph, stats, timeline] = await Promise.all([
client.memory.getCoreFacts(),
client.memory.getGraph({ includeEntities: true }),
client.memory.getStats(),
client.memory.getTimeline({ groupBy: 'week' }),
]);
console.log('=== Core Facts ===');
for (const fact of facts.coreFacts) {
console.log('-', fact);
}
console.log('\n=== Knowledge Graph ===');
console.log(`${graph.nodes.length} nodes, ${graph.edges.length} edges`);
console.log('\n=== Stats ===');
console.log(stats);
console.log('\n=== Timeline ===');
for (const group of timeline.timeline) {
console.log(`${group.date}: ${group.memories.length} memories`);
}
}
showMemoryDashboard().catch(console.error);
Real-Time Memory Events
By default, memory extraction happens silently in the background. If you want to be notified when new memories are extracted during a conversation, enable realtimeMemory in your client config:
const client = new EstuaryClient({
serverUrl: 'https://api.estuary-ai.com',
apiKey: 'est_your_api_key',
characterId: 'your-character-uuid',
playerId: 'user-123',
realtimeMemory: true,
});
client.on('memoryUpdated', (event) => {
console.log(`Extracted ${event.memoriesExtracted} memories, ${event.factsExtracted} facts`);
for (const memory of event.newMemories) {
console.log(`[${memory.memoryType}] ${memory.content} (confidence: ${memory.confidence})`);
}
});
await client.connect();
The memoryUpdated event fires after each bot response when the server finishes extracting memories from the conversation turn. The event includes:
| Field | Type | Description |
|---|---|---|
agentId | string | Character (agent) ID |
playerId | string | Player ID |
memoriesExtracted | number | Number of memories extracted this turn |
factsExtracted | number | Number of core facts extracted |
conversationId | string | Conversation ID |
newMemories | MemoryData[] | Array of newly extracted memory objects |
timestamp | string | ISO timestamp |
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
- Action System -- Handle action tags in bot responses
- API Reference: Data Models -- Memory type definitions
- Memory System (Platform) -- How memory works under the hood