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
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
- Retrieve relevant memories before generation under a bounded timeout.
- Inject them as non-authoritative background.
- 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
adapterMemoryAdapterFactoryrequiredinjectbooleandefault: trueextractbooleandefault: truelimitnumberdefault: 6minScorenumberdefault: 0retrieveTimeoutMsnumberdefault: 1500formatForPrompt(memories, ctx) => stringisEnabledForUser(ctx) => boolean | Promise<boolean>scopesMemoryScope[]default: ['user']autoSaveScopeMemoryScopedefault: userresolveOrgId(ctx) => string | null | Promise<string | null>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:
| Route | Effect |
|---|---|
GET /memory | List the bound user's user-tier memories |
DELETE /memory | Delete every memory row owned by the bound user for this agent, across tiers |
DELETE /memory/:id | Delete one memory row owned by the bound user |
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.