StateStore used for durability checkpoints — no hand-rolled per-project memory table, and no separate persistence layer to configure.
Attaching memory to routes
withMemory is a middleware that attaches a MemoryStore to ctx.state, namespaced per request:
x-session-id request header, falling back to 'default' if the header is absent. Pass a custom function to derive the namespace differently — from a JWT claim, a cookie, or a route param:
Reading and writing memory in a handler
getMemory(ctx) returns undefined if withMemory wasn’t attached upstream — always check before use, or attach it at the root _middleware.ts so every route has it.
MemoryStore API
<T>(key: string) => Promise<T | undefined>
Read a typed value. Returns
undefined if the key was never set.(key: string, value: unknown) => Promise<void>
Write a value, overwriting anything already stored under
key.<T>(key: string, item: T) => Promise<number>
Append
item to an array value, creating the array if it doesn’t exist yet. Returns the new array length. Useful for conversation history without a separate read-modify-write round trip in handler code.(key: string) => Promise<void>
Remove a key.
() => Promise<string[]>
List all keys currently set within this instance’s namespace.
anvil:memory:<namespace>:<key>) in the underlying StateStore, so different sessions never collide even when sharing one store instance.
Choosing a backing store
MemoryStore works over any StateStore implementation:
See also
- RAG & retrieval — semantic search over documents, distinct from per-session conversational memory
- Semantic cache — cache LLM responses across sessions by prompt similarity
- Durable execution — checkpoint and resume agent runs using the same
StateStoreinterface
StateStore used for durability checkpoints — no hand-rolled per-project memory table, and no separate persistence layer to configure.
Attaching memory to routes
withMemory is a middleware that attaches a MemoryStore to ctx.state, namespaced per request:
x-session-id request header, falling back to 'default' if the header is absent. Pass a custom function to derive the namespace differently — from a JWT claim, a cookie, or a route param:
Reading and writing memory in a handler
getMemory(ctx) returns undefined if withMemory wasn’t attached upstream — always check before use, or attach it at the root _middleware.ts so every route has it.
MemoryStore API
<T>(key: string) => Promise<T | undefined>
Read a typed value. Returns
undefined if the key was never set.(key: string, value: unknown) => Promise<void>
Write a value, overwriting anything already stored under
key.<T>(key: string, item: T) => Promise<number>
Append
item to an array value, creating the array if it doesn’t exist yet. Returns the new array length. Useful for conversation history without a separate read-modify-write round trip in handler code.(key: string) => Promise<void>
Remove a key.
() => Promise<string[]>
List all keys currently set within this instance’s namespace.
anvil:memory:<namespace>:<key>) in the underlying StateStore, so different sessions never collide even when sharing one store instance.
Choosing a backing store
MemoryStore works over any StateStore implementation:
See also
- RAG & retrieval — semantic search over documents, distinct from per-session conversational memory
- Semantic cache — cache LLM responses across sessions by prompt similarity
- Durable execution — checkpoint and resume agent runs using the same
StateStoreinterface