Memory
Persistent state across conversations and sessions
Memory
Memory gives agents the ability to persist information across conversations, learn from past interactions, and maintain context over time. Without memory, every conversation starts from zero.
Memory Types
The SDK provides three types of memory, mirroring how human cognition works:
| Type | Purpose | Example |
|---|---|---|
| Semantic | Facts and knowledge | "User prefers dark mode" |
| Episodic | Past experiences | "Last time user asked about X, they wanted Y" |
| Procedural | How to do things | "To deploy, run npm run deploy" |
Quick Start
import { Agent, Memory } from 'assistme-agent-sdk'
import { claude } from 'assistme-agent-sdk-provider-claude'
const agent = new Agent({
name: 'assistant',
model: claude('claude-sonnet-4-6'),
instructions: 'You are a helpful assistant. Use your memory to personalize interactions.',
memory: Memory.persistent({
store: Memory.stores.sqlite('./memory.db'),
namespace: 'user-123',
}),
})Memory Stores
Built-in Stores
// SQLite (local, single-process)
Memory.stores.sqlite('./memory.db')
// Redis (distributed, multi-process)
Memory.stores.redis({ url: 'redis://localhost:6379' })
// PostgreSQL (persistent, scalable)
Memory.stores.postgres({ connectionString: process.env.DATABASE_URL })
// In-memory (testing, ephemeral)
Memory.stores.inMemory()Custom Stores
Implement the MemoryStore interface to use any storage backend:
import { MemoryStore, MemoryEntry } from 'assistme-agent-sdk'
class CustomStore implements MemoryStore {
async get(namespace: string, key: string): Promise<MemoryEntry | null> {
// Your implementation
}
async set(namespace: string, key: string, entry: MemoryEntry): Promise<void> {
// Your implementation
}
async search(namespace: string, query: string, limit?: number): Promise<MemoryEntry[]> {
// Your implementation (semantic search)
}
async list(namespace: string): Promise<MemoryEntry[]> {
// Your implementation
}
async delete(namespace: string, key: string): Promise<void> {
// Your implementation
}
}Automatic Memory
When memory is configured, the SDK automatically:
- Loads relevant memories into context at the start of each run
- Extracts and stores new memories after each run
const agent = new Agent({
name: 'assistant',
model: claude('claude-sonnet-4-6'),
instructions: 'You are a helpful assistant.',
memory: Memory.persistent({
store: Memory.stores.sqlite('./memory.db'),
namespace: 'user-123',
auto: {
/** Automatically extract and store memories from conversations */
extract: true,
/** Load relevant memories into context before each run */
recall: true,
/** Maximum memories to inject into context */
maxRecall: 10,
},
}),
})
// First conversation
await Runner.run(agent, {
messages: [{ role: 'user', content: 'My name is Alice and I prefer Python over JavaScript.' }],
})
// Second conversation — agent automatically recalls "User's name is Alice, prefers Python"
await Runner.run(agent, {
messages: [{ role: 'user', content: 'What programming language should I use for this project?' }],
})Manual Memory
For full control, manage memory explicitly:
const memory = Memory.persistent({
store: Memory.stores.sqlite('./memory.db'),
namespace: 'user-123',
})
// Write memories
await memory.set('preferences', {
type: 'semantic',
content: 'User prefers dark mode and compact layouts',
metadata: { source: 'settings', updatedAt: new Date() },
})
await memory.set('last-project', {
type: 'episodic',
content: 'User was working on a React dashboard for inventory management',
metadata: { date: '2026-03-12', project: 'inventory-dashboard' },
})
// Search memories
const relevant = await memory.search('What does the user prefer?', { limit: 5 })
// List all memories
const all = await memory.list()
// Delete a memory
await memory.delete('last-project')Scoped Memory
Different agents in a multi-agent system can share or isolate memory:
// Shared memory — both agents read and write to the same namespace
const sharedMemory = Memory.persistent({
store: Memory.stores.redis({ url: 'redis://localhost:6379' }),
namespace: 'team-shared',
})
const agent1 = new Agent({ name: 'agent-1', memory: sharedMemory, ... })
const agent2 = new Agent({ name: 'agent-2', memory: sharedMemory, ... })
// Isolated memory — each agent has its own namespace
const agent3 = new Agent({
name: 'agent-3',
memory: Memory.persistent({
store: sharedMemory.store,
namespace: 'agent-3-private',
}),
...
})Memory Lifecycle
User Message
│
▼
┌─────────────┐
│ Recall │ ← Load relevant memories into context
│ (before) │
└──────┬──────┘
│
▼
┌─────────────┐
│ Agent Run │ ← Agent sees memories as part of context
└──────┬──────┘
│
▼
┌─────────────┐
│ Extract │ ← Extract new memories from conversation
│ (after) │
└──────┬──────┘
│
▼
┌─────────────┐
│ Store │ ← Persist new/updated memories
└─────────────┘Memory with Conversation History
Memory is distinct from conversation history. Conversation history is the full message thread; memory is extracted knowledge:
const agent = new Agent({
name: 'assistant',
model: claude('claude-sonnet-4-6'),
instructions: 'You are a helpful assistant.',
memory: Memory.persistent({
store: Memory.stores.sqlite('./memory.db'),
namespace: 'user-123',
auto: { extract: true, recall: true },
}),
})
// Conversation 1: 50 messages about project setup
// → Memory extracts: "User's project uses Next.js 15, TypeScript, Supabase"
// Full 50-message history is NOT stored in memory
// Conversation 2: Agent recalls the extracted facts, not the 50 messages
// → Context contains: "User's project uses Next.js 15, TypeScript, Supabase"
// This is far more token-efficient than replaying the full historyAdvanced: Knowledge Networks
For complex use cases, organize memories into interconnected networks:
const memory = Memory.persistent({
store: Memory.stores.postgres({ connectionString }),
namespace: 'user-123',
indexing: {
/** Create bidirectional links between related memories */
linkRelated: true,
/** Use embedding-based similarity for memory retrieval */
embedding: true,
/** Decay low-relevance memories over time */
decay: {
enabled: true,
halfLife: '30d',
},
},
})Best Practices
-
Namespace by user — Each user should have their own memory namespace. Never mix memories between users.
-
Prefer automatic extraction — Let the SDK extract memories. Manual memory management is more work and less comprehensive.
-
Limit recall count — Don't inject 100 memories into every context. Use
maxRecallto keep context focused (5-15 is typical). -
Use semantic search for recall — Instead of loading all memories, search for relevant ones based on the current query.
-
Separate concerns — Use different namespaces for different types of data (user preferences, project context, learned procedures).
-
Clean up periodically — Old, irrelevant memories add noise. Enable decay or periodically prune stale entries.