- MCP Server ToolsUpdated
- Managed MCP with chat()Updated
- Manual MCPUpdated
- MCP Type GenerationUpdated
- MCP Client InputUpdated
- MCP Server Tools: AdvancedNew
- MCP EventsNew
- MCP AppsUpdated
- Serve Tools over HTTPUpdated
- Serve Resources and PromptsUpdated
- Ask for InputUpdated
- Draft Text from a ToolUpdated
- MCP Server TasksUpdated
- MCP Server AuthUpdated
- MCP Server SessionsUpdated
- MCP Server on stdioUpdated
Persistence (Advanced)
- GenerationsUpdated
- Realtime Voice ChatUpdated
- Text-to-SpeechUpdated
- TranscriptionUpdated
- Transcription: AdvancedNew
- Voice CreationUpdated
- Audio RecordingUpdated
- Audio GenerationUpdated
- Image GenerationUpdated
- Image Generation: AdvancedNew
- Video GenerationUpdated
- Video Generation: AdvancedNew
- Live GenerationUpdated
- World GenerationUpdated
- Generation HooksUpdated
- OverviewUpdated
- Quick StartUpdated
- ProvidersUpdated
- HarnessesUpdated
- Harness AuthUpdated
- WorkspaceUpdated
- ToolsUpdated
- PolicyUpdated
- Lifecycle & SnapshotsUpdated
- Portable SnapshotsUpdated
- Keep Files After ReloadUpdated
- Save a Named VersionUpdated
- Branch From a VersionUpdated
- Send a Frozen FileUpdated
- Let the Agent Save and ForkUpdated
- Pick Which Files to KeepUpdated
- What a Snapshot StoresUpdated
- Instance DurabilityUpdated
- Durable RunsUpdated
- EventsUpdated
Sandboxes (Advanced)
- Runtime ContextUpdated
- Bring Your Own KeyUpdated
- Debug LoggingUpdated
- Multimodal ContentUpdated
- Files APIUpdated
- Per-Model Type SafetyUpdated
- Runtime Adapter SwitchingUpdated
- Tree-ShakingUpdated
- Extend AdapterUpdated
- Extend Adapter: AdvancedNew
- Typed Pre-Configured OptionsUpdated
- Test with a Fake ModelUpdated
- Prompt CachingUpdated
- Mid-Conversation ChangesUpdated
- Approval Flow ProcessingUpdated
Overview
Your assistant forgets everything the moment a session ends. A user tells it their name this week; next week it asks again. memoryMiddleware fixes that. It gives a chat() run memory that survives across turns and across sessions.
It works in two moves. Before the model runs, it recalls relevant memory from a pluggable adapter and adds it to the system prompt. After the run finishes, it saves the turn. The save is deferred, so it never blocks streaming.
Reach for it when you need recall across turns or sessions. To keep the last few messages of the same request, just pass them in messages. Memory is overkill for that.
Everything lives in @tanstack/ai-memory: the middleware, the adapter contract, and the built-in and vendor adapters.
Want a copy-paste setup? See the Quickstart. Building an adapter for a backend that isn't shipped? See the Custom Adapter guide.
When to reach for it#
| Need | Use this |
|---|---|
| "Remember what the user told me last week" | Memory middleware with a persistent adapter |
| "Each user has their own context" | Memory middleware with a scoped adapter |
| "Use a hosted memory service (mem0, Honcho, Hindsight)" | The matching vendor adapter |
| Keep the last few turns in the same request | Pass them in messages, skip memory |
The contract: recall and save#
A memory adapter has one identifier and two verbs. Extraction, ranking, rendering, and storage are all the adapter's job. The middleware never looks inside a record.
| Member | Purpose |
|---|---|
| id | Stable identifier used in logs and devtools. |
| recall(scope, query) | Return what's relevant to query within scope: a rendered systemPrompt, optional fragments, and optional LLM tools plus toolGuidance. |
| save(scope, turn) | Persist a finished { user, assistant } turn. Extraction happens here. Returns one SaveReceipt per write. |
| inspect(scope)? | Optional. A full snapshot for a devtools panel. |
| listFacts(scope)? | Optional. A flat fact list for a devtools panel. |
// The MemoryAdapter contract, from `@tanstack/ai-memory`:
import type { MemoryAdapter } from '@tanstack/ai-memory'Built-in adapters, each a tree-shakeable subpath:
import { inMemory } from '@tanstack/ai-memory/in-memory'
import { redis } from '@tanstack/ai-memory/redis'Vendor adapters:
import { hindsight } from '@tanstack/ai-memory/hindsight'
import { mem0 } from '@tanstack/ai-memory/mem0'
import { honcho } from '@tanstack/ai-memory/honcho'See Adapters for every adapter and its options.
How a turn flows#
- Recall runs before the model, during the run's init phase. adapter.recall(scope, userText) returns memory, and the middleware adds the systemPrompt, toolGuidance, and any tools to the run.
- Save runs after the stream finishes, deferred through ctx.defer so it never blocks the response. The middleware hands the { user, assistant } turn to adapter.save(scope, turn).
To add telemetry, watch memory in devtools, persist without recalling, or handle failures, see Operating memory.
Scope and security#
MemoryScope is the isolation boundary. It is an alias of the shared Scope identity type from @tanstack/ai — the same vocabulary used by persistence — so memory and chat center on one conversation key:
// MemoryScope is an alias of Scope from `@tanstack/ai`, exported by `@tanstack/ai-memory`:
type MemoryScope = {
threadId: string // required — same as ChatMiddlewareContext.threadId
userId?: string
tenantId?: string
namespace?: string // reserved — no adapter keys on it yet
}Always resolve scope on the server from trusted session/auth state. A client-originated threadId is fine only after you validate it belongs to the session user; never accept userId/tenantId from the request body alone. The function form of scope runs per request and only sees what your server attached to the chat context:
import { memoryMiddleware } from '@tanstack/ai-memory'
import type { MemoryAdapter } from '@tanstack/ai-memory'
declare const adapter: MemoryAdapter
declare function getSession(ctx: unknown): { threadId: string; userId: string }
memoryMiddleware({
adapter,
scope: (ctx) => {
const session = getSession(ctx) // your server-validated session
return { threadId: session.threadId, userId: session.userId }
},
})Next steps#
- Quickstart: wire memoryMiddleware into a real chat() call
- Adapters: every adapter's options, with an example of each
- Custom Adapter: implement recall/save for a backend that isn't shipped
- Operating memory: options, telemetry, devtools events, and failure behavior