fix: update skills and docs (#4868)

This commit is contained in:
Kartik
2026-04-18 11:42:37 +05:30
committed by GitHub
parent c1c5bd62f6
commit 93da5ef8f7
23 changed files with 461 additions and 662 deletions
+17 -8
View File
@@ -15,10 +15,10 @@ description: >
license: Apache-2.0
metadata:
author: mem0ai
version: "2.0.0"
version: "3.0.0"
category: ai-memory
tags: "memory, personalization, ai, python, typescript, vector-search"
compatibility: Requires Python 3.10+ or Node.js 18+, pip install mem0ai or npm install mem0ai, MEM0_API_KEY env var (Platform), and internet access to api.mem0.ai
compatibility: Requires Python 3.10+ or Node.js 18+, pip install mem0ai or npm install mem0ai, MEM0_API_KEY env var (Platform), and internet access to api.mem0.ai. SDK v3 with v2 compatibility mode available.
---
# Mem0 Platform Integration
@@ -77,14 +77,14 @@ client.add(messages, user_id="alice")
### Search memories
```python
results = client.search("dietary preferences", user_id="alice")
results = client.search("dietary preferences", filters={"user_id": "alice"})
for mem in results.get("results", []):
print(mem["memory"])
```
### Get all memories
```python
all_memories = client.get_all(user_id="alice")
all_memories = client.get_all(filters={"user_id": "alice"})
```
### Update a memory
@@ -109,12 +109,12 @@ openai = OpenAI()
def chat(user_input: str, user_id: str) -> str:
# 1. Retrieve relevant memories
memories = mem0.search(user_input, user_id=user_id)
memories = mem0.search(user_input, filters={"user_id": user_id})
context = "\n".join([m["memory"] for m in memories.get("results", [])])
# 2. Generate response with memory context
response = openai.chat.completions.create(
model="gpt-4.1-nano-2025-04-14",
model="gpt-5-mini",
messages=[
{"role": "system", "content": f"User context:\n{context}"},
{"role": "user", "content": user_input},
@@ -132,11 +132,20 @@ def chat(user_input: str, user_id: str) -> str:
## Common edge cases
- **Search returns empty:** Memories process asynchronously. Wait 2-3s after `add()` before searching. Also verify `user_id` matches exactly (case-sensitive).
- **Search returns empty:** Memories process asynchronously. Wait 2-3s after `add()` before searching. Also verify `user_id` matches exactly (case-sensitive) and use `filters={"user_id": "..."}` syntax.
- **AND filter with user_id + agent_id returns empty:** Entities are stored separately. Use `OR` instead, or query separately.
- **Duplicate memories:** Don't mix `infer=True` (default) and `infer=False` for the same data. Stick to one mode.
- **Wrong import:** Always use `from mem0 import MemoryClient` (or `AsyncMemoryClient` for async). Do not use `from mem0 import Memory`.
- **Immutable memories:** Cannot be updated or deleted once created. Use `client.history(memory_id)` to track changes over time.
- **v3 defaults:** `top_k=20`, `threshold=0.1`, `rerank=False`. Adjust as needed for your use case.
## v2 Compatibility
If you're using SDK v2.x, note these differences:
- **Entity IDs:** Pass `user_id` as top-level kwarg to `search()` instead of inside `filters`
- **Defaults:** `top_k=100`, no threshold, `rerank=True`
- **Graph memory:** Available via `enable_graph=True`
See the [migration guide](https://docs.mem0.ai/migration/oss-v2-to-v3) for details.
## Live documentation search
+18 -14
View File
@@ -46,18 +46,16 @@ Both read from `MEM0_API_KEY` env var if no key provided.
```python
# Python: kwargs
client.add(messages, user_id="alice", metadata={"source": "chat"})
client.search("query", user_id="alice", top_k=5, rerank=True)
client.search("query", filters={"user_id": "alice"}, top_k=5, rerank=True)
```
```typescript
// TypeScript: options object
await client.add(messages, { user_id: 'alice', metadata: { source: 'chat' } });
await client.search('query', { user_id: 'alice', top_k: 5, rerank: true });
// TypeScript: options object with camelCase for top-level params, snake_case for filter keys
await client.add(messages, { userId: 'alice', metadata: { source: 'chat' } });
await client.search('query', { filters: { user_id: 'alice' }, topK: 5, rerank: true });
```
**Important:** Both use `snake_case` for API parameter names (`user_id`, `agent_id`, `top_k`, etc.). Only method names differ.
Exception: OSS TypeScript uses `camelCase` for config params (`userId`, `agentId`, `runId`).
**v3:** Python uses `snake_case` everywhere. TypeScript uses `camelCase` for top-level params (`userId`, `topK`) but `snake_case` for filter keys (`user_id`, `agent_id`).
## Architectural Differences
@@ -97,10 +95,8 @@ These methods exist in Python but not TypeScript:
| Python config key | TypeScript config key |
|-------------------|----------------------|
| `vector_store` | `vectorStore` |
| `graph_store` | `graphStore` |
| `history_db_path` | `historyDbPath` |
| `custom_instructions` | `customInstructions` |
| `enable_graph` | `enableGraph` |
## OSS Scope Parameter Naming
@@ -110,16 +106,24 @@ These methods exist in Python but not TypeScript:
| `agent_id="bot"` | `agentId: 'bot'` |
| `run_id="session"` | `runId: 'session'` |
## Entity ID Passing (v3)
| Method | Python | TypeScript |
|--------|--------|------------|
| add() | Top-level: `user_id="alice"` | Top-level: `{ userId: 'alice' }` |
| search() | In filters: `filters={"user_id": "alice"}` | In filters: `{ filters: { user_id: 'alice' } }` |
| get_all() | In filters: `filters={"user_id": "alice"}` | In filters: `{ filters: { user_id: 'alice' } }` |
## Common Gotcha
When searching/filtering, **both SDKs use `snake_case`** for filter keys:
When searching/filtering, both Python and TypeScript use `snake_case` for filter keys. TypeScript only uses `camelCase` for top-level method parameters:
```python
# Python
filters = {"AND": [{"user_id": "alice"}, {"categories": {"contains": "health"}}]}
# Python - snake_case in filters
results = client.search("query", filters={"user_id": "alice"})
```
```typescript
// TypeScript -- same snake_case in filter objects!
const filters = { AND: [{ user_id: 'alice' }, { categories: { contains: 'health' } }] };
// TypeScript - snake_case in filters, camelCase for top-level params
const results = await client.search('query', { filters: { user_id: 'alice' }, topK: 20 });
```
+75 -69
View File
@@ -41,23 +41,18 @@ const messages = [
{ role: 'user', content: "I'm a vegetarian and allergic to nuts." },
{ role: 'assistant', content: "Got it! I'll remember that." },
];
await client.add(messages, { user_id: 'alice' });
await client.add(messages, { userId: 'alice' });
```
| Parameter | Type | Description |
|-----------|------|-------------|
| `messages` | `Message[]` | Array of `{role, content}` objects |
| `options.user_id` | string | User identifier |
| `options.agent_id` | string | Agent identifier |
| `options.app_id` | string | Application identifier |
| `options.run_id` | string | Session identifier |
| `options.userId` | string | User identifier |
| `options.agentId` | string | Agent identifier |
| `options.appId` | string | Application identifier |
| `options.runId` | string | Session identifier |
| `options.metadata` | object | Custom key-value pairs |
| `options.enable_graph` | boolean | Activate knowledge graph |
| `options.infer` | boolean | If false, store raw text (default: true) |
| `options.immutable` | boolean | Prevent future modification |
| `options.expiration_date` | string | Auto-expiry (`YYYY-MM-DD`) |
| `options.includes` | string | Preference filter for inclusion |
| `options.excludes` | string | Preference filter for exclusion |
**Returns:** `Promise<any>` -- list of events
@@ -66,7 +61,7 @@ await client.add(messages, { user_id: 'alice' });
Search memories by semantic similarity.
```typescript
const results = await client.search('dietary preferences', { user_id: 'alice' });
const results = await client.search('dietary preferences', { filters: { user_id: 'alice' }, topK: 20 });
for (const mem of results.results) {
console.log(mem.memory, mem.score);
}
@@ -75,17 +70,12 @@ for (const mem of results.results) {
| Parameter | Type | Description |
|-----------|------|-------------|
| `query` | string | Natural language search query |
| `options.user_id` | string | Filter by user |
| `options.agent_id` | string | Filter by agent |
| `options.filters` | object | V2 filter object (`AND`/`OR`/`NOT`) |
| `options.top_k` | number | Number of results (default: 10) |
| `options.rerank` | boolean | Enable semantic reranking |
| `options.threshold` | number | Minimum similarity (default: 0.3) |
| `options.keyword_search` | boolean | Enable keyword search |
| `options.enable_graph` | boolean | Include graph relations |
| `options.filter_memories` | boolean | Precision filtering |
| `options.filters` | object | Filter object with entity IDs (`user_id`, `agent_id`, etc.) and/or `AND`/`OR`/`NOT` conditions |
| `options.topK` | number | Number of results (default: 20) |
| `options.rerank` | boolean | Enable semantic reranking (default: false) |
| `options.threshold` | number | Minimum similarity (default: 0.1) |
**Returns:** `Promise<SearchResult>` -- `{results: [{id, memory, score, ...}], relations: [...]}`
**Returns:** `Promise<SearchResult>` -- `{results: [{id, memory, score, ...}]}`
#### get(memoryId)
@@ -98,7 +88,7 @@ const memory = await client.get('ea925981-...');
Retrieve all memories. Requires at least one entity identifier in filters.
```typescript
const memories = await client.getAll({ user_id: 'alice' });
const memories = await client.getAll({ filters: { user_id: 'alice' } });
// With filters
const filtered = await client.getAll({
filters: { AND: [{ user_id: 'alice' }, { categories: { contains: 'health' } }] },
@@ -107,11 +97,9 @@ const filtered = await client.getAll({
| Parameter | Type | Description |
|-----------|------|-------------|
| `options.user_id` | string | Filter by user |
| `options.filters` | object | V2 filter object |
| `options.filters` | object | Filter object with entity IDs (`user_id`, `agent_id`, etc.) and/or `AND`/`OR`/`NOT` conditions |
| `options.page` | number | Page number |
| `options.page_size` | number | Results per page |
| `options.enable_graph` | boolean | Include graph relations |
| `options.pageSize` | number | Results per page |
#### update(memoryId, data)
@@ -136,14 +124,14 @@ await client.delete('ea925981-...');
#### deleteAll(options?)
```typescript
await client.deleteAll({ user_id: 'alice' });
await client.deleteAll({ userId: 'alice' });
```
#### history(memoryId)
```typescript
const history = await client.history('ea925981-...');
// Returns: [{previous_value, new_value, action, timestamps}]
// Returns: [{previousValue, newValue, action, timestamps}]
```
---
@@ -179,8 +167,8 @@ const users = await client.users();
#### deleteUser(data) / deleteUsers(data)
```typescript
await client.deleteUser({ user_id: 'alice' }); // Single entity
await client.deleteUsers({ agent_id: 'bot-1' }); // Flexible
await client.deleteUser({ userId: 'alice' }); // Single entity
await client.deleteUsers({ agentId: 'bot-1' }); // Flexible
```
---
@@ -189,13 +177,12 @@ await client.deleteUsers({ agent_id: 'bot-1' }); // Flexible
```typescript
// Get project config
const config = await client.getProject({ fields: ['custom_categories'] });
const config = await client.getProject({ fields: ['customCategories'] });
// Update project settings
await client.updateProject({
custom_instructions: 'Extract dietary preferences and health info',
custom_categories: [{ health: 'Medical and dietary info' }],
enable_graph: true,
customInstructions: 'Extract dietary preferences and health info',
customCategories: [{ health: 'Medical and dietary info' }],
});
```
@@ -205,25 +192,25 @@ await client.updateProject({
```typescript
// List
const webhooks = await client.getWebhooks({ project_id: 'proj_123' });
const webhooks = await client.getWebhooks({ projectId: 'proj_123' });
// Create
const webhook = await client.createWebhook({
url: 'https://your-app.com/webhook',
name: 'Memory Logger',
project_id: 'proj_123',
event_types: ['memory_add', 'memory_update'],
projectId: 'proj_123',
eventTypes: ['memory_add', 'memory_update'],
});
// Update
await client.updateWebhook({
webhook_id: 'wh_123',
webhookId: 'wh_123',
name: 'Updated Logger',
url: 'https://new-url.com',
});
// Delete
await client.deleteWebhook({ webhook_id: 'wh_123' });
await client.deleteWebhook({ webhookId: 'wh_123' });
```
---
@@ -232,9 +219,9 @@ await client.deleteWebhook({ webhook_id: 'wh_123' });
```typescript
await client.feedback({
memory_id: 'mem-123',
memoryId: 'mem-123',
feedback: 'POSITIVE',
feedback_reason: 'Accurately captured preference',
feedbackReason: 'Accurately captured preference',
});
```
@@ -248,7 +235,7 @@ const exportReq = await client.createMemoryExport({
filters: { user_id: 'alice' },
});
const result = await client.getMemoryExport({ memory_export_id: exportReq.id });
const result = await client.getMemoryExport({ memoryExportId: exportReq.id });
```
---
@@ -259,14 +246,12 @@ Key interfaces from `mem0.types.ts`:
```typescript
interface Message { role: string; content: string; }
interface Memory { id: string; memory: string; user_id: string; categories: string[]; score?: number; /* ... */ }
interface MemoryOptions { user_id?: string; agent_id?: string; app_id?: string; run_id?: string; metadata?: object; /* ... */ }
interface SearchOptions { user_id?: string; filters?: object; top_k?: number; rerank?: boolean; threshold?: number; /* ... */ }
interface MemoryHistory { id: string; memory_id: string; previous_value: string; new_value: string; action: string; /* ... */ }
interface FeedbackPayload { memory_id: string; feedback: string; feedback_reason?: string; }
interface WebhookCreatePayload { url: string; name: string; project_id: string; event_types: string[]; }
enum OutputFormat { v1_0 = 'v1.0', v1_1 = 'v1.1' }
enum API_VERSION { v1 = 'v1', v2 = 'v2' }
interface Memory { id: string; memory: string; userId: string; categories: string[]; score?: number; /* ... */ }
interface MemoryOptions { userId?: string; agentId?: string; appId?: string; runId?: string; metadata?: object; /* ... */ }
interface SearchOptions { filters?: object; topK?: number; rerank?: boolean; threshold?: number; /* ... */ }
interface MemoryHistory { id: string; memoryId: string; previousValue: string; newValue: string; action: string; /* ... */ }
interface FeedbackPayload { memoryId: string; feedback: string; feedbackReason?: string; }
interface WebhookCreatePayload { url: string; name: string; projectId: string; eventTypes: string[]; }
```
---
@@ -296,7 +281,7 @@ const config = {
llm: {
provider: 'openai', // openai, groq, anthropic, google, ollama, lmstudio, mistral, azure
config: {
model: 'gpt-4o-mini',
model: 'gpt-5-mini',
apiKey: 'sk-xxx',
},
},
@@ -315,17 +300,8 @@ const config = {
port: 6333,
},
},
graphStore: { // Optional
provider: 'neo4j',
config: {
url: 'neo4j://localhost:7687',
username: 'neo4j',
password: 'password',
},
},
historyDbPath: 'history.db',
customPrompt: '...',
enableGraph: false,
customInstructions: '...',
disableHistory: false,
};
@@ -363,17 +339,14 @@ await m.add([
#### search(query, config)
```typescript
const results = await m.search('dietary preferences', { userId: 'alice', limit: 5 });
const results = await m.search('dietary preferences', { filters: { user_id: 'alice' }, topK: 5 });
```
| Parameter | Type | Description |
|-----------|------|-------------|
| `query` | string | Search query |
| `config.userId` | string | Filter by user |
| `config.agentId` | string | Filter by agent |
| `config.runId` | string | Filter by run |
| `config.limit` | number | Max results (default: 100) |
| `config.filters` | object | Advanced filters |
| `config.filters` | object | Filter object with entity IDs (`user_id`, `agent_id`, `run_id`, etc.) |
| `config.topK` | number | Max results (default: 20) |
#### get(memoryId) / getAll(config) / update(memoryId, data) / delete(memoryId) / deleteAll(config) / history(memoryId)
@@ -401,12 +374,45 @@ await m.reset();
| **Auth** | API key required (`MEM0_API_KEY`) | No API key -- config-based |
| **Execution** | API calls to `api.mem0.ai` | Local execution |
| **Infrastructure** | Fully managed | Self-managed vector DB, embedder, LLM |
| **Param style** | `snake_case` in options (`user_id`) | `camelCase` in config (`userId`) |
| **Param style** | Top-level: `camelCase` (`userId`, `topK`), filter keys: `snake_case` (`user_id`) | Top-level: `camelCase` (`userId`, `topK`), filter keys: `snake_case` (`user_id`) |
| **Batch ops** | `batchUpdate`, `batchDelete` | Not available |
| **Webhooks** | Full CRUD | Not available |
| **Export** | `createMemoryExport` | Not available |
| **Feedback** | `feedback()` | Not available |
| **Project mgmt** | `getProject`, `updateProject` | Not available |
| **User listing** | `users()`, `deleteUser()` | Not available |
| **Graph store** | Platform-managed | Self-managed (Neo4j) |
| **History** | Platform-managed | SQLite (configurable) |
---
## v2 Compatibility
If you're using SDK v2.x:
**Naming Changes:**
- Top-level params now use camelCase: `topK`, `rerank` (not `top_k`)
- Filter keys use snake_case: `user_id`, `agent_id`
- OSS: `limit` renamed to `topK`
**API Changes:**
```typescript
// v2 - top-level entity IDs, snake_case
await client.search("query", { user_id: "alice", top_k: 20 });
// v3 - filters object with snake_case keys, camelCase top-level params
await client.search("query", { filters: { user_id: "alice" }, topK: 20 });
```
**Default Changes:**
| Param | v2 | v3 |
|-------|----|----|
| `topK` | 100 | 20 |
| `threshold` | none | 0.1 |
| `rerank` | true | false |
**Removed:**
- `OutputFormat` and `API_VERSION` enums
- `organizationId`, `projectId` from constructor
- `enableGraph`, `asyncMode`, `outputFormat`, `immutable`, `expirationDate`, `filterMemories`, `batchSize`, `forceAddOnly`, `includes`, `excludes`, `keywordSearch`
See the [v2 to v3 migration guide](https://docs.mem0.ai/migration/oss-v2-to-v3) for details.
+53 -47
View File
@@ -36,7 +36,7 @@ client = AsyncMemoryClient(api_key="m0-xxx")
# Or use as context manager
async with AsyncMemoryClient(api_key="m0-xxx") as client:
results = await client.search("query", user_id="alice")
results = await client.search("query", filters={"user_id": "alice"})
```
Same methods as `MemoryClient`, all `async`/`await`. Supports async context manager.
@@ -65,25 +65,19 @@ client.add(messages, user_id="alice")
| `app_id` | str | None | Application identifier |
| `run_id` | str | None | Session/run identifier |
| `metadata` | dict | None | Custom key-value pairs |
| `enable_graph` | bool | None | Activate knowledge graph extraction |
| `infer` | bool | True | If False, store raw text without LLM inference |
| `immutable` | bool | None | If True, prevents future modification |
| `expiration_date` | str | None | Auto-expiry date (`YYYY-MM-DD`) |
| `includes` | str | None | Preference filter for inclusion |
| `excludes` | str | None | Preference filter for exclusion |
| `async_mode` | bool | True | If False, wait for processing to complete |
| `custom_categories` | list | None | Override project categories |
| `custom_instructions` | str | None | Override extraction instructions |
| `timestamp` | int \| float \| str | None | Custom timestamp (Unix epoch or ISO 8601) |
**Returns:** `dict` -- list of events: `[{"id": "...", "event": "ADD|UPDATE|DELETE", "data": {"memory": "..."}}]`
**Returns:** `dict` -- list of events: `[{"id": "...", "event": "ADD", "data": {"memory": "..."}}]`
#### search(query, **kwargs)
Search memories by semantic similarity.
```python
results = client.search("dietary preferences", user_id="alice")
results = client.search("dietary preferences", filters={"user_id": "alice"})
for mem in results.get("results", []):
print(mem["memory"], mem["score"])
```
@@ -91,20 +85,14 @@ for mem in results.get("results", []):
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `query` | str | required | Natural language search query |
| `user_id` | str | None | Filter by user |
| `agent_id` | str | None | Filter by agent |
| `app_id` | str | None | Filter by app |
| `filters` | dict | None | Filter object with entity IDs and/or `AND`/`OR`/`NOT` conditions (e.g., `{"user_id": "alice"}`) |
| `top_k` | int | 10 | Number of results |
| `filters` | dict | None | V2 filter object (`AND`/`OR`/`NOT`) |
| `rerank` | bool | None | Enable deep semantic reranking (+150-200ms) |
| `threshold` | float | 0.3 | Minimum similarity score |
| `keyword_search` | bool | None | Enable keyword-based search (+10ms) |
| `enable_graph` | bool | None | Include graph relations in results |
| `filter_memories` | bool | None | Precision filtering, removes low-relevance (+200-300ms) |
| `rerank` | bool | False | Enable deep semantic reranking (+150-200ms) |
| `threshold` | float | 0.1 | Minimum similarity score |
| `fields` | list | None | Specific fields to return |
| `categories` | list | None | Filter by category |
**Returns:** `dict` -- `{"results": [{id, memory, user_id, categories, score, created_at, ...}], "relations": [...]}`
**Returns:** `dict` -- `{"results": [{id, memory, user_id, categories, score, created_at, ...}]}`
#### get(memory_id)
@@ -121,27 +109,23 @@ memory = client.get(memory_id="ea925981-...")
Retrieve all memories with optional filtering. Requires at least one entity identifier.
```python
memories = client.get_all(user_id="alice")
# With filters
memories = client.get_all(filters={"user_id": "alice"})
# With compound filters
memories = client.get_all(filters={"AND": [{"user_id": "alice"}, {"categories": {"contains": "health"}}]})
```
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `user_id` | str | None | Filter by user |
| `agent_id` | str | None | Filter by agent |
| `app_id` | str | None | Filter by app |
| `filters` | dict | None | Filter object with entity IDs and/or `AND`/`OR`/`NOT` conditions |
| `top_k` | int | None | Limit results |
| `page` | int | None | Page number |
| `page_size` | int | None | Results per page |
| `filters` | dict | None | V2 filter object |
| `enable_graph` | bool | None | Include graph relations |
**Returns:** `dict` -- `{"results": [...]}`
#### update(memory_id, text=None, metadata=None, timestamp=None)
Update a memory's content, metadata, or timestamp. At least one parameter required. Cannot update immutable memories.
Update a memory's content, metadata, or timestamp. At least one parameter required.
```python
client.update("ea925981-...", text="Updated: vegan since 2024")
@@ -320,11 +304,10 @@ config = client.project.get(fields=["custom_categories", "custom_instructions"])
client.project.update(
custom_instructions="Extract dietary preferences and health info",
custom_categories=[{"health": "Medical and dietary info"}],
enable_graph=True,
multilingual=True,
)
# Create/delete project (requires org_id)
# Create/delete project
client.project.create(name="My Project", description="...")
client.project.delete()
@@ -362,7 +345,7 @@ config = {
"llm": {
"provider": "openai", # openai, groq, azure, ollama, lmstudio, google, anthropic, mistral
"config": {
"model": "gpt-4o-mini",
"model": "gpt-5-mini",
"api_key": "sk-xxx",
}
},
@@ -381,18 +364,8 @@ config = {
"port": 6333,
}
},
"graph_store": { # Optional
"provider": "neo4j",
"config": {
"url": "neo4j://localhost:7687",
"username": "neo4j",
"password": "password",
}
},
"history_db_path": "history.db", # SQLite path for change history
"custom_instructions": "...", # Custom LLM prompt for extraction
"custom_update_memory_prompt": "...", # Custom LLM prompt for updates
"enable_graph": False, # Enable graph memory
"custom_instructions": "...", # Custom LLM prompt for extraction
}
m = Memory.from_config(config)
@@ -403,7 +376,7 @@ m = Memory.from_config(config)
```python
with Memory(config) as m:
m.add("I prefer dark mode", user_id="alice")
results = m.search("preferences", user_id="alice")
results = m.search("preferences", filters={"user_id": "alice"})
# SQLite connections released automatically
```
@@ -425,12 +398,14 @@ At least one of `user_id`, `agent_id`, `run_id` required.
**Returns:** `{"results": [...], "relations": [...]}`
#### search(query, *, user_id, agent_id, run_id, limit=100, filters=None, threshold=None, rerank=True)
#### search(query, *, filters=None, top_k=20, threshold=0.1, rerank=False)
```python
results = m.search("dietary preferences", user_id="alice", limit=5)
results = m.search("dietary preferences", filters={"user_id": "alice"}, top_k=5)
```
Entity IDs (`user_id`, `agent_id`, `run_id`) must be passed inside the `filters` dict.
Supports filter operators: `eq`, `ne`, `in`, `nin`, `gt`, `gte`, `lt`, `lte`, `contains`, `not_contains`.
#### get(memory_id) / get_all(**kwargs) / update(memory_id, data, metadata=None) / delete(memory_id) / delete_all(**kwargs) / history(memory_id)
@@ -456,7 +431,7 @@ from mem0 import AsyncMemory
m = AsyncMemory(config)
await m.add("text", user_id="alice")
results = await m.search("query", user_id="alice")
results = await m.search("query", filters={"user_id": "alice"})
```
---
@@ -469,13 +444,44 @@ results = await m.search("query", user_id="alice")
| **Auth** | API key required (`MEM0_API_KEY`) | No API key -- config-based |
| **Execution** | API calls to `api.mem0.ai` | Local execution |
| **Infrastructure** | Fully managed | Self-managed vector DB, embedder, LLM |
| **Entity filtering** | `filters={"user_id": "..."}` | `filters={"user_id": "..."}` |
| **Batch ops** | `batch_update`, `batch_delete` | Not available |
| **Webhooks** | Full CRUD | Not available |
| **Export** | `create_memory_export`, `get_memory_export` | Not available |
| **Feedback** | `feedback()` | Not available |
| **Project mgmt** | `client.project.*` | Not available |
| **User listing** | `users()`, `delete_users()` | Not available |
| **Custom prompts** | Via project settings | Direct config |
| **Graph store** | Platform-managed | Self-managed (Neo4j) |
| **Custom prompts** | Via project settings | Direct config (`custom_instructions`) |
| **History** | Platform-managed | SQLite (configurable) |
| **Async** | `AsyncMemoryClient` | `AsyncMemory` |
---
## v2 Compatibility
If you're using SDK v2.x or the v2 API:
**API Changes:**
- **Entity IDs in search/get_all:** Pass `user_id`, `agent_id` as top-level kwargs instead of inside `filters`
```python
# v2
results = client.search("query", user_id="alice")
# v3
results = client.search("query", filters={"user_id": "alice"})
```
- **add() returns:** v2 returns ADD, UPDATE, DELETE events; v3 returns ADD only
**Default Changes:**
| Param | v2 | v3 |
|-------|----|----|
| `top_k` | 100 | 20 |
| `threshold` | None | 0.1 |
| `rerank` | True | False |
**Removed Parameters:**
- Constructor: `org_id`, `project_id`
- add(): `async_mode`, `output_format`, `enable_graph`, `immutable`, `expiration_date`, `filter_memories`, `batch_size`, `force_add_only`, `includes`, `excludes`, `keyword_search`
- search()/get_all(): `enable_graph`
- Config: `enable_graph`, `graph_store`, `custom_fact_extraction_prompt` (renamed to `custom_instructions`)
See the [v2 to v3 migration guide](https://docs.mem0.ai/migration/oss-v2-to-v3) for full details.
+29 -19
View File
@@ -8,13 +8,15 @@ All endpoints require: `Authorization: Token <MEM0_API_KEY>`
| Operation | Method | URL |
|-----------|--------|-----|
| Add Memories | `POST` | `/v1/memories/` |
| Search Memories | `POST` | `/v2/memories/search/` |
| Get All Memories | `POST` | `/v2/memories/` |
| Add Memories | `POST` | `/v3/memories/add/` |
| Search Memories | `POST` | `/v3/memories/search/` |
| Get All Memories | `POST` | `/v3/memories/` |
| Get Single Memory | `GET` | `/v1/memories/{memory_id}/` |
| Update Memory | `PUT` | `/v1/memories/{memory_id}/` |
| Delete Memory | `DELETE` | `/v1/memories/{memory_id}/` |
Note: v1/v2 endpoints still work (backward compatible).
## Memory Object Structure
| Field | Type | Description |
@@ -27,8 +29,6 @@ All endpoints require: `Authorization: Token <MEM0_API_KEY>`
| `run_id` | string (nullable) | Run/session identifier |
| `metadata` | object | Custom key-value pairs |
| `categories` | array of strings | Auto-assigned category tags |
| `immutable` | boolean | If true, prevents modification |
| `expiration_date` | datetime (nullable) | Auto-expiry date |
| `hash` | string | Content hash |
| `created_at` | datetime | Creation timestamp |
| `updated_at` | datetime | Last modification timestamp |
@@ -50,10 +50,9 @@ Memories can be scoped to different levels:
## Processing Model
- Memories are processed **asynchronously by default** (`async_mode=true`)
- Add responses return queued events (`ADD`, `UPDATE`, `DELETE`) for tracking
- Set `async_mode=false` for synchronous processing when needed
- Graph metadata is processed asynchronously -- use `get_all()` for complete graph data
- Memories are processed **asynchronously** (v3 default)
- Add responses return queued `ADD` events only (v3 is ADD-only, no UPDATE/DELETE)
- Poll status via `GET /v1/event/{event_id}/`
## Filter System
@@ -106,19 +105,17 @@ Root must be `AND`, `OR`, or `NOT`. Simple shorthand `{"user_id": "alice"}` also
## Response Formats
### Add Response
### Add Response (v3)
```json
[
{
"id": "mem_01JF8ZS4Y0R0SPM13R5R6H32CJ",
"event": "ADD",
"data": { "memory": "The user moved to Austin in 2025." }
}
]
{
"message": "Memory processing has been queued for background execution",
"status": "PENDING",
"event_id": "evt-uuid"
}
```
Event types: `ADD`, `UPDATE`, `DELETE`. A single add can trigger multiple events.
v3 is ADD-only. No UPDATE or DELETE events.
### Search Response
@@ -137,4 +134,17 @@ Event types: `ADD`, `UPDATE`, `DELETE`. A single add can trigger multiple events
}
```
With `enable_graph=true`, includes additional `relations` array with entity relationships.
In v3, `score` is a combined multi-signal relevance score.
### Get All Response (v3)
```json
{
"count": 123,
"next": "https://api.mem0.ai/v3/memories/?page=2&page_size=50",
"previous": null,
"results": [...]
}
```
v3 returns paginated envelope. Use `page` and `page_size` query params.
+44 -100
View File
@@ -25,9 +25,9 @@ User Input → Retrieve relevant memories → Enrich LLM prompt → Generate res
Mem0 handles the complexity of extraction, deduplication, conflict resolution, and semantic retrieval so your application only needs to call `search()` and `add()`.
**Dual storage architecture:**
**Storage architecture:**
- **Vector store**: Embeddings for semantic similarity search
- **Graph store** (optional): Entity nodes and relationship edges for structured knowledge
- **Entity store**: Automatic entity linking for relationship-aware retrieval
---
@@ -40,41 +40,32 @@ Messages In
│
▼
┌─────────────────────┐
│ 1. EXTRACTION │ LLM analyzes messages, extracts key facts
│ 1. EXTRACTION │ Single LLM call extracts all distinct new facts
│ (infer=True) │ If infer=False, stores raw text as-is
└─────────┬───────────┘
│
▼
┌─────────────────────┐
│ 2. CONFLICT │ Checks existing memories for duplicates
│ RESOLUTION │ Latest truth wins (newer overrides older)
│ │ Only runs when infer=True
│ 2. DEDUPLICATION │ Hash-based dedup (MD5 prevents exact duplicates)
│ │ No UPDATE/DELETE - v3 is ADD-only
└─────────┬───────────┘
│
▼
┌─────────────────────┐
│ 3. STORAGE │ Generates embeddings → vector store
│ │ Optional: entity extraction → graph store
│ │ Indexes metadata, categories, timestamps
│ 3. STORAGE │ Batch embed → vector store
│ │ Entity extraction → entity store
└─────────┬───────────┘
│
▼
Memory Object
(id, memory, categories, structured_attributes)
```
### Processing modes
### Processing (v3)
**Async (default, `async_mode=True`):**
- API returns immediately: `{"status": "PENDING", "event_id": "..."}`
- Processing happens in background
v3 processes memories asynchronously by default:
- API returns immediately: `{"status": "PENDING", "event_id": "evt-..."}`
- Poll status via `GET /v1/event/{event_id}/`
- Use webhooks for completion notifications
- Best for: high-throughput, non-blocking workflows
**Sync (`async_mode=False`):**
- API waits for full processing
- Returns complete memory object with `id`, `event`, `memory`
- Best for: real-time access immediately after add
### Extraction modes
@@ -93,7 +84,7 @@ Messages In
---
## Retrieval Pipeline
## Retrieval Pipeline (v3)
### What happens when you call `client.search()`
@@ -102,45 +93,37 @@ Query In
│
▼
┌─────────────────────┐
│ 1. QUERY EMBEDDING │ Convert query to vector representation
│ 1. PREPROCESSING │ Lemmatize keywords, extract entities
└─────────┬───────────┘
│
▼
┌─────────────────────┐
│ 2. VECTOR SEARCH │ Cosine similarity across stored embeddings
│ │ Scoped by filters (user_id, agent_id, etc.)
└─────────┬───────────┘
│
▼ (optional enhancements)
┌─────────────────────┐
│ 3a. KEYWORD SEARCH │ Expands results with specific terms (+10ms)
│ 3b. RERANKING │ Deep semantic reordering (+150-200ms)
│ 3c. FILTER MEMORIES │ Precision filtering, removes low-relevance (+200-300ms)
└─────────┬───────────┘
│
▼ (if enable_graph=True)
┌─────────────────────┐
│ 4. GRAPH LOOKUP │ Finds entity relationships
│ │ Appends relations WITHOUT reranking vector results
│ 2. PARALLEL SCORING │ Semantic search (vector similarity)
│ │ BM25 keyword search (term matching)
│ │ Entity matching (entity graph boost)
└─────────┬───────────┘
│
▼
Results + Relations
┌─────────────────────┐
│ 3. SCORE FUSION │ Combine signals into single score
│ │ Optional: rerank=True for deep reordering
└─────────┬───────────┘
│
▼
Results (combined score per memory)
```
### Retrieval enhancement combinations
### v3 Search Defaults
| Configuration | Latency | Best for |
|--------------|---------|----------|
| Base search only | ~100ms | Simple lookups |
| `keyword_search=True` | ~110ms | Entity-heavy queries, broad coverage |
| `rerank=True` | ~250-300ms | User-facing results, top-N precision |
| `keyword_search=True` + `rerank=True` | ~310ms | Balanced (recommended for most apps) |
| `rerank=True` + `filter_memories=True` | ~400-500ms | Safety-critical, production systems |
| Parameter | Default | Notes |
|-----------|---------|-------|
| `top_k` | 20 | Was 100 in v2 |
| `threshold` | 0.1 | Was None in v2 |
| `rerank` | False | Was True in v2 |
### Implicit null scoping
When you search with `user_id="alice"` only, Mem0 returns memories where `agent_id`, `app_id`, and `run_id` are all null. This prevents cross-scope leakage by default.
When you search with `filters={"user_id": "alice"}` only, Mem0 returns memories where `agent_id`, `app_id`, and `run_id` are all null. This prevents cross-scope leakage by default.
To include memories with non-null fields, use explicit filters:
```python
@@ -150,53 +133,23 @@ filters={"OR": [{"user_id": "alice"}]}
---
## Memory Lifecycle
## Memory Lifecycle (v3)
```
CREATE ──→ ACTIVE ──→ UPDATE ──→ ACTIVE
│ │ │
│ ▼ ▼
│ EXPIRED EXPIRED
│ (still stored, (still stored,
│ not retrieved) not retrieved)
│ │ │
▼ ▼ ▼
DELETE DELETE DELETE
(permanent)
```
v3 uses ADD-only extraction. Memories accumulate over time rather than being consolidated.
### Creation
- Triggered by `client.add(messages, user_id="...")`
- Messages processed through extraction → conflict resolution → storage
- Gets unique UUID, `created_at` timestamp
- Optional: custom `timestamp`, `expiration_date`, `metadata`, `immutable`
- `client.add(messages, user_id="...")`
- Single-pass extraction → deduplication → storage
- Returns `{"event_id": "...", "status": "PENDING"}`
### Updates
- `client.update(memory_id, text="...")` replaces text and reindexes
- `client.batch_update([...])` for up to 1000 memories at once
- Immutable memories (`immutable=True`) cannot be updated — must delete and re-add
### Deduplication
- Automatic during `add()` with `infer=True`
- Conflict resolution merges duplicate facts
- Latest truth wins when contradictions detected
- Prevents memory bloat from repeated information
### Expiration
- Optional `expiration_date` parameter (ISO 8601 or `YYYY-MM-DD`)
- After expiration: memory NOT returned in searches but remains in storage
- Useful for time-sensitive info (events, temporary preferences, session state)
- `client.update(memory_id, text="...")` replaces text
- Batch: `client.batch_update([...])`
### Deletion
- Single: `client.delete(memory_id)` — permanent, no recovery
- Batch: `client.batch_delete([memory_ids])` — up to 1000
- Bulk: `client.delete_all(user_id="alice")` — all memories for entity
- `delete_all()` without filters raises error to prevent accidental data loss
### History tracking
- `client.history(memory_id)` returns version timeline
- Shows all changes: `{previous_value, new_value, action, timestamps}`
- Useful for audit trails and debugging
- Single: `client.delete(memory_id)`
- Batch: `client.batch_delete([...])`
- Bulk: `client.delete_all(filters={"user_id": "alice"})`
---
@@ -214,8 +167,6 @@ DELETE DELETE DELETE
"categories": ["health", "preferences"],
"created_at": "2025-03-12T12:34:56Z",
"updated_at": "2025-03-12T12:34:56Z",
"expiration_date": null,
"immutable": false,
"structured_attributes": {
"day": 12, "month": 3, "year": 2025,
"hour": 12, "minute": 34,
@@ -239,8 +190,6 @@ DELETE DELETE DELETE
| `categories` | array | Auto-assigned or custom category tags |
| `created_at` | datetime | Creation timestamp |
| `updated_at` | datetime | Last modification timestamp |
| `expiration_date` | datetime | Auto-expiry date (stops retrieval, data persists) |
| `immutable` | boolean | If true, prevents modification |
| `structured_attributes` | object | Temporal breakdown for time-based queries |
| `score` | float | Semantic similarity (search results only, 0-1) |
@@ -322,7 +271,7 @@ Mem0 supports three layers of memory, from shortest to longest lived:
```python
def chat(user_input: str, user_id: str, session_id: str) -> str:
# 1. Retrieve user memories (long-term preferences)
user_mems = mem0.search(user_input, user_id=user_id)
user_mems = mem0.search(user_input, filters={"user_id": user_id})
# 2. Retrieve session memories (current task context)
session_mems = mem0.search(user_input, filters={
@@ -350,18 +299,13 @@ def chat(user_input: str, user_id: str, session_id: str) -> str:
| Operation | Typical Latency |
|-----------|----------------|
| Base vector search | ~100ms |
| + keyword_search | +10ms |
| Hybrid search (v3 default) | ~100-150ms |
| + reranking | +150-200ms |
| + filter_memories | +200-300ms |
| Add (async, default) | < 50ms response, background processing |
| Add (sync) | 500ms-2s depending on extraction complexity |
| Graph operations | Slight overhead for large stores |
| Add (async) | < 50ms response |
### Processing
- **Async mode (default):** Returns immediately, processes in background
- **Sync mode:** Waits for full extraction + storage pipeline
- **Async (default):** Returns immediately, processes in background
- **Batch operations:** Up to 1000 memories per batch_update/batch_delete
- **Webhooks:** Real-time notifications when async processing completes
+26 -92
View File
@@ -5,7 +5,7 @@ Additional platform capabilities beyond core CRUD operations.
## Table of Contents
- [Advanced Retrieval](#advanced-retrieval)
- [Graph Memory](#graph-memory)
- [Entity Linking](#entity-linking)
- [Custom Categories](#custom-categories)
- [Custom Instructions](#custom-instructions)
- [Criteria Retrieval](#criteria-retrieval)
@@ -18,124 +18,58 @@ Additional platform capabilities beyond core CRUD operations.
## Advanced Retrieval
Three enhancement options for tuning search precision, recall, and latency.
### Hybrid Search (v3 Default)
### Keyword Search (`keyword_search=True`)
v3 uses multi-signal hybrid search combining:
- **Semantic search** (vector similarity)
- **BM25 keyword search** (normalized term matching)
- **Entity matching** (entity graph boost)
Expands results to include memories with specific terms, names, and technical keywords.
- Latency: +10ms
- Recall: Significantly increased
- Best for: entity-heavy queries, comprehensive coverage
This is automatic — no configuration needed.
### Reranking (`rerank=True`)
Deep semantic reordering of results — most relevant first.
- Latency: +150-200ms
- Accuracy: Significantly improved
- Default: `False` (was `True` in v2)
- Best for: user-facing results, top-N precision
### Filter Memories (`filter_memories=True`)
Precision filtering — removes low-relevance results entirely.
- Latency: +200-300ms
- Precision: Maximized
- Best for: safety-critical applications, production systems
### Recommended Combinations
**Python:**
```python
# Fast & broad
results = client.search(query, keyword_search=True, user_id="user123")
# Balanced (recommended for most apps)
results = client.search(query, keyword_search=True, rerank=True, user_id="user123")
# High precision (critical apps)
results = client.search(query, rerank=True, filter_memories=True, user_id="user123")
results = client.search(query, filters={"user_id": "user123"}, rerank=True)
```
**TypeScript:**
```typescript
const results = await client.search(query, {
user_id: 'user123',
keyword_search: true,
filters: { user_id: 'user123' },
rerank: true,
});
```
---
## Graph Memory
## Entity Linking
Entity-level knowledge graph that creates relationships between memories.
v3 replaces graph memory with built-in entity linking. Entities (proper nouns, quoted text, compound noun phrases) are automatically extracted and linked across memories.
### How It Works
1. **Extraction**: LLM analyzes conversation and identifies entities and relationships
2. **Storage**: Embeddings go to vector store; entity nodes and edges go to graph store
3. **Retrieval**: Vector search returns semantic matches; graph relations are appended to results
1. **Extraction**: During `add()`, entities are automatically extracted from memory text
2. **Storage**: Entities are stored in a parallel collection (`{collection}_entities`)
3. **Retrieval**: During `search()`, query entities are matched and used to boost relevant memories
Graph relations **augment** vector results without reordering them. Vector similarity always determines hit sequence.
Entity linking is automatic — no configuration required. The boost is folded into the combined `score` on each result.
### Enabling Graph Memory
### v2 Migration Note
**Per request:**
```python
client.add(messages, user_id="alice", enable_graph=True)
client.search("query", user_id="alice", enable_graph=True)
client.get_all(filters={"AND": [{"user_id": "alice"}]}, enable_graph=True)
```
If you were using `enable_graph=True` in v2:
- Remove `enable_graph` from all API calls
- Remove `graph_store` from OSS configuration
- Entity relationships are now consumed through retrieval ranking, not exposed as a separate `relations` array
**Project-level (default for all operations):**
```python
client.project.update(enable_graph=True)
```
```javascript
await client.updateProject({ enable_graph: true });
```
### Relation Structure
Each relation in the response contains:
| Field | Type | Description |
|-------|------|-------------|
| `source` | string | Source entity name |
| `source_type` | string | Source entity type (e.g., "Person") |
| `relationship` | string | Relationship label (e.g., "lives_in") |
| `target` | string | Target entity name |
| `target_type` | string | Target entity type (e.g., "City") |
| `score` | number | Confidence score |
**Example:**
```json
{
"relations": [
{
"source": "Joseph",
"source_type": "Person",
"relationship": "lives_in",
"target": "Seattle",
"target_type": "City",
"score": 0.92
}
]
}
```
### Technical Notes
- Graph Memory adds processing time; see docs for current plan availability
- Works optimally with rich conversation histories containing entity relationships
- Best suited for long-running assistants tracking evolving information
- Graph writes and reads toggle independently per request
- Multi-agent context supported via `user_id`, `agent_id`, `run_id` scoping
- Add operations are asynchronous; graph metadata may not be immediately available
See the [v2 to v3 migration guide](https://docs.mem0.ai/migration/oss-v2-to-v3) for details.
---
@@ -160,7 +94,7 @@ client.project.update(custom_categories=new_categories)
```
```javascript
await client.updateProject({ custom_categories: new_categories });
await client.updateProject({ customCategories: newCategories });
```
**Retrieve active categories:**
@@ -185,7 +119,7 @@ client.project.update(custom_instructions="Your guidelines here...")
```
```javascript
await client.updateProject({ custom_instructions: "Your guidelines here..." });
await client.updateProject({ customInstructions: "Your guidelines here..." });
```
### Template Structure
@@ -229,7 +163,7 @@ client.project.update(retrieval_criteria=retrieval_criteria)
```typescript
await client.updateProject({
retrieval_criteria: [
retrievalCriteria: [
{ name: 'joy', description: 'Positive emotions', weight: 3 },
{ name: 'urgency', description: 'Time-sensitive items', weight: 4 },
],
@@ -281,7 +215,7 @@ for item in feedback_data:
```typescript
await client.feedback('mem-123', {
feedback: 'POSITIVE',
feedback_reason: 'Accurately captured dietary preference',
feedbackReason: 'Accurately captured dietary preference',
});
```
@@ -27,7 +27,7 @@ from langchain_core.messages import SystemMessage, HumanMessage
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from mem0 import MemoryClient
llm = ChatOpenAI(model="gpt-4.1-nano-2025-04-14")
llm = ChatOpenAI(model="gpt-5-mini")
mem0 = MemoryClient()
prompt = ChatPromptTemplate.from_messages([
@@ -128,7 +128,7 @@ import { createMem0 } from "@mem0/vercel-ai-provider";
const mem0 = createMem0();
const { text } = await generateText({
model: mem0("gpt-4-turbo", { user_id: "borat" }),
model: mem0("gpt-5-mini", { user_id: "borat" }),
prompt: "Suggest me a good car to buy!",
});
```
@@ -167,7 +167,7 @@ agent = Agent(
Use search_memory to recall past conversations.
Use save_memory to store important information.""",
tools=[search_memory, save_memory],
model="gpt-4.1-nano-2025-04-14"
model="gpt-5-mini"
)
result = Runner.run_sync(agent, "I love Italian food and I'm planning a trip to Rome next month")
@@ -183,21 +183,21 @@ travel_agent = Agent(
name="Travel Planner",
instructions="You are a travel planning specialist. Use search_memory and save_memory tools.",
tools=[search_memory, save_memory],
model="gpt-4.1-nano-2025-04-14"
model="gpt-5-mini"
)
health_agent = Agent(
name="Health Advisor",
instructions="You are a health and wellness advisor. Use search_memory and save_memory tools.",
tools=[search_memory, save_memory],
model="gpt-4.1-nano-2025-04-14"
model="gpt-5-mini"
)
triage_agent = Agent(
name="Personal Assistant",
instructions="""Route travel questions to Travel Planner, health questions to Health Advisor.""",
handoffs=[travel_agent, health_agent],
model="gpt-4.1-nano-2025-04-14"
model="gpt-5-mini"
)
result = Runner.run_sync(triage_agent, "Plan a healthy meal for my Italy trip")
@@ -254,7 +254,7 @@ from langchain_openai import ChatOpenAI
from mem0 import MemoryClient
from langchain_core.messages import SystemMessage, HumanMessage, AIMessage
llm = ChatOpenAI(model="gpt-4")
llm = ChatOpenAI(model="gpt-5-mini")
mem0 = MemoryClient()
class State(TypedDict):
@@ -319,7 +319,7 @@ memory = Mem0Memory.from_client(
from llama_index.core.agent import FunctionCallingAgent
from llama_index.llms.openai import OpenAI
llm = OpenAI(model="gpt-4")
llm = OpenAI(model="gpt-5-mini")
agent = FunctionCallingAgent.from_tools(
tools=[],
llm=llm,
@@ -352,7 +352,7 @@ USER_ID = "alice"
agent = ConversableAgent(
"chatbot",
llm_config={"config_list": [{"model": "gpt-4", "api_key": os.environ["OPENAI_API_KEY"]}]},
llm_config={"config_list": [{"model": "gpt-5-mini", "api_key": os.environ["OPENAI_API_KEY"]}]},
code_execution_config=False,
human_input_mode="NEVER",
)
+2 -2
View File
@@ -59,11 +59,11 @@ const messages = [
{"role": "user", "content": "I'm a vegetarian and allergic to nuts."},
{"role": "assistant", "content": "Got it! I'll remember your dietary preferences."}
];
await client.add(messages, { user_id: "user123" });
await client.add(messages, { userId: "user123" });
// Search memories
const results = await client.search("What are my dietary restrictions?", {
user_id: "user123"
filters: { user_id: "user123" }
});
console.log(results);
```
+96 -53
View File
@@ -40,16 +40,12 @@ client.add(messages, user_id="alice")
# With metadata
client.add(messages, user_id="alice", metadata={"source": "onboarding"})
# With graph memory
client.add(messages, user_id="alice", enable_graph=True)
```
**TypeScript:**
```typescript
await client.add(messages, { user_id: "alice" });
await client.add(messages, { user_id: "alice", metadata: { source: "onboarding" } });
await client.add(messages, { user_id: "alice", enable_graph: true });
await client.add(messages, { userId: "alice" });
await client.add(messages, { userId: "alice", metadata: { source: "onboarding" } });
```
### Parameters
@@ -61,32 +57,14 @@ await client.add(messages, { user_id: "alice", enable_graph: true });
| `agent_id` | string | Agent identifier |
| `run_id` | string | Session identifier |
| `metadata` | object | Custom key-value pairs |
| `enable_graph` | boolean | Activate knowledge graph |
| `infer` | boolean | If `false`, store raw text without inference (default: `true`) |
| `immutable` | boolean | Prevents modification after creation |
| `expiration_date` | string | Auto-expiry date (`YYYY-MM-DD`) |
| `includes` | string | Preference filters for inclusion |
| `excludes` | string | Preference filters for exclusion |
| `async_mode` | boolean | Async processing (default: `true`). Set `false` to wait |
### Advanced Add Options
```python
# Immutable -- cannot be modified or overwritten
client.add(messages, user_id="alice", immutable=True)
# Expiring memory
client.add(messages, user_id="alice", expiration_date="2025-12-31")
# Selective extraction
client.add(messages, user_id="alice", includes="dietary preferences", excludes="payment info")
# Agent + session scoping
client.add(messages, user_id="alice", agent_id="nutrition-agent", run_id="session-456")
# Synchronous processing (wait for completion)
client.add(messages, user_id="alice", async_mode=False)
# Raw text -- skip LLM inference
client.add(
[{"role": "user", "content": "User prefers dark mode."}],
@@ -101,7 +79,7 @@ client.add(
**Python:**
```python
results = client.search("dietary preferences?", user_id="alice")
results = client.search("dietary preferences?", filters={"user_id": "alice"})
# With filters and reranking
results = client.search(
@@ -111,20 +89,14 @@ results = client.search(
rerank=True,
threshold=0.5
)
# With graph relations
results = client.search("colleagues", user_id="alice", enable_graph=True)
# Keyword search
results = client.search("vegetarian", user_id="alice", keyword_search=True)
```
**TypeScript:**
```typescript
const results = await client.search("dietary preferences", { user_id: "alice" });
const results = await client.search("dietary preferences", { filters: { user_id: "alice" } });
const results = await client.search("work experience", {
filters: { AND: [{ user_id: "alice" }, { categories: { contains: "professional_details" } }] },
top_k: 5,
topK: 5,
rerank: true,
});
```
@@ -134,19 +106,17 @@ const results = await client.search("work experience", {
| Name | Type | Description |
|------|------|-------------|
| `query` | string | Natural language search query |
| `user_id` | string | Filter by user |
| `filters` | object | V2 filter object (AND/OR operators) |
| `top_k` | number | Number of results (default: 10) |
| `rerank` | boolean | Enable reranking for better relevance |
| `threshold` | number | Minimum similarity score (default: 0.3) |
| `keyword_search` | boolean | Use keyword-based search |
| `enable_graph` | boolean | Include graph relations |
| `filters` | object | Filter object (AND/OR operators). Use `{"user_id": "..."}` to filter by user |
| `top_k` | number | Number of results (default: 10 for Platform) |
| `rerank` | boolean | Enable reranking for better relevance (default: `false`) |
| `threshold` | number | Minimum similarity score (default: 0.1) |
### Common Filter Patterns
**Python:**
```python
# Single user (shorthand)
client.search("query", user_id="alice")
# Single user filter
filters={"user_id": "alice"}
# OR across agents
filters={"OR": [{"user_id": "alice"}, {"agent_id": {"in": ["travel-agent", "sports-agent"]}}]}
@@ -179,6 +149,21 @@ filters={"AND": [
]}
```
**TypeScript:**
```typescript
// Single user filter
filters: { user_id: "alice" }
// OR across agents
filters: { OR: [{ user_id: "alice" }, { agent_id: { in: ["travel-agent", "sports-agent"] } }] }
// Category filtering (partial match)
filters: { AND: [{ user_id: "alice" }, { categories: { contains: "finance" } }] }
// Category filtering (exact match)
filters: { AND: [{ user_id: "alice" }, { categories: { in: ["personal_information"] } }] }
```
---
## get() / getAll() -- Retrieve Memories
@@ -189,7 +174,7 @@ filters={"AND": [
memory = client.get(memory_id="ea925981-...")
# All memories for a user
memories = client.get_all(filters={"AND": [{"user_id": "alice"}]})
memories = client.get_all(filters={"user_id": "alice"})
# With date range
memories = client.get_all(
@@ -198,15 +183,12 @@ memories = client.get_all(
{"created_at": {"gte": "2024-07-01", "lte": "2024-07-31"}}
]}
)
# With graph data
memories = client.get_all(filters={"AND": [{"user_id": "alice"}]}, enable_graph=True)
```
**TypeScript:**
```typescript
const memory = await client.get("ea925981-...");
const memories = await client.getAll({ filters: { AND: [{ user_id: "alice" }] } });
const memories = await client.getAll({ filters: { user_id: "alice" } });
```
**Note:** `get_all` requires at least one of `user_id`, `agent_id`, `app_id`, or `run_id` in filters.
@@ -226,8 +208,6 @@ client.update(memory_id="ea925981-...", text="Updated", metadata={"verified": Tr
await client.update("ea925981-...", { text: "Updated: vegan since 2024" });
```
Cannot update immutable memories.
---
## delete() / deleteAll() -- Remove Memories
@@ -241,7 +221,7 @@ client.delete_all(user_id="alice") # Irreversible bulk delete
**TypeScript:**
```typescript
await client.delete("ea925981-...");
await client.deleteAll({ user_id: "alice" });
await client.deleteAll({ userId: "alice" });
```
---
@@ -301,10 +281,73 @@ data = client.get_memory_export(memory_export_id=export["id"])
2. **SQL operators rejected** -- use `gte`, `lt`, etc. Not `>=`, `<`.
3. **Metadata filtering is limited** -- only top-level keys with `eq`, `contains`, `ne`.
4. **Wildcard `*` excludes null** -- only matches non-null values.
5. **Default threshold is 0.3** -- increase for stricter matching.
5. **Default threshold is 0.1** -- increase for stricter matching.
6. **Async processing** -- memories process asynchronously. Wait 2-3s after `add()` before searching.
7. **Immutable memories** -- cannot be updated or deleted once created.
## Naming Conventions
Python uses `snake_case` (`user_id`, `memory_id`, `get_all`). TypeScript uses `camelCase` for methods (`getAll`, `deleteAll`, `batchUpdate`) but `snake_case` for API parameters (`user_id`, `agent_id`).
Python uses `snake_case` everywhere (`user_id`, `memory_id`, `get_all`). TypeScript uses `camelCase` for methods (`getAll`, `deleteAll`, `batchUpdate`) and top-level parameters (`userId`, `topK`, `pageSize`), but filter keys use `snake_case` (`user_id`, `agent_id`).
---
## v2 to v3 Migration
### Breaking Changes in v3
**1. Entity IDs in search() and getAll()**
v3 requires entity IDs (`user_id`, `agent_id`, `run_id`) inside `filters` instead of as top-level parameters:
```python
# v2 (deprecated)
client.search("query", user_id="alice")
client.get_all(user_id="alice")
# v3
client.search("query", filters={"user_id": "alice"})
client.get_all(filters={"user_id": "alice"})
```
```typescript
// v2 (deprecated)
await client.search("query", { user_id: "alice" });
await client.getAll({ user_id: "alice" });
// v3
await client.search("query", { filters: { user_id: "alice" } });
await client.getAll({ filters: { user_id: "alice" } });
```
**2. TypeScript Parameter Naming**
v3 TypeScript uses camelCase for all parameters:
| v2 | v3 |
|----|-----|
| `user_id` | `userId` |
| `agent_id` | `agentId` |
| `run_id` | `runId` |
| `top_k` | `topK` |
| `page_size` | `pageSize` |
**3. Default Values Changed**
| Parameter | v2 Default | v3 Default |
|-----------|------------|------------|
| `threshold` | 0.3 | 0.1 |
| `rerank` | (not specified) | `false` |
**4. Removed Parameters**
The following parameters are no longer supported:
| Parameter | Status |
|-----------|--------|
| `enable_graph` | Removed from add/search/getAll |
| `keyword_search` | Removed from search |
| `filter_memories` | Removed |
| `immutable` | Removed from add |
| `expiration_date` | Removed from add |
| `includes` | Removed from add |
| `excludes` | Removed from add |
| `async_mode` | Removed from add |
+24 -24
View File
@@ -39,7 +39,7 @@ Use these known facts about the user to personalize your response:
{context if context else 'No prior context yet.'}"""
response = openai_client.chat.completions.create(
model="gpt-4.1-nano-2025-04-14",
model="gpt-5-mini",
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_input},
@@ -72,14 +72,14 @@ const openai = new OpenAI();
async function chat(userInput: string, userId: string): Promise<string> {
// 1. Retrieve relevant memories
const memories = await mem0.search(userInput, { user_id: userId });
const memories = await mem0.search(userInput, { filters: { user_id: userId } });
const context = memories.results
?.map((m: any) => `- ${m.memory}`)
.join('\n') || 'No prior context yet.';
// 2. Generate response with memory context
const response = await openai.chat.completions.create({
model: 'gpt-4.1-nano-2025-04-14',
model: 'gpt-5-mini',
messages: [
{ role: 'system', content: `You are Ray, a personal fitness coach.\nUser context:\n${context}` },
{ role: 'user', content: userInput },
@@ -90,7 +90,7 @@ async function chat(userInput: string, userId: string): Promise<string> {
// 3. Store interaction
await mem0.add(
[{ role: 'user', content: userInput }, { role: 'assistant', content: reply }],
{ user_id: userId }
{ userId: userId }
);
return reply;
}
@@ -182,7 +182,7 @@ await client.updateProject({
async function logInteraction(userId: string, message: string, priority = 'normal') {
await client.add(
[{ role: 'user', content: message }],
{ user_id: userId, metadata: { priority, source: 'support_chat' } }
{ userId: userId, metadata: { priority, source: 'support_chat' } }
);
}
@@ -230,7 +230,7 @@ def consult(user_id: str, question: str) -> str:
context = "\n".join([f"- {m['memory']}" for m in memories.get("results", [])])
response = openai_client.chat.completions.create(
model="gpt-4.1-nano-2025-04-14",
model="gpt-5-mini",
messages=[
{"role": "system", "content": f"You are a health coach. Patient context:\n{context}"},
{"role": "user", "content": question},
@@ -264,20 +264,20 @@ const openai = new OpenAI();
async function savePatientInfo(userId: string, info: string) {
await mem0.add(
[{ role: 'user', content: info }],
{ user_id: userId, run_id: 'healthcare_session', metadata: { type: 'patient_information' } }
{ userId: userId, runId: 'healthcare_session', metadata: { type: 'patient_information' } }
);
}
async function consult(userId: string, question: string): Promise<string> {
const memories = await mem0.search(question, {
user_id: userId,
top_k: 5,
filters: { user_id: userId },
topK: 5,
threshold: 0.7,
});
const context = memories.results?.map((m: any) => `- ${m.memory}`).join('\n') || '';
const response = await openai.chat.completions.create({
model: 'gpt-4.1-nano-2025-04-14',
model: 'gpt-5-mini',
messages: [
{ role: 'system', content: `You are a health coach. Patient context:\n${context}` },
{ role: 'user', content: question },
@@ -287,7 +287,7 @@ async function consult(userId: string, question: string): Promise<string> {
await mem0.add(
[{ role: 'user', content: question }, { role: 'assistant', content: reply }],
{ user_id: userId, run_id: 'healthcare_session' }
{ userId: userId, runId: 'healthcare_session' }
);
return reply;
}
@@ -333,7 +333,7 @@ def draft_content(user_id: str, topic: str) -> str:
style_context = "\n".join([f"- {m['memory']}" for m in prefs.get("results", [])])
response = openai_client.chat.completions.create(
model="gpt-4.1-nano-2025-04-14",
model="gpt-5-mini",
messages=[
{"role": "system", "content": f"Write content matching these style preferences:\n{style_context}"},
{"role": "user", "content": f"Write a blog post about: {topic}"},
@@ -359,7 +359,7 @@ const openai = new OpenAI();
async function storePreferences(userId: string, preferences: string) {
await mem0.add(
[{ role: 'user', content: preferences }],
{ user_id: userId, run_id: 'editing_session', metadata: { type: 'preferences' } }
{ userId: userId, runId: 'editing_session', metadata: { type: 'preferences' } }
);
}
@@ -370,7 +370,7 @@ async function draftContent(userId: string, topic: string): Promise<string> {
const styleContext = prefs.results?.map((m: any) => `- ${m.memory}`).join('\n') || '';
const response = await openai.chat.completions.create({
model: 'gpt-4.1-nano-2025-04-14',
model: 'gpt-5-mini',
messages: [
{ role: 'system', content: `Write content matching these preferences:\n${styleContext}` },
{ role: 'user', content: `Write a blog post about: ${topic}` },
@@ -465,10 +465,10 @@ async function storeScopedMemory(
userId: string, agentId: string, runId: string, appId: string
) {
await client.add(messages, {
user_id: userId,
agent_id: agentId,
run_id: runId,
app_id: appId,
userId: userId,
agentId: agentId,
runId: runId,
appId: appId,
});
}
@@ -520,7 +520,7 @@ def personalized_search(user_id: str, query: str, search_results: list) -> str:
user_context = "\n".join([f"- {m['memory']}" for m in memories.get("results", [])])
response = openai_client.chat.completions.create(
model="gpt-4.1-nano-2025-04-14",
model="gpt-5-mini",
messages=[
{"role": "system", "content": f"Personalize search results using user context:\n{user_context}"},
{"role": "user", "content": f"Query: {query}\n\nSearch results:\n{search_results}"},
@@ -551,11 +551,11 @@ const mem0 = new MemoryClient({ apiKey: process.env.MEM0_API_KEY! });
const openai = new OpenAI();
async function personalizedSearch(userId: string, query: string, searchResults: string[]): Promise<string> {
const memories = await mem0.search(query, { user_id: userId, top_k: 5 });
const memories = await mem0.search(query, { filters: { user_id: userId }, topK: 5 });
const context = memories.results?.map((m: any) => `- ${m.memory}`).join('\n') || '';
const response = await openai.chat.completions.create({
model: 'gpt-4.1-nano-2025-04-14',
model: 'gpt-5-mini',
messages: [
{ role: 'system', content: `Personalize results using user context:\n${context}` },
{ role: 'user', content: `Query: ${query}\nResults: ${searchResults.join(', ')}` },
@@ -563,7 +563,7 @@ async function personalizedSearch(userId: string, query: string, searchResults:
});
const reply = response.choices[0].message.content!;
await mem0.add([{ role: 'user', content: query }], { user_id: userId });
await mem0.add([{ role: 'user', content: query }], { userId: userId });
return reply;
}
```
@@ -631,14 +631,14 @@ const client = new MemoryClient({ apiKey: process.env.MEM0_API_KEY! });
async function storeEmail(userId: string, sender: string, subject: string, body: string, date: string) {
await client.add(
[{ role: 'user', content: `Email from ${sender}: ${subject}\n\n${body}` }],
{ user_id: userId, metadata: { email_type: 'incoming', sender, subject, date } }
{ userId: userId, metadata: { email_type: 'incoming', sender, subject, date } }
);
}
async function searchEmails(userId: string, query: string) {
return client.search(query, {
filters: { AND: [{ user_id: userId }, { categories: { contains: 'email' } }] },
top_k: 10,
topK: 10,
});
}
```