From 54aa760720c96c90bda8ee77948da26768174ff1 Mon Sep 17 00:00:00 2001 From: Kartik Date: Thu, 12 Mar 2026 22:30:39 +0530 Subject: [PATCH] feat(skills): add Mem0 Platform Claude Code skill (#4309) --- skills/mem0/LICENSE | 189 +++++ skills/mem0/README.md | 79 ++ skills/mem0/SKILL.md | 156 ++++ skills/mem0/references/api-reference.md | 140 ++++ skills/mem0/references/architecture.md | 386 ++++++++++ skills/mem0/references/features.md | 496 ++++++++++++ .../mem0/references/integration-patterns.md | 444 +++++++++++ skills/mem0/references/quickstart.md | 119 +++ skills/mem0/references/sdk-guide.md | 308 ++++++++ skills/mem0/references/use-cases.md | 720 ++++++++++++++++++ skills/mem0/scripts/mem0_doc_search.py | 224 ++++++ 11 files changed, 3261 insertions(+) create mode 100644 skills/mem0/LICENSE create mode 100644 skills/mem0/README.md create mode 100644 skills/mem0/SKILL.md create mode 100644 skills/mem0/references/api-reference.md create mode 100644 skills/mem0/references/architecture.md create mode 100644 skills/mem0/references/features.md create mode 100644 skills/mem0/references/integration-patterns.md create mode 100644 skills/mem0/references/quickstart.md create mode 100644 skills/mem0/references/sdk-guide.md create mode 100644 skills/mem0/references/use-cases.md create mode 100755 skills/mem0/scripts/mem0_doc_search.py diff --git a/skills/mem0/LICENSE b/skills/mem0/LICENSE new file mode 100644 index 000000000..78c99ae28 --- /dev/null +++ b/skills/mem0/LICENSE @@ -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. diff --git a/skills/mem0/README.md b/skills/mem0/README.md new file mode 100644 index 000000000..aa4e49f62 --- /dev/null +++ b/skills/mem0/README.md @@ -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 diff --git a/skills/mem0/SKILL.md b/skills/mem0/SKILL.md new file mode 100644 index 000000000..8a01c64f3 --- /dev/null +++ b/skills/mem0/SKILL.md @@ -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) | diff --git a/skills/mem0/references/api-reference.md b/skills/mem0/references/api-reference.md new file mode 100644 index 000000000..e9fd20f24 --- /dev/null +++ b/skills/mem0/references/api-reference.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 ` + +## 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. diff --git a/skills/mem0/references/architecture.md b/skills/mem0/references/architecture.md new file mode 100644 index 000000000..f0c5c1bc8 --- /dev/null +++ b/skills/mem0/references/architecture.md @@ -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. diff --git a/skills/mem0/references/features.md b/skills/mem0/references/features.md new file mode 100644 index 000000000..fa2130f47 --- /dev/null +++ b/skills/mem0/references/features.md @@ -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") +``` diff --git a/skills/mem0/references/integration-patterns.md b/skills/mem0/references/integration-patterns.md new file mode 100644 index 000000000..e00d07ba7 --- /dev/null +++ b/skills/mem0/references/integration-patterns.md @@ -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). diff --git a/skills/mem0/references/quickstart.md b/skills/mem0/references/quickstart.md new file mode 100644 index 000000000..0954f0c88 --- /dev/null +++ b/skills/mem0/references/quickstart.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. diff --git a/skills/mem0/references/sdk-guide.md b/skills/mem0/references/sdk-guide.md new file mode 100644 index 000000000..dc744d625 --- /dev/null +++ b/skills/mem0/references/sdk-guide.md @@ -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`). diff --git a/skills/mem0/references/use-cases.md b/skills/mem0/references/use-cases.md new file mode 100644 index 000000000..eaca88896 --- /dev/null +++ b/skills/mem0/references/use-cases.md @@ -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 { + // 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 { + 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 { + 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 { + 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) diff --git a/skills/mem0/scripts/mem0_doc_search.py b/skills/mem0/scripts/mem0_doc_search.py new file mode 100755 index 000000000..19b4c903f --- /dev/null +++ b/skills/mem0/scripts/mem0_doc_search.py @@ -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()