CtrlK
BlogDocsLog inGet started
Tessl Logo

tanstack-ai-memory

Use when wiring memoryMiddleware from @tanstack/ai-memory into a chat() call — covers the recall/save adapter contract, scope shape and server-side scope security, the recall-inject / deferred-save lifecycle, choosing an adapter (inMemory, redis, hindsight, mem0, honcho), and devtools events.

68

Quality

82%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Low

Low-risk findings worth noting

SKILL.md
Quality
Evals
Security

TanStack AI Memory Middleware

Use this when adding server-side memory to a chat() call. Everything lives in @tanstack/ai-memory. A memory adapter is a single contract with two verbs — recall and save — and the middleware is thin: it recalls into the system prompt before the model runs and defers save after the turn finishes.

When to reach for it

  • A user expects "remember what I told you last time."
  • Per-user or per-thread context that must survive across sessions.
  • A hosted memory service (mem0, Honcho, Hindsight).

Do NOT use this just to keep recent messages — that's the messages array on chat(). Memory is for cross-turn / cross-session recall, not within-turn history.

Wire it up

import { chat } from '@tanstack/ai'
import { openaiText } from '@tanstack/ai-openai'
import { memoryMiddleware } from '@tanstack/ai-memory'
import { inMemory } from '@tanstack/ai-memory/in-memory'

const memory = inMemory() // dev/tests only — see the in-memory skill

const stream = chat({
  adapter: openaiText('gpt-5.5'),
  messages,
  context: { session }, // attached by your auth middleware
  middleware: [
    memoryMiddleware({
      adapter: memory,
      // Derive scope server-side from trusted session state.
      scope: (ctx) => {
        const session = getSession(ctx)
        return { threadId: session.threadId, userId: session.userId }
      },
    }),
  ],
})

memoryMiddleware options: adapter, scope (static or a function of ctx), role ('recall+save' default, or 'save-only'), and onRecall / onSave telemetry callbacks.

The contract

interface MemoryAdapter {
  id: string
  recall(scope, query): Promise<RecallResult> // { systemPrompt, fragments?, tools?, toolGuidance? }
  save(scope, turn): Promise<Array<SaveReceipt>> // turn = { user, assistant }; extraction lives HERE
  inspect?(scope): Promise<MemorySnapshot> // optional (devtools)
  listFacts?(scope): Promise<Array<MemoryFact>> // optional (devtools)
}
  • recall decides relevance and renders a systemPrompt; it may also return tools + toolGuidance to hand the model direct control of memory (hindsight does this).
  • save owns extraction — turning the raw turn into whatever gets persisted.

Scope security

MemoryScope is an alias of the shared Scope type from @tanstack/ai: { threadId, userId?, tenantId?, namespace? }. It is the isolation boundary. Never trust a client-supplied userId/threadId. Resolve scope server-side from session/auth and pass the validated session through chat({ context: { session } }). If you accept a thread id from the request body, validate it belongs to the session user BEFORE using it.

Adapters

  • inMemory() / redis() — exact match on threadId + optional userId/tenantId (namespace ignored). Redis index keys include all three segments.
  • hindsight() — bank {tenant|_}__{user}__{threadId}.
  • mem0()user_id + run_id (threadId); no tenantId.
  • honcho() — session {tenant|_}__{threadId}; peer tenant-prefixed when set.
  • Custom — implement recall/save and run @tanstack/ai-memory/tests/contract.

Failure modes

Memory failures are non-fatal: a throwing recall or save emits memory:error and the run continues with degraded memory. Streaming is never blocked; a failed save never fails the turn.

Devtools

Five events on aiEventClient (from @tanstack/ai-event-client): memory:retrieve:started / :completed, memory:persist:started / :completed, memory:error (phase: 'recall' | 'save'). Payloads carry the adapter id and fragment/receipt counts, not full memory text. Error events include scope only when it was already resolved; if the resolver threw, scope is omitted.

Repository
TanStack/ai
Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.