docs(skills): refresh mem0 skills against SDK 2.2.1 / TS 3.3.1 (#7548)
This commit is contained in:
@@ -37,7 +37,7 @@ curl -X POST https://api.anthropic.com/v1/skills \
|
||||
### Prerequisites
|
||||
|
||||
- **Node.js 18+**
|
||||
- **Vercel AI SDK v5** (`ai` package version 5.x)
|
||||
- **Vercel AI SDK v6** (`ai` package version 6.x)
|
||||
- A Mem0 Platform API key ([Get one here](https://app.mem0.ai/dashboard/api-keys?utm_source=oss&utm_medium=skill-mem0-vercel-ai-sdk-readme))
|
||||
- An LLM provider API key (OpenAI, Anthropic, Google, Groq, or Cohere)
|
||||
- Set environment variables:
|
||||
@@ -54,7 +54,7 @@ After installing, just ask Claude:
|
||||
- "Add memory to my Vercel AI SDK app"
|
||||
- "Set up mem0 with streamText in my Next.js API route"
|
||||
- "Use retrieveMemories with Anthropic instead of the wrapped model"
|
||||
- "Show me how to use graph memories with the Vercel AI provider"
|
||||
- "Show me how to read the Mem0 source from generateText with the Vercel AI provider"
|
||||
- "Help me store conversation history with addMemories"
|
||||
|
||||
## What's Inside
|
||||
@@ -67,7 +67,7 @@ skills/mem0-vercel-ai-sdk/
|
||||
└── references/ # Documentation (loaded on demand)
|
||||
├── provider-api.md # createMem0, Mem0Provider, types, config
|
||||
├── memory-utilities.md # addMemories, retrieveMemories, getMemories, searchMemories
|
||||
└── usage-patterns.md # Working examples: streaming, Next.js, multi-provider, graph
|
||||
└── usage-patterns.md # Working examples: streaming, Next.js, multi-provider
|
||||
```
|
||||
|
||||
## Links
|
||||
|
||||
@@ -12,10 +12,11 @@ description: >
|
||||
license: Apache-2.0
|
||||
metadata:
|
||||
author: mem0ai
|
||||
version: "1.1.0"
|
||||
version: "2.0.0"
|
||||
category: ai-memory
|
||||
tags: "vercel, ai-sdk, memory, nextjs, typescript, provider"
|
||||
compatibility: Node.js 18+, npm install @mem0/vercel-ai-provider, Vercel AI SDK v5 (ai package), MEM0_API_KEY + LLM provider API key
|
||||
mem0_tested_versions: "@mem0/vercel-ai-provider (npm) >=3.0.0,<4.0.0; ai (npm) >=6.0.0,<7.0.0; mem0ai (npm) >=3.0.0,<4.0.0"
|
||||
compatibility: Node.js 18+, npm install @mem0/vercel-ai-provider, Vercel AI SDK v6 (ai package ^6), MEM0_API_KEY + LLM provider API key
|
||||
---
|
||||
|
||||
# Mem0 Vercel AI SDK Provider
|
||||
@@ -25,9 +26,11 @@ Memory-enhanced AI provider for Vercel AI SDK. Automatically retrieves and store
|
||||
## Step 1: Install
|
||||
|
||||
```bash
|
||||
npm install @mem0/vercel-ai-provider ai
|
||||
npm install @mem0/vercel-ai-provider ai@^6
|
||||
```
|
||||
|
||||
`ai` and the `@ai-sdk/*` provider packages ship as regular dependencies of `@mem0/vercel-ai-provider`, so nothing else needs installing. The only peer dependency is `zod` (optional, `^3.0.0`).
|
||||
|
||||
## Step 2: Set up environment variables
|
||||
|
||||
```bash
|
||||
@@ -53,10 +56,23 @@ const { text } = await generateText({
|
||||
```
|
||||
|
||||
What happens under the hood:
|
||||
1. The prompt is sent to Mem0 search (`POST /v3/memories/search/`) to retrieve relevant memories
|
||||
2. Retrieved memories are injected as a system message at the start of the prompt
|
||||
3. The underlying LLM (e.g., OpenAI gpt-5-mini) generates a response using the enriched prompt
|
||||
4. The conversation is stored back to Mem0 (`POST /v3/memories/add/`) as a fire-and-forget async call (no await)
|
||||
1. The prompt is stored to Mem0 (`POST /v3/memories/add/`), awaited before the LLM call (a failed write is logged and ignored)
|
||||
2. The prompt is sent to Mem0 search (`POST /v3/memories/search/`) to retrieve relevant memories
|
||||
3. If any memories are found, they are injected as a system message at the start of the prompt
|
||||
4. The underlying LLM (e.g., OpenAI gpt-5-mini) generates a response using the enriched prompt
|
||||
|
||||
For `generateText`, the retrieved memories are also attached to the result as a source:
|
||||
|
||||
```typescript
|
||||
const { text, sources } = await generateText({
|
||||
model: mem0("gpt-5-mini", { user_id: "alice" }),
|
||||
prompt: "Recommend a restaurant",
|
||||
});
|
||||
|
||||
console.log(sources.find((s) => s.title === "Mem0 Memories")?.providerMetadata?.mem0);
|
||||
```
|
||||
|
||||
The source has `title: "Mem0 Memories"` and `providerMetadata.mem0` holds `memories` (array of memory objects) and `memoriesText`. It is only present when at least one memory was retrieved.
|
||||
|
||||
## Pattern 2: Standalone Utilities
|
||||
|
||||
@@ -111,7 +127,7 @@ for await (const chunk of result.textStream) {
|
||||
}
|
||||
```
|
||||
|
||||
The wrapped model handles memory retrieval before streaming begins and stores the conversation after.
|
||||
The wrapped model stores the conversation and retrieves memories before streaming begins.
|
||||
|
||||
## Supported Providers
|
||||
|
||||
@@ -119,7 +135,7 @@ The wrapped model handles memory retrieval before streaming begins and stores th
|
||||
|----------|-------------|------------------|
|
||||
| OpenAI (default) | `"openai"` | `OPENAI_API_KEY` |
|
||||
| Anthropic | `"anthropic"` | `ANTHROPIC_API_KEY` |
|
||||
| Google | `"google"` | `GOOGLE_GENERATIVE_AI_API_KEY` |
|
||||
| Google | `"google"` (alias `"gemini"`) | `GOOGLE_GENERATIVE_AI_API_KEY` |
|
||||
| Groq | `"groq"` | `GROQ_API_KEY` |
|
||||
| Cohere | `"cohere"` | `COHERE_API_KEY` |
|
||||
|
||||
@@ -128,7 +144,7 @@ Select a provider when creating the Mem0 instance:
|
||||
```typescript
|
||||
const mem0 = createMem0({ provider: "anthropic" });
|
||||
const { text } = await generateText({
|
||||
model: mem0("gpt-5-mini", { user_id: "alice" }),
|
||||
model: mem0("claude-sonnet-4-20250514", { user_id: "alice" }),
|
||||
prompt: "Hello!",
|
||||
});
|
||||
```
|
||||
@@ -139,11 +155,11 @@ const { text } = await generateText({
|
||||
|
||||
```
|
||||
User prompt
|
||||
--> searchInternalMemories (POST /v3/memories/search/)
|
||||
--> memories injected as system message at start of prompt
|
||||
--> processMemories: addMemories (POST /v3/memories/add/, awaited)
|
||||
--> processMemories: getMemories (POST /v3/memories/search/)
|
||||
--> memories (if any) injected as system message at start of prompt
|
||||
--> underlying LLM generates response (doGenerate or doStream)
|
||||
--> processMemories fires addMemories as fire-and-forget (no await)
|
||||
--> response returned to caller
|
||||
--> response returned to caller (doGenerate also attaches a "Mem0 Memories" source)
|
||||
```
|
||||
|
||||
### Standalone flow
|
||||
@@ -162,18 +178,20 @@ User controls each step:
|
||||
|----------|---------|----------|
|
||||
| `retrieveMemories` | Formatted system prompt **string** | Injecting directly into `system` parameter |
|
||||
| `getMemories` | Raw memory **array** | Processing memories programmatically |
|
||||
| `searchMemories` | Full search **response** (results + relations) | Need relations, scores, metadata |
|
||||
| `searchMemories` | Raw search **response** (as returned by the API) | Need scores and full metadata |
|
||||
| `addMemories` | API response | Storing new messages to Mem0 |
|
||||
|
||||
All four accept `LanguageModelV2Prompt | string` as the first argument and optional `Mem0ConfigSettings` as the second.
|
||||
`retrieveMemories`, `getMemories`, and `searchMemories` accept `LanguageModelV3Prompt | string` as the first argument; `addMemories` is typed as `LanguageModelV3Prompt` (a string also works at runtime). All four take optional `Mem0ConfigSettings` as the second argument.
|
||||
|
||||
## Common Edge Cases and Tips
|
||||
|
||||
- **Always provide `user_id`** (or `agent_id`/`app_id`/`run_id`) for consistent memory retrieval. Without an entity identifier, memories cannot be scoped.
|
||||
- **Always provide `user_id`** (or `agent_id`/`app_id`/`run_id`) for consistent memory retrieval. The search endpoint requires at least one entity ID in `filters`; the provider places these IDs there for you.
|
||||
- **Standalone utilities require explicit API key**: pass `mem0ApiKey` in the config object, or set the `MEM0_API_KEY` environment variable.
|
||||
- **This uses Vercel AI SDK v5** (LanguageModelV2 / ProviderV2 interfaces). It is not compatible with AI SDK v3 or v4.
|
||||
- **`processMemories` fires `addMemories` as fire-and-forget** (`.then()` without `await`). Memory storage happens asynchronously and does not block the LLM response.
|
||||
- **The `"gemini"` alias** exists in the provider switch but is NOT in the `supportedProviders` list. Use `"google"` instead.
|
||||
- **This uses Vercel AI SDK v6** (LanguageModelV3 / ProviderV3 interfaces, `@mem0/vercel-ai-provider` 3.x). Provider 2.x targeted AI SDK v5. It is not compatible with AI SDK v4 or earlier.
|
||||
- **`processMemories` awaits `addMemories`** before searching and calling the LLM, so each wrapped call includes one memory write and one memory search. If either request fails, the error is logged and the LLM call proceeds without memories.
|
||||
- **`"google"` and `"gemini"`** are both accepted and map to `@ai-sdk/google`.
|
||||
- **Removed in 3.0.0**: `org_id`, `project_id`, `org_name`, `project_name`, `output_format`, `filter_memories`, `async_mode`, `enable_graph`, `version`, `api_version`. Graph memory is now a Mem0 Platform project setting, not a provider option.
|
||||
- **Default `top_k` is 10.** `threshold` and `rerank` are only sent when set (the API default for `rerank` is `false`; `threshold` is a server-side cutoff, not a floor on the returned score).
|
||||
- **Custom host**: set `host` in the config to point to a different Mem0 API endpoint (default: `https://api.mem0.ai`).
|
||||
|
||||
## References
|
||||
|
||||
@@ -24,7 +24,7 @@ await addMemories(
|
||||
|
||||
```typescript
|
||||
async function addMemories(
|
||||
messages: LanguageModelV2Prompt | string,
|
||||
messages: LanguageModelV3Prompt,
|
||||
config?: Mem0ConfigSettings
|
||||
): Promise<any>;
|
||||
```
|
||||
@@ -33,15 +33,16 @@ async function addMemories(
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|-----------|------|-------------|
|
||||
| `messages` | `LanguageModelV2Prompt \| string` | Messages to store. If a string, wrapped as `[{ role: "user", content: string }]` |
|
||||
| `messages` | `LanguageModelV3Prompt` | Messages to store. A plain string is also handled at runtime (wrapped as `[{ role: "user", content: string }]`) but is not part of the declared type |
|
||||
| `config` | `Mem0ConfigSettings` | Optional. Must include entity scope (`user_id`, etc.) and API key |
|
||||
|
||||
**Behavior:**
|
||||
1. If `messages` is a string, wraps it as a single user message
|
||||
2. Otherwise, converts `LanguageModelV2Prompt` to Mem0 format via `convertToMem0Format` (handles multimodal content)
|
||||
3. Calls `POST /v1/memories/` with the converted messages and config
|
||||
2. Otherwise, converts `LanguageModelV3Prompt` to Mem0 format via `convertToMem0Format` (maps multimodal parts, but the add endpoint rejects them with a 400)
|
||||
3. Calls `POST {host}/v3/memories/add/` with body `{ messages, user_id?, app_id?, agent_id?, run_id?, metadata?, infer? }` (entity IDs are top-level on add)
|
||||
4. Throws `HTTP error! status: <code>` on a non-2xx response
|
||||
|
||||
**Returns:** The API response from Mem0 (memory operation result).
|
||||
**Returns:** The parsed JSON response from Mem0. The v3 add endpoint queues extraction and responds with `{ status: "PENDING", event_id }` (the provider returns the raw REST JSON, so keys stay snake_case, unlike the `mem0ai` client). With `infer: false` messages are stored verbatim synchronously and the response also includes `results`.
|
||||
|
||||
---
|
||||
|
||||
@@ -63,7 +64,7 @@ const systemPrompt = await retrieveMemories("What restaurants do I like?", {
|
||||
|
||||
```typescript
|
||||
async function retrieveMemories(
|
||||
prompt: LanguageModelV2Prompt | string,
|
||||
prompt: LanguageModelV3Prompt | string,
|
||||
config?: Mem0ConfigSettings
|
||||
): Promise<string>;
|
||||
```
|
||||
@@ -72,13 +73,13 @@ async function retrieveMemories(
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|-----------|------|-------------|
|
||||
| `prompt` | `LanguageModelV2Prompt \| string` | The query to search memories for |
|
||||
| `prompt` | `LanguageModelV3Prompt \| string` | The query to search memories for |
|
||||
| `config` | `Mem0ConfigSettings` | Optional. Entity scope and API key |
|
||||
|
||||
**Behavior:**
|
||||
1. Flattens the prompt to a plain string (extracts text from `LanguageModelV2Prompt` parts)
|
||||
2. Calls `searchInternalMemories` (`POST /v2/memories/search/`)
|
||||
3. Formats each memory as `"Memory: {memory.memory}\n\n"`
|
||||
1. Flattens the prompt to a plain string (extracts text from `LanguageModelV3Prompt` parts)
|
||||
2. Calls `searchInternalMemories` (`POST /v3/memories/search/`)
|
||||
3. Accepts either a flat array or a `{ results: [...] }` response and formats each memory as `"Memory: {memory.memory}\n\n"`
|
||||
4. Wraps everything in a system prompt preamble
|
||||
|
||||
**Returns:** A **string** containing the formatted system prompt with embedded memories. Returns `""` (empty string) if no memories found.
|
||||
@@ -112,7 +113,7 @@ const memories = await getMemories("What are my preferences?", {
|
||||
|
||||
```typescript
|
||||
async function getMemories(
|
||||
prompt: LanguageModelV2Prompt | string,
|
||||
prompt: LanguageModelV3Prompt | string,
|
||||
config?: Mem0ConfigSettings
|
||||
): Promise<any>;
|
||||
```
|
||||
@@ -121,21 +122,21 @@ async function getMemories(
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|-----------|------|-------------|
|
||||
| `prompt` | `LanguageModelV2Prompt \| string` | The query to search memories for |
|
||||
| `prompt` | `LanguageModelV3Prompt \| string` | The query to search memories for |
|
||||
| `config` | `Mem0ConfigSettings` | Optional. Entity scope and API key |
|
||||
|
||||
**Behavior:**
|
||||
1. Flattens the prompt to a plain string
|
||||
2. Calls `searchInternalMemories` (`POST /v2/memories/search/`)
|
||||
3. Returns `memories.results` (the array of memory objects)
|
||||
2. Calls `searchInternalMemories` (`POST /v3/memories/search/`)
|
||||
3. Normalizes the response: returns the response itself if it is an array, otherwise `response.results` (or `[]`)
|
||||
|
||||
**Returns:** Memory object array.
|
||||
**Returns:** Flat memory object array.
|
||||
|
||||
---
|
||||
|
||||
## `searchMemories(prompt, config?)`
|
||||
|
||||
Retrieves the **full search API response** including results, relations, scores, and metadata.
|
||||
Retrieves the **raw search API response** including results, scores, and metadata.
|
||||
|
||||
```typescript
|
||||
import { searchMemories } from "@mem0/vercel-ai-provider";
|
||||
@@ -144,14 +145,14 @@ const response = await searchMemories("cooking preferences", {
|
||||
user_id: "alice",
|
||||
mem0ApiKey: "m0-xxx",
|
||||
});
|
||||
// Returns: { results: [{ memory: "...", score: 0.95, ... }], relations: [...] }
|
||||
// Returns: { results: [{ memory: "...", score: 0.95, ... }] }
|
||||
```
|
||||
|
||||
**Signature:**
|
||||
|
||||
```typescript
|
||||
async function searchMemories(
|
||||
prompt: LanguageModelV2Prompt | string,
|
||||
prompt: LanguageModelV3Prompt | string,
|
||||
config?: Mem0ConfigSettings
|
||||
): Promise<any>;
|
||||
```
|
||||
@@ -160,17 +161,17 @@ async function searchMemories(
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|-----------|------|-------------|
|
||||
| `prompt` | `LanguageModelV2Prompt \| string` | The query to search memories for |
|
||||
| `prompt` | `LanguageModelV3Prompt \| string` | The query to search memories for |
|
||||
| `config` | `Mem0ConfigSettings` | Optional. Entity scope and API key |
|
||||
|
||||
**Behavior:**
|
||||
1. Flattens the prompt to a plain string
|
||||
2. Calls `searchInternalMemories` (`POST /v2/memories/search/`)
|
||||
3. Returns the full response without any filtering
|
||||
2. Calls `searchInternalMemories` (`POST /v3/memories/search/`)
|
||||
3. Returns the response without any normalization
|
||||
|
||||
**Returns:** The complete API response object. On error, returns `[]`.
|
||||
**Returns:** The API response as-is (an object with `results`, or a flat array if the API returns one). On error, logs and returns `[]` instead of throwing (unlike the other utilities, which rethrow).
|
||||
|
||||
**Note:** Unlike `getMemories`, this always returns the full response.
|
||||
**Note:** Unlike `getMemories`, this does not unwrap `results`.
|
||||
|
||||
---
|
||||
|
||||
@@ -180,7 +181,7 @@ async function searchMemories(
|
||||
|----------|---------|----------|
|
||||
| `retrieveMemories` | Formatted system prompt **string** | Injecting directly into a `system` parameter for `generateText`/`streamText` |
|
||||
| `getMemories` | Memory **array** | Processing memories programmatically (filtering, transforming, counting) |
|
||||
| `searchMemories` | Full API **response** (results + relations) | Need relations, similarity scores, or complete metadata |
|
||||
| `searchMemories` | Raw API **response** | Need similarity scores or complete metadata |
|
||||
| `addMemories` | API response | Storing new conversation messages as memories |
|
||||
|
||||
## Internal: `searchInternalMemories(query, config?, top_k?)`
|
||||
@@ -191,25 +192,27 @@ Not exported. Used by all retrieval functions.
|
||||
async function searchInternalMemories(
|
||||
query: string,
|
||||
config?: Mem0ConfigSettings,
|
||||
top_k: number = 5
|
||||
top_k: number = 10
|
||||
): Promise<any>;
|
||||
```
|
||||
|
||||
**Behavior:**
|
||||
1. Builds a `filters` object from entity identifiers (`user_id`, `app_id`, `agent_id`, `run_id`)
|
||||
2. Resolves entity identifiers
|
||||
3. Loads the API key from `config.mem0ApiKey` or `MEM0_API_KEY` env var
|
||||
4. Calls `POST {host}/v2/memories/search/` with:
|
||||
1. Builds a `filters` object from `config.filters`, then sets `user_id`, `app_id`, `agent_id`, `run_id` on it when present (entity IDs go inside `filters`, never top-level)
|
||||
2. Loads the API key from `config.mem0ApiKey` or `MEM0_API_KEY` env var
|
||||
3. Calls `POST {host}/v3/memories/search/` with:
|
||||
- `query`: the search string
|
||||
- `filters`: the filter object with entity identifiers
|
||||
- `top_k`: from config or default 5
|
||||
- All other config fields spread into the request body
|
||||
- `top_k`: `config.top_k` or default 10 (an explicit `0` is respected)
|
||||
- `threshold`, `rerank`, `metadata`: only when set in config
|
||||
- No other config fields (`infer`, `page`, `page_size`, `host`, `mem0ApiKey`) are sent
|
||||
4. Sends `Authorization: Token <key>` plus `X-Mem0-Source: VERCEL_AI_SDK` and `X-Mem0-Client: mem0-vercel-ai-provider/<version>` headers
|
||||
5. Throws `HTTP error! status: <code>` on a non-2xx response
|
||||
|
||||
**Default host:** `https://api.mem0.ai`
|
||||
|
||||
## Internal: `convertToMem0Format(messages)`
|
||||
|
||||
Not exported. Used by `addMemories` to convert `LanguageModelV2Prompt` messages to Mem0's format.
|
||||
Not exported. Used by `addMemories` to convert `LanguageModelV3Prompt` messages to Mem0's format.
|
||||
|
||||
**Multimodal content mapping:**
|
||||
|
||||
@@ -223,6 +226,8 @@ Not exported. Used by `addMemories` to convert `LanguageModelV2Prompt` messages
|
||||
| MDX content | `{ type: "mdx_url", mdx_url: { url } }` or `{ type: "mdx", ... }` | MDX URL | `{ role, content: { type: "mdx_url", mdx_url: { url } } }` |
|
||||
| PDF content | `{ type: "pdf_url", pdf_url: { url } }` or `{ type: "pdf", ... }` | PDF URL | `{ role, content: { type: "pdf_url", pdf_url: { url } } }` |
|
||||
|
||||
`/v3/memories/add/` rejects structured (non-string) `content` with a 400 `Not a valid string.` (live-tested on the Python SDK with `infer` true and false), so a prompt containing these parts is expected to fail with `HTTP error! status: 400` (checked against the endpoint, not through the provider). Only text parts are storable.
|
||||
|
||||
The function handles three message content shapes:
|
||||
1. **String content**: passed through directly
|
||||
2. **Array content**: each element mapped individually, nulls filtered out
|
||||
@@ -230,7 +235,7 @@ The function handles three message content shapes:
|
||||
|
||||
## Internal: `flattenPrompt(prompt)`
|
||||
|
||||
Not exported. Extracts plain text from `LanguageModelV2Prompt` for use as a search query.
|
||||
Not exported. Extracts plain text from `LanguageModelV3Prompt` for use as a search query.
|
||||
|
||||
- Iterates over prompt parts, extracting text from `user` role messages
|
||||
- For `text` type content: extracts `.text`
|
||||
@@ -249,12 +254,12 @@ All fields are optional. Used across all utility functions.
|
||||
| `agent_id` | `string` | -- | Scope memories to an agent |
|
||||
| `run_id` | `string` | -- | Scope memories to a session/run |
|
||||
| `metadata` | `Record<string, any>` | -- | Custom metadata |
|
||||
| `filters` | `Record<string, any>` | -- | Custom search filters |
|
||||
| `infer` | `boolean` | -- | Enable inference |
|
||||
| `page` | `number` | -- | Pagination page number |
|
||||
| `page_size` | `number` | -- | Results per page |
|
||||
| `filters` | `Record<string, any>` | -- | Custom search filters (entity IDs above are merged in and win on conflicts) |
|
||||
| `infer` | `boolean` | -- | Sent on add only. `false` stores messages verbatim without extraction |
|
||||
| `page` | `number` | -- | Declared in the type, not sent by the provider |
|
||||
| `page_size` | `number` | -- | Declared in the type, not sent by the provider |
|
||||
| `mem0ApiKey` | `string` | `MEM0_API_KEY` env | Mem0 API key |
|
||||
| `top_k` | `number` | `5` | Number of memories to retrieve |
|
||||
| `threshold` | `number` | -- | Minimum similarity score |
|
||||
| `rerank` | `boolean` | -- | Enable re-ranking |
|
||||
| `top_k` | `number` | `10` | Number of memories to retrieve |
|
||||
| `threshold` | `number` | -- | Server-side relevance cutoff, not a floor on the returned score; sent only when set |
|
||||
| `rerank` | `boolean` | -- (API default `false`) | Enable re-ranking, sent only when set |
|
||||
| `host` | `string` | `https://api.mem0.ai` | Custom API host |
|
||||
|
||||
@@ -25,26 +25,26 @@ When called with no arguments, defaults to `{ provider: "openai" }`.
|
||||
|
||||
## `Mem0Provider` Interface
|
||||
|
||||
Implements `ProviderV2` from `@ai-sdk/provider`.
|
||||
Implements `ProviderV3` from `@ai-sdk/provider` (`specificationVersion: "v3"`, AI SDK v6).
|
||||
|
||||
```typescript
|
||||
interface Mem0Provider extends ProviderV2 {
|
||||
interface Mem0Provider extends ProviderV3 {
|
||||
// Call directly as a function
|
||||
(modelId: Mem0ChatModelId, settings?: Mem0ChatSettings): LanguageModelV2;
|
||||
(modelId: Mem0ChatModelId, settings?: Mem0ChatSettings): LanguageModelV3;
|
||||
|
||||
// Or use named methods
|
||||
chat(modelId: Mem0ChatModelId, settings?: Mem0ChatSettings): LanguageModelV2;
|
||||
completion(modelId: Mem0ChatModelId, settings?: Mem0ChatSettings): LanguageModelV2;
|
||||
languageModel(modelId: Mem0ChatModelId, settings?: Mem0ChatSettings): LanguageModelV2;
|
||||
chat(modelId: Mem0ChatModelId, settings?: Mem0ChatSettings): LanguageModelV3;
|
||||
completion(modelId: Mem0ChatModelId, settings?: Mem0ChatSettings): LanguageModelV3;
|
||||
languageModel(modelId: Mem0ChatModelId, settings?: Mem0ChatSettings): LanguageModelV3;
|
||||
}
|
||||
```
|
||||
|
||||
- **Direct call** (`mem0("gpt-5-mini", {...})`): creates a generic language model (neither chat nor completion mode forced).
|
||||
- **`chat()`**: creates a model with `modelType: "chat"` (note: in the current source, the chat constructor sets `modelType: "completion"` -- this appears to be a bug; functionally equivalent to `completion()` at present).
|
||||
- **`chat()`**: creates a model with `modelType: "chat"`.
|
||||
- **`completion()`**: creates a model with `modelType: "completion"`.
|
||||
- **`languageModel()`**: alias for the generic model (same as direct call).
|
||||
|
||||
All three return a `Mem0GenericLanguageModel` instance implementing `LanguageModelV2`.
|
||||
All three return a `Mem0GenericLanguageModel` instance implementing `LanguageModelV3`.
|
||||
|
||||
## `Mem0ProviderSettings` Interface
|
||||
|
||||
@@ -52,14 +52,14 @@ Configuration passed to `createMem0()`.
|
||||
|
||||
```typescript
|
||||
interface Mem0ProviderSettings {
|
||||
baseURL?: string; // Base URL for the LLM provider (default: "http://api.openai.com")
|
||||
headers?: Record<string, string>; // Custom headers for LLM requests
|
||||
baseURL?: string; // Stored on the model config (default: "https://api.openai.com"), not applied to upstream LLM requests
|
||||
headers?: Record<string, string | undefined>; // Stored on the model config, not applied to upstream LLM requests
|
||||
provider?: string; // LLM provider name (default: "openai")
|
||||
mem0ApiKey?: string; // Mem0 Platform API key (or use MEM0_API_KEY env var)
|
||||
apiKey?: string; // LLM provider API key (e.g., OpenAI key)
|
||||
mem0Config?: Mem0Config; // Default Mem0 config (user_id, etc.) applied to all calls
|
||||
config?: LLMProviderSettings; // Provider-specific settings (OpenAI, Anthropic, etc.)
|
||||
fetch?: typeof fetch; // Custom fetch implementation (for testing/middleware)
|
||||
fetch?: typeof fetch; // Stored on the model config, not used by the upstream LLM client or Mem0 API calls
|
||||
generateId?: () => string; // Custom ID generator (internal use)
|
||||
name?: string; // Provider instance name
|
||||
modelType?: "completion" | "chat"; // Force model type
|
||||
@@ -75,7 +75,7 @@ interface Mem0ProviderSettings {
|
||||
| `apiKey` | LLM provider API key | `"sk-xxx"` (OpenAI), `"sk-ant-xxx"` (Anthropic) |
|
||||
| `mem0Config` | Default Mem0 settings for all calls | `{ user_id: "alice" }` |
|
||||
| `config` | Provider-specific SDK settings | `{ organization: "org-xxx" }` for OpenAI |
|
||||
| `baseURL` | Override LLM provider base URL | `"https://my-proxy.example.com"` |
|
||||
| `config.baseURL` | Override LLM provider base URL (put it inside `config`; the top-level `baseURL` does not reach the upstream client) | `{ baseURL: "https://my-proxy.example.com/v1" }` |
|
||||
|
||||
## `mem0` Singleton
|
||||
|
||||
@@ -94,7 +94,7 @@ Equivalent to `createMem0()` with no arguments.
|
||||
|
||||
## `Mem0ConfigSettings` Interface
|
||||
|
||||
Configuration for memory operations. Used as `Mem0ChatSettings` (per-call) or `Mem0Config` (provider-level default). All fields are optional.
|
||||
Configuration for memory operations. Used as `Mem0ChatSettings` (per-call) or `Mem0Config` (provider-level default; same shape, not exported from the package entry point). All fields are optional.
|
||||
|
||||
```typescript
|
||||
interface Mem0ConfigSettings {
|
||||
@@ -104,13 +104,13 @@ interface Mem0ConfigSettings {
|
||||
run_id?: string; // Scope memories to a specific run/session
|
||||
metadata?: Record<string, any>; // Custom metadata attached to memories
|
||||
filters?: Record<string, any>; // Custom filters for memory search
|
||||
infer?: boolean; // Enable inference during memory operations
|
||||
page?: number; // Pagination: page number
|
||||
page_size?: number; // Pagination: results per page
|
||||
infer?: boolean; // Sent on add only: false stores messages verbatim without extraction
|
||||
page?: number; // Declared in the type, not sent by the provider
|
||||
page_size?: number; // Declared in the type, not sent by the provider
|
||||
mem0ApiKey?: string; // Mem0 API key (overrides provider-level key)
|
||||
top_k?: number; // Number of memories to retrieve (default: 5)
|
||||
threshold?: number; // Minimum similarity score for retrieval (default: 0.1)
|
||||
rerank?: boolean; // Enable re-ranking of search results (default: false)
|
||||
top_k?: number; // Number of memories to retrieve (default: 10)
|
||||
threshold?: number; // Server-side relevance cutoff; sent only when set
|
||||
rerank?: boolean; // Enable re-ranking of search results; sent only when set (API default: false)
|
||||
host?: string; // Custom Mem0 API host (default: "https://api.mem0.ai")
|
||||
}
|
||||
```
|
||||
@@ -137,17 +137,18 @@ mem0("gpt-5-mini", { user_id: "alice" })
|
||||
|
||||
## `LLMProviderSettings` Type
|
||||
|
||||
Union of provider-specific settings. Extends all supported provider setting interfaces:
|
||||
Union of provider-specific settings for all supported provider SDKs:
|
||||
|
||||
```typescript
|
||||
interface LLMProviderSettings extends
|
||||
OpenAIProviderSettings,
|
||||
AnthropicProviderSettings,
|
||||
CohereProviderSettings,
|
||||
GroqProviderSettings {}
|
||||
type LLMProviderSettings =
|
||||
| OpenAIProviderSettings
|
||||
| AnthropicProviderSettings
|
||||
| CohereProviderSettings
|
||||
| GroqProviderSettings
|
||||
| GoogleGenerativeAIProviderSettings;
|
||||
```
|
||||
|
||||
Pass via the `config` field of `Mem0ProviderSettings` to forward settings to the underlying LLM provider SDK.
|
||||
Pass via the `config` field of `Mem0ProviderSettings` to forward settings (e.g., `baseURL`, `headers`, `apiKey`) to the underlying LLM provider SDK. `config` is spread after `apiKey`, so a `config.apiKey` takes precedence.
|
||||
|
||||
## Provider Selection: `Mem0ClassSelector`
|
||||
|
||||
@@ -155,12 +156,12 @@ Internal class that maps the `provider` string to the correct AI SDK provider.
|
||||
|
||||
```typescript
|
||||
class Mem0ClassSelector {
|
||||
static supportedProviders = ["openai", "anthropic", "cohere", "groq", "google"];
|
||||
static supportedProviders = ["openai", "anthropic", "cohere", "groq", "google", "gemini"];
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
**Important:** The `"gemini"` alias exists in the provider switch statement (maps to `createGoogleGenerativeAI`) but is **NOT** in the `supportedProviders` list. The constructor validates against `supportedProviders`, so using `"gemini"` will throw `"Model not supported: gemini"`. Use `"google"` instead.
|
||||
`"gemini"` is an alias of `"google"` (both map to `createGoogleGenerativeAI`). Any other value throws `"Model not supported: <value>"`.
|
||||
|
||||
### Provider mapping
|
||||
|
||||
@@ -170,7 +171,7 @@ class Mem0ClassSelector {
|
||||
| `"anthropic"` | `@ai-sdk/anthropic` | `createAnthropic` |
|
||||
| `"cohere"` | `@ai-sdk/cohere` | `createCohere` |
|
||||
| `"groq"` | `@ai-sdk/groq` | `createGroq` |
|
||||
| `"google"` | `@ai-sdk/google` | `createGoogleGenerativeAI` |
|
||||
| `"google"` or `"gemini"` | `@ai-sdk/google` | `createGoogleGenerativeAI` |
|
||||
|
||||
## `Mem0` Facade Class
|
||||
|
||||
@@ -184,7 +185,7 @@ const chatModel = mem0.chat("gpt-5-mini", { user_id: "alice" });
|
||||
const completionModel = mem0.completion("gpt-5-mini");
|
||||
```
|
||||
|
||||
The facade defaults its base URL to `"http://127.0.0.1:11434/api"` (Ollama-style) rather than `"http://api.openai.com"`. It always uses `"openai"` as the provider for created models.
|
||||
The facade defaults its base URL to `"https://api.openai.com"`. It always uses `"openai"` as the provider for created models, and only stores `baseURL` and `headers` from its options: the `provider`, `mem0ApiKey`, and `apiKey` options are ignored, so `MEM0_API_KEY` and `OPENAI_API_KEY` must come from the environment. Prefer `createMem0` for anything beyond a quick start.
|
||||
|
||||
**Methods:**
|
||||
- `chat(modelId, settings?)` -- creates a model with `modelType: "chat"`
|
||||
@@ -192,13 +193,11 @@ The facade defaults its base URL to `"http://127.0.0.1:11434/api"` (Ollama-style
|
||||
|
||||
## `Mem0GenericLanguageModel` Class
|
||||
|
||||
The core class implementing `LanguageModelV2`. Created by `createMem0` or the `Mem0` facade.
|
||||
The core class implementing `LanguageModelV3`. Created by `createMem0` or the `Mem0` facade.
|
||||
|
||||
```typescript
|
||||
class Mem0GenericLanguageModel implements LanguageModelV2 {
|
||||
readonly specificationVersion = "v2";
|
||||
readonly defaultObjectGenerationMode = "json";
|
||||
readonly supportsImageUrls = false;
|
||||
class Mem0GenericLanguageModel implements LanguageModelV3 {
|
||||
readonly specificationVersion = "v3";
|
||||
readonly supportedUrls: Record<string, RegExp[]> = { '*': [/.*/] };
|
||||
|
||||
provider: string; // e.g., "openai"
|
||||
@@ -206,22 +205,26 @@ class Mem0GenericLanguageModel implements LanguageModelV2 {
|
||||
settings: Mem0ChatSettings;
|
||||
config: Mem0ChatConfig;
|
||||
|
||||
async doGenerate(options: LanguageModelV2CallOptions): Promise<...>;
|
||||
async doStream(options: LanguageModelV2CallOptions): Promise<...>;
|
||||
async doGenerate(options: LanguageModelV3CallOptions): Promise<...>;
|
||||
async doStream(options: LanguageModelV3CallOptions): Promise<...>;
|
||||
}
|
||||
```
|
||||
|
||||
`defaultObjectGenerationMode` and `supportsImageUrls` (V2 properties) no longer exist.
|
||||
|
||||
Both `doGenerate` and `doStream` follow the same internal flow:
|
||||
|
||||
1. Build `Mem0ConfigSettings` from `config.mem0Config` merged with `settings`
|
||||
1. Build `Mem0ConfigSettings` from `config.mem0ApiKey`, then `config.mem0Config`, then `settings` (later entries win)
|
||||
2. Call `processMemories`:
|
||||
- Fire `addMemories` as fire-and-forget (no await, `.then().catch()`)
|
||||
- Await `getMemories` to retrieve relevant memories
|
||||
- Format memories as a system message and prepend to the prompt
|
||||
- Await `addMemories` (errors are logged and ignored)
|
||||
- Await `getMemories` to retrieve relevant memories (on failure, continue with no memories)
|
||||
- If any memories were found, format them as a system message and prepend it to a copy of the prompt
|
||||
3. Create the underlying LLM model via `Mem0ClassSelector`
|
||||
4. Delegate to the underlying model's `doGenerate` or `doStream`
|
||||
5. Return the result
|
||||
|
||||
`doGenerate` additionally appends a `source` content part (`title: "Mem0 Memories"`) with `providerMetadata.mem0.memories` and `providerMetadata.mem0.memoriesText` when memories were retrieved. `doStream` returns the underlying stream result unchanged (no Mem0 source) and throws `"Streaming failed or method not implemented."` if streaming setup fails.
|
||||
|
||||
**Note:** Entity identifier fields use snake_case (`user_id`, `app_id`, `agent_id`, `run_id`) to match the Mem0 API.
|
||||
|
||||
## Type: `Mem0ChatModelId`
|
||||
@@ -230,4 +233,4 @@ Both `doGenerate` and `doStream` follow the same internal flow:
|
||||
type Mem0ChatModelId = string & NonNullable<unknown>;
|
||||
```
|
||||
|
||||
Any non-null string. The model ID is passed through to the underlying provider (e.g., `"gpt-5-mini"`, `"gemini-pro"`).
|
||||
Any non-null string. The model ID is passed through to the underlying provider (e.g., `"gpt-5-mini"`, `"gemini-2.5-flash"`).
|
||||
|
||||
@@ -20,7 +20,7 @@ const { text } = await generateText({
|
||||
console.log(text);
|
||||
```
|
||||
|
||||
Memories are automatically retrieved before the call and stored after.
|
||||
The prompt is stored to Mem0 and relevant memories are retrieved before the LLM call (see section 8).
|
||||
|
||||
## 2. Wrapped Model with streamText (Streaming)
|
||||
|
||||
@@ -42,7 +42,7 @@ for await (const chunk of result.textStream) {
|
||||
}
|
||||
```
|
||||
|
||||
Memory retrieval happens before streaming begins. The conversation is stored to Mem0 as a fire-and-forget call (non-blocking).
|
||||
The add request and the memory search both finish before streaming begins (extraction itself is async). The Mem0 source (`sources`) is only attached by `generateText`, not by streaming.
|
||||
|
||||
## 3. Standalone Utilities with OpenAI
|
||||
|
||||
@@ -136,7 +136,7 @@ console.log(object);
|
||||
// { breakfast: "Avocado toast (you mentioned loving it)", lunch: "...", ... }
|
||||
```
|
||||
|
||||
The `defaultObjectGenerationMode` is `"json"`, so structured output works out of the box.
|
||||
The wrapped model forwards all call options (including the response format) to the underlying provider, so structured output works out of the box. `generateObject` is deprecated in AI SDK v6 in favor of `generateText` with `output: Output.object({ schema })`; both go through the same wrapped model.
|
||||
|
||||
## 6. Multi-Provider Setup
|
||||
|
||||
@@ -195,22 +195,20 @@ A POST handler that uses the wrapped model in a Next.js App Router API route.
|
||||
|
||||
```typescript
|
||||
// app/api/chat/route.ts
|
||||
import { streamText } from "ai";
|
||||
import { convertToModelMessages, streamText, UIMessage } from "ai";
|
||||
import { createMem0 } from "@mem0/vercel-ai-provider";
|
||||
|
||||
const mem0 = createMem0();
|
||||
|
||||
export async function POST(req: Request) {
|
||||
const { messages, user_id } = await req.json();
|
||||
|
||||
const lastMessage = messages[messages.length - 1];
|
||||
const { messages, user_id }: { messages: UIMessage[]; user_id: string } = await req.json();
|
||||
|
||||
const result = streamText({
|
||||
model: mem0("gpt-5-mini", { user_id }),
|
||||
prompt: lastMessage.content,
|
||||
messages: await convertToModelMessages(messages),
|
||||
});
|
||||
|
||||
return result.toDataStreamResponse();
|
||||
return result.toUIMessageStreamResponse();
|
||||
}
|
||||
```
|
||||
|
||||
@@ -219,22 +217,25 @@ export async function POST(req: Request) {
|
||||
```typescript
|
||||
// app/api/chat/route.ts
|
||||
import { openai } from "@ai-sdk/openai";
|
||||
import { streamText } from "ai";
|
||||
import { convertToModelMessages, streamText, UIMessage } from "ai";
|
||||
import { retrieveMemories, addMemories } from "@mem0/vercel-ai-provider";
|
||||
|
||||
export async function POST(req: Request) {
|
||||
const { messages, user_id } = await req.json();
|
||||
const { messages, user_id }: { messages: UIMessage[]; user_id: string } = await req.json();
|
||||
const lastMessage = messages[messages.length - 1];
|
||||
const lastText = lastMessage.parts
|
||||
.flatMap((part) => (part.type === "text" ? [part.text] : []))
|
||||
.join(" ");
|
||||
|
||||
// Retrieve relevant memories
|
||||
const memories = await retrieveMemories(lastMessage.content, {
|
||||
const memories = await retrieveMemories(lastText, {
|
||||
user_id,
|
||||
});
|
||||
|
||||
// Stream the response
|
||||
const result = streamText({
|
||||
model: openai("gpt-5-mini"),
|
||||
prompt: lastMessage.content,
|
||||
messages: await convertToModelMessages(messages),
|
||||
system: memories,
|
||||
});
|
||||
|
||||
@@ -242,14 +243,14 @@ export async function POST(req: Request) {
|
||||
result.text.then(async (text) => {
|
||||
await addMemories(
|
||||
[
|
||||
{ role: "user", content: [{ type: "text", text: lastMessage.content }] },
|
||||
{ role: "user", content: [{ type: "text", text: lastText }] },
|
||||
{ role: "assistant", content: [{ type: "text", text }] },
|
||||
],
|
||||
{ user_id }
|
||||
);
|
||||
});
|
||||
|
||||
return result.toDataStreamResponse();
|
||||
return result.toUIMessageStreamResponse();
|
||||
}
|
||||
```
|
||||
|
||||
@@ -260,25 +261,26 @@ export async function POST(req: Request) {
|
||||
```
|
||||
1. doGenerate(options) or doStream(options) is called
|
||||
2. processMemories(messagesPrompts, mem0Config):
|
||||
a. addMemories(messagesPrompts, mem0Config)
|
||||
--> fire-and-forget: .then().catch(), NO await
|
||||
a. await addMemories(messagesPrompts, mem0Config)
|
||||
--> POST /v3/memories/add/ with converted messages
|
||||
--> errors are caught and logged
|
||||
b. await getMemories(messagesPrompts, mem0Config)
|
||||
--> POST /v3/memories/search/ with flattened prompt
|
||||
--> returns memory array
|
||||
c. Format memories into system message string
|
||||
d. Prepend system message to messagesPrompts array
|
||||
d. If memories were found, prepend the system message to a copy of messagesPrompts
|
||||
e. Return { memories, messagesPrompts }
|
||||
3. Create underlying LLM via Mem0ClassSelector.createProvider()
|
||||
4. Call model.doGenerate(updatedOptions) or model.doStream(updatedOptions)
|
||||
5. Return result
|
||||
5. doGenerate appends the "Mem0 Memories" source when memories were found
|
||||
6. Return result
|
||||
```
|
||||
|
||||
**Critical detail:** The `addMemories` call in step 2a is **NON-BLOCKING**. It uses `.then().catch()` without `await`, meaning:
|
||||
- Memory storage happens asynchronously in the background
|
||||
- The LLM response is not delayed by the memory write
|
||||
- If the memory write fails, it logs an error but does not affect the response
|
||||
- There is a brief window where the latest conversation is not yet stored
|
||||
**Critical detail:** The `addMemories` call in step 2a is **awaited**, meaning:
|
||||
- The add request is sent (and awaited) before the search and the LLM call, but extraction is async (`/v3/memories/add/` only queues the work and returns `PENDING`), so facts from the current prompt are usually not searchable until a later call
|
||||
- Each wrapped call adds one Mem0 write and one Mem0 search of latency before the LLM starts
|
||||
- If the memory write fails, it logs an error and the call continues
|
||||
- `messagesPrompts` is the full prompt (all roles, including earlier turns), so every call sends the entire conversation to the add endpoint
|
||||
|
||||
### Memory injection format
|
||||
|
||||
@@ -318,8 +320,8 @@ const memories = await retrieveMemories(prompt, {
|
||||
const mem0 = createMem0();
|
||||
const model = mem0("gpt-5-mini", {
|
||||
user_id: "alice",
|
||||
top_k: 10, // retrieve up to 10 memories (default: 5)
|
||||
threshold: 0.8, // only memories with score >= 0.8
|
||||
top_k: 20, // retrieve up to 20 memories (default: 10)
|
||||
threshold: 0.8, // server-side cutoff applied before score blending
|
||||
rerank: true, // enable re-ranking of results
|
||||
});
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user