Memory

Memory retrieves durable background before generation and records new facts after a completed turn. It is off by default and must be bound to the verified user.

Enable Drizzle memory

code
import { createDrizzleMemory }
  from '@mordn/chat-widget/server/memory/drizzle';
 
export const { GET, POST, DELETE } = createChatHandler({
  getUserId: getChatUserId,
  model: anthropic('claude-sonnet-4-5'),
  store: createDrizzleChatStore(),
  memory: {
    adapter: createDrizzleMemory({
      agentId: 'support-bot',
      // Optional AI SDK models:
      // embeddingModel: google.textEmbeddingModel('text-embedding-004'),
      // extractionModel: anthropic('claude-haiku-4-5'),
    }),
    inject: true,
    extract: true,
    limit: 6,
    retrieveTimeoutMs: 1500,
  },
});

Without an embedding model, the Drizzle adapter uses keyword retrieval. Without an extraction model, it uses heuristic extraction.

Lifecycle

  1. Retrieve relevant memories before generation under a bounded timeout.
  2. Inject them as non-authoritative background.
  3. After answer content settles, extract and record memories during stream finalization.

Recording is fail-soft, but it is intentionally awaited during finalization so a serverless runtime does not freeze before writes finish. It is post-content, not fire-and-forget.

Configuration

adapterMemoryAdapterFactoryrequired
User-bound adapter factory.
injectbooleandefault: true
Retrieve and inject memories.
extractbooleandefault: true
Extract and record after turns.
limitnumberdefault: 6
Maximum injected memories.
minScorenumberdefault: 0
Minimum adapter score.
retrieveTimeoutMsnumberdefault: 1500
Hot-path retrieval budget.
formatForPrompt(memories, ctx) => string
Custom safe prompt block.
isEnabledForUser(ctx) => boolean | Promise<boolean>
Consent gate for read and write.
scopesMemoryScope[]default: ['user']
Requested retrieval tiers.
autoSaveScopeMemoryScopedefault: user
Tier used for extraction writes.
resolveOrgId(ctx) => string | null | Promise<string | null>
Server-verified org id for org memory.

Tiers and adapters

  • session: bound to user, agent, and conversation.
  • user: durable across the bound user's conversations.
  • org: intentionally shared across users in the same server-verified org and agent namespace.

Warning

Tier behavior is adapter-dependent. The current Drizzle adapter implements session/user/org filtering. The hosted and mem0 adapters do not yet apply the scope, conversation, or org options in the same way. Use the user tier unless you have verified the chosen adapter's tier support.

Org retrieval is not restricted to facts written by the current user; sharing is the purpose of that tier. resolveOrgId must therefore be server-authoritative.

Built-in user controls

When memory is configured, the handler exposes:

RouteEffect
GET /memoryList the bound user's user-tier memories
DELETE /memoryDelete every memory row owned by the bound user for this agent, across tiers
DELETE /memory/:idDelete one memory row owned by the bound user
code
const response = await fetch('/api/chat/memory');
const { memories } = await response.json();

The built-in list route does not expose every session/org memory. The bulk-delete route removes rows owned by the bound user, including session/org rows they wrote, but never removes shared org rows owned by other users. Do not describe the list route as a complete cross-tier transparency view without adding an explicit, authorized admin surface.