---
title: "Memory"
description: "Configure long-term memory, understand adapter-dependent tiers, and expose the built-in user-tier controls accurately."
---

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

```ts
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


- **`adapter`** · `MemoryAdapterFactory` · required

  User-bound adapter factory.

- **`inject`** · `boolean` · default `true`

  Retrieve and inject memories.

- **`extract`** · `boolean` · default `true`

  Extract and record after turns.

- **`limit`** · `number` · default `6`

  Maximum injected memories.

- **`minScore`** · `number` · default `0`

  Minimum adapter score.

- **`retrieveTimeoutMs`** · `number` · default `1500`

  Hot-path retrieval budget.

- **`formatForPrompt`** · `(memories, ctx) => string`

  Custom safe prompt block.

- **`isEnabledForUser`** · `(ctx) => boolean \| Promise<boolean>`

  Consent gate for read and write.

- **`scopes`** · `MemoryScope[]` · default `['user']`

  Requested retrieval tiers.

- **`autoSaveScope`** · `MemoryScope` · default `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:

| 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 |

```ts
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.
