feat(skills): add Mem0 Platform Claude Code skill (#4309)
This commit is contained in:
@@ -0,0 +1,189 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but not
|
||||||
|
limited to compiled object code, generated documentation, and
|
||||||
|
conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work.
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to the Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by the Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding any notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
Copyright 2024 Mem0.ai
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
# Mem0 Skill for Claude
|
||||||
|
|
||||||
|
Add persistent memory to any AI application in minutes using [Mem0 Platform](https://app.mem0.ai).
|
||||||
|
|
||||||
|
## What This Skill Does
|
||||||
|
|
||||||
|
When installed, Claude can:
|
||||||
|
|
||||||
|
- **Set up Mem0** in your Python or TypeScript project
|
||||||
|
- **Integrate memory** into your existing AI app (LangChain, CrewAI, Vercel AI, OpenAI Agents, LangGraph, LlamaIndex, etc.)
|
||||||
|
- **Generate working code** using real API references and tested patterns
|
||||||
|
- **Search live docs** on demand for the latest Mem0 documentation
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
### Claude.ai
|
||||||
|
|
||||||
|
1. Download this `skills/mem0` folder as a ZIP
|
||||||
|
2. Go to **Settings > Capabilities > Skills**
|
||||||
|
3. Click **Upload skill** and select the ZIP
|
||||||
|
|
||||||
|
### Claude API (Skills API)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST https://api.anthropic.com/v1/skills \
|
||||||
|
-H "x-api-key: $ANTHROPIC_API_KEY" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"name": "mem0", "source": "https://github.com/mem0ai/mem0/tree/main/skills/mem0"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
- A Mem0 Platform API key ([Get one here](https://app.mem0.ai/dashboard/api-keys))
|
||||||
|
- Python 3.10+ or Node.js 18+
|
||||||
|
- Set the environment variable:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export MEM0_API_KEY="m0-your-api-key"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
After installing, just ask Claude:
|
||||||
|
|
||||||
|
- "Set up mem0 in my project"
|
||||||
|
- "Add memory to my chatbot"
|
||||||
|
- "Help me search user memories with filters"
|
||||||
|
- "Integrate mem0 with my LangChain app"
|
||||||
|
- "Add graph memory to track entity relationships"
|
||||||
|
|
||||||
|
## What's Inside
|
||||||
|
|
||||||
|
```text
|
||||||
|
skills/mem0/
|
||||||
|
├── SKILL.md # Skill definition and instructions
|
||||||
|
├── README.md # This file
|
||||||
|
├── LICENSE # Apache-2.0
|
||||||
|
├── scripts/
|
||||||
|
│ └── mem0_doc_search.py # Search live Mem0 docs on demand
|
||||||
|
└── references/ # Documentation (loaded on demand)
|
||||||
|
├── quickstart.md # Full quickstart (Python, TS, cURL)
|
||||||
|
├── sdk-guide.md # All SDK methods (Python + TypeScript)
|
||||||
|
├── api-reference.md # REST endpoints, filters, memory object
|
||||||
|
├── architecture.md # Processing pipeline, lifecycle, scoping, performance
|
||||||
|
├── features.md # Retrieval, graph, categories, MCP, webhooks, multimodal
|
||||||
|
├── integration-patterns.md # LangChain, CrewAI, Vercel AI, LangGraph, LlamaIndex, etc.
|
||||||
|
└── use-cases.md # 7 real-world patterns with Python + TypeScript code
|
||||||
|
```
|
||||||
|
|
||||||
|
## Links
|
||||||
|
|
||||||
|
- [Mem0 Platform Dashboard](https://app.mem0.ai)
|
||||||
|
- [Mem0 Documentation](https://docs.mem0.ai)
|
||||||
|
- [Mem0 GitHub](https://github.com/mem0ai/mem0)
|
||||||
|
- [API Reference](https://docs.mem0.ai/api-reference)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Apache-2.0
|
||||||
@@ -0,0 +1,156 @@
|
|||||||
|
---
|
||||||
|
name: mem0
|
||||||
|
description: >
|
||||||
|
Integrate Mem0 Platform into AI applications for persistent memory, personalization, and semantic search.
|
||||||
|
Use this skill when the user mentions "mem0", "memory layer", "remember user preferences",
|
||||||
|
"persistent context", "personalization", or needs to add long-term memory to chatbots, agents,
|
||||||
|
or AI apps. Covers Python and TypeScript SDKs, framework integrations (LangChain, CrewAI,
|
||||||
|
Vercel AI SDK, OpenAI Agents SDK, Pipecat), and the full Platform API. Use even when the user
|
||||||
|
doesn't explicitly say "mem0" but describes needing conversation memory, user context retention,
|
||||||
|
or knowledge retrieval across sessions.
|
||||||
|
license: Apache-2.0
|
||||||
|
metadata:
|
||||||
|
author: mem0ai
|
||||||
|
version: "1.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, and internet access to api.mem0.ai
|
||||||
|
---
|
||||||
|
|
||||||
|
# Mem0 Platform Integration
|
||||||
|
|
||||||
|
Mem0 is a managed memory layer for AI applications. It stores, retrieves, and manages user memories via API — no infrastructure to deploy.
|
||||||
|
|
||||||
|
## Step 1: Install and authenticate
|
||||||
|
|
||||||
|
**Python:**
|
||||||
|
```bash
|
||||||
|
pip install mem0ai
|
||||||
|
export MEM0_API_KEY="m0-your-api-key"
|
||||||
|
```
|
||||||
|
|
||||||
|
**TypeScript/JavaScript:**
|
||||||
|
```bash
|
||||||
|
npm install mem0ai
|
||||||
|
export MEM0_API_KEY="m0-your-api-key"
|
||||||
|
```
|
||||||
|
|
||||||
|
Get an API key at: https://app.mem0.ai/dashboard/api-keys
|
||||||
|
|
||||||
|
## Step 2: Initialize the client
|
||||||
|
|
||||||
|
**Python:**
|
||||||
|
```python
|
||||||
|
from mem0 import MemoryClient
|
||||||
|
client = MemoryClient(api_key="m0-xxx")
|
||||||
|
```
|
||||||
|
|
||||||
|
**TypeScript:**
|
||||||
|
```typescript
|
||||||
|
import MemoryClient from 'mem0ai';
|
||||||
|
const client = new MemoryClient({ apiKey: 'm0-xxx' });
|
||||||
|
```
|
||||||
|
|
||||||
|
For async Python, use `AsyncMemoryClient`.
|
||||||
|
|
||||||
|
## Step 3: Core operations
|
||||||
|
|
||||||
|
Every Mem0 integration follows the same pattern: **retrieve → generate → store**.
|
||||||
|
|
||||||
|
### Add memories
|
||||||
|
```python
|
||||||
|
messages = [
|
||||||
|
{"role": "user", "content": "I'm a vegetarian and allergic to nuts."},
|
||||||
|
{"role": "assistant", "content": "Got it! I'll remember that."}
|
||||||
|
]
|
||||||
|
client.add(messages, user_id="alice")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Search memories
|
||||||
|
```python
|
||||||
|
results = client.search("dietary preferences", user_id="alice")
|
||||||
|
for mem in results.get("results", []):
|
||||||
|
print(mem["memory"])
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get all memories
|
||||||
|
```python
|
||||||
|
all_memories = client.get_all(user_id="alice")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Update a memory
|
||||||
|
```python
|
||||||
|
client.update("memory-uuid", text="Updated: vegetarian, nut allergy, prefers organic")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Delete a memory
|
||||||
|
```python
|
||||||
|
client.delete("memory-uuid")
|
||||||
|
client.delete_all(user_id="alice") # delete all for a user
|
||||||
|
```
|
||||||
|
|
||||||
|
## Common integration pattern
|
||||||
|
|
||||||
|
```python
|
||||||
|
from mem0 import MemoryClient
|
||||||
|
from openai import OpenAI
|
||||||
|
|
||||||
|
mem0 = MemoryClient()
|
||||||
|
openai = OpenAI()
|
||||||
|
|
||||||
|
def chat(user_input: str, user_id: str) -> str:
|
||||||
|
# 1. Retrieve relevant memories
|
||||||
|
memories = mem0.search(user_input, 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",
|
||||||
|
messages=[
|
||||||
|
{"role": "system", "content": f"User context:\n{context}"},
|
||||||
|
{"role": "user", "content": user_input},
|
||||||
|
]
|
||||||
|
)
|
||||||
|
reply = response.choices[0].message.content
|
||||||
|
|
||||||
|
# 3. Store interaction for future context
|
||||||
|
mem0.add(
|
||||||
|
[{"role": "user", "content": user_input}, {"role": "assistant", "content": reply}],
|
||||||
|
user_id=user_id
|
||||||
|
)
|
||||||
|
return reply
|
||||||
|
```
|
||||||
|
|
||||||
|
## Common edge cases
|
||||||
|
|
||||||
|
- **Search returns empty:** Memories process asynchronously. Wait 2-3s after `add()` before searching. Also verify `user_id` matches exactly (case-sensitive).
|
||||||
|
- **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.
|
||||||
|
|
||||||
|
## Live documentation search
|
||||||
|
|
||||||
|
For the latest docs beyond what's in the references, use the doc search tool:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python scripts/mem0_doc_search.py --query "topic"
|
||||||
|
python scripts/mem0_doc_search.py --page "/platform/features/graph-memory"
|
||||||
|
python scripts/mem0_doc_search.py --index
|
||||||
|
```
|
||||||
|
|
||||||
|
No API key needed — searches docs.mem0.ai directly.
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
Load these on demand for deeper detail:
|
||||||
|
|
||||||
|
| Topic | File |
|
||||||
|
|-------|------|
|
||||||
|
| Quickstart (Python, TS, cURL) | [references/quickstart.md](references/quickstart.md) |
|
||||||
|
| SDK guide (all methods, both languages) | [references/sdk-guide.md](references/sdk-guide.md) |
|
||||||
|
| API reference (endpoints, filters, object schema) | [references/api-reference.md](references/api-reference.md) |
|
||||||
|
| Architecture (pipeline, lifecycle, scoping, performance) | [references/architecture.md](references/architecture.md) |
|
||||||
|
| Platform features (retrieval, graph, categories, MCP, etc.) | [references/features.md](references/features.md) |
|
||||||
|
| Framework integrations (LangChain, CrewAI, Vercel AI, etc.) | [references/integration-patterns.md](references/integration-patterns.md) |
|
||||||
|
| Use cases & examples (real-world patterns with code) | [references/use-cases.md](references/use-cases.md) |
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
# Mem0 Platform API Reference
|
||||||
|
|
||||||
|
REST API endpoints for the Mem0 Platform. Base URL: `https://api.mem0.ai`
|
||||||
|
|
||||||
|
All endpoints require: `Authorization: Token <MEM0_API_KEY>`
|
||||||
|
|
||||||
|
## Endpoints
|
||||||
|
|
||||||
|
| Operation | Method | URL |
|
||||||
|
|-----------|--------|-----|
|
||||||
|
| Add Memories | `POST` | `/v1/memories/` |
|
||||||
|
| Search Memories | `POST` | `/v2/memories/search/` |
|
||||||
|
| Get All Memories | `POST` | `/v2/memories/` |
|
||||||
|
| Get Single Memory | `GET` | `/v1/memories/{memory_id}/` |
|
||||||
|
| Update Memory | `PUT` | `/v1/memories/{memory_id}/` |
|
||||||
|
| Delete Memory | `DELETE` | `/v1/memories/{memory_id}/` |
|
||||||
|
|
||||||
|
## Memory Object Structure
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `id` | string (UUID) | Unique memory identifier |
|
||||||
|
| `memory` | string | Text content of the memory |
|
||||||
|
| `user_id` | string | Associated user |
|
||||||
|
| `agent_id` | string (nullable) | Agent identifier |
|
||||||
|
| `app_id` | string (nullable) | Application identifier |
|
||||||
|
| `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 |
|
||||||
|
|
||||||
|
Search results additionally include `score` (relevance metric).
|
||||||
|
|
||||||
|
## Scoping Identifiers
|
||||||
|
|
||||||
|
Memories can be scoped to different levels:
|
||||||
|
|
||||||
|
| Scope | Parameter | Use Case |
|
||||||
|
|-------|-----------|----------|
|
||||||
|
| User | `user_id` | Per-user memory isolation |
|
||||||
|
| Agent | `agent_id` | Per-agent memory partitioning |
|
||||||
|
| Application | `app_id` | Cross-agent app-level memory |
|
||||||
|
| Run/Session | `run_id` | Session-scoped temporary memory |
|
||||||
|
|
||||||
|
**Critical:** Combining `user_id` and `agent_id` in a single AND filter yields empty results. Entities are stored separately. Use `OR` logic or separate queries.
|
||||||
|
|
||||||
|
## 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
|
||||||
|
|
||||||
|
## Filter System
|
||||||
|
|
||||||
|
Filters use nested JSON with a logical operator at the root:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"AND": [
|
||||||
|
{"user_id": "alice"},
|
||||||
|
{"categories": {"contains": "finance"}},
|
||||||
|
{"created_at": {"gte": "2024-01-01"}}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Root must be `AND`, `OR`, or `NOT`. Simple shorthand `{"user_id": "alice"}` also works.
|
||||||
|
|
||||||
|
### Supported Operators
|
||||||
|
|
||||||
|
| Operator | Description |
|
||||||
|
|----------|-------------|
|
||||||
|
| `eq` | Equal to (default) |
|
||||||
|
| `ne` | Not equal to |
|
||||||
|
| `in` | Matches any value in array |
|
||||||
|
| `gt`, `gte` | Greater than / greater than or equal |
|
||||||
|
| `lt`, `lte` | Less than / less than or equal |
|
||||||
|
| `contains` | Case-sensitive containment |
|
||||||
|
| `icontains` | Case-insensitive containment |
|
||||||
|
| `*` | Wildcard -- matches any non-null value |
|
||||||
|
|
||||||
|
### Filterable Fields
|
||||||
|
|
||||||
|
| Field | Valid Operators |
|
||||||
|
|-------|-----------------|
|
||||||
|
| `user_id`, `agent_id`, `app_id`, `run_id` | `eq`, `ne`, `in`, `*` |
|
||||||
|
| `created_at`, `updated_at`, `timestamp` | `gt`, `gte`, `lt`, `lte`, `eq`, `ne` |
|
||||||
|
| `categories` | `eq`, `ne`, `in`, `contains` |
|
||||||
|
| `metadata` | `eq`, `ne`, `contains` (top-level keys only) |
|
||||||
|
| `keywords` | `contains`, `icontains` |
|
||||||
|
| `memory_ids` | `in` |
|
||||||
|
|
||||||
|
### Filter Constraints
|
||||||
|
|
||||||
|
1. **Entity scope partitioning:** `user_id` AND `agent_id` in one `AND` block yields empty results.
|
||||||
|
2. **Metadata limitations:** Only top-level keys. Only `eq`, `contains`, `ne`. No `in` or `gt`.
|
||||||
|
3. **Operator syntax:** Use `gte`, `lt`, `ne`. SQL-style (`>=`, `!=`) rejected.
|
||||||
|
4. **Entity filter required for get-all:** At least one of `user_id`, `agent_id`, `app_id`, or `run_id`.
|
||||||
|
5. **Wildcard excludes null:** `*` matches only non-null values.
|
||||||
|
6. **Date format:** ISO 8601 (`YYYY-MM-DDTHH:MM:SSZ`). Timezone-naive defaults to UTC.
|
||||||
|
|
||||||
|
## Response Formats
|
||||||
|
|
||||||
|
### Add Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "mem_01JF8ZS4Y0R0SPM13R5R6H32CJ",
|
||||||
|
"event": "ADD",
|
||||||
|
"data": { "memory": "The user moved to Austin in 2025." }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
Event types: `ADD`, `UPDATE`, `DELETE`. A single add can trigger multiple events.
|
||||||
|
|
||||||
|
### Search Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"results": [
|
||||||
|
{
|
||||||
|
"id": "ea925981-...",
|
||||||
|
"memory": "Is a vegetarian and allergic to nuts.",
|
||||||
|
"user_id": "user123",
|
||||||
|
"categories": ["food", "health"],
|
||||||
|
"score": 0.89,
|
||||||
|
"created_at": "2024-07-26T10:29:36.630547-07:00"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
With `enable_graph=true`, includes additional `relations` array with entity relationships.
|
||||||
@@ -0,0 +1,386 @@
|
|||||||
|
# Mem0 Platform Architecture
|
||||||
|
|
||||||
|
How Mem0 processes, stores, and retrieves memories under the hood.
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
- [Core Concept](#core-concept)
|
||||||
|
- [Memory Processing Pipeline](#memory-processing-pipeline)
|
||||||
|
- [Retrieval Pipeline](#retrieval-pipeline)
|
||||||
|
- [Memory Lifecycle](#memory-lifecycle)
|
||||||
|
- [Memory Object Structure](#memory-object-structure)
|
||||||
|
- [Scoping & Multi-Tenancy](#scoping--multi-tenancy)
|
||||||
|
- [Memory Layers](#memory-layers)
|
||||||
|
- [Performance Characteristics](#performance-characteristics)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Core Concept
|
||||||
|
|
||||||
|
Mem0 is a managed memory layer that sits between your AI application and users. Every integration follows the same 3-step loop:
|
||||||
|
|
||||||
|
```
|
||||||
|
User Input → Retrieve relevant memories → Enrich LLM prompt → Generate response → Store new memories
|
||||||
|
```
|
||||||
|
|
||||||
|
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:**
|
||||||
|
- **Vector store**: Embeddings for semantic similarity search
|
||||||
|
- **Graph store** (optional): Entity nodes and relationship edges for structured knowledge
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Memory Processing Pipeline
|
||||||
|
|
||||||
|
### What happens when you call `client.add()`
|
||||||
|
|
||||||
|
```
|
||||||
|
Messages In
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────────┐
|
||||||
|
│ 1. EXTRACTION │ LLM analyzes messages, extracts key 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
|
||||||
|
└─────────┬───────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────────┐
|
||||||
|
│ 3. STORAGE │ Generates embeddings → vector store
|
||||||
|
│ │ Optional: entity extraction → graph store
|
||||||
|
│ │ Indexes metadata, categories, timestamps
|
||||||
|
└─────────┬───────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
Memory Object
|
||||||
|
(id, memory, categories, structured_attributes)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Processing modes
|
||||||
|
|
||||||
|
**Async (default, `async_mode=True`):**
|
||||||
|
- API returns immediately: `{"status": "PENDING", "event_id": "..."}`
|
||||||
|
- Processing happens in background
|
||||||
|
- 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
|
||||||
|
|
||||||
|
**Inferred (`infer=True`, default):**
|
||||||
|
- LLM extracts structured facts from conversation
|
||||||
|
- Conflict resolution deduplicates and resolves contradictions
|
||||||
|
- Best for: natural conversation → memory
|
||||||
|
|
||||||
|
**Raw (`infer=False`):**
|
||||||
|
- Stores text exactly as provided, no LLM processing
|
||||||
|
- Skips conflict resolution — same fact can be stored twice
|
||||||
|
- Only `user` role messages are stored; `assistant` messages ignored
|
||||||
|
- Best for: bulk imports, pre-structured data, migrations
|
||||||
|
|
||||||
|
**Warning:** Don't mix `infer=True` and `infer=False` for the same data — the same fact will be stored twice.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Retrieval Pipeline
|
||||||
|
|
||||||
|
### What happens when you call `client.search()`
|
||||||
|
|
||||||
|
```
|
||||||
|
Query In
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────────┐
|
||||||
|
│ 1. QUERY EMBEDDING │ Convert query to vector representation
|
||||||
|
└─────────┬───────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────────┐
|
||||||
|
│ 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
|
||||||
|
└─────────┬───────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
Results + Relations
|
||||||
|
```
|
||||||
|
|
||||||
|
### Retrieval enhancement combinations
|
||||||
|
|
||||||
|
| 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 |
|
||||||
|
|
||||||
|
### 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.
|
||||||
|
|
||||||
|
To include memories with non-null fields, use explicit filters:
|
||||||
|
```python
|
||||||
|
# Gets memories for alice regardless of agent/app/run
|
||||||
|
filters={"OR": [{"user_id": "alice"}]}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Memory Lifecycle
|
||||||
|
|
||||||
|
```
|
||||||
|
CREATE ──→ ACTIVE ──→ UPDATE ──→ ACTIVE
|
||||||
|
│ │ │
|
||||||
|
│ ▼ ▼
|
||||||
|
│ EXPIRED EXPIRED
|
||||||
|
│ (still stored, (still stored,
|
||||||
|
│ not retrieved) not retrieved)
|
||||||
|
│ │ │
|
||||||
|
▼ ▼ ▼
|
||||||
|
DELETE DELETE DELETE
|
||||||
|
(permanent)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 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`
|
||||||
|
|
||||||
|
### 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)
|
||||||
|
|
||||||
|
### 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
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Memory Object Structure
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "uuid-string",
|
||||||
|
"memory": "Extracted memory text",
|
||||||
|
"user_id": "user-identifier",
|
||||||
|
"agent_id": null,
|
||||||
|
"app_id": null,
|
||||||
|
"run_id": null,
|
||||||
|
"metadata": { "source": "chat", "priority": "high" },
|
||||||
|
"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,
|
||||||
|
"day_of_week": "wednesday",
|
||||||
|
"is_weekend": false,
|
||||||
|
"quarter": 1, "week_of_year": 11
|
||||||
|
},
|
||||||
|
"score": 0.85
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `id` | UUID | Unique identifier, used for update/delete |
|
||||||
|
| `memory` | string | Extracted or stored text content |
|
||||||
|
| `user_id` | string | Primary entity scope |
|
||||||
|
| `agent_id` | string | Agent scope |
|
||||||
|
| `app_id` | string | Application scope |
|
||||||
|
| `run_id` | string | Session/run scope |
|
||||||
|
| `metadata` | object | Custom key-value pairs for filtering |
|
||||||
|
| `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) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Scoping & Multi-Tenancy
|
||||||
|
|
||||||
|
Mem0 separates memories across four dimensions to prevent data mixing:
|
||||||
|
|
||||||
|
| Dimension | Field | Purpose | Example |
|
||||||
|
|-----------|-------|---------|---------|
|
||||||
|
| User | `user_id` | Persistent persona or account | `"customer_6412"` |
|
||||||
|
| Agent | `agent_id` | Distinct agent or tool | `"meal_planner"` |
|
||||||
|
| App | `app_id` | Product surface or deployment | `"ios_retail_app"` |
|
||||||
|
| Session | `run_id` | Short-lived flow or thread | `"ticket-9241"` |
|
||||||
|
|
||||||
|
### Storage model
|
||||||
|
|
||||||
|
Each entity combination creates separate records. A memory with `user_id="alice"` is stored separately from one with `user_id="alice"` + `agent_id="bot"`.
|
||||||
|
|
||||||
|
### Critical: cross-entity queries
|
||||||
|
|
||||||
|
```python
|
||||||
|
# This returns NOTHING — user and agent memories are stored separately
|
||||||
|
filters={"AND": [{"user_id": "alice"}, {"agent_id": "bot"}]}
|
||||||
|
|
||||||
|
# Use OR to query multiple scopes
|
||||||
|
filters={"OR": [{"user_id": "alice"}, {"agent_id": "bot"}]}
|
||||||
|
|
||||||
|
# Use wildcard to include any non-null value
|
||||||
|
filters={"AND": [{"user_id": "*"}]} # All users (excludes null)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Recommended scoping patterns
|
||||||
|
|
||||||
|
```python
|
||||||
|
# User-level: persistent preferences
|
||||||
|
client.add(messages, user_id="alice")
|
||||||
|
|
||||||
|
# Session-level: temporary context
|
||||||
|
client.add(messages, user_id="alice", run_id="session_123")
|
||||||
|
# Clean up when done: client.delete_all(run_id="session_123")
|
||||||
|
|
||||||
|
# Agent-level: agent-specific knowledge
|
||||||
|
client.add(messages, agent_id="support_bot", app_id="helpdesk")
|
||||||
|
|
||||||
|
# Multi-tenant: full isolation
|
||||||
|
client.add(messages, user_id="alice", agent_id="bot", app_id="acme_corp", run_id="ticket_42")
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Memory Layers
|
||||||
|
|
||||||
|
Mem0 supports three layers of memory, from shortest to longest lived:
|
||||||
|
|
||||||
|
### Conversation memory
|
||||||
|
- In-flight messages within a single turn
|
||||||
|
- Tool calls, chain-of-thought reasoning
|
||||||
|
- **Lifetime:** Single response — lost after turn finishes
|
||||||
|
- **Managed by:** Your application, not Mem0
|
||||||
|
|
||||||
|
### Session memory
|
||||||
|
- Short-lived facts for current task or channel
|
||||||
|
- Multi-step flows (onboarding, debugging, support tickets)
|
||||||
|
- **Lifetime:** Minutes to hours
|
||||||
|
- **Managed by:** Mem0 via `run_id` parameter
|
||||||
|
- Clean up with `client.delete_all(run_id="session_id")`
|
||||||
|
|
||||||
|
### User memory
|
||||||
|
- Long-lived knowledge tied to a person or account
|
||||||
|
- Personal preferences, account state, compliance details
|
||||||
|
- **Lifetime:** Weeks to forever
|
||||||
|
- **Managed by:** Mem0 via `user_id` parameter
|
||||||
|
- Persists across all sessions and interactions
|
||||||
|
|
||||||
|
### How layering works in practice
|
||||||
|
|
||||||
|
```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)
|
||||||
|
|
||||||
|
# 2. Retrieve session memories (current task context)
|
||||||
|
session_mems = mem0.search(user_input, filters={
|
||||||
|
"AND": [{"user_id": user_id}, {"run_id": session_id}]
|
||||||
|
})
|
||||||
|
|
||||||
|
# 3. Combine both layers for LLM context
|
||||||
|
context = format_memories(user_mems) + format_memories(session_mems)
|
||||||
|
|
||||||
|
# 4. Generate response
|
||||||
|
response = llm.generate(context=context, input=user_input)
|
||||||
|
|
||||||
|
# 5. Store in session scope (temporary) + user scope (persistent)
|
||||||
|
messages = [{"role": "user", "content": user_input}, {"role": "assistant", "content": response}]
|
||||||
|
mem0.add(messages, user_id=user_id, run_id=session_id)
|
||||||
|
|
||||||
|
return response
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Performance Characteristics
|
||||||
|
|
||||||
|
### Latency
|
||||||
|
|
||||||
|
| Operation | Typical Latency |
|
||||||
|
|-----------|----------------|
|
||||||
|
| Base vector search | ~100ms |
|
||||||
|
| + keyword_search | +10ms |
|
||||||
|
| + 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 |
|
||||||
|
|
||||||
|
### Processing
|
||||||
|
|
||||||
|
- **Async mode (default):** Returns immediately, processes in background
|
||||||
|
- **Sync mode:** Waits for full extraction + storage pipeline
|
||||||
|
- **Batch operations:** Up to 1000 memories per batch_update/batch_delete
|
||||||
|
- **Webhooks:** Real-time notifications when async processing completes
|
||||||
|
|
||||||
|
### Scoping strategy for performance
|
||||||
|
|
||||||
|
- Use `user_id` for all user-facing queries (most common, fastest)
|
||||||
|
- Add `run_id` for session isolation (narrows search space)
|
||||||
|
- Avoid wildcard `"*"` filters on large datasets (scans all non-null records)
|
||||||
|
- Use `top_k` to limit result count when you only need a few memories
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Comparison with Alternatives
|
||||||
|
|
||||||
|
| Approach | Pros | Cons |
|
||||||
|
|----------|------|------|
|
||||||
|
| **Raw vector DB** | Fast, full control | No extraction, no dedup, no conflict resolution |
|
||||||
|
| **In-memory chat history** | Zero latency | Lost on restart, no cross-session, grows unbounded |
|
||||||
|
| **RAG over documents** | Good for static knowledge | No personalization, no memory updates |
|
||||||
|
| **Mem0 Platform** | Managed extraction + dedup + graph + scoping | External dependency, async processing delay |
|
||||||
|
|
||||||
|
Mem0 combines the best of vector search (semantic retrieval) with automatic extraction (LLM-powered), conflict resolution (deduplication), and structured scoping (multi-tenancy) — in a single managed API.
|
||||||
@@ -0,0 +1,496 @@
|
|||||||
|
# Platform Features -- Mem0 Platform
|
||||||
|
|
||||||
|
Additional platform capabilities beyond core CRUD operations.
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
- [Advanced Retrieval](#advanced-retrieval)
|
||||||
|
- [Graph Memory](#graph-memory)
|
||||||
|
- [Custom Categories](#custom-categories)
|
||||||
|
- [Custom Instructions](#custom-instructions)
|
||||||
|
- [Criteria Retrieval](#criteria-retrieval)
|
||||||
|
- [Feedback Mechanism](#feedback-mechanism)
|
||||||
|
- [Memory Export](#memory-export)
|
||||||
|
- [Group Chat](#group-chat)
|
||||||
|
- [MCP Integration](#mcp-integration)
|
||||||
|
- [Webhooks](#webhooks)
|
||||||
|
- [Multimodal Support](#multimodal-support)
|
||||||
|
|
||||||
|
## Advanced Retrieval
|
||||||
|
|
||||||
|
Three enhancement options for tuning search precision, recall, and latency.
|
||||||
|
|
||||||
|
### Keyword Search (`keyword_search=True`)
|
||||||
|
|
||||||
|
Expands results to include memories with specific terms, names, and technical keywords.
|
||||||
|
|
||||||
|
- Latency: +10ms
|
||||||
|
- Recall: Significantly increased
|
||||||
|
- Best for: entity-heavy queries, comprehensive coverage
|
||||||
|
|
||||||
|
### Reranking (`rerank=True`)
|
||||||
|
|
||||||
|
Deep semantic reordering of results — most relevant first.
|
||||||
|
|
||||||
|
- Latency: +150-200ms
|
||||||
|
- Accuracy: Significantly improved
|
||||||
|
- 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")
|
||||||
|
```
|
||||||
|
|
||||||
|
**TypeScript:**
|
||||||
|
```typescript
|
||||||
|
const results = await client.search(query, {
|
||||||
|
user_id: 'user123',
|
||||||
|
keyword_search: true,
|
||||||
|
rerank: true,
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Graph Memory
|
||||||
|
|
||||||
|
Entity-level knowledge graph that creates relationships between 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
|
||||||
|
|
||||||
|
Graph relations **augment** vector results without reordering them. Vector similarity always determines hit sequence.
|
||||||
|
|
||||||
|
### Enabling Graph Memory
|
||||||
|
|
||||||
|
**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)
|
||||||
|
```
|
||||||
|
|
||||||
|
**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
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Custom Categories
|
||||||
|
|
||||||
|
Replace Mem0's default 15 labels with domain-specific categories. The system automatically tags memories to the closest matching category.
|
||||||
|
|
||||||
|
### Default Categories (15)
|
||||||
|
|
||||||
|
`personal_details`, `family`, `professional_details`, `sports`, `travel`, `food`, `music`, `health`, `technology`, `hobbies`, `fashion`, `entertainment`, `milestones`, `user_preferences`, `misc`
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
**Set project-level categories:**
|
||||||
|
```python
|
||||||
|
new_categories = [
|
||||||
|
{"lifestyle_management": "Tracks daily routines, habits, wellness activities"},
|
||||||
|
{"seeking_structure": "Documents goals around creating routines and systems"},
|
||||||
|
{"personal_information": "Basic information about the user"}
|
||||||
|
]
|
||||||
|
client.project.update(custom_categories=new_categories)
|
||||||
|
```
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
await client.updateProject({ custom_categories: new_categories });
|
||||||
|
```
|
||||||
|
|
||||||
|
**Retrieve active categories:**
|
||||||
|
```python
|
||||||
|
categories = client.project.get(fields=["custom_categories"])
|
||||||
|
```
|
||||||
|
|
||||||
|
### Key Constraint
|
||||||
|
|
||||||
|
Per-request overrides (`custom_categories=...` on `client.add`) are **not supported** on the managed API. Only project-level configuration works. Workaround: store ad-hoc labels in `metadata` field.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Custom Instructions
|
||||||
|
|
||||||
|
Natural language filters that control what information Mem0 extracts when creating memories.
|
||||||
|
|
||||||
|
### Set Instructions
|
||||||
|
|
||||||
|
```python
|
||||||
|
client.project.update(custom_instructions="Your guidelines here...")
|
||||||
|
```
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
await client.updateProject({ custom_instructions: "Your guidelines here..." });
|
||||||
|
```
|
||||||
|
|
||||||
|
### Template Structure
|
||||||
|
|
||||||
|
1. **Task Description** -- brief extraction overview
|
||||||
|
2. **Information Categories** -- numbered sections with specific details to capture
|
||||||
|
3. **Processing Guidelines** -- quality and handling rules
|
||||||
|
4. **Exclusion List** -- sensitive/irrelevant data to filter out
|
||||||
|
|
||||||
|
### Domain Examples
|
||||||
|
|
||||||
|
**E-commerce:** Capture product issues, preferences, service experience; exclude payment data.
|
||||||
|
|
||||||
|
**Education:** Extract learning progress, student preferences, performance patterns; exclude specific grades.
|
||||||
|
|
||||||
|
**Finance:** Track financial goals, life events, investment interests; exclude account numbers and SSNs.
|
||||||
|
|
||||||
|
### Best Practices
|
||||||
|
|
||||||
|
- Start simply, test with sample messages, iterate based on results
|
||||||
|
- Avoid overly lengthy instructions
|
||||||
|
- Be specific about what to include AND exclude
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Criteria Retrieval
|
||||||
|
|
||||||
|
Custom attribute-based memory ranking using LLM-evaluated criteria with weights. Goes beyond semantic similarity to prioritize memories based on domain-specific signals.
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Define criteria at project level
|
||||||
|
retrieval_criteria = [
|
||||||
|
{"name": "joy", "description": "Positive emotions like happiness and excitement", "weight": 3},
|
||||||
|
{"name": "curiosity", "description": "Inquisitiveness and desire to learn", "weight": 2},
|
||||||
|
{"name": "urgency", "description": "Time-sensitive or high-priority items", "weight": 4},
|
||||||
|
]
|
||||||
|
client.project.update(retrieval_criteria=retrieval_criteria)
|
||||||
|
```
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
await client.updateProject({
|
||||||
|
retrieval_criteria: [
|
||||||
|
{ name: 'joy', description: 'Positive emotions', weight: 3 },
|
||||||
|
{ name: 'urgency', description: 'Time-sensitive items', weight: 4 },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
Once configured, `client.search()` automatically applies criteria ranking:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Criteria-weighted results returned automatically
|
||||||
|
results = client.search("Why am I feeling happy?", filters={"user_id": "alice"})
|
||||||
|
```
|
||||||
|
|
||||||
|
**Best for:** Wellness assistants, tutoring platforms, productivity tools — any app needing intent-aware retrieval.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Feedback Mechanism
|
||||||
|
|
||||||
|
Provide feedback on extracted memories to improve system quality over time.
|
||||||
|
|
||||||
|
### Feedback Types
|
||||||
|
|
||||||
|
| Type | Meaning |
|
||||||
|
|------|---------|
|
||||||
|
| `POSITIVE` | Memory is useful and accurate |
|
||||||
|
| `NEGATIVE` | Memory is not useful |
|
||||||
|
| `VERY_NEGATIVE` | Memory is harmful or completely wrong |
|
||||||
|
| `None` | Clear existing feedback |
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
**Python:**
|
||||||
|
```python
|
||||||
|
client.feedback(
|
||||||
|
memory_id="mem-123",
|
||||||
|
feedback="POSITIVE",
|
||||||
|
feedback_reason="Accurately captured dietary preference"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Bulk feedback
|
||||||
|
for item in feedback_data:
|
||||||
|
client.feedback(**item)
|
||||||
|
```
|
||||||
|
|
||||||
|
**TypeScript:**
|
||||||
|
```typescript
|
||||||
|
await client.feedback('mem-123', {
|
||||||
|
feedback: 'POSITIVE',
|
||||||
|
feedback_reason: 'Accurately captured dietary preference',
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Memory Export
|
||||||
|
|
||||||
|
Create structured exports of memories using customizable schemas with filters.
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
```python
|
||||||
|
import json
|
||||||
|
|
||||||
|
# Define export schema
|
||||||
|
schema = {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"name": {"type": "string"},
|
||||||
|
"preferences": {"type": "array", "items": {"type": "string"}},
|
||||||
|
"health_info": {"type": "string"},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create export
|
||||||
|
response = client.create_memory_export(
|
||||||
|
schema=json.dumps(schema),
|
||||||
|
filters={"user_id": "alice"},
|
||||||
|
export_instructions="Create comprehensive profile based on all memories"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Retrieve export (may take a moment to process)
|
||||||
|
result = client.get_memory_export(memory_export_id=response["id"])
|
||||||
|
```
|
||||||
|
|
||||||
|
**Best for:** Data analytics, user profile generation, compliance audits, CRM sync.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Group Chat
|
||||||
|
|
||||||
|
Process multi-participant conversations and automatically attribute memories to individual speakers.
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
```python
|
||||||
|
messages = [
|
||||||
|
{"role": "user", "name": "Alice", "content": "I think we should use React for the frontend"},
|
||||||
|
{"role": "user", "name": "Bob", "content": "I prefer Vue.js, it's simpler for our use case"},
|
||||||
|
{"role": "assistant", "content": "Both are great choices. Let me note your preferences."},
|
||||||
|
]
|
||||||
|
|
||||||
|
# Mem0 automatically attributes memories to each speaker
|
||||||
|
response = client.add(messages, run_id="team_meeting_1")
|
||||||
|
|
||||||
|
# Retrieve Alice's memories from that session
|
||||||
|
alice_mems = client.get_all(
|
||||||
|
filters={"AND": [{"user_id": "alice"}, {"run_id": "team_meeting_1"}]}
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
Use the `name` field in messages to identify speakers. Mem0 maps names to entity scopes automatically.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## MCP Integration
|
||||||
|
|
||||||
|
Model Context Protocol integration enables AI clients (Claude Desktop, Cursor, custom agents) to manage Mem0 memory autonomously.
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"mem0": {
|
||||||
|
"command": "uvx",
|
||||||
|
"args": ["mem0-mcp-server"],
|
||||||
|
"env": {
|
||||||
|
"MEM0_API_KEY": "m0-your-api-key",
|
||||||
|
"MEM0_DEFAULT_USER_ID": "your-user-id"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Available MCP Tools
|
||||||
|
|
||||||
|
The MCP server exposes 9 memory tools that AI agents can use autonomously:
|
||||||
|
- Add, search, get, update, delete memories
|
||||||
|
- Get history, list users, delete users
|
||||||
|
- Search Mem0 documentation
|
||||||
|
|
||||||
|
### How It Works
|
||||||
|
|
||||||
|
1. Configure the MCP server in your AI client
|
||||||
|
2. The agent autonomously decides when to store/retrieve memories
|
||||||
|
3. No manual API calls needed — the agent manages memory as part of its reasoning
|
||||||
|
|
||||||
|
**Best for:** Universal AI client integration — one protocol works everywhere.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Webhooks
|
||||||
|
|
||||||
|
Real-time event notifications for memory operations.
|
||||||
|
|
||||||
|
### Supported Events
|
||||||
|
|
||||||
|
| Event | Trigger |
|
||||||
|
|-------|---------|
|
||||||
|
| `memory_add` | Memory created |
|
||||||
|
| `memory_update` | Memory modified |
|
||||||
|
| `memory_delete` | Memory removed |
|
||||||
|
| `memory_categorize` | Memory tagged |
|
||||||
|
|
||||||
|
### Create Webhook
|
||||||
|
|
||||||
|
Note: `project_id` here refers to the Mem0 dashboard project scope for webhooks — not the deprecated client init parameter.
|
||||||
|
|
||||||
|
```python
|
||||||
|
webhook = client.create_webhook(
|
||||||
|
url="https://your-app.com/webhook",
|
||||||
|
name="Memory Logger",
|
||||||
|
project_id="proj_123",
|
||||||
|
event_types=["memory_add", "memory_categorize"]
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Manage Webhooks
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Retrieve
|
||||||
|
webhooks = client.get_webhooks(project_id="proj_123")
|
||||||
|
|
||||||
|
# Update
|
||||||
|
client.update_webhook(
|
||||||
|
name="Updated Logger",
|
||||||
|
url="https://your-app.com/new-webhook",
|
||||||
|
event_types=["memory_update", "memory_add"],
|
||||||
|
webhook_id="wh_123"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Delete
|
||||||
|
client.delete_webhook(webhook_id="wh_123")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Payload Structure
|
||||||
|
|
||||||
|
Memory events contain: ID, data object with memory content, event type (`ADD`/`UPDATE`/`DELETE`).
|
||||||
|
Categorization events contain: memory ID, event type (`CATEGORIZE`), assigned category labels.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Multimodal Support
|
||||||
|
|
||||||
|
Mem0 can process images and documents alongside text.
|
||||||
|
|
||||||
|
### Supported Media Types
|
||||||
|
|
||||||
|
- Images: JPG, PNG
|
||||||
|
- Documents: MDX, TXT, PDF
|
||||||
|
|
||||||
|
### Image via URL
|
||||||
|
|
||||||
|
```python
|
||||||
|
image_message = {
|
||||||
|
"role": "user",
|
||||||
|
"content": {
|
||||||
|
"type": "image_url",
|
||||||
|
"image_url": {"url": "https://example.com/image.jpg"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
client.add([image_message], user_id="alice")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Image via Base64
|
||||||
|
|
||||||
|
```python
|
||||||
|
import base64
|
||||||
|
with open("photo.jpg", "rb") as f:
|
||||||
|
base64_image = base64.b64encode(f.read()).decode("utf-8")
|
||||||
|
|
||||||
|
image_message = {
|
||||||
|
"role": "user",
|
||||||
|
"content": {
|
||||||
|
"type": "image_url",
|
||||||
|
"image_url": {"url": f"data:image/jpeg;base64,{base64_image}"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
client.add([image_message], user_id="alice")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Document (MDX/TXT)
|
||||||
|
|
||||||
|
```python
|
||||||
|
doc_message = {
|
||||||
|
"role": "user",
|
||||||
|
"content": {"type": "mdx_url", "mdx_url": {"url": document_url}}
|
||||||
|
}
|
||||||
|
client.add([doc_message], user_id="alice")
|
||||||
|
```
|
||||||
|
|
||||||
|
### PDF Document
|
||||||
|
|
||||||
|
```python
|
||||||
|
pdf_message = {
|
||||||
|
"role": "user",
|
||||||
|
"content": {"type": "pdf_url", "pdf_url": {"url": pdf_url}}
|
||||||
|
}
|
||||||
|
client.add([pdf_message], user_id="alice")
|
||||||
|
```
|
||||||
@@ -0,0 +1,444 @@
|
|||||||
|
# Mem0 Integration Patterns
|
||||||
|
|
||||||
|
Working code examples for integrating Mem0 Platform with popular AI frameworks.
|
||||||
|
All examples use `MemoryClient` (Platform API key).
|
||||||
|
|
||||||
|
Code examples are sourced from official Mem0 integration docs at docs.mem0.ai, simplified for quick reference.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Common Pattern
|
||||||
|
|
||||||
|
Every integration follows the same 3-step loop:
|
||||||
|
|
||||||
|
1. **Retrieve** -- search relevant memories before generating a response
|
||||||
|
2. **Generate** -- include memories as context in the LLM prompt
|
||||||
|
3. **Store** -- save the interaction back to Mem0 for future use
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## LangChain
|
||||||
|
|
||||||
|
Source: [docs.mem0.ai/integrations/langchain](https://docs.mem0.ai/integrations/langchain)
|
||||||
|
|
||||||
|
```python
|
||||||
|
from langchain_openai import ChatOpenAI
|
||||||
|
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")
|
||||||
|
mem0 = MemoryClient()
|
||||||
|
|
||||||
|
prompt = ChatPromptTemplate.from_messages([
|
||||||
|
SystemMessage(content="You are a helpful travel agent AI. Use the provided context to personalize your responses."),
|
||||||
|
MessagesPlaceholder(variable_name="context"),
|
||||||
|
HumanMessage(content="{input}")
|
||||||
|
])
|
||||||
|
|
||||||
|
def retrieve_context(query: str, user_id: str):
|
||||||
|
"""Retrieve relevant memories from Mem0"""
|
||||||
|
memories = mem0.search(query, user_id=user_id)
|
||||||
|
memory_list = memories['results']
|
||||||
|
serialized = ' '.join([m["memory"] for m in memory_list])
|
||||||
|
return [
|
||||||
|
{"role": "system", "content": f"Relevant information: {serialized}"},
|
||||||
|
{"role": "user", "content": query}
|
||||||
|
]
|
||||||
|
|
||||||
|
def chat_turn(user_input: str, user_id: str) -> str:
|
||||||
|
# 1. Retrieve
|
||||||
|
context = retrieve_context(user_input, user_id)
|
||||||
|
# 2. Generate
|
||||||
|
chain = prompt | llm
|
||||||
|
response = chain.invoke({"context": context, "input": user_input})
|
||||||
|
# 3. Store
|
||||||
|
mem0.add(
|
||||||
|
[{"role": "user", "content": user_input}, {"role": "assistant", "content": response.content}],
|
||||||
|
user_id=user_id
|
||||||
|
)
|
||||||
|
return response.content
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## CrewAI
|
||||||
|
|
||||||
|
Source: [docs.mem0.ai/integrations/crewai](https://docs.mem0.ai/integrations/crewai)
|
||||||
|
|
||||||
|
CrewAI has native Mem0 integration via `memory_config`:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from crewai import Agent, Task, Crew, Process
|
||||||
|
from mem0 import MemoryClient
|
||||||
|
|
||||||
|
client = MemoryClient()
|
||||||
|
|
||||||
|
# Store user preferences first
|
||||||
|
messages = [
|
||||||
|
{"role": "user", "content": "I am more of a beach person than a mountain person."},
|
||||||
|
{"role": "assistant", "content": "Noted! I'll recommend beach destinations."},
|
||||||
|
{"role": "user", "content": "I like Airbnb more than hotels."},
|
||||||
|
]
|
||||||
|
client.add(messages, user_id="crew_user_1")
|
||||||
|
|
||||||
|
# Create agent
|
||||||
|
travel_agent = Agent(
|
||||||
|
role="Personalized Travel Planner",
|
||||||
|
goal="Plan personalized travel itineraries",
|
||||||
|
backstory="You are a seasoned travel planner.",
|
||||||
|
memory=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create task
|
||||||
|
task = Task(
|
||||||
|
description="Find places to live, eat, and visit in San Francisco.",
|
||||||
|
expected_output="A detailed list of places to live, eat, and visit.",
|
||||||
|
agent=travel_agent,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Setup crew with Mem0 memory
|
||||||
|
crew = Crew(
|
||||||
|
agents=[travel_agent],
|
||||||
|
tasks=[task],
|
||||||
|
process=Process.sequential,
|
||||||
|
memory=True,
|
||||||
|
memory_config={
|
||||||
|
"provider": "mem0",
|
||||||
|
"config": {"user_id": "crew_user_1"},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
result = crew.kickoff()
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Vercel AI SDK
|
||||||
|
|
||||||
|
Source: [docs.mem0.ai/integrations/vercel-ai-sdk](https://docs.mem0.ai/integrations/vercel-ai-sdk)
|
||||||
|
|
||||||
|
Install: `npm install @mem0/vercel-ai-provider`
|
||||||
|
|
||||||
|
### Basic Text Generation with Memory
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { generateText } from "ai";
|
||||||
|
import { createMem0 } from "@mem0/vercel-ai-provider";
|
||||||
|
|
||||||
|
const mem0 = createMem0({
|
||||||
|
provider: "openai",
|
||||||
|
mem0ApiKey: "m0-xxx",
|
||||||
|
apiKey: "openai-api-key",
|
||||||
|
});
|
||||||
|
|
||||||
|
const { text } = await generateText({
|
||||||
|
model: mem0("gpt-4-turbo", { user_id: "borat" }),
|
||||||
|
prompt: "Suggest me a good car to buy!",
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Streaming with Memory
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { streamText } from "ai";
|
||||||
|
import { createMem0 } from "@mem0/vercel-ai-provider";
|
||||||
|
|
||||||
|
const mem0 = createMem0();
|
||||||
|
|
||||||
|
const { textStream } = streamText({
|
||||||
|
model: mem0("gpt-4-turbo", { user_id: "borat" }),
|
||||||
|
prompt: "Suggest me a good car to buy!",
|
||||||
|
});
|
||||||
|
|
||||||
|
for await (const textPart of textStream) {
|
||||||
|
process.stdout.write(textPart);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using Memory Utilities Standalone
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { openai } from "@ai-sdk/openai";
|
||||||
|
import { generateText } from "ai";
|
||||||
|
import { retrieveMemories, addMemories } from "@mem0/vercel-ai-provider";
|
||||||
|
|
||||||
|
// Retrieve memories and inject into any provider
|
||||||
|
const prompt = "Suggest me a good car to buy.";
|
||||||
|
const memories = await retrieveMemories(prompt, { user_id: "borat", mem0ApiKey: "m0-xxx" });
|
||||||
|
|
||||||
|
const { text } = await generateText({
|
||||||
|
model: openai("gpt-4-turbo"),
|
||||||
|
prompt: prompt,
|
||||||
|
system: memories,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Store new memories
|
||||||
|
await addMemories(
|
||||||
|
[{ role: "user", content: [{ type: "text", text: "I love red cars." }] }],
|
||||||
|
{ user_id: "borat", mem0ApiKey: "m0-xxx" }
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Supported Providers
|
||||||
|
|
||||||
|
`openai`, `anthropic`, `google`, `groq`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## OpenAI Agents SDK
|
||||||
|
|
||||||
|
Source: [docs.mem0.ai/integrations/openai-agents-sdk](https://docs.mem0.ai/integrations/openai-agents-sdk)
|
||||||
|
|
||||||
|
```python
|
||||||
|
from agents import Agent, Runner, function_tool
|
||||||
|
from mem0 import MemoryClient
|
||||||
|
|
||||||
|
mem0 = MemoryClient()
|
||||||
|
|
||||||
|
@function_tool
|
||||||
|
def search_memory(query: str, user_id: str) -> str:
|
||||||
|
"""Search through past conversations and memories"""
|
||||||
|
memories = mem0.search(query, user_id=user_id, top_k=3)
|
||||||
|
if memories and memories.get('results'):
|
||||||
|
return "\n".join([f"- {mem['memory']}" for mem in memories['results']])
|
||||||
|
return "No relevant memories found."
|
||||||
|
|
||||||
|
@function_tool
|
||||||
|
def save_memory(content: str, user_id: str) -> str:
|
||||||
|
"""Save important information to memory"""
|
||||||
|
mem0.add([{"role": "user", "content": content}], user_id=user_id)
|
||||||
|
return "Information saved to memory."
|
||||||
|
|
||||||
|
agent = Agent(
|
||||||
|
name="Personal Assistant",
|
||||||
|
instructions="""You are a helpful personal assistant with memory capabilities.
|
||||||
|
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"
|
||||||
|
)
|
||||||
|
|
||||||
|
result = Runner.run_sync(agent, "I love Italian food and I'm planning a trip to Rome next month")
|
||||||
|
print(result.final_output)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Multi-Agent with Handoffs
|
||||||
|
|
||||||
|
```python
|
||||||
|
from agents import Agent, Runner, function_tool
|
||||||
|
|
||||||
|
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"
|
||||||
|
)
|
||||||
|
|
||||||
|
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"
|
||||||
|
)
|
||||||
|
|
||||||
|
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"
|
||||||
|
)
|
||||||
|
|
||||||
|
result = Runner.run_sync(triage_agent, "Plan a healthy meal for my Italy trip")
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Pipecat (Voice / Real-Time)
|
||||||
|
|
||||||
|
Source: [docs.mem0.ai/integrations/pipecat](https://docs.mem0.ai/integrations/pipecat)
|
||||||
|
|
||||||
|
```python
|
||||||
|
from pipecat.services.mem0 import Mem0MemoryService
|
||||||
|
|
||||||
|
memory = Mem0MemoryService(
|
||||||
|
api_key=os.getenv("MEM0_API_KEY"),
|
||||||
|
user_id="alice",
|
||||||
|
agent_id="voice_bot",
|
||||||
|
params={
|
||||||
|
"search_limit": 10,
|
||||||
|
"search_threshold": 0.1,
|
||||||
|
"system_prompt": "Here are your past memories:",
|
||||||
|
"add_as_system_message": True,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Use in pipeline
|
||||||
|
pipeline = Pipeline([
|
||||||
|
transport.input(),
|
||||||
|
stt,
|
||||||
|
user_context,
|
||||||
|
memory, # Memory enhances context automatically
|
||||||
|
llm,
|
||||||
|
transport.output(),
|
||||||
|
assistant_context
|
||||||
|
])
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## LangGraph
|
||||||
|
|
||||||
|
Source: [docs.mem0.ai/integrations/langgraph](https://docs.mem0.ai/integrations/langgraph)
|
||||||
|
|
||||||
|
State-based agent workflows with memory persistence. Best for complex conversation flows with branching logic.
|
||||||
|
|
||||||
|
```python
|
||||||
|
from typing import Annotated, TypedDict, List
|
||||||
|
from langgraph.graph import StateGraph, START
|
||||||
|
from langgraph.graph.message import add_messages
|
||||||
|
from langchain_openai import ChatOpenAI
|
||||||
|
from mem0 import MemoryClient
|
||||||
|
from langchain_core.messages import SystemMessage, HumanMessage, AIMessage
|
||||||
|
|
||||||
|
llm = ChatOpenAI(model="gpt-4")
|
||||||
|
mem0 = MemoryClient()
|
||||||
|
|
||||||
|
class State(TypedDict):
|
||||||
|
messages: Annotated[List[HumanMessage | AIMessage], add_messages]
|
||||||
|
mem0_user_id: str
|
||||||
|
|
||||||
|
def chatbot(state: State):
|
||||||
|
messages = state["messages"]
|
||||||
|
user_id = state["mem0_user_id"]
|
||||||
|
|
||||||
|
# Retrieve relevant memories
|
||||||
|
memories = mem0.search(messages[-1].content, user_id=user_id)
|
||||||
|
context = "Relevant context:\n"
|
||||||
|
for memory in memories["results"]:
|
||||||
|
context += f"- {memory['memory']}\n"
|
||||||
|
|
||||||
|
system_message = SystemMessage(content=f"""You are a helpful support assistant.
|
||||||
|
{context}""")
|
||||||
|
|
||||||
|
response = llm.invoke([system_message] + messages)
|
||||||
|
|
||||||
|
# Store the interaction
|
||||||
|
mem0.add(
|
||||||
|
[{"role": "user", "content": messages[-1].content},
|
||||||
|
{"role": "assistant", "content": response.content}],
|
||||||
|
user_id=user_id
|
||||||
|
)
|
||||||
|
return {"messages": [response]}
|
||||||
|
|
||||||
|
graph = StateGraph(State)
|
||||||
|
graph.add_node("chatbot", chatbot)
|
||||||
|
graph.add_edge(START, "chatbot")
|
||||||
|
app = graph.compile()
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
result = app.invoke({
|
||||||
|
"messages": [HumanMessage(content="I need help with my order")],
|
||||||
|
"mem0_user_id": "customer_123"
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## LlamaIndex
|
||||||
|
|
||||||
|
Source: [docs.mem0.ai/integrations/llama-index](https://docs.mem0.ai/integrations/llama-index)
|
||||||
|
|
||||||
|
Install: `pip install llama-index-core llama-index-memory-mem0`
|
||||||
|
|
||||||
|
LlamaIndex has native Mem0 support via `Mem0Memory`. Works with ReAct and FunctionCalling agents.
|
||||||
|
|
||||||
|
```python
|
||||||
|
from llama_index.memory.mem0 import Mem0Memory
|
||||||
|
|
||||||
|
context = {"user_id": "alice", "agent_id": "llama_agent_1"}
|
||||||
|
memory = Mem0Memory.from_client(
|
||||||
|
context=context,
|
||||||
|
search_msg_limit=4, # messages from chat history used for retrieval (default: 5)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Use with LlamaIndex agent
|
||||||
|
from llama_index.core.agent import FunctionCallingAgent
|
||||||
|
from llama_index.llms.openai import OpenAI
|
||||||
|
|
||||||
|
llm = OpenAI(model="gpt-4")
|
||||||
|
agent = FunctionCallingAgent.from_tools(
|
||||||
|
tools=[],
|
||||||
|
llm=llm,
|
||||||
|
memory=memory,
|
||||||
|
verbose=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
response = agent.chat("I prefer vegetarian restaurants")
|
||||||
|
# Memory automatically stores and retrieves context
|
||||||
|
response = agent.chat("What kind of food do I like?")
|
||||||
|
# Agent retrieves the vegetarian preference from Mem0
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## AutoGen
|
||||||
|
|
||||||
|
Source: [docs.mem0.ai/integrations/autogen](https://docs.mem0.ai/integrations/autogen)
|
||||||
|
|
||||||
|
Install: `pip install autogen mem0ai`
|
||||||
|
|
||||||
|
Multi-agent conversational systems with memory persistence.
|
||||||
|
|
||||||
|
```python
|
||||||
|
from autogen import ConversableAgent
|
||||||
|
from mem0 import MemoryClient
|
||||||
|
|
||||||
|
memory_client = MemoryClient()
|
||||||
|
USER_ID = "alice"
|
||||||
|
|
||||||
|
agent = ConversableAgent(
|
||||||
|
"chatbot",
|
||||||
|
llm_config={"config_list": [{"model": "gpt-4", "api_key": os.environ["OPENAI_API_KEY"]}]},
|
||||||
|
code_execution_config=False,
|
||||||
|
human_input_mode="NEVER",
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_context_aware_response(question: str) -> str:
|
||||||
|
# Retrieve memories for context
|
||||||
|
relevant_memories = memory_client.search(question, user_id=USER_ID)
|
||||||
|
context = "\n".join([m["memory"] for m in relevant_memories.get("results", [])])
|
||||||
|
|
||||||
|
prompt = f"""Answer considering previous interactions:
|
||||||
|
Previous context: {context}
|
||||||
|
Question: {question}"""
|
||||||
|
|
||||||
|
reply = agent.generate_reply(messages=[{"content": prompt, "role": "user"}])
|
||||||
|
|
||||||
|
# Store the new interaction
|
||||||
|
memory_client.add(
|
||||||
|
[{"role": "user", "content": question}, {"role": "assistant", "content": reply}],
|
||||||
|
user_id=USER_ID
|
||||||
|
)
|
||||||
|
return reply
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## All Supported Frameworks
|
||||||
|
|
||||||
|
Beyond the examples above, Mem0 integrates with:
|
||||||
|
|
||||||
|
| Framework | Type | Install |
|
||||||
|
|-----------|------|---------|
|
||||||
|
| [Mastra](https://docs.mem0.ai/integrations/mastra) | TS agent framework | `npm install @mastra/mem0` |
|
||||||
|
| [ElevenLabs](https://docs.mem0.ai/integrations/elevenlabs) | Voice AI | `pip install elevenlabs mem0ai` |
|
||||||
|
| [LiveKit](https://docs.mem0.ai/integrations/livekit) | Real-time voice/video | `pip install livekit-agents mem0ai` |
|
||||||
|
| [Camel AI](https://docs.mem0.ai/integrations/camel-ai) | Multi-agent framework | `pip install camel-ai[all] mem0ai` |
|
||||||
|
| [AWS Bedrock](https://docs.mem0.ai/integrations/aws-bedrock) | Cloud LLM provider | `pip install boto3 mem0ai` |
|
||||||
|
| [Dify](https://docs.mem0.ai/integrations/dify) | Low-code AI platform | Plugin-based |
|
||||||
|
| [Google AI ADK](https://docs.mem0.ai/integrations/google-ai-adk) | Google agent framework | `pip install google-adk mem0ai` |
|
||||||
|
|
||||||
|
For the general Python pattern (no framework), see the "Common integration pattern" in [SKILL.md](../SKILL.md).
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
# Mem0 Platform Quickstart
|
||||||
|
|
||||||
|
Get running with Mem0 in 2 minutes. No infrastructure to deploy -- just an API key.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Python 3.10+ or Node.js 18+
|
||||||
|
- A Mem0 Platform API key ([Get one here](https://app.mem0.ai/dashboard/api-keys))
|
||||||
|
|
||||||
|
## Python Setup
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install mem0ai
|
||||||
|
export MEM0_API_KEY="m0-your-api-key"
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
from mem0 import MemoryClient
|
||||||
|
|
||||||
|
client = MemoryClient(api_key="your-api-key")
|
||||||
|
|
||||||
|
# Add a memory
|
||||||
|
messages = [
|
||||||
|
{"role": "user", "content": "I'm a vegetarian and allergic to nuts."},
|
||||||
|
{"role": "assistant", "content": "Got it! I'll remember your dietary preferences."}
|
||||||
|
]
|
||||||
|
client.add(messages, user_id="user123")
|
||||||
|
|
||||||
|
# Search memories
|
||||||
|
results = client.search("What are my dietary restrictions?", user_id="user123")
|
||||||
|
print(results)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Async Client
|
||||||
|
|
||||||
|
```python
|
||||||
|
from mem0 import AsyncMemoryClient
|
||||||
|
|
||||||
|
client = AsyncMemoryClient(api_key="your-api-key")
|
||||||
|
|
||||||
|
await client.add(messages, user_id="user123")
|
||||||
|
results = await client.search("query", user_id="user123")
|
||||||
|
```
|
||||||
|
|
||||||
|
## TypeScript / JavaScript Setup
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install mem0ai
|
||||||
|
export MEM0_API_KEY="m0-your-api-key"
|
||||||
|
```
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import MemoryClient from 'mem0ai';
|
||||||
|
|
||||||
|
const client = new MemoryClient({ apiKey: 'your-api-key' });
|
||||||
|
|
||||||
|
// Add a memory
|
||||||
|
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" });
|
||||||
|
|
||||||
|
// Search memories
|
||||||
|
const results = await client.search("What are my dietary restrictions?", {
|
||||||
|
user_id: "user123"
|
||||||
|
});
|
||||||
|
console.log(results);
|
||||||
|
```
|
||||||
|
|
||||||
|
## cURL
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export MEM0_API_KEY="m0-your-api-key"
|
||||||
|
|
||||||
|
# Add memory
|
||||||
|
curl -X POST https://api.mem0.ai/v1/memories/ \
|
||||||
|
-H "Authorization: Token $MEM0_API_KEY" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"messages": [
|
||||||
|
{"role": "user", "content": "I am a vegetarian and allergic to nuts."},
|
||||||
|
{"role": "assistant", "content": "Got it! I will remember your dietary preferences."}
|
||||||
|
],
|
||||||
|
"user_id": "user123"
|
||||||
|
}'
|
||||||
|
|
||||||
|
# Search memories
|
||||||
|
curl -X POST https://api.mem0.ai/v2/memories/search/ \
|
||||||
|
-H "Authorization: Token $MEM0_API_KEY" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"query": "What are my dietary restrictions?",
|
||||||
|
"filters": {"user_id": "user123"}
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Sample Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"results": [
|
||||||
|
{
|
||||||
|
"id": "14e1b28a-2014-40ad-ac42-69c9ef42193d",
|
||||||
|
"memory": "Allergic to nuts",
|
||||||
|
"user_id": "user123",
|
||||||
|
"categories": ["health"],
|
||||||
|
"created_at": "2025-10-22T04:40:22.864647-07:00",
|
||||||
|
"score": 0.30
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
- [SDK Guide](sdk-guide.md) -- all methods for Python and TypeScript
|
||||||
|
- [API Reference](api-reference.md) -- REST endpoints and memory object structure
|
||||||
|
- [Integration Patterns](integration-patterns.md) -- LangChain, CrewAI, Vercel AI, etc.
|
||||||
@@ -0,0 +1,308 @@
|
|||||||
|
# Mem0 SDK Guide
|
||||||
|
|
||||||
|
Complete SDK reference for Python and TypeScript. All methods use `MemoryClient` (Platform API).
|
||||||
|
|
||||||
|
## Initialization
|
||||||
|
|
||||||
|
**Python:**
|
||||||
|
```python
|
||||||
|
from mem0 import MemoryClient
|
||||||
|
client = MemoryClient(api_key="m0-your-api-key")
|
||||||
|
```
|
||||||
|
|
||||||
|
**Python (Async):**
|
||||||
|
```python
|
||||||
|
from mem0 import AsyncMemoryClient
|
||||||
|
client = AsyncMemoryClient(api_key="m0-your-api-key")
|
||||||
|
```
|
||||||
|
|
||||||
|
**TypeScript:**
|
||||||
|
```typescript
|
||||||
|
import MemoryClient from 'mem0ai';
|
||||||
|
const client = new MemoryClient({ apiKey: 'm0-your-api-key' });
|
||||||
|
```
|
||||||
|
|
||||||
|
Constructor accepts `apiKey` (required) and `host` (optional, default: `https://api.mem0.ai`).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## add() -- Store Memories
|
||||||
|
|
||||||
|
**Python:**
|
||||||
|
```python
|
||||||
|
messages = [
|
||||||
|
{"role": "user", "content": "I'm a vegetarian and allergic to nuts."},
|
||||||
|
{"role": "assistant", "content": "Got it! I'll remember that."}
|
||||||
|
]
|
||||||
|
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 });
|
||||||
|
```
|
||||||
|
|
||||||
|
### Parameters
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
|------|------|-------------|
|
||||||
|
| `messages` | array | `[{"role": "user", "content": "..."}]` |
|
||||||
|
| `user_id` | string | User identifier (recommended) |
|
||||||
|
| `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."}],
|
||||||
|
user_id="alice",
|
||||||
|
infer=False,
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## search() -- Find Memories
|
||||||
|
|
||||||
|
**Python:**
|
||||||
|
```python
|
||||||
|
results = client.search("dietary preferences?", user_id="alice")
|
||||||
|
|
||||||
|
# With filters and reranking
|
||||||
|
results = client.search(
|
||||||
|
query="work experience",
|
||||||
|
filters={"AND": [{"user_id": "alice"}, {"categories": {"contains": "professional_details"}}]},
|
||||||
|
top_k=5,
|
||||||
|
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("work experience", {
|
||||||
|
filters: { AND: [{ user_id: "alice" }, { categories: { contains: "professional_details" } }] },
|
||||||
|
top_k: 5,
|
||||||
|
rerank: true,
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Parameters
|
||||||
|
|
||||||
|
| 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 |
|
||||||
|
|
||||||
|
### Common Filter Patterns
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Single user (shorthand)
|
||||||
|
client.search("query", 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"]}}]}
|
||||||
|
|
||||||
|
# Wildcard (match any non-null run)
|
||||||
|
filters={"AND": [{"user_id": "alice"}, {"run_id": "*"}]}
|
||||||
|
|
||||||
|
# Date range
|
||||||
|
filters={"AND": [
|
||||||
|
{"user_id": "alice"},
|
||||||
|
{"created_at": {"gte": "2024-01-01T00:00:00Z"}},
|
||||||
|
{"created_at": {"lt": "2024-02-01T00:00:00Z"}}
|
||||||
|
]}
|
||||||
|
|
||||||
|
# Exclude categories with NOT
|
||||||
|
filters={"AND": [{"user_id": "user_123"}, {"NOT": {"categories": {"in": ["spam", "test"]}}}]}
|
||||||
|
|
||||||
|
# Multi-dimensional query
|
||||||
|
filters={"AND": [
|
||||||
|
{"user_id": "user_123"},
|
||||||
|
{"keywords": {"icontains": "invoice"}},
|
||||||
|
{"categories": {"in": ["finance"]}},
|
||||||
|
{"created_at": {"gte": "2024-01-01T00:00:00Z"}}
|
||||||
|
]}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## get() / getAll() -- Retrieve Memories
|
||||||
|
|
||||||
|
**Python:**
|
||||||
|
```python
|
||||||
|
# Single memory by ID
|
||||||
|
memory = client.get(memory_id="ea925981-...")
|
||||||
|
|
||||||
|
# All memories for a user
|
||||||
|
memories = client.get_all(filters={"AND": [{"user_id": "alice"}]})
|
||||||
|
|
||||||
|
# With date range
|
||||||
|
memories = client.get_all(
|
||||||
|
filters={"AND": [
|
||||||
|
{"user_id": "alex"},
|
||||||
|
{"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" }] } });
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note:** `get_all` requires at least one of `user_id`, `agent_id`, `app_id`, or `run_id` in filters.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## update() -- Modify Memories
|
||||||
|
|
||||||
|
**Python:**
|
||||||
|
```python
|
||||||
|
client.update(memory_id="ea925981-...", text="Updated: vegan since 2024")
|
||||||
|
client.update(memory_id="ea925981-...", text="Updated", metadata={"verified": True})
|
||||||
|
```
|
||||||
|
|
||||||
|
**TypeScript:**
|
||||||
|
```typescript
|
||||||
|
await client.update("ea925981-...", { text: "Updated: vegan since 2024" });
|
||||||
|
```
|
||||||
|
|
||||||
|
Cannot update immutable memories.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## delete() / deleteAll() -- Remove Memories
|
||||||
|
|
||||||
|
**Python:**
|
||||||
|
```python
|
||||||
|
client.delete(memory_id="ea925981-...")
|
||||||
|
client.delete_all(user_id="alice") # Irreversible bulk delete
|
||||||
|
```
|
||||||
|
|
||||||
|
**TypeScript:**
|
||||||
|
```typescript
|
||||||
|
await client.delete("ea925981-...");
|
||||||
|
await client.deleteAll({ user_id: "alice" });
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## history() -- Track Changes
|
||||||
|
|
||||||
|
**Python:**
|
||||||
|
```python
|
||||||
|
history = client.history(memory_id="ea925981-...")
|
||||||
|
# Returns: [{previous_value, new_value, action, timestamps}]
|
||||||
|
```
|
||||||
|
|
||||||
|
**TypeScript:**
|
||||||
|
```typescript
|
||||||
|
const history = await client.history("ea925981-...");
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Batch Operations (TypeScript)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Batch update
|
||||||
|
await client.batchUpdate([
|
||||||
|
{ memoryId: "uuid-1", text: "Updated text" },
|
||||||
|
{ memoryId: "uuid-2", text: "Another updated text" },
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Batch delete
|
||||||
|
await client.batchDelete(["uuid-1", "uuid-2", "uuid-3"]);
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Additional Methods
|
||||||
|
|
||||||
|
```python
|
||||||
|
# List all users/agents/sessions with memories
|
||||||
|
users = client.users()
|
||||||
|
|
||||||
|
# Delete a user/agent entity
|
||||||
|
client.delete_users(user_id="alice")
|
||||||
|
|
||||||
|
# Submit feedback on a memory
|
||||||
|
client.feedback(memory_id="...", feedback="POSITIVE", feedback_reason="Accurate extraction")
|
||||||
|
|
||||||
|
# Export memories
|
||||||
|
export = client.create_memory_export(filters={"AND": [{"user_id": "alice"}]})
|
||||||
|
data = client.get_memory_export(memory_export_id=export["id"])
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Common Pitfalls
|
||||||
|
|
||||||
|
1. **Entity cross-filtering fails silently** -- `AND` with `user_id` + `agent_id` returns empty. Use `OR`.
|
||||||
|
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.
|
||||||
|
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`).
|
||||||
@@ -0,0 +1,720 @@
|
|||||||
|
# Mem0 Use Cases & Examples
|
||||||
|
|
||||||
|
Real-world implementation patterns for Mem0 Platform. Each use case includes complete, runnable code in both Python and TypeScript.
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
- [Personalized AI Companion](#1-personalized-ai-companion)
|
||||||
|
- [Customer Support with Categories](#2-customer-support-with-categories)
|
||||||
|
- [Healthcare Coach](#3-healthcare-coach)
|
||||||
|
- [Content Creation Workflow](#4-content-creation-workflow)
|
||||||
|
- [Multi-Agent / Multi-Tenant](#5-multi-agent--multi-tenant)
|
||||||
|
- [Personalized Search](#6-personalized-search)
|
||||||
|
- [Email Intelligence](#7-email-intelligence)
|
||||||
|
- [Common Patterns Across Use Cases](#common-patterns-across-use-cases)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Personalized AI Companion
|
||||||
|
|
||||||
|
A fitness coach that remembers goals, preferences, and progress across sessions. Mem0 persists context across app restarts — no session state needed.
|
||||||
|
|
||||||
|
### Implementation (Python)
|
||||||
|
|
||||||
|
```python
|
||||||
|
from mem0 import MemoryClient
|
||||||
|
from openai import OpenAI
|
||||||
|
|
||||||
|
mem0 = MemoryClient()
|
||||||
|
openai_client = OpenAI()
|
||||||
|
|
||||||
|
def chat(user_input: str, user_id: str) -> str:
|
||||||
|
# 1. Retrieve relevant memories
|
||||||
|
memories = mem0.search(user_input, user_id=user_id)
|
||||||
|
context = "\n".join([f"- {m['memory']}" for m in memories.get("results", [])])
|
||||||
|
|
||||||
|
# 2. Generate response with memory context
|
||||||
|
system_prompt = f"""You are Ray, a personal fitness coach.
|
||||||
|
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",
|
||||||
|
messages=[
|
||||||
|
{"role": "system", "content": system_prompt},
|
||||||
|
{"role": "user", "content": user_input},
|
||||||
|
]
|
||||||
|
)
|
||||||
|
reply = response.choices[0].message.content
|
||||||
|
|
||||||
|
# 3. Store interaction for future context
|
||||||
|
mem0.add(
|
||||||
|
[{"role": "user", "content": user_input}, {"role": "assistant", "content": reply}],
|
||||||
|
user_id=user_id
|
||||||
|
)
|
||||||
|
return reply
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
chat("I want to run a marathon in under 4 hours", user_id="max")
|
||||||
|
# Next day, app restarted:
|
||||||
|
chat("What should I focus on today?", user_id="max")
|
||||||
|
# Ray remembers the sub-4 marathon goal
|
||||||
|
```
|
||||||
|
|
||||||
|
### Implementation (TypeScript)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import MemoryClient from 'mem0ai';
|
||||||
|
import OpenAI from 'openai';
|
||||||
|
|
||||||
|
const mem0 = new MemoryClient({ apiKey: process.env.MEM0_API_KEY! });
|
||||||
|
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 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',
|
||||||
|
messages: [
|
||||||
|
{ role: 'system', content: `You are Ray, a personal fitness coach.\nUser context:\n${context}` },
|
||||||
|
{ role: 'user', content: userInput },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const reply = response.choices[0].message.content!;
|
||||||
|
|
||||||
|
// 3. Store interaction
|
||||||
|
await mem0.add(
|
||||||
|
[{ role: 'user', content: userInput }, { role: 'assistant', content: reply }],
|
||||||
|
{ user_id: userId }
|
||||||
|
);
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Key Benefits
|
||||||
|
|
||||||
|
- Context persists across app restarts — no session management needed
|
||||||
|
- Memories are automatically deduplicated and updated
|
||||||
|
- Works with any LLM provider (OpenAI, Anthropic, etc.)
|
||||||
|
|
||||||
|
**Best for:** Fitness coaches, tutors, therapists — any assistant that needs to remember goals across sessions.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Customer Support with Categories
|
||||||
|
|
||||||
|
Auto-categorize support data so teams retrieve the right facts fast. Uses custom categories for structured retrieval.
|
||||||
|
|
||||||
|
### Implementation (Python)
|
||||||
|
|
||||||
|
```python
|
||||||
|
from mem0 import MemoryClient
|
||||||
|
|
||||||
|
client = MemoryClient()
|
||||||
|
|
||||||
|
# 1. Define categories at the project level (one-time setup)
|
||||||
|
custom_categories = [
|
||||||
|
{"support_tickets": "Customer issues and resolutions"},
|
||||||
|
{"account_info": "Account details and preferences"},
|
||||||
|
{"billing": "Payment history and billing questions"},
|
||||||
|
{"product_feedback": "Feature requests and feedback"},
|
||||||
|
]
|
||||||
|
client.project.update(custom_categories=custom_categories)
|
||||||
|
|
||||||
|
# 2. Store interactions — auto-classified into categories
|
||||||
|
def log_support_interaction(user_id: str, message: str, priority: str = "normal"):
|
||||||
|
client.add(
|
||||||
|
[{"role": "user", "content": message}],
|
||||||
|
user_id=user_id,
|
||||||
|
metadata={"priority": priority, "source": "support_chat"}
|
||||||
|
)
|
||||||
|
|
||||||
|
# 3. Retrieve by category
|
||||||
|
def get_billing_issues(user_id: str):
|
||||||
|
return client.get_all(
|
||||||
|
filters={
|
||||||
|
"AND": [
|
||||||
|
{"user_id": user_id},
|
||||||
|
{"categories": {"in": ["billing"]}}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
def search_support_history(user_id: str, query: str):
|
||||||
|
return client.search(
|
||||||
|
query,
|
||||||
|
filters={
|
||||||
|
"AND": [
|
||||||
|
{"user_id": user_id},
|
||||||
|
{"categories": {"contains": "support_tickets"}}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
top_k=5
|
||||||
|
)
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
log_support_interaction("maria", "I was charged twice for last month's subscription", priority="high")
|
||||||
|
log_support_interaction("maria", "The dashboard is loading slowly on mobile")
|
||||||
|
billing = get_billing_issues("maria") # Returns only billing-related memories
|
||||||
|
```
|
||||||
|
|
||||||
|
### Implementation (TypeScript)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import MemoryClient from 'mem0ai';
|
||||||
|
|
||||||
|
const client = new MemoryClient({ apiKey: process.env.MEM0_API_KEY! });
|
||||||
|
|
||||||
|
// Setup categories (one-time)
|
||||||
|
await client.updateProject({
|
||||||
|
custom_categories: [
|
||||||
|
{ support_tickets: 'Customer issues and resolutions' },
|
||||||
|
{ billing: 'Payment history and billing questions' },
|
||||||
|
{ product_feedback: 'Feature requests and feedback' },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
async function logInteraction(userId: string, message: string, priority = 'normal') {
|
||||||
|
await client.add(
|
||||||
|
[{ role: 'user', content: message }],
|
||||||
|
{ user_id: userId, metadata: { priority, source: 'support_chat' } }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getBillingIssues(userId: string) {
|
||||||
|
return client.getAll({
|
||||||
|
filters: { AND: [{ user_id: userId }, { categories: { in: ['billing'] } }] },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Key Benefits
|
||||||
|
|
||||||
|
- Automatic categorization — no manual tagging
|
||||||
|
- Filter by category for structured retrieval
|
||||||
|
- Metadata (`priority`, `source`) enables multi-dimensional queries
|
||||||
|
|
||||||
|
**Best for:** Help desks, SaaS support, e-commerce — structured retrieval by category eliminates manual scanning.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Healthcare Coach
|
||||||
|
|
||||||
|
Guide patients with an assistant that remembers medical history. Uses high `threshold` for confident retrieval in safety-critical contexts.
|
||||||
|
|
||||||
|
### Implementation (Python)
|
||||||
|
|
||||||
|
```python
|
||||||
|
from mem0 import MemoryClient
|
||||||
|
from openai import OpenAI
|
||||||
|
|
||||||
|
mem0 = MemoryClient()
|
||||||
|
openai_client = OpenAI()
|
||||||
|
|
||||||
|
def save_patient_info(user_id: str, information: str):
|
||||||
|
mem0.add(
|
||||||
|
[{"role": "user", "content": information}],
|
||||||
|
user_id=user_id,
|
||||||
|
run_id="healthcare_session",
|
||||||
|
metadata={"type": "patient_information"}
|
||||||
|
)
|
||||||
|
|
||||||
|
def consult(user_id: str, question: str) -> str:
|
||||||
|
# High threshold for medical accuracy
|
||||||
|
memories = mem0.search(question, user_id=user_id, top_k=5, threshold=0.7)
|
||||||
|
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",
|
||||||
|
messages=[
|
||||||
|
{"role": "system", "content": f"You are a health coach. Patient context:\n{context}"},
|
||||||
|
{"role": "user", "content": question},
|
||||||
|
]
|
||||||
|
)
|
||||||
|
reply = response.choices[0].message.content
|
||||||
|
|
||||||
|
# Store the interaction
|
||||||
|
mem0.add(
|
||||||
|
[{"role": "user", "content": question}, {"role": "assistant", "content": reply}],
|
||||||
|
user_id=user_id,
|
||||||
|
run_id="healthcare_session",
|
||||||
|
)
|
||||||
|
return reply
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
save_patient_info("alex", "I'm allergic to penicillin and take metformin for type 2 diabetes")
|
||||||
|
consult("alex", "Can I take amoxicillin for my sore throat?")
|
||||||
|
# Remembers penicillin allergy — amoxicillin is a penicillin-type antibiotic
|
||||||
|
```
|
||||||
|
|
||||||
|
### Implementation (TypeScript)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import MemoryClient from 'mem0ai';
|
||||||
|
import OpenAI from 'openai';
|
||||||
|
|
||||||
|
const mem0 = new MemoryClient({ apiKey: process.env.MEM0_API_KEY! });
|
||||||
|
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' } }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function consult(userId: string, question: string): Promise<string> {
|
||||||
|
const memories = await mem0.search(question, {
|
||||||
|
user_id: userId,
|
||||||
|
top_k: 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',
|
||||||
|
messages: [
|
||||||
|
{ role: 'system', content: `You are a health coach. Patient context:\n${context}` },
|
||||||
|
{ role: 'user', content: question },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const reply = response.choices[0].message.content!;
|
||||||
|
|
||||||
|
await mem0.add(
|
||||||
|
[{ role: 'user', content: question }, { role: 'assistant', content: reply }],
|
||||||
|
{ user_id: userId, run_id: 'healthcare_session' }
|
||||||
|
);
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Key Benefits
|
||||||
|
|
||||||
|
- High threshold (0.7) ensures only confident matches for safety-critical retrieval
|
||||||
|
- Session scoping via `run_id` groups related health interactions
|
||||||
|
- Metadata tagging separates patient info from conversation history
|
||||||
|
|
||||||
|
**Best for:** Telehealth, wellness apps, patient management — persistent health context across visits.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Content Creation Workflow
|
||||||
|
|
||||||
|
Store voice guidelines once and apply them across every draft. Uses `run_id` and `metadata` to scope writing preferences per session.
|
||||||
|
|
||||||
|
### Implementation (Python)
|
||||||
|
|
||||||
|
```python
|
||||||
|
from mem0 import MemoryClient
|
||||||
|
from openai import OpenAI
|
||||||
|
|
||||||
|
mem0 = MemoryClient()
|
||||||
|
openai_client = OpenAI()
|
||||||
|
|
||||||
|
def store_writing_preferences(user_id: str, preferences: str):
|
||||||
|
mem0.add(
|
||||||
|
[{"role": "user", "content": preferences}],
|
||||||
|
user_id=user_id,
|
||||||
|
run_id="editing_session",
|
||||||
|
metadata={"type": "preferences", "category": "writing_style"}
|
||||||
|
)
|
||||||
|
|
||||||
|
def draft_content(user_id: str, topic: str) -> str:
|
||||||
|
# Retrieve writing preferences
|
||||||
|
prefs = mem0.search(
|
||||||
|
"writing style preferences",
|
||||||
|
filters={"AND": [{"user_id": user_id}, {"run_id": "editing_session"}]}
|
||||||
|
)
|
||||||
|
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",
|
||||||
|
messages=[
|
||||||
|
{"role": "system", "content": f"Write content matching these style preferences:\n{style_context}"},
|
||||||
|
{"role": "user", "content": f"Write a blog post about: {topic}"},
|
||||||
|
]
|
||||||
|
)
|
||||||
|
return response.choices[0].message.content
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
store_writing_preferences("writer_01", "I prefer short sentences. Active voice. No jargon. Use analogies.")
|
||||||
|
draft_content("writer_01", "Why AI memory matters for chatbots")
|
||||||
|
# Drafts content matching the stored voice guidelines
|
||||||
|
```
|
||||||
|
|
||||||
|
### Implementation (TypeScript)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import MemoryClient from 'mem0ai';
|
||||||
|
import OpenAI from 'openai';
|
||||||
|
|
||||||
|
const mem0 = new MemoryClient({ apiKey: process.env.MEM0_API_KEY! });
|
||||||
|
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' } }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function draftContent(userId: string, topic: string): Promise<string> {
|
||||||
|
const prefs = await mem0.search('writing style preferences', {
|
||||||
|
filters: { AND: [{ user_id: userId }, { run_id: 'editing_session' }] },
|
||||||
|
});
|
||||||
|
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',
|
||||||
|
messages: [
|
||||||
|
{ role: 'system', content: `Write content matching these preferences:\n${styleContext}` },
|
||||||
|
{ role: 'user', content: `Write a blog post about: ${topic}` },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
return response.choices[0].message.content!;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Key Benefits
|
||||||
|
|
||||||
|
- Voice consistency across all content without repeating guidelines
|
||||||
|
- Scoped sessions let you maintain different style profiles
|
||||||
|
- Preferences update automatically as you refine them
|
||||||
|
|
||||||
|
**Best for:** Marketing teams, technical writers, agencies — consistent voice across all content.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Multi-Agent / Multi-Tenant
|
||||||
|
|
||||||
|
Keep memories separate using `user_id`, `agent_id`, `app_id`, and `run_id` scoping. Critical for multi-agent workflows and multi-tenant apps.
|
||||||
|
|
||||||
|
### Implementation (Python)
|
||||||
|
|
||||||
|
```python
|
||||||
|
from mem0 import MemoryClient
|
||||||
|
|
||||||
|
client = MemoryClient()
|
||||||
|
|
||||||
|
# Store memories scoped to user + agent + session
|
||||||
|
def store_scoped_memory(messages: list, user_id: str, agent_id: str, run_id: str, app_id: str):
|
||||||
|
client.add(
|
||||||
|
messages,
|
||||||
|
user_id=user_id,
|
||||||
|
agent_id=agent_id,
|
||||||
|
run_id=run_id,
|
||||||
|
app_id=app_id
|
||||||
|
)
|
||||||
|
|
||||||
|
# Query within a specific scope
|
||||||
|
def search_user_session(query: str, user_id: str, app_id: str, run_id: str):
|
||||||
|
"""Search memories for a specific user within a specific session."""
|
||||||
|
return client.search(
|
||||||
|
query,
|
||||||
|
filters={
|
||||||
|
"AND": [
|
||||||
|
{"user_id": user_id},
|
||||||
|
{"app_id": app_id},
|
||||||
|
{"run_id": run_id}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
def search_agent_knowledge(query: str, agent_id: str, app_id: str):
|
||||||
|
"""Search all memories an agent has across all users."""
|
||||||
|
return client.search(
|
||||||
|
query,
|
||||||
|
filters={
|
||||||
|
"AND": [
|
||||||
|
{"agent_id": agent_id},
|
||||||
|
{"app_id": app_id}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Usage: Travel concierge app with multiple agents
|
||||||
|
store_scoped_memory(
|
||||||
|
[{"role": "user", "content": "I'm vegetarian and prefer window seats"}],
|
||||||
|
user_id="traveler_cam",
|
||||||
|
agent_id="travel_planner",
|
||||||
|
run_id="tokyo-2025",
|
||||||
|
app_id="concierge_app"
|
||||||
|
)
|
||||||
|
|
||||||
|
# User-scoped query: "What does Cam prefer?"
|
||||||
|
user_mems = search_user_session("dietary restrictions?", "traveler_cam", "concierge_app", "tokyo-2025")
|
||||||
|
|
||||||
|
# Agent-scoped query: "What do all travelers prefer?" (across users)
|
||||||
|
agent_mems = search_agent_knowledge("common dietary restrictions?", "travel_planner", "concierge_app")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Implementation (TypeScript)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import MemoryClient from 'mem0ai';
|
||||||
|
|
||||||
|
const client = new MemoryClient({ apiKey: process.env.MEM0_API_KEY! });
|
||||||
|
|
||||||
|
async function storeScopedMemory(
|
||||||
|
messages: Array<{ role: string; content: string }>,
|
||||||
|
userId: string, agentId: string, runId: string, appId: string
|
||||||
|
) {
|
||||||
|
await client.add(messages, {
|
||||||
|
user_id: userId,
|
||||||
|
agent_id: agentId,
|
||||||
|
run_id: runId,
|
||||||
|
app_id: appId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function searchUserSession(query: string, userId: string, appId: string, runId: string) {
|
||||||
|
return client.search(query, {
|
||||||
|
filters: { AND: [{ user_id: userId }, { app_id: appId }, { run_id: runId }] },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function searchAgentKnowledge(query: string, agentId: string, appId: string) {
|
||||||
|
return client.search(query, {
|
||||||
|
filters: { AND: [{ agent_id: agentId }, { app_id: appId }] },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Key Benefits
|
||||||
|
|
||||||
|
- Full isolation between users, agents, sessions, and apps
|
||||||
|
- Query at any scope level — user, agent, session, or app-wide
|
||||||
|
- No memory leakage between tenants
|
||||||
|
|
||||||
|
**Best for:** Multi-agent workflows, multi-tenant SaaS — proper isolation at every level.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Personalized Search
|
||||||
|
|
||||||
|
Blend real-time search results with personal context. Uses `custom_instructions` to infer preferences from queries.
|
||||||
|
|
||||||
|
### Implementation (Python)
|
||||||
|
|
||||||
|
```python
|
||||||
|
from mem0 import MemoryClient
|
||||||
|
from openai import OpenAI
|
||||||
|
|
||||||
|
mem0 = MemoryClient()
|
||||||
|
openai_client = OpenAI()
|
||||||
|
|
||||||
|
# One-time setup: configure Mem0 to infer from queries
|
||||||
|
mem0.project.update(
|
||||||
|
custom_instructions="""Infer user preferences and facts from their search queries.
|
||||||
|
Extract dietary preferences, location, interests, and purchase history."""
|
||||||
|
)
|
||||||
|
|
||||||
|
def personalized_search(user_id: str, query: str, search_results: list) -> str:
|
||||||
|
# Get user context from memory
|
||||||
|
memories = mem0.search(query, user_id=user_id, top_k=5)
|
||||||
|
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",
|
||||||
|
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}"},
|
||||||
|
]
|
||||||
|
)
|
||||||
|
reply = response.choices[0].message.content
|
||||||
|
|
||||||
|
# Store the query to learn preferences over time
|
||||||
|
mem0.add(
|
||||||
|
[{"role": "user", "content": query}],
|
||||||
|
user_id=user_id
|
||||||
|
)
|
||||||
|
return reply
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
personalized_search("user_42", "best restaurants nearby", ["Restaurant A", "Restaurant B"])
|
||||||
|
# Over time, Mem0 learns: "user prefers vegetarian, lives in Austin"
|
||||||
|
# Future searches are automatically personalized
|
||||||
|
```
|
||||||
|
|
||||||
|
### Implementation (TypeScript)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import MemoryClient from 'mem0ai';
|
||||||
|
import OpenAI from 'openai';
|
||||||
|
|
||||||
|
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 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',
|
||||||
|
messages: [
|
||||||
|
{ role: 'system', content: `Personalize results using user context:\n${context}` },
|
||||||
|
{ role: 'user', content: `Query: ${query}\nResults: ${searchResults.join(', ')}` },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const reply = response.choices[0].message.content!;
|
||||||
|
|
||||||
|
await mem0.add([{ role: 'user', content: query }], { user_id: userId });
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Key Benefits
|
||||||
|
|
||||||
|
- Learns preferences from queries automatically via `custom_instructions`
|
||||||
|
- Personalizes any search provider (Tavily, Google, Bing)
|
||||||
|
- Zero manual preference setup — improves over time
|
||||||
|
|
||||||
|
**Best for:** Personalized search engines, recommendation systems — search results tailored to individual users.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Email Intelligence
|
||||||
|
|
||||||
|
Capture, categorize, and recall inbox threads using persistent memories with rich metadata.
|
||||||
|
|
||||||
|
### Implementation (Python)
|
||||||
|
|
||||||
|
```python
|
||||||
|
from mem0 import MemoryClient
|
||||||
|
|
||||||
|
client = MemoryClient()
|
||||||
|
|
||||||
|
def store_email(user_id: str, sender: str, subject: str, body: str, date: str):
|
||||||
|
client.add(
|
||||||
|
[{"role": "user", "content": f"Email from {sender}: {subject}\n\n{body}"}],
|
||||||
|
user_id=user_id,
|
||||||
|
metadata={"email_type": "incoming", "sender": sender, "subject": subject, "date": date}
|
||||||
|
)
|
||||||
|
|
||||||
|
def search_emails(user_id: str, query: str):
|
||||||
|
return client.search(
|
||||||
|
query,
|
||||||
|
filters={"AND": [{"user_id": user_id}, {"categories": {"contains": "email"}}]},
|
||||||
|
top_k=10
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_emails_from_sender(user_id: str, sender: str):
|
||||||
|
return client.get_all(
|
||||||
|
filters={
|
||||||
|
"AND": [
|
||||||
|
{"user_id": user_id},
|
||||||
|
{"metadata": {"contains": sender}}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
store_email("alice", "bob@acme.com", "Q3 Budget Review", "Attached is the Q3 budget...", "2025-01-15")
|
||||||
|
store_email("alice", "carol@acme.com", "Sprint Planning", "Here are the priorities...", "2025-01-16")
|
||||||
|
|
||||||
|
results = search_emails("alice", "budget discussions")
|
||||||
|
sender_emails = get_emails_from_sender("alice", "bob@acme.com")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Implementation (TypeScript)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import MemoryClient from 'mem0ai';
|
||||||
|
|
||||||
|
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 } }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function searchEmails(userId: string, query: string) {
|
||||||
|
return client.search(query, {
|
||||||
|
filters: { AND: [{ user_id: userId }, { categories: { contains: 'email' } }] },
|
||||||
|
top_k: 10,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Key Benefits
|
||||||
|
|
||||||
|
- Rich metadata enables multi-dimensional queries (sender, date, subject)
|
||||||
|
- Category filtering separates emails from other memory types
|
||||||
|
- Semantic search across all email content
|
||||||
|
|
||||||
|
**Best for:** Inbox management, email automation — searchable email memories with metadata filtering.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Common Patterns Across Use Cases
|
||||||
|
|
||||||
|
### Pattern 1: Retrieve → Generate → Store
|
||||||
|
|
||||||
|
Every use case follows the same 3-step loop:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# 1. Retrieve relevant context
|
||||||
|
memories = mem0.search(user_input, user_id=user_id)
|
||||||
|
context = "\n".join([m["memory"] for m in memories.get("results", [])])
|
||||||
|
|
||||||
|
# 2. Generate with context
|
||||||
|
response = llm.generate(system_prompt=f"Context:\n{context}", user_input=user_input)
|
||||||
|
|
||||||
|
# 3. Store the interaction
|
||||||
|
mem0.add(
|
||||||
|
[{"role": "user", "content": user_input}, {"role": "assistant", "content": response}],
|
||||||
|
user_id=user_id
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pattern 2: Scope with Entity Identifiers
|
||||||
|
|
||||||
|
Use `user_id`, `agent_id`, `app_id`, and `run_id` to isolate memories:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# User-level: personal preferences
|
||||||
|
client.add(messages, user_id="alice")
|
||||||
|
|
||||||
|
# Session-level: conversation within one session
|
||||||
|
client.add(messages, user_id="alice", run_id="session_123")
|
||||||
|
|
||||||
|
# Agent-level: agent-specific knowledge
|
||||||
|
client.add(messages, agent_id="support_bot", app_id="helpdesk")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pattern 3: Rich Metadata for Filtering
|
||||||
|
|
||||||
|
Attach structured metadata for multi-dimensional queries:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Store with metadata
|
||||||
|
client.add(messages, user_id="alice", metadata={"priority": "high", "source": "phone_call"})
|
||||||
|
|
||||||
|
# Filter by category + metadata
|
||||||
|
client.search("billing issues", filters={
|
||||||
|
"AND": [{"user_id": "alice"}, {"categories": {"contains": "billing"}}]
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pattern 4: Custom Instructions for Domain-Specific Extraction
|
||||||
|
|
||||||
|
Control what Mem0 extracts from conversations:
|
||||||
|
|
||||||
|
```python
|
||||||
|
client.project.update(
|
||||||
|
custom_instructions="Extract medical conditions, medications, and allergies. Exclude billing info."
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## More Examples
|
||||||
|
|
||||||
|
For 30+ cookbooks with complete working code: [docs.mem0.ai/cookbooks](https://docs.mem0.ai/cookbooks)
|
||||||
Executable
+224
@@ -0,0 +1,224 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Mem0 Documentation Search Agent (Mintlify-based)
|
||||||
|
On-demand search tool for querying Mem0 documentation without storing content locally.
|
||||||
|
|
||||||
|
This tool leverages Mintlify's documentation structure to perform just-in-time
|
||||||
|
retrieval of technical information from docs.mem0.ai.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
python mem0_doc_search.py --query "how to add graph memory"
|
||||||
|
python mem0_doc_search.py --query "filter syntax for categories"
|
||||||
|
python mem0_doc_search.py --page "/platform/features/graph-memory"
|
||||||
|
python mem0_doc_search.py --index
|
||||||
|
python mem0_doc_search.py --query "webhook events" --section platform
|
||||||
|
|
||||||
|
Purpose:
|
||||||
|
- Avoid bloating local context with full documentation
|
||||||
|
- Enable just-in-time retrieval of technical details
|
||||||
|
- Query specific documentation pages on demand
|
||||||
|
- Search across the full Mem0 documentation site
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
import urllib.error
|
||||||
|
import urllib.parse
|
||||||
|
import urllib.request
|
||||||
|
|
||||||
|
DOCS_BASE = "https://docs.mem0.ai"
|
||||||
|
SEARCH_ENDPOINT = f"{DOCS_BASE}/api/search"
|
||||||
|
LLMS_INDEX = f"{DOCS_BASE}/llms.txt"
|
||||||
|
|
||||||
|
# Known documentation sections for targeted retrieval
|
||||||
|
SECTION_MAP = {
|
||||||
|
"platform": [
|
||||||
|
"/platform/overview",
|
||||||
|
"/platform/quickstart",
|
||||||
|
"/platform/features",
|
||||||
|
"/platform/features/graph-memory",
|
||||||
|
"/platform/features/selective-memory",
|
||||||
|
"/platform/features/custom-categories",
|
||||||
|
"/platform/features/v2-memory-filters",
|
||||||
|
"/platform/features/async-client",
|
||||||
|
"/platform/features/webhooks",
|
||||||
|
"/platform/features/multimodal",
|
||||||
|
],
|
||||||
|
"api": [
|
||||||
|
"/api-reference/memory/add-memories",
|
||||||
|
"/api-reference/memory/v2-search-memories",
|
||||||
|
"/api-reference/memory/v2-get-memories",
|
||||||
|
"/api-reference/memory/get-memory",
|
||||||
|
"/api-reference/memory/update-memory",
|
||||||
|
"/api-reference/memory/delete-memory",
|
||||||
|
],
|
||||||
|
"open-source": [
|
||||||
|
"/open-source/overview",
|
||||||
|
"/open-source/python-quickstart",
|
||||||
|
"/open-source/node-quickstart",
|
||||||
|
"/open-source/features",
|
||||||
|
"/open-source/features/graph-memory",
|
||||||
|
"/open-source/features/rest-api",
|
||||||
|
"/open-source/configure-components",
|
||||||
|
],
|
||||||
|
"openmemory": [
|
||||||
|
"/openmemory/overview",
|
||||||
|
"/openmemory/quickstart",
|
||||||
|
],
|
||||||
|
"sdks": [
|
||||||
|
"/sdks/python",
|
||||||
|
"/sdks/js",
|
||||||
|
],
|
||||||
|
"integrations": [
|
||||||
|
"/integrations",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_url(url: str) -> str:
|
||||||
|
"""Fetch content from a URL."""
|
||||||
|
req = urllib.request.Request(url, headers={"User-Agent": "Mem0DocSearchAgent/1.0"})
|
||||||
|
try:
|
||||||
|
with urllib.request.urlopen(req, timeout=15) as resp:
|
||||||
|
return resp.read().decode("utf-8")
|
||||||
|
except urllib.error.HTTPError as e:
|
||||||
|
return f"HTTP Error {e.code}: {e.reason}"
|
||||||
|
except urllib.error.URLError as e:
|
||||||
|
return f"URL Error: {e.reason}"
|
||||||
|
|
||||||
|
|
||||||
|
def search_docs(query: str, section: str | None = None) -> dict:
|
||||||
|
"""
|
||||||
|
Search Mem0 documentation using Mintlify's search API.
|
||||||
|
Falls back to the llms.txt index for keyword matching if the API is unavailable.
|
||||||
|
"""
|
||||||
|
# Try Mintlify search API first
|
||||||
|
params = urllib.parse.urlencode({"query": query})
|
||||||
|
search_url = f"{SEARCH_ENDPOINT}?{params}"
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = fetch_url(search_url)
|
||||||
|
data = json.loads(result)
|
||||||
|
if isinstance(data, dict) and data.get("results"):
|
||||||
|
results = data["results"]
|
||||||
|
if section and section in SECTION_MAP:
|
||||||
|
section_paths = SECTION_MAP[section]
|
||||||
|
results = [r for r in results if any(r.get("url", "").startswith(p) for p in section_paths)]
|
||||||
|
return {"source": "mintlify_search", "results": results}
|
||||||
|
except (json.JSONDecodeError, Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Fallback: search llms.txt index for matching URLs
|
||||||
|
index_content = fetch_url(LLMS_INDEX)
|
||||||
|
query_lower = query.lower()
|
||||||
|
matching_urls = []
|
||||||
|
|
||||||
|
for line in index_content.splitlines():
|
||||||
|
line = line.strip()
|
||||||
|
if not line or line.startswith("#"):
|
||||||
|
continue
|
||||||
|
if query_lower in line.lower():
|
||||||
|
matching_urls.append(line)
|
||||||
|
|
||||||
|
if section and section in SECTION_MAP:
|
||||||
|
section_paths = SECTION_MAP[section]
|
||||||
|
matching_urls = [u for u in matching_urls if any(p in u for p in section_paths)]
|
||||||
|
|
||||||
|
return {
|
||||||
|
"source": "llms_txt_index",
|
||||||
|
"query": query,
|
||||||
|
"matching_urls": matching_urls[:20],
|
||||||
|
"suggestion": "Fetch specific URLs for detailed content",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_page(page_path: str) -> dict:
|
||||||
|
"""Fetch a specific documentation page."""
|
||||||
|
url = f"{DOCS_BASE}{page_path}" if page_path.startswith("/") else page_path
|
||||||
|
content = fetch_url(url)
|
||||||
|
return {"url": url, "content": content[:10000], "truncated": len(content) > 10000}
|
||||||
|
|
||||||
|
|
||||||
|
def get_index() -> dict:
|
||||||
|
"""Fetch the full documentation index from llms.txt."""
|
||||||
|
content = fetch_url(LLMS_INDEX)
|
||||||
|
urls = [line.strip() for line in content.splitlines() if line.strip() and not line.startswith("#")]
|
||||||
|
return {"total_pages": len(urls), "urls": urls, "sections": list(SECTION_MAP.keys())}
|
||||||
|
|
||||||
|
|
||||||
|
def list_section(section: str) -> dict:
|
||||||
|
"""List all known pages in a documentation section."""
|
||||||
|
if section not in SECTION_MAP:
|
||||||
|
return {"error": f"Unknown section: {section}", "available": list(SECTION_MAP.keys())}
|
||||||
|
return {
|
||||||
|
"section": section,
|
||||||
|
"pages": [f"{DOCS_BASE}{p}" for p in SECTION_MAP[section]],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description="Search Mem0 documentation on demand")
|
||||||
|
parser.add_argument("--query", help="Search query for documentation")
|
||||||
|
parser.add_argument("--page", help="Fetch a specific page path (e.g., /platform/features/graph-memory)")
|
||||||
|
parser.add_argument("--index", action="store_true", help="Show full documentation index")
|
||||||
|
parser.add_argument("--section", help="Filter by section or list section pages")
|
||||||
|
parser.add_argument("--json", action="store_true", help="Output as JSON")
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.index:
|
||||||
|
result = get_index()
|
||||||
|
elif args.section and not args.query:
|
||||||
|
result = list_section(args.section)
|
||||||
|
elif args.page:
|
||||||
|
result = fetch_page(args.page)
|
||||||
|
elif args.query:
|
||||||
|
result = search_docs(args.query, section=args.section)
|
||||||
|
else:
|
||||||
|
parser.print_help()
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if args.json:
|
||||||
|
print(json.dumps(result, indent=2))
|
||||||
|
else:
|
||||||
|
if isinstance(result, dict):
|
||||||
|
if "results" in result:
|
||||||
|
print(f"Source: {result.get('source', 'unknown')}")
|
||||||
|
for r in result["results"]:
|
||||||
|
print(f" - {r.get('title', 'N/A')}: {r.get('url', 'N/A')}")
|
||||||
|
if r.get("description"):
|
||||||
|
print(f" {r['description'][:200]}")
|
||||||
|
elif "matching_urls" in result:
|
||||||
|
print(f"Source: {result['source']}")
|
||||||
|
print(f"Query: {result['query']}")
|
||||||
|
for url in result["matching_urls"]:
|
||||||
|
print(f" - {url}")
|
||||||
|
if result.get("suggestion"):
|
||||||
|
print(f"\n{result['suggestion']}")
|
||||||
|
elif "urls" in result:
|
||||||
|
print(f"Total documentation pages: {result['total_pages']}")
|
||||||
|
print(f"Sections: {', '.join(result['sections'])}")
|
||||||
|
for url in result["urls"][:30]:
|
||||||
|
print(f" - {url}")
|
||||||
|
if result["total_pages"] > 30:
|
||||||
|
print(f" ... and {result['total_pages'] - 30} more")
|
||||||
|
elif "pages" in result:
|
||||||
|
print(f"Section: {result['section']}")
|
||||||
|
for page in result["pages"]:
|
||||||
|
print(f" - {page}")
|
||||||
|
elif "content" in result:
|
||||||
|
print(f"URL: {result['url']}")
|
||||||
|
if result.get("truncated"):
|
||||||
|
print("[Content truncated to 10000 chars]")
|
||||||
|
print(result["content"])
|
||||||
|
elif "error" in result:
|
||||||
|
print(f"Error: {result['error']}")
|
||||||
|
if result.get("available"):
|
||||||
|
print(f"Available sections: {', '.join(result['available'])}")
|
||||||
|
else:
|
||||||
|
print(json.dumps(result, indent=2))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user