Compare commits
45
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db5524d0db | ||
|
|
9d82e2329d | ||
|
|
789cc9d607 | ||
|
|
e59e3d5f0c | ||
|
|
d926f3697c | ||
|
|
c996b0e7fa | ||
|
|
78ca85a260 | ||
|
|
88f696a60a | ||
|
|
081eca6d8f | ||
|
|
2434b9d550 | ||
|
|
3ffea554bc | ||
|
|
1ad8a59b0c | ||
|
|
a670333d67 | ||
|
|
4c2db3e68b | ||
|
|
07f0d4f1e0 | ||
|
|
3565404eef | ||
|
|
144627c4ce | ||
|
|
6984958138 | ||
|
|
b13748c446 | ||
|
|
4642a1d6e3 | ||
|
|
686d5e987d | ||
|
|
c55447c1e4 | ||
|
|
ee67602c58 | ||
|
|
0daa5d7d03 | ||
|
|
cfb3f58e4a | ||
|
|
66230b3f1f | ||
|
|
1941cae031 | ||
|
|
fcbb70ab3b | ||
|
|
33d2bc495d | ||
|
|
c0cae68646 | ||
|
|
3b2f01796e | ||
|
|
9cd3d2cca8 | ||
|
|
c53f1f126d | ||
|
|
0b7615fa87 | ||
|
|
66d34fab3c | ||
|
|
868b63af63 | ||
|
|
6cc1c15320 | ||
|
|
7a20da59ee | ||
|
|
f89f7c7c81 | ||
|
|
5723136bed | ||
|
|
b5345f8498 | ||
|
|
6577ae7616 | ||
|
|
5e00d5c452 | ||
|
|
3b152a3e85 | ||
|
|
beca7cc873 |
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "mem0-plugins",
|
||||
"interface": {
|
||||
"displayName": "Mem0 Plugins"
|
||||
},
|
||||
"plugins": [
|
||||
{
|
||||
"name": "mem0",
|
||||
"source": {
|
||||
"source": "local",
|
||||
"path": "./mem0-plugin"
|
||||
},
|
||||
"policy": {
|
||||
"installation": "AVAILABLE",
|
||||
"authentication": "ON_INSTALL"
|
||||
},
|
||||
"category": "Productivity"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -7,6 +7,7 @@ on:
|
||||
jobs:
|
||||
build-n-publish:
|
||||
name: Build and publish Python 🐍 distributions 📦 to PyPI and TestPyPI
|
||||
if: startsWith(github.event.release.tag_name, 'v')
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
name: Publish @mem0/cli 📦 to npm
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
build-n-publish:
|
||||
name: Build and publish @mem0/cli 📦 to npm
|
||||
if: startsWith(github.event.release.tag_name, 'cli-node-v')
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write
|
||||
defaults:
|
||||
run:
|
||||
working-directory: cli/node
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '22'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
cache: 'pnpm'
|
||||
cache-dependency-path: cli/node/pnpm-lock.yaml
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build
|
||||
run: pnpm run build
|
||||
|
||||
- name: Publish to npm
|
||||
run: |
|
||||
if [ "${{ github.event.release.prerelease }}" = "true" ]; then
|
||||
PREID=$(node -p "require('./package.json').version.split('-')[1].split('.')[0]")
|
||||
npx npm@latest publish --provenance --access public --tag "$PREID"
|
||||
else
|
||||
npx npm@latest publish --provenance --access public
|
||||
fi
|
||||
@@ -0,0 +1,46 @@
|
||||
name: Publish @mem0/openclaw-mem0 📦 to npm
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
build-n-publish:
|
||||
name: Build and publish @mem0/openclaw-mem0 📦 to npm
|
||||
if: startsWith(github.event.release.tag_name, 'openclaw-v')
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write
|
||||
defaults:
|
||||
run:
|
||||
working-directory: openclaw
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '22'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
cache: 'pnpm'
|
||||
cache-dependency-path: openclaw/pnpm-lock.yaml
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build
|
||||
run: pnpm build
|
||||
|
||||
- name: Publish to npm
|
||||
run: |
|
||||
if [ "${{ github.event.release.prerelease }}" = "true" ]; then
|
||||
PREID=$(node -p "require('./package.json').version.split('-')[1].split('.')[0]")
|
||||
npx npm@latest publish --provenance --access public --tag "$PREID"
|
||||
else
|
||||
npx npm@latest publish --provenance --access public
|
||||
fi
|
||||
@@ -0,0 +1,46 @@
|
||||
name: Publish mem0ai 📦 to npm
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
build-n-publish:
|
||||
name: Build and publish mem0ai 📦 to npm
|
||||
if: startsWith(github.event.release.tag_name, 'ts-v')
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write
|
||||
defaults:
|
||||
run:
|
||||
working-directory: mem0-ts
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '22'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
cache: 'pnpm'
|
||||
cache-dependency-path: mem0-ts/pnpm-lock.yaml
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build
|
||||
run: pnpm run build
|
||||
|
||||
- name: Publish to npm
|
||||
run: |
|
||||
if [ "${{ github.event.release.prerelease }}" = "true" ]; then
|
||||
PREID=$(node -p "require('./package.json').version.split('-')[1].split('.')[0]")
|
||||
npx npm@latest publish --provenance --access public --tag "$PREID"
|
||||
else
|
||||
npx npm@latest publish --provenance --access public
|
||||
fi
|
||||
@@ -0,0 +1,46 @@
|
||||
name: Publish @mem0/vercel-ai-provider 📦 to npm
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
build-n-publish:
|
||||
name: Build and publish @mem0/vercel-ai-provider 📦 to npm
|
||||
if: startsWith(github.event.release.tag_name, 'vercel-ai-v')
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write
|
||||
defaults:
|
||||
run:
|
||||
working-directory: vercel-ai-sdk
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '22'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
cache: 'pnpm'
|
||||
cache-dependency-path: vercel-ai-sdk/pnpm-lock.yaml
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build
|
||||
run: pnpm run build
|
||||
|
||||
- name: Publish to npm
|
||||
run: |
|
||||
if [ "${{ github.event.release.prerelease }}" = "true" ]; then
|
||||
PREID=$(node -p "require('./package.json').version.split('-')[1].split('.')[0]")
|
||||
npx npm@latest publish --provenance --access public --tag "$PREID"
|
||||
else
|
||||
npx npm@latest publish --provenance --access public
|
||||
fi
|
||||
@@ -0,0 +1,580 @@
|
||||
# AGENTS.md
|
||||
|
||||
This file provides context for AI coding assistants (Claude Code, Cursor, GitHub Copilot, Codex, etc.) working with the Mem0 repository.
|
||||
|
||||
## Project Overview
|
||||
|
||||
**Mem0** ("mem-zero") is an intelligent memory layer for AI agents and assistants. It provides persistent, personalized memory via both a hosted platform API and self-hosted open-source SDKs.
|
||||
|
||||
- **Repository**: https://github.com/mem0ai/mem0
|
||||
- **Documentation**: https://docs.mem0.ai
|
||||
- **License**: Apache-2.0
|
||||
|
||||
## Repository Structure
|
||||
|
||||
This is a **polyglot monorepo** containing Python and TypeScript packages, CLIs, servers, plugins, documentation, and evaluation tooling.
|
||||
|
||||
### Key Directories
|
||||
|
||||
| Directory | Description |
|
||||
|-----------|-------------|
|
||||
| `mem0/` | Core Python SDK (`mem0ai` on PyPI) — memory, LLMs, embeddings, vector stores, graphs, rerankers |
|
||||
| `mem0-ts/` | TypeScript SDK (`mem0ai` on npm) — client + OSS memory |
|
||||
| `cli/python/` | Python CLI (`mem0-cli` on PyPI) — Typer-based, entry point `mem0` |
|
||||
| `cli/node/` | Node CLI (`@mem0/cli` on npm) — Commander-based, entry point `mem0` |
|
||||
| `vercel-ai-sdk/` | `@mem0/vercel-ai-provider` — Vercel AI SDK memory provider |
|
||||
| `openclaw/` | `@mem0/openclaw-mem0` — OpenClaw plugin for Claude Code / AI editors |
|
||||
| `server/` | FastAPI REST server for self-hosted Mem0 (Docker: FastAPI + PostgreSQL/pgvector + Neo4j) |
|
||||
| `openmemory/` | Self-hosted memory platform — `api/` (FastAPI + Alembic + MCP server) and `ui/` (Next.js 15 + React 19) |
|
||||
| `mem0-plugin/` | AI editor plugins (Claude Code, Cursor, Codex) — MCP server connection, lifecycle hooks, skills |
|
||||
| `skills/` | Claude Code skill definitions — `mem0/`, `mem0-cli/`, `mem0-vercel-ai-sdk/` |
|
||||
| `docs/` | Documentation site (Mintlify) |
|
||||
| `tests/` | Python SDK tests (pytest) |
|
||||
| `evaluation/` | Benchmarking framework — LOCOMO evals, experiment runner, score generation |
|
||||
| `examples/` | Sample projects — demo apps, Chrome extension, multi-agent patterns |
|
||||
| `cookbooks/` | Jupyter notebooks — customer support chatbot, AutoGen integration |
|
||||
| `embedchain/` | Legacy Embedchain RAG framework (maintained separately, Poetry-based) |
|
||||
| `pr-reviews/` | Pull request review materials |
|
||||
|
||||
### Core Package Dependencies
|
||||
|
||||
```
|
||||
mem0 (Python SDK) mem0-ts (TypeScript SDK)
|
||||
├── mem0/memory/ ├── src/client/ (MemoryClient — hosted)
|
||||
├── mem0/llms/ └── src/oss/ (Memory — self-hosted)
|
||||
├── mem0/embeddings/ ├── src/llms/
|
||||
├── mem0/vector_stores/ ├── src/embeddings/
|
||||
├── mem0/graphs/ ├── src/vector_stores/
|
||||
└── mem0/reranker/ └── src/graphs/
|
||||
|
||||
cli/python/ ──▶ mem0ai (optional, for OSS mode)
|
||||
cli/node/ ──▶ mem0ai (npm, for API calls)
|
||||
vercel-ai-sdk/ ──▶ ai, @ai-sdk/* providers
|
||||
openclaw/ ──▶ mem0ai (npm)
|
||||
```
|
||||
|
||||
## Development Setup
|
||||
|
||||
### Requirements
|
||||
|
||||
- **Python**: 3.9+ (3.10+ for CLI)
|
||||
- **Node.js**: v18+ (v20 or v22 recommended)
|
||||
- **pnpm**: v10+ (`npm install -g pnpm@10`) — used for all TypeScript packages
|
||||
- **Hatch**: Python build/environment tool (`pip install hatch`)
|
||||
- **Docker**: Required for `server/` and `openmemory/` development
|
||||
|
||||
### Initial Setup
|
||||
|
||||
```bash
|
||||
# Python SDK
|
||||
hatch shell dev_py_3_11 # creates environment with all deps
|
||||
pre-commit install # install git hooks
|
||||
|
||||
# TypeScript packages
|
||||
cd mem0-ts && pnpm install # TS SDK
|
||||
cd cli/node && pnpm install # Node CLI
|
||||
cd vercel-ai-sdk && pnpm install # Vercel AI provider
|
||||
cd openclaw && pnpm install # OpenClaw plugin
|
||||
```
|
||||
|
||||
## Build, Lint, and Test Commands
|
||||
|
||||
### Python SDK (`mem0/`)
|
||||
|
||||
```bash
|
||||
# Environment setup (uses Hatch)
|
||||
hatch shell dev_py_3_11 # or dev_py_3_9, dev_py_3_10, dev_py_3_12
|
||||
|
||||
# Linting and formatting
|
||||
make lint # ruff check
|
||||
make format # ruff format
|
||||
make sort # isort mem0/
|
||||
|
||||
# Tests
|
||||
make test # pytest tests/
|
||||
make test-py-3.9 # test specific Python version (3.9–3.12)
|
||||
|
||||
# Build and publish
|
||||
make build # hatch build
|
||||
make publish # hatch publish
|
||||
```
|
||||
|
||||
- **Python:** 3.9, 3.10, 3.11, 3.12
|
||||
- **Linter/formatter:** Ruff (line length **120**)
|
||||
- **Import sorting:** isort (`profile = "black"`)
|
||||
- **Test framework:** pytest (with pytest-mock, pytest-asyncio)
|
||||
- **Pre-commit hooks:** ruff + isort — run `pre-commit install` before committing
|
||||
|
||||
### TypeScript SDK (`mem0-ts/`)
|
||||
|
||||
```bash
|
||||
cd mem0-ts
|
||||
pnpm install
|
||||
pnpm run build # tsup
|
||||
pnpm run test # jest (all tests)
|
||||
pnpm run test:unit # jest --coverage (unit tests only)
|
||||
pnpm run test:integration # jest (integration tests, needs MEM0_API_KEY)
|
||||
pnpm run test:ci # jest --coverage --ci (CI mode)
|
||||
pnpm run test:watch # jest watch mode
|
||||
```
|
||||
|
||||
- **Node:** 20, 22 (CI-tested)
|
||||
- **Build:** tsup (CJS + ESM)
|
||||
- **Test:** jest
|
||||
- **Formatter:** prettier
|
||||
|
||||
### Python CLI (`cli/python/`)
|
||||
|
||||
```bash
|
||||
cd cli/python
|
||||
pip install -e ".[dev]" # dev install with ruff + pytest
|
||||
ruff check . # lint
|
||||
ruff format . # format
|
||||
pytest # test
|
||||
hatch build # build
|
||||
```
|
||||
|
||||
- **Python:** 3.10+ (not 3.9)
|
||||
- **Linter/formatter:** Ruff (line length **100** — different from root SDK)
|
||||
- **Ruff rules:** E, F, I, W, UP, B, SIM, RUF (ignores E501, B008 for Typer patterns, SIM108)
|
||||
- **Framework:** Typer + Rich + httpx
|
||||
- **Entry point:** `mem0 = "mem0_cli.app:main"`
|
||||
- **Source layout:** `src/mem0_cli/`
|
||||
- **Optional dependency:** `mem0ai` (for OSS mode, via `[oss]` extra)
|
||||
|
||||
### Node CLI (`cli/node/`)
|
||||
|
||||
```bash
|
||||
cd cli/node
|
||||
pnpm install
|
||||
pnpm run build # tsup
|
||||
pnpm run lint # biome check src/
|
||||
pnpm run lint:fix # biome check --write src/
|
||||
pnpm run typecheck # tsc --noEmit
|
||||
pnpm run test # vitest run
|
||||
pnpm run test:watch # vitest (watch mode)
|
||||
pnpm run dev # tsx src/index.ts (development)
|
||||
```
|
||||
|
||||
- **Node:** 18+ required
|
||||
- **Build:** tsup (ESM)
|
||||
- **Linter:** Biome (not ESLint, not Ruff)
|
||||
- **Test:** vitest (not jest)
|
||||
- **Framework:** Commander + Chalk + ora + cli-table3
|
||||
|
||||
### Vercel AI SDK Provider (`vercel-ai-sdk/`)
|
||||
|
||||
```bash
|
||||
cd vercel-ai-sdk
|
||||
pnpm install
|
||||
pnpm run build # tsup
|
||||
pnpm run lint # eslint
|
||||
pnpm run type-check # tsc --noEmit
|
||||
pnpm run prettier-check # prettier --check
|
||||
pnpm run test # jest
|
||||
pnpm run test:edge # vitest (edge runtime)
|
||||
pnpm run test:node # vitest (node runtime)
|
||||
```
|
||||
|
||||
- **Build:** tsup (CJS + ESM)
|
||||
- **Lint:** ESLint + Prettier
|
||||
- **Test:** jest + vitest (edge/node configs)
|
||||
|
||||
### OpenClaw Plugin (`openclaw/`)
|
||||
|
||||
```bash
|
||||
cd openclaw
|
||||
pnpm install
|
||||
pnpm run build # tsup
|
||||
pnpm run test # vitest run
|
||||
```
|
||||
|
||||
- **Build:** tsup (ESM)
|
||||
- **Test:** vitest (with Codecov in CI)
|
||||
- **Plugin manifest:** `openclaw.plugin.json`
|
||||
|
||||
### Server (`server/`)
|
||||
|
||||
```bash
|
||||
# Docker production build
|
||||
cd server
|
||||
make build # docker build -t mem0-api-server .
|
||||
make run_local # docker run -p 8000:8000 with .env
|
||||
|
||||
# Docker Compose development (FastAPI + PostgreSQL/pgvector + Neo4j)
|
||||
cd server
|
||||
docker-compose up # starts all 3 services
|
||||
# mem0 API: localhost:8888
|
||||
# PostgreSQL: localhost:8432
|
||||
# Neo4j HTTP: localhost:8474, Bolt: localhost:8687
|
||||
```
|
||||
|
||||
- **Framework:** FastAPI with uvicorn (auto-reload in dev)
|
||||
- **Services:** PostgreSQL with pgvector, Neo4j 5.x with APOC plugin
|
||||
- **Hot reload:** Dev Dockerfile mounts `server/` and `mem0/` for live changes
|
||||
|
||||
### OpenMemory (`openmemory/`)
|
||||
|
||||
```bash
|
||||
# Full stack via Docker Compose
|
||||
cd openmemory
|
||||
docker-compose up
|
||||
# Qdrant: localhost:6333
|
||||
# API (MCP): localhost:8765
|
||||
# UI: localhost:3000
|
||||
|
||||
# Individual development
|
||||
cd openmemory/api && uvicorn main:app --reload # FastAPI backend
|
||||
cd openmemory/ui && npm run dev # Next.js frontend
|
||||
|
||||
# Tests
|
||||
cd openmemory/api && pytest tests/ # API tests (e.g., test_mcp_server.py)
|
||||
```
|
||||
|
||||
- **API:** FastAPI + Alembic (DB migrations) + MCP server (Model Context Protocol)
|
||||
- **UI:** Next.js 15, React 19, Radix UI, Redux Toolkit, TailwindCSS, Recharts
|
||||
- **Vector store:** Qdrant
|
||||
|
||||
### Documentation (`docs/`)
|
||||
|
||||
```bash
|
||||
make docs # or: cd docs && mintlify dev
|
||||
```
|
||||
|
||||
- **Framework:** Mintlify
|
||||
- **API spec:** `docs/openapi.json`
|
||||
- **Structure:** `api-reference/`, `open-source/`, `platform/`, `integrations/`, `cookbooks/`, `core-concepts/`
|
||||
|
||||
### Evaluation (`evaluation/`)
|
||||
|
||||
```bash
|
||||
cd evaluation
|
||||
make run-mem0-add # Run mem0 add experiments
|
||||
make run-mem0-search # Run mem0 search experiments
|
||||
make run-mem0-plus-add # With graph memory
|
||||
make run-mem0-plus-search # With graph memory
|
||||
make run-rag # RAG baseline
|
||||
make run-full-context # Full context baseline
|
||||
make run-langmem # LangMem comparison
|
||||
make run-openai # OpenAI comparison
|
||||
```
|
||||
|
||||
## Core APIs
|
||||
|
||||
### Python
|
||||
|
||||
| Function / Class | Purpose | Import |
|
||||
|-----------------|---------|--------|
|
||||
| `Memory` | Self-hosted memory (sync) | `from mem0 import Memory` |
|
||||
| `AsyncMemory` | Self-hosted memory (async) | `from mem0 import AsyncMemory` |
|
||||
| `MemoryClient` | Hosted platform client (sync) | `from mem0 import MemoryClient` |
|
||||
| `AsyncMemoryClient` | Hosted platform client (async) | `from mem0 import AsyncMemoryClient` |
|
||||
|
||||
**Key `Memory` / `MemoryClient` methods:**
|
||||
|
||||
| Method | Purpose |
|
||||
|--------|---------|
|
||||
| `add(messages, *, user_id, agent_id, run_id, metadata)` | Store a new memory |
|
||||
| `search(query, *, user_id, agent_id, run_id, limit, filters)` | Search memories |
|
||||
| `get(memory_id)` | Retrieve a single memory by ID |
|
||||
| `get_all(*, user_id, agent_id, run_id, limit)` | List all memories |
|
||||
| `update(memory_id, data)` | Update a memory |
|
||||
| `delete(memory_id)` | Delete a memory |
|
||||
| `delete_all(*, user_id, agent_id, run_id)` | Delete all memories |
|
||||
| `history(memory_id)` | Get change history for a memory |
|
||||
|
||||
### TypeScript
|
||||
|
||||
| Export | Purpose | Import |
|
||||
|--------|---------|--------|
|
||||
| `MemoryClient` | Hosted platform client | `import { MemoryClient } from 'mem0ai'` |
|
||||
| `Memory` | Self-hosted OSS memory | `import { Memory } from 'mem0ai/oss'` |
|
||||
|
||||
## Import Patterns
|
||||
|
||||
### Python
|
||||
|
||||
| What | Import |
|
||||
|------|--------|
|
||||
| Core memory classes | `from mem0 import Memory, AsyncMemory` |
|
||||
| Platform client | `from mem0 import MemoryClient, AsyncMemoryClient` |
|
||||
| Configuration | `from mem0.configs.base import MemoryConfig` |
|
||||
| LLM providers | `from mem0.llms.<provider> import <ProviderLLM>` |
|
||||
| Embedding providers | `from mem0.embeddings.<provider> import <ProviderEmbedding>` |
|
||||
| Vector store providers | `from mem0.vector_stores.<provider> import <ProviderVectorStore>` |
|
||||
|
||||
### TypeScript
|
||||
|
||||
| What | Import |
|
||||
|------|--------|
|
||||
| Hosted client | `import { MemoryClient } from 'mem0ai'` |
|
||||
| OSS memory | `import { Memory } from 'mem0ai/oss'` |
|
||||
| Specific providers (OSS) | `import { OpenAIEmbedding } from 'mem0ai/oss'` |
|
||||
|
||||
## Coding Standards
|
||||
|
||||
### File Naming Conventions
|
||||
|
||||
- **Python source files:** `snake_case.py` (e.g., `azure_openai.py`, `cohere_reranker.py`)
|
||||
- **Python test files:** `test_<module>.py` (e.g., `test_memory.py`, `test_main.py`)
|
||||
- **TypeScript source files:** `snake_case.ts` (e.g., `azure_ai_search.ts`)
|
||||
- **TypeScript test files:** `<module>.test.ts` (e.g., `memory.test.ts`)
|
||||
- **Config/manifest files:** `kebab-case` (e.g., `openclaw.plugin.json`, `jest.config.js`)
|
||||
|
||||
### Python Conventions
|
||||
|
||||
- **Provider pattern:** All providers (LLMs, embeddings, vector stores, graphs, rerankers) inherit from a `base.py` abstract class in their directory. Config classes live in `configs.py`.
|
||||
- **Pydantic v2** for all data models and configuration.
|
||||
- **Ruff** is the single linting and formatting tool — no black, no flake8.
|
||||
- Root SDK: line length **120**
|
||||
- Python CLI: line length **100** with extended rule set (UP, B, SIM, RUF)
|
||||
- **isort** with `profile = "black"` for import sorting.
|
||||
- Ruff excludes `embedchain/` and `openmemory/` from root config.
|
||||
|
||||
### TypeScript Conventions
|
||||
|
||||
- **Build:** tsup across all packages.
|
||||
- **Package manager:** pnpm everywhere (no npm, no yarn).
|
||||
- **TypeScript strict mode** across all packages.
|
||||
- **Linting varies by package:**
|
||||
|
||||
| Package | Linter | Formatter | Test Framework |
|
||||
|---------|--------|-----------|---------------|
|
||||
| `mem0-ts/` | — | Prettier | jest |
|
||||
| `cli/node/` | Biome | Biome | vitest |
|
||||
| `vercel-ai-sdk/` | ESLint | Prettier | jest + vitest |
|
||||
| `openclaw/` | — | — | vitest |
|
||||
|
||||
### Type Checking
|
||||
|
||||
Always run type checking after modifying TypeScript code:
|
||||
|
||||
```bash
|
||||
cd <package> && pnpm run typecheck # or: tsc --noEmit
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
### Provider Pattern
|
||||
|
||||
The SDK uses a consistent plugin architecture across 5 categories. Each category has a `base.py` abstract class and concrete provider implementations:
|
||||
|
||||
| Category | Count | Examples |
|
||||
|----------|-------|---------|
|
||||
| **LLMs** | 24 | OpenAI, Anthropic, AWS Bedrock, Azure OpenAI, Gemini, Groq, Ollama, Together, DeepSeek, vLLM, LiteLLM, LM Studio, xAI |
|
||||
| **Vector Stores** | 30 | Qdrant, Pinecone, Chroma, Weaviate, Milvus, MongoDB, Redis, Elasticsearch, pgvector, Supabase, Faiss, S3 Vectors |
|
||||
| **Embeddings** | 15 | OpenAI, Azure OpenAI, Gemini, HuggingFace, FastEmbed, Together, AWS Bedrock, Ollama, Vertex AI |
|
||||
| **Graph Stores** | 4 | Neo4j, Memgraph, Kuzu, Apache AGE |
|
||||
| **Rerankers** | 5 | Cohere, HuggingFace, LLM-based, Sentence Transformer, Zero Entropy |
|
||||
|
||||
### Two Usage Modes
|
||||
|
||||
Self-hosted `Memory` / `AsyncMemory` classes and hosted-platform `MemoryClient` — both in Python and TypeScript.
|
||||
|
||||
### Graph Memory
|
||||
|
||||
Optional layer on top of vector memory for relationship-aware retrieval. Configured via the `graph` section of `MemoryConfig`.
|
||||
|
||||
### MCP Integration
|
||||
|
||||
Model Context Protocol support in multiple places:
|
||||
|
||||
- **Remote:** MCP server at `mcp.mem0.ai`
|
||||
- **Local:** MCP server in `openmemory/api/` (FastAPI-based)
|
||||
- **Plugin:** MCP tools in `mem0-plugin/` — 9 tools: `add_memory`, `search_memories`, `get_memories`, `get_memory`, `update_memory`, `delete_memory`, `delete_all_memories`, `delete_entities`, `list_entities`
|
||||
|
||||
### Plugin & Skills System
|
||||
|
||||
- `mem0-plugin/` provides integrations for Claude Code, Cursor, and Codex via MCP server connections and lifecycle hooks for automatic memory capture.
|
||||
- `skills/` contains structured skill definitions for AI agents, covering SDK usage, CLI workflows, and Vercel AI SDK patterns.
|
||||
|
||||
### Adding a New Provider
|
||||
|
||||
To add a new LLM, embedding, vector store, or reranker provider:
|
||||
|
||||
1. Create `mem0/<category>/<provider_name>.py`
|
||||
2. Inherit from the abstract base class in `mem0/<category>/base.py`
|
||||
3. Add configuration to `mem0/<category>/configs.py` (if the category uses one)
|
||||
4. Register the provider in `mem0/<category>/__init__.py`
|
||||
5. Add tests in `tests/<category>/<provider_name>/`
|
||||
6. Add any new dependencies to the appropriate optional group in `pyproject.toml` (never to core `dependencies`)
|
||||
7. Follow the exact pattern of existing providers in the same category — match method signatures, error handling, and config structure
|
||||
|
||||
## CI/CD
|
||||
|
||||
### CI Workflows (automated testing)
|
||||
|
||||
| Workflow | File | Triggers | Tests |
|
||||
|----------|------|----------|-------|
|
||||
| Python SDK | `ci.yml` | Push to main, PRs on `mem0/`, `tests/`, `pyproject.toml` | Ruff lint + pytest on Python 3.10, 3.11, 3.12 |
|
||||
| TypeScript SDK | `ts-sdk-ci.yml` | Push to main, PRs on `mem0-ts/` | Prettier + build + jest on Node 20, 22 |
|
||||
| Python CLI | `cli-python-ci.yml` | Push to `cli/python/`, PRs, manual | Ruff lint + pytest + hatch build on Python 3.10, 3.11, 3.12 |
|
||||
| Node CLI | `cli-node-ci.yml` | Push to `cli/node/`, PRs, manual | Biome lint + tsc + vitest + tsup build on Node 20, 22 |
|
||||
| OpenClaw | `openclaw-checks.yml` | Push to `openclaw/`, PRs, manual | tsc + vitest (with Codecov) + tsup build on Node 20, 22 |
|
||||
| Embedchain | `ci.yml` (shared) | PRs on `embedchain/` | Ruff + pytest + coverage on Python 3.9–3.12 |
|
||||
|
||||
### CD Workflows (automated publishing)
|
||||
|
||||
| Workflow | File | Tag Prefix | Target |
|
||||
|----------|------|------------|--------|
|
||||
| Python SDK | `cd.yml` | `v*` | PyPI (`mem0ai`) |
|
||||
| TypeScript SDK | `ts-sdk-cd.yml` | `ts-v*` | npm (`mem0ai`) |
|
||||
| Python CLI | `cli-python-cd.yml` | `cli-v*` | PyPI (`mem0-cli`) |
|
||||
| Node CLI | `cli-node-cd.yml` | `cli-node-v*` | npm (`@mem0/cli`) |
|
||||
| Vercel AI SDK | `vercel-ai-cd.yml` | `vercel-ai-v*` | npm (`@mem0/vercel-ai-provider`) |
|
||||
| OpenClaw | `openclaw-cd.yml` | `openclaw-v*` | npm (`@mem0/openclaw-mem0`) |
|
||||
|
||||
- All publishing uses **OIDC trusted publishing** — no tokens or secrets required.
|
||||
- First publish of a new npm package must be done manually; OIDC works for subsequent versions.
|
||||
|
||||
### Utility Workflows
|
||||
|
||||
| Workflow | File | Purpose |
|
||||
|----------|------|---------|
|
||||
| Issue Labeler | `issue-labeler.yml` | Automatic issue labeling |
|
||||
| Stale Bot | `stale.yml` | Marks stale issues and PRs |
|
||||
|
||||
## Task Completion Guidelines
|
||||
|
||||
These guidelines outline typical artifacts for different task types. Use judgment to adapt based on scope and context.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
1. **Unit tests**: Add tests that would fail without the fix (regression tests)
|
||||
2. **Implementation**: Fix the bug
|
||||
3. **Manual verification**: Run the relevant test suite to confirm the fix
|
||||
4. **Lint**: Run the appropriate linter for the package you modified
|
||||
|
||||
### New Features
|
||||
|
||||
1. **Implementation**: Build the feature following existing patterns
|
||||
2. **Unit tests**: Comprehensive test coverage for new functionality
|
||||
3. **Documentation**: Update relevant docs in `docs/` for public APIs
|
||||
4. **Examples**: Add usage examples if the feature introduces new user-facing behavior
|
||||
|
||||
### New Provider (LLM / Embedding / Vector Store / Reranker)
|
||||
|
||||
1. **Implementation**: Follow the "Adding a New Provider" steps above
|
||||
2. **Tests**: Add unit tests matching the pattern of existing providers
|
||||
3. **Configuration**: Add to the appropriate `configs.py` and `__init__.py`
|
||||
4. **Dependencies**: Add to the correct optional group in `pyproject.toml`
|
||||
5. **Documentation**: Add an integration guide in `docs/integrations/`
|
||||
|
||||
### Refactoring / Internal Changes
|
||||
|
||||
- Unit tests for any changed behavior
|
||||
- No documentation needed for internal-only changes
|
||||
- Ensure all existing tests still pass
|
||||
|
||||
### When to Deviate
|
||||
|
||||
These are guidelines, not rigid rules. Adjust based on:
|
||||
|
||||
- **Scope**: Trivial fixes (typos, comments) may not need tests
|
||||
- **Visibility**: Internal changes may not need documentation
|
||||
- **Context**: Some changes span multiple categories — use judgment
|
||||
|
||||
When uncertain about expected artifacts, ask for clarification.
|
||||
|
||||
## Contributing Guidelines
|
||||
|
||||
### Workflow
|
||||
|
||||
1. Fork and clone the repository.
|
||||
2. Create a feature branch from `main` (e.g., `feature/my-new-feature`).
|
||||
3. Make your changes — add tests, docs, and examples as appropriate.
|
||||
4. Run linting and tests for every package you modified (see commands above).
|
||||
5. Run `pre-commit install` on first setup — hooks run ruff + isort automatically.
|
||||
6. Commit with a clear message following [Conventional Commits](https://www.conventionalcommits.org/) (e.g., `feat:`, `fix:`, `docs:`, `refactor:`).
|
||||
7. Push and open a Pull Request against `main`.
|
||||
|
||||
### Pull Request Requirements
|
||||
|
||||
Every PR must follow the repo's PR template (`.github/PULL_REQUEST_TEMPLATE.md`):
|
||||
|
||||
1. **Linked Issue** — Reference the issue with `Closes #<number>`. If no issue exists, create one first or explain why in the description.
|
||||
2. **Description** — Explain what the PR does and why it's needed.
|
||||
3. **Type of Change** — Check the appropriate box:
|
||||
- Bug fix / New feature / Breaking change / Refactor / Documentation update
|
||||
4. **Breaking Changes** — If applicable, describe what breaks and the migration path.
|
||||
5. **Test Coverage** — Check what applies:
|
||||
- Added/updated unit tests
|
||||
- Added/updated integration tests
|
||||
- Tested manually (describe how)
|
||||
- No tests needed (explain why)
|
||||
6. **Checklist** — All must be checked before merge:
|
||||
- [ ] Code follows the project's style guidelines
|
||||
- [ ] Self-review performed
|
||||
- [ ] Tests added that prove the fix/feature works
|
||||
- [ ] New and existing tests pass locally
|
||||
- [ ] Documentation updated if needed
|
||||
|
||||
### PR Description Template
|
||||
|
||||
```markdown
|
||||
## Linked Issue
|
||||
|
||||
Closes #<!-- issue number -->
|
||||
|
||||
## Description
|
||||
|
||||
<!-- What does this PR do? Why is it needed? -->
|
||||
|
||||
## Type of Change
|
||||
|
||||
- [ ] Bug fix (non-breaking change that fixes an issue)
|
||||
- [ ] New feature (non-breaking change that adds functionality)
|
||||
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
|
||||
- [ ] Refactor (no functional changes)
|
||||
- [ ] Documentation update
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
N/A
|
||||
|
||||
## Test Coverage
|
||||
|
||||
- [ ] I added/updated unit tests
|
||||
- [ ] I added/updated integration tests
|
||||
- [ ] I tested manually (describe below)
|
||||
- [ ] No tests needed (explain why)
|
||||
|
||||
## Checklist
|
||||
|
||||
- [ ] My code follows the project's style guidelines
|
||||
- [ ] I have performed a self-review of my code
|
||||
- [ ] I have added tests that prove my fix/feature works
|
||||
- [ ] New and existing tests pass locally
|
||||
- [ ] I have updated documentation if needed
|
||||
```
|
||||
|
||||
### General Rules
|
||||
|
||||
- Follow existing code patterns — don't introduce new frameworks or abstractions without discussion.
|
||||
- Version bumps go in `pyproject.toml` (Python) or `package.json` (TypeScript).
|
||||
- For `server/` and `openmemory/` work, use Docker Compose for local development.
|
||||
- Do NOT use `pip` or `conda` for dependency management — use `hatch` (see `docs/contributing/development.mdx`).
|
||||
|
||||
### Contributing Guides
|
||||
|
||||
| Task | Guide |
|
||||
|------|-------|
|
||||
| Code contributions | `docs/contributing/development.mdx` |
|
||||
| Documentation contributions | `docs/contributing/documentation.mdx` |
|
||||
| PR template | `.github/PULL_REQUEST_TEMPLATE.md` |
|
||||
| Bug reports | `.github/ISSUE_TEMPLATE/bug_report.yml` |
|
||||
| Feature requests | `.github/ISSUE_TEMPLATE/feature_request.yml` |
|
||||
| Documentation issues | `.github/ISSUE_TEMPLATE/documentation_issue.yml` |
|
||||
|
||||
## Do NOT
|
||||
|
||||
- Modify CI/CD workflows without explicit approval.
|
||||
- Add new Python dependencies to the core `dependencies` list in `pyproject.toml` without discussion — use optional dependency groups instead.
|
||||
- Commit `.env` files, API keys, or credentials.
|
||||
- Modify `embedchain/` unless specifically working on that package — it has its own build system (Poetry).
|
||||
- Skip pre-commit hooks.
|
||||
- Use npm or yarn in TypeScript packages — this repo uses pnpm exclusively.
|
||||
- Use `require()` for imports in TypeScript — use ES module `import` syntax.
|
||||
- Mix up linter configs: root Python SDK uses line-length 120, Python CLI uses 100, Node CLI uses Biome (not ESLint/Ruff).
|
||||
- Modify `openmemory/` database migrations without understanding the Alembic migration chain.
|
||||
- Change public APIs without updating documentation in `docs/`.
|
||||
@@ -61,3 +61,31 @@ make test # After activating a shell with hatch shell test_XX
|
||||
Make sure that all tests pass across all supported Python versions before submitting a pull request.
|
||||
|
||||
We look forward to your pull requests and can't wait to see your contributions!
|
||||
|
||||
### 🚀 Releasing
|
||||
|
||||
All packages are published automatically via GitHub Actions when a GitHub Release is created with the correct tag prefix.
|
||||
|
||||
#### Tag Prefixes
|
||||
|
||||
| Package | Registry | Tag Prefix | Example |
|
||||
|---------|----------|------------|---------|
|
||||
| `mem0ai` (Python SDK) | PyPI | `v*` | `v0.1.31` |
|
||||
| `mem0-cli` (Python CLI) | PyPI | `cli-v*` | `cli-v0.2.1` |
|
||||
| `mem0ai` (TypeScript SDK) | npm | `ts-v*` | `ts-v2.4.6` |
|
||||
| `@mem0/cli` (Node CLI) | npm | `cli-node-v*` | `cli-node-v0.1.2` |
|
||||
| `@mem0/vercel-ai-provider` | npm | `vercel-ai-v*` | `vercel-ai-v2.0.6` |
|
||||
| `@mem0/openclaw-mem0` | npm | `openclaw-v*` | `openclaw-v1.0.1` |
|
||||
|
||||
#### How to Release
|
||||
|
||||
1. Bump the version in `pyproject.toml` (Python) or `package.json` (Node)
|
||||
2. Create a [GitHub Release](https://github.com/mem0ai/mem0/releases/new) with the matching tag prefix
|
||||
3. The correct workflow will trigger automatically — verify in the [Actions tab](https://github.com/mem0ai/mem0/actions)
|
||||
|
||||
#### Publishing Details
|
||||
|
||||
- **PyPI packages** use OIDC trusted publishing via `pypa/gh-action-pypi-publish`
|
||||
- **npm packages** use OIDC trusted publishing via npm CLI (>= 11.5.1) — no tokens or secrets required
|
||||
- All workflows require `permissions: id-token: write` for OIDC authentication
|
||||
- First publish of a new npm package must be done manually; OIDC works for subsequent versions
|
||||
|
||||
+2
-2
@@ -10,8 +10,8 @@
|
||||
"logoMini": "\u25c6 mem0",
|
||||
"tagline": "The Memory Layer for AI Agents",
|
||||
"colors": {
|
||||
"brand": "#F1C96C",
|
||||
"accent": "#F5D78E",
|
||||
"brand": "#8b5cf6",
|
||||
"accent": "#a78bfa",
|
||||
"success": "#22c55e",
|
||||
"error": "#ef4444",
|
||||
"warning": "#f59e0b",
|
||||
|
||||
+299
-37
@@ -2,10 +2,12 @@
|
||||
|
||||
The official command-line interface for [mem0](https://mem0.ai) — the memory layer for AI agents. TypeScript implementation.
|
||||
|
||||
> **Built for AI agents.** Pass `--agent` (or `--json`) as a global flag on any command to get structured JSON output optimized for programmatic consumption — sanitized fields, no colors or spinners, and errors as JSON too.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Node.js **18+**
|
||||
- pnpm (`npm install -g pnpm`)
|
||||
- pnpm (`npm install -g pnpm`) — for development only
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -13,22 +15,307 @@ The official command-line interface for [mem0](https://mem0.ai) — the memory l
|
||||
npm install -g @mem0/cli
|
||||
```
|
||||
|
||||
Or from source:
|
||||
## Quick start
|
||||
|
||||
```bash
|
||||
cd node
|
||||
pnpm install
|
||||
pnpm build
|
||||
pnpm link --global
|
||||
# Interactive setup wizard
|
||||
mem0 init
|
||||
|
||||
# Now use it like a normal CLI
|
||||
mem0 --help
|
||||
# Or login via email
|
||||
mem0 init --email alice@company.com
|
||||
|
||||
# Or authenticate with an existing API key
|
||||
mem0 init --api-key m0-xxx
|
||||
|
||||
# Add a memory
|
||||
mem0 add "I prefer dark mode and use vim keybindings" --user-id alice
|
||||
|
||||
# Search memories
|
||||
mem0 search "What are Alice's preferences?" --user-id alice
|
||||
|
||||
# List all memories for a user
|
||||
mem0 list --user-id alice
|
||||
|
||||
# Get a specific memory
|
||||
mem0 get <memory-id>
|
||||
|
||||
# Update a memory
|
||||
mem0 update <memory-id> "I switched to light mode"
|
||||
|
||||
# Delete a memory
|
||||
mem0 delete <memory-id>
|
||||
```
|
||||
|
||||
## Running during development
|
||||
## Commands
|
||||
|
||||
### `mem0 init`
|
||||
|
||||
Interactive setup wizard. Prompts for your API key and default user ID.
|
||||
|
||||
```bash
|
||||
cd node
|
||||
mem0 init
|
||||
mem0 init --api-key m0-xxx --user-id alice
|
||||
mem0 init --email alice@company.com
|
||||
```
|
||||
|
||||
If an existing configuration is detected, the CLI asks for confirmation before overwriting. Use `--force` to skip the prompt (useful in CI/CD).
|
||||
|
||||
```bash
|
||||
mem0 init --api-key m0-xxx --user-id alice --force
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--api-key` | API key (skip prompt) |
|
||||
| `-u, --user-id` | Default user ID (skip prompt) |
|
||||
| `--email` | Login via email verification code |
|
||||
| `--code` | Verification code (use with `--email` for non-interactive login) |
|
||||
| `--force` | Overwrite existing config without confirmation |
|
||||
|
||||
### `mem0 add`
|
||||
|
||||
Add a memory from text, a JSON messages array, a file, or stdin.
|
||||
|
||||
```bash
|
||||
mem0 add "I prefer dark mode" --user-id alice
|
||||
mem0 add --file conversation.json --user-id alice
|
||||
echo "Loves hiking on weekends" | mem0 add --user-id alice
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `-u, --user-id` | Scope to a user |
|
||||
| `--agent-id` | Scope to an agent |
|
||||
| `--messages` | Conversation messages as JSON |
|
||||
| `-f, --file` | Read messages from a JSON file |
|
||||
| `-m, --metadata` | Custom metadata as JSON |
|
||||
| `--categories` | Categories (JSON array or comma-separated) |
|
||||
| `--graph / --no-graph` | Enable or disable graph memory extraction |
|
||||
| `-o, --output` | Output format: `text`, `json`, `quiet` |
|
||||
|
||||
### `mem0 search`
|
||||
|
||||
Search memories using natural language.
|
||||
|
||||
```bash
|
||||
mem0 search "dietary restrictions" --user-id alice
|
||||
mem0 search "preferred tools" --user-id alice --output json --top-k 5
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `-u, --user-id` | Filter by user |
|
||||
| `-k, --top-k` | Number of results (default: 10) |
|
||||
| `--threshold` | Minimum similarity score (default: 0.3) |
|
||||
| `--rerank` | Enable reranking |
|
||||
| `--keyword` | Use keyword search instead of semantic |
|
||||
| `--filter` | Advanced filter expression (JSON) |
|
||||
| `--graph / --no-graph` | Enable or disable graph in search |
|
||||
| `-o, --output` | Output format: `text`, `json`, `table` |
|
||||
|
||||
### `mem0 list`
|
||||
|
||||
List memories with optional filters and pagination.
|
||||
|
||||
```bash
|
||||
mem0 list --user-id alice
|
||||
mem0 list --user-id alice --category preferences --output json
|
||||
mem0 list --user-id alice --after 2024-01-01 --page-size 50
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `-u, --user-id` | Filter by user |
|
||||
| `--page` | Page number (default: 1) |
|
||||
| `--page-size` | Results per page (default: 100) |
|
||||
| `--category` | Filter by category |
|
||||
| `--after` | Created after date (YYYY-MM-DD) |
|
||||
| `--before` | Created before date (YYYY-MM-DD) |
|
||||
| `-o, --output` | Output format: `text`, `json`, `table` |
|
||||
|
||||
### `mem0 get`
|
||||
|
||||
Retrieve a specific memory by ID.
|
||||
|
||||
```bash
|
||||
mem0 get 7b3c1a2e-4d5f-6789-abcd-ef0123456789
|
||||
mem0 get 7b3c1a2e-4d5f-6789-abcd-ef0123456789 --output json
|
||||
```
|
||||
|
||||
### `mem0 update`
|
||||
|
||||
Update the text or metadata of an existing memory.
|
||||
|
||||
```bash
|
||||
mem0 update <memory-id> "Updated preference text"
|
||||
mem0 update <memory-id> --metadata '{"priority": "high"}'
|
||||
echo "new text" | mem0 update <memory-id>
|
||||
```
|
||||
|
||||
### `mem0 delete`
|
||||
|
||||
Delete a single memory, all memories for a scope, or an entire entity.
|
||||
|
||||
```bash
|
||||
# Delete a single memory
|
||||
mem0 delete <memory-id>
|
||||
|
||||
# Delete all memories for a user
|
||||
mem0 delete --all --user-id alice --force
|
||||
|
||||
# Delete all memories project-wide
|
||||
mem0 delete --all --project --force
|
||||
|
||||
# Preview what would be deleted
|
||||
mem0 delete --all --user-id alice --dry-run
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--all` | Delete all memories matching scope filters |
|
||||
| `--entity` | Delete the entity and all its memories |
|
||||
| `--project` | With `--all`: delete all memories project-wide |
|
||||
| `--dry-run` | Preview without deleting |
|
||||
| `--force` | Skip confirmation prompt |
|
||||
|
||||
### `mem0 import`
|
||||
|
||||
Bulk import memories from a JSON file.
|
||||
|
||||
```bash
|
||||
mem0 import data.json --user-id alice
|
||||
```
|
||||
|
||||
The file should be a JSON array where each item has a `memory` (or `text` or `content`) field and optional `user_id`, `agent_id`, and `metadata` fields.
|
||||
|
||||
### `mem0 config`
|
||||
|
||||
View or modify the local CLI configuration.
|
||||
|
||||
```bash
|
||||
mem0 config show # Display current config (secrets redacted)
|
||||
mem0 config get api_key # Get a specific value
|
||||
mem0 config set user_id bob # Set a value
|
||||
```
|
||||
|
||||
### `mem0 entity`
|
||||
|
||||
List or delete entities (users, agents, apps, runs).
|
||||
|
||||
```bash
|
||||
mem0 entity list users
|
||||
mem0 entity list agents --output json
|
||||
mem0 entity delete --user-id alice --force
|
||||
```
|
||||
|
||||
### `mem0 event`
|
||||
|
||||
Inspect background processing events created by async operations (e.g. bulk deletes, large add jobs).
|
||||
|
||||
```bash
|
||||
# List recent events
|
||||
mem0 event list
|
||||
|
||||
# Check the status of a specific event
|
||||
mem0 event status <event-id>
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `-o, --output` | Output format: `text`, `json` |
|
||||
|
||||
### `mem0 status`
|
||||
|
||||
Verify your API connection and display the current project.
|
||||
|
||||
```bash
|
||||
mem0 status
|
||||
```
|
||||
|
||||
### `mem0 version`
|
||||
|
||||
Print the CLI version.
|
||||
|
||||
```bash
|
||||
mem0 version
|
||||
```
|
||||
|
||||
## Agent mode
|
||||
|
||||
Pass `--agent` (or its alias `--json`) as a **global flag** on any command to get output designed for AI agent tool loops:
|
||||
|
||||
```bash
|
||||
mem0 --agent search "user preferences" --user-id alice
|
||||
mem0 --agent add "User prefers dark mode" --user-id alice
|
||||
mem0 --agent list --user-id alice
|
||||
mem0 --agent delete --all --user-id alice --force
|
||||
```
|
||||
|
||||
Every command returns the same envelope shape:
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"command": "search",
|
||||
"duration_ms": 134,
|
||||
"scope": { "user_id": "alice" },
|
||||
"count": 2,
|
||||
"data": [
|
||||
{ "id": "abc-123", "memory": "User prefers dark mode", "score": 0.97, "created_at": "2026-01-15", "categories": ["preferences"] }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
What agent mode does differently from `--output json`:
|
||||
|
||||
- **Sanitized `data`**: only the fields an agent needs (id, memory, score, etc.) — no internal API noise
|
||||
- **No human output**: spinners, colors, and banners are suppressed entirely
|
||||
- **Errors as JSON**: errors go to stdout as `{"status": "error", "command": "...", "error": "..."}` with a non-zero exit code
|
||||
|
||||
Use `mem0 help --json` to get the full command tree as JSON — useful for agents that need to self-discover available commands.
|
||||
|
||||
## Output formats
|
||||
|
||||
Control how results are displayed with `--output`:
|
||||
|
||||
| Format | Description |
|
||||
|--------|-------------|
|
||||
| `text` | Human-readable with colors and formatting (default) |
|
||||
| `json` | Structured JSON for piping to `jq` (raw API response) |
|
||||
| `table` | Tabular format (default for `list`) |
|
||||
| `quiet` | Minimal — just IDs or status codes |
|
||||
| `agent` | Structured JSON envelope with sanitized fields (set by `--agent`/`--json`) |
|
||||
|
||||
## Global flags
|
||||
|
||||
These flags are available on all commands:
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--json` | Enable agent mode: structured JSON envelope output, no colors or spinners |
|
||||
| `--agent` | Alias for `--json` |
|
||||
| `--api-key` | Override the configured API key for this request |
|
||||
| `--base-url` | Override the configured API base URL for this request |
|
||||
| `-o, --output` | Set the output format |
|
||||
|
||||
## Environment variables
|
||||
|
||||
| Variable | Description |
|
||||
|----------|-------------|
|
||||
| `MEM0_API_KEY` | API key (overrides config file) |
|
||||
| `MEM0_BASE_URL` | API base URL |
|
||||
| `MEM0_USER_ID` | Default user ID |
|
||||
| `MEM0_AGENT_ID` | Default agent ID |
|
||||
| `MEM0_APP_ID` | Default app ID |
|
||||
| `MEM0_RUN_ID` | Default run ID |
|
||||
| `MEM0_ENABLE_GRAPH` | Enable graph memory (`true` / `false`) |
|
||||
|
||||
Environment variables take precedence over values in the config file, which take precedence over defaults.
|
||||
|
||||
## Development
|
||||
|
||||
```bash
|
||||
cd cli/node
|
||||
pnpm install
|
||||
|
||||
# Development mode (runs TypeScript directly, no build needed)
|
||||
@@ -39,36 +326,11 @@ pnpm dev search "test" --user-id alice
|
||||
# Or build first, then run the compiled JS
|
||||
pnpm build
|
||||
node dist/index.js --help
|
||||
node dist/index.js add "test memory" --user-id alice
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
## Documentation
|
||||
|
||||
```bash
|
||||
# Set up your configuration
|
||||
mem0 init
|
||||
|
||||
# Add a memory
|
||||
mem0 add "I prefer dark mode and use vim keybindings" --user-id alice
|
||||
|
||||
# Search memories
|
||||
mem0 search "What are Alice's preferences?" --user-id alice
|
||||
|
||||
# List all memories
|
||||
mem0 list --user-id alice
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
| Variable | Description |
|
||||
|----------|-------------|
|
||||
| `MEM0_API_KEY` | API key (overrides config file) |
|
||||
| `MEM0_BASE_URL` | API base URL |
|
||||
| `MEM0_USER_ID` | Default user ID |
|
||||
| `MEM0_AGENT_ID` | Default agent ID |
|
||||
| `MEM0_APP_ID` | Default app ID |
|
||||
| `MEM0_RUN_ID` | Default run ID |
|
||||
| `MEM0_ENABLE_GRAPH` | Enable graph memory (true/false) |
|
||||
Full documentation is available at [docs.mem0.ai/platform/cli](https://docs.mem0.ai/platform/cli).
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mem0/cli",
|
||||
"version": "0.1.0",
|
||||
"version": "0.2.2",
|
||||
"description": "The official CLI for mem0 — the memory layer for AI agents",
|
||||
"type": "module",
|
||||
"bin": {
|
||||
@@ -20,6 +20,11 @@
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"author": "mem0.ai <founders@mem0.ai>",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mem0ai/mem0",
|
||||
"directory": "cli/node"
|
||||
},
|
||||
"keywords": ["mem0", "memory", "ai", "agents", "cli"],
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
||||
@@ -89,6 +89,8 @@ export interface Backend {
|
||||
|
||||
deleteEntities(opts: EntityIds): Promise<Record<string, unknown>>;
|
||||
|
||||
ping(): Promise<Record<string, unknown>>;
|
||||
|
||||
status(opts?: { userId?: string; agentId?: string }): Promise<
|
||||
Record<string, unknown>
|
||||
>;
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
*/
|
||||
|
||||
import type { PlatformConfig } from "../config.js";
|
||||
import { isAgentMode } from "../state.js";
|
||||
import { CLI_VERSION } from "../version.js";
|
||||
import {
|
||||
APIError,
|
||||
type AddOptions,
|
||||
@@ -24,6 +26,9 @@ export class PlatformBackend implements Backend {
|
||||
this.headers = {
|
||||
Authorization: `Token ${config.apiKey}`,
|
||||
"Content-Type": "application/json",
|
||||
"X-Mem0-Source": "cli",
|
||||
"X-Mem0-Client-Language": "node",
|
||||
"X-Mem0-Client-Version": CLI_VERSION,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -38,9 +43,14 @@ export class PlatformBackend implements Backend {
|
||||
url += `?${qs}`;
|
||||
}
|
||||
|
||||
const headers = {
|
||||
...this.headers,
|
||||
"X-Mem0-Caller-Type": isAgentMode() ? "agent" : "user",
|
||||
};
|
||||
|
||||
const fetchOpts: RequestInit = {
|
||||
method,
|
||||
headers: this.headers,
|
||||
headers,
|
||||
signal: AbortSignal.timeout(30_000),
|
||||
};
|
||||
if (opts?.json) {
|
||||
@@ -286,11 +296,15 @@ export class PlatformBackend implements Backend {
|
||||
return result;
|
||||
}
|
||||
|
||||
async ping(): Promise<Record<string, unknown>> {
|
||||
return (await this._request("GET", "/v1/ping/")) as Record<string, unknown>;
|
||||
}
|
||||
|
||||
async status(
|
||||
opts: { userId?: string; agentId?: string } = {},
|
||||
): Promise<Record<string, unknown>> {
|
||||
try {
|
||||
await this._request("GET", "/v1/ping/");
|
||||
await this.ping();
|
||||
return { connected: true, backend: "platform", base_url: this.baseUrl };
|
||||
} catch (e) {
|
||||
return {
|
||||
|
||||
@@ -19,8 +19,8 @@ export const LOGO = `
|
||||
export const LOGO_MINI = "◆ mem0";
|
||||
export const TAGLINE = "The Memory Layer for AI Agents";
|
||||
|
||||
export const BRAND_COLOR = "#F1C96C";
|
||||
export const ACCENT_COLOR = "#F5D78E";
|
||||
export const BRAND_COLOR = "#8b5cf6";
|
||||
export const ACCENT_COLOR = "#a78bfa";
|
||||
export const SUCCESS_COLOR = "#22c55e";
|
||||
export const ERROR_COLOR = "#ef4444";
|
||||
export const WARNING_COLOR = "#f59e0b";
|
||||
|
||||
@@ -41,10 +41,16 @@ async function emailLogin(
|
||||
const url = baseUrl.replace(/\/+$/, "");
|
||||
let codeValue = code;
|
||||
|
||||
const sourceHeaders = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Mem0-Source": "cli",
|
||||
"X-Mem0-Client-Language": "node",
|
||||
};
|
||||
|
||||
if (!codeValue) {
|
||||
const resp = await fetch(`${url}/api/v1/auth/email_code/`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
headers: sourceHeaders,
|
||||
body: JSON.stringify({ email }),
|
||||
signal: AbortSignal.timeout(30_000),
|
||||
});
|
||||
@@ -85,7 +91,7 @@ async function emailLogin(
|
||||
|
||||
const verifyResp = await fetch(`${url}/api/v1/auth/email_code/verify/`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
headers: sourceHeaders,
|
||||
body: JSON.stringify({ email, code: codeValue.trim() }),
|
||||
signal: AbortSignal.timeout(30_000),
|
||||
});
|
||||
@@ -215,6 +221,16 @@ async function validatePlatform(config: Mem0Config): Promise<void> {
|
||||
});
|
||||
if (status.connected) {
|
||||
printSuccess("Connected to mem0 Platform!");
|
||||
// Cache user_email from ping response for telemetry distinct_id
|
||||
try {
|
||||
const pingData = (await backend.ping()) as Record<string, unknown>;
|
||||
const userEmail = pingData?.user_email as string | undefined;
|
||||
if (userEmail) {
|
||||
config.platform.userEmail = userEmail;
|
||||
}
|
||||
} catch {
|
||||
/* ignore — telemetry ID will fall back to API key hash */
|
||||
}
|
||||
} else {
|
||||
printError(
|
||||
`Could not connect: ${status.error ?? "Unknown error"}`,
|
||||
@@ -307,6 +323,7 @@ export async function runInit(
|
||||
|
||||
config.platform.apiKey = apiKeyVal;
|
||||
config.platform.baseUrl = baseUrl;
|
||||
config.platform.userEmail = email;
|
||||
config.defaults.userId =
|
||||
opts.userId || process.env.USER || process.env.USERNAME || "mem0-cli";
|
||||
|
||||
@@ -385,6 +402,7 @@ export async function runInit(
|
||||
|
||||
config.platform.apiKey = apiKeyVal;
|
||||
config.platform.baseUrl = baseUrl;
|
||||
config.platform.userEmail = email;
|
||||
config.defaults.userId =
|
||||
opts.userId || process.env.USER || process.env.USERNAME || "mem0-cli";
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ export const CONFIG_VERSION = 1;
|
||||
export interface PlatformConfig {
|
||||
apiKey: string;
|
||||
baseUrl: string;
|
||||
userEmail: string;
|
||||
}
|
||||
|
||||
export interface DefaultsConfig {
|
||||
@@ -49,6 +50,7 @@ export function createDefaultConfig(): Mem0Config {
|
||||
platform: {
|
||||
apiKey: "",
|
||||
baseUrl: DEFAULT_BASE_URL,
|
||||
userEmail: "",
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -70,6 +72,7 @@ export function loadConfig(): Mem0Config {
|
||||
const plat = data.platform ?? {};
|
||||
config.platform.apiKey = plat.api_key ?? "";
|
||||
config.platform.baseUrl = plat.base_url ?? DEFAULT_BASE_URL;
|
||||
config.platform.userEmail = plat.user_email ?? "";
|
||||
|
||||
const defaults = data.defaults ?? {};
|
||||
config.defaults.userId = defaults.user_id ?? "";
|
||||
@@ -114,6 +117,7 @@ export function saveConfig(config: Mem0Config): void {
|
||||
platform: {
|
||||
api_key: config.platform.apiKey,
|
||||
base_url: config.platform.baseUrl,
|
||||
user_email: config.platform.userEmail,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -131,6 +135,7 @@ export function redactKey(key: string): string {
|
||||
const KEY_MAP: Record<string, [keyof Mem0Config, string]> = {
|
||||
"platform.api_key": ["platform", "apiKey"],
|
||||
"platform.base_url": ["platform", "baseUrl"],
|
||||
"platform.user_email": ["platform", "userEmail"],
|
||||
"defaults.user_id": ["defaults", "userId"],
|
||||
"defaults.agent_id": ["defaults", "agentId"],
|
||||
"defaults.app_id": ["defaults", "appId"],
|
||||
@@ -139,6 +144,7 @@ const KEY_MAP: Record<string, [keyof Mem0Config, string]> = {
|
||||
// Short-form aliases
|
||||
api_key: ["platform", "apiKey"],
|
||||
base_url: ["platform", "baseUrl"],
|
||||
user_email: ["platform", "userEmail"],
|
||||
user_id: ["defaults", "userId"],
|
||||
agent_id: ["defaults", "agentId"],
|
||||
app_id: ["defaults", "appId"],
|
||||
|
||||
+106
-22
@@ -8,22 +8,27 @@ import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { Command } from "commander";
|
||||
import { type Backend, getBackend } from "./backend/index.js";
|
||||
import { colors, printError } from "./branding.js";
|
||||
import { AuthError, type Backend, getBackend } from "./backend/index.js";
|
||||
import { colors, printError, printWarning } from "./branding.js";
|
||||
import type { Mem0Config } from "./config.js";
|
||||
import { loadConfig } from "./config.js";
|
||||
import { loadConfig, saveConfig } from "./config.js";
|
||||
import { richFormatHelp } from "./help.js";
|
||||
import { setAgentMode } from "./state.js";
|
||||
import { captureEvent } from "./telemetry.js";
|
||||
import { CLI_VERSION } from "./version.js";
|
||||
|
||||
const program = new Command();
|
||||
|
||||
// ── Validated user identity (set by getBackendAndConfig) ─────────────────
|
||||
|
||||
let _validatedUserEmail: string | undefined;
|
||||
|
||||
// ── Helpers ──────────────────────────────────────────────────────────────
|
||||
|
||||
function getBackendAndConfig(
|
||||
async function getBackendAndConfig(
|
||||
apiKey?: string,
|
||||
baseUrl?: string,
|
||||
): { backend: Backend; config: Mem0Config } {
|
||||
): Promise<{ backend: Backend; config: Mem0Config }> {
|
||||
const config = loadConfig();
|
||||
|
||||
if (apiKey) config.platform.apiKey = apiKey;
|
||||
@@ -37,11 +42,51 @@ function getBackendAndConfig(
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
return { backend: getBackend(config), config };
|
||||
const backend = getBackend(config);
|
||||
|
||||
// Validate the API key upfront with a fast timeout
|
||||
try {
|
||||
const pingData = (await Promise.race([
|
||||
backend.ping(),
|
||||
new Promise<never>((_, reject) =>
|
||||
setTimeout(() => reject(new Error("timeout")), 5000),
|
||||
),
|
||||
])) as Record<string, unknown>;
|
||||
|
||||
const email = pingData?.user_email as string | undefined;
|
||||
if (email) {
|
||||
_validatedUserEmail = email;
|
||||
if (config.platform.userEmail !== email) {
|
||||
config.platform.userEmail = email;
|
||||
try {
|
||||
saveConfig(config);
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
if (e instanceof AuthError) {
|
||||
printError(
|
||||
"Invalid or expired API key.",
|
||||
"Run 'mem0 init' or set MEM0_API_KEY environment variable.",
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
// Network error / timeout — warn but proceed
|
||||
printWarning(
|
||||
"Could not validate API key (network issue). Proceeding anyway.",
|
||||
);
|
||||
}
|
||||
|
||||
return { backend, config };
|
||||
}
|
||||
|
||||
function getBackendOnly(apiKey?: string, baseUrl?: string): Backend {
|
||||
return getBackendAndConfig(apiKey, baseUrl).backend;
|
||||
async function getBackendOnly(
|
||||
apiKey?: string,
|
||||
baseUrl?: string,
|
||||
): Promise<Backend> {
|
||||
return (await getBackendAndConfig(apiKey, baseUrl)).backend;
|
||||
}
|
||||
|
||||
function checkAgentMode(): boolean {
|
||||
@@ -123,6 +168,30 @@ program
|
||||
.addHelpCommand(false)
|
||||
.configureHelp({ formatHelp: richFormatHelp });
|
||||
|
||||
// ── Telemetry hook ───────────────────────────────────────────────────────
|
||||
|
||||
program.hook("preAction", (_thisCommand, actionCommand) => {
|
||||
try {
|
||||
const commandName = actionCommand.name();
|
||||
const parentName = actionCommand.parent?.name();
|
||||
const fullCommand =
|
||||
parentName && parentName !== "mem0"
|
||||
? `${parentName}.${commandName}`
|
||||
: commandName;
|
||||
const isAgent = !!(program.opts().json || program.opts().agent);
|
||||
captureEvent(
|
||||
`cli.${fullCommand}`,
|
||||
{
|
||||
command: fullCommand,
|
||||
is_agent: isAgent,
|
||||
},
|
||||
_validatedUserEmail,
|
||||
);
|
||||
} catch {
|
||||
/* silently swallow */
|
||||
}
|
||||
});
|
||||
|
||||
// ── Init ──────────────────────────────────────────────────────────────────
|
||||
|
||||
program
|
||||
@@ -179,7 +248,10 @@ program
|
||||
.action(async (text, opts) => {
|
||||
const { cmdAdd } = await import("./commands/memory.js");
|
||||
const isAgent = checkAgentMode();
|
||||
const { backend, config } = getBackendAndConfig(opts.apiKey, opts.baseUrl);
|
||||
const { backend, config } = await getBackendAndConfig(
|
||||
opts.apiKey,
|
||||
opts.baseUrl,
|
||||
);
|
||||
const ids = resolveIds(config, opts);
|
||||
const enableGraph = resolveGraph(config, opts);
|
||||
const output = isAgent ? "agent" : opts.output;
|
||||
@@ -233,7 +305,10 @@ program
|
||||
}
|
||||
const { cmdSearch } = await import("./commands/memory.js");
|
||||
const isAgent = checkAgentMode();
|
||||
const { backend, config } = getBackendAndConfig(opts.apiKey, opts.baseUrl);
|
||||
const { backend, config } = await getBackendAndConfig(
|
||||
opts.apiKey,
|
||||
opts.baseUrl,
|
||||
);
|
||||
const ids = resolveIds(config, opts);
|
||||
const enableGraph = resolveGraph(config, opts);
|
||||
const output = isAgent ? "agent" : opts.output;
|
||||
@@ -265,7 +340,7 @@ program
|
||||
.action(async (memoryId, opts) => {
|
||||
const { cmdGet } = await import("./commands/memory.js");
|
||||
const isAgent = checkAgentMode();
|
||||
const backend = getBackendOnly(opts.apiKey, opts.baseUrl);
|
||||
const backend = await getBackendOnly(opts.apiKey, opts.baseUrl);
|
||||
const output = isAgent ? "agent" : opts.output;
|
||||
await cmdGet(backend, memoryId, { output });
|
||||
});
|
||||
@@ -301,7 +376,10 @@ program
|
||||
.action(async (opts) => {
|
||||
const { cmdList } = await import("./commands/memory.js");
|
||||
const isAgent = checkAgentMode();
|
||||
const { backend, config } = getBackendAndConfig(opts.apiKey, opts.baseUrl);
|
||||
const { backend, config } = await getBackendAndConfig(
|
||||
opts.apiKey,
|
||||
opts.baseUrl,
|
||||
);
|
||||
const ids = resolveIds(config, opts);
|
||||
const enableGraph = resolveGraph(config, opts);
|
||||
const output = isAgent ? "agent" : opts.output;
|
||||
@@ -337,7 +415,7 @@ program
|
||||
}
|
||||
const { cmdUpdate } = await import("./commands/memory.js");
|
||||
const isAgent = checkAgentMode();
|
||||
const backend = getBackendOnly(opts.apiKey, opts.baseUrl);
|
||||
const backend = await getBackendOnly(opts.apiKey, opts.baseUrl);
|
||||
const output = isAgent ? "agent" : opts.output;
|
||||
await cmdUpdate(backend, memoryId, resolvedText, {
|
||||
metadata: opts.metadata,
|
||||
@@ -407,7 +485,7 @@ program
|
||||
// ── Dispatch: single memory ──
|
||||
if (memoryId) {
|
||||
const { cmdDelete } = await import("./commands/memory.js");
|
||||
const backend = getBackendOnly(opts.apiKey, opts.baseUrl);
|
||||
const backend = await getBackendOnly(opts.apiKey, opts.baseUrl);
|
||||
await cmdDelete(backend, memoryId, {
|
||||
output,
|
||||
dryRun: opts.dryRun,
|
||||
@@ -419,7 +497,7 @@ program
|
||||
// ── Dispatch: --all ──
|
||||
if (opts.all) {
|
||||
const { cmdDeleteAll } = await import("./commands/memory.js");
|
||||
const { backend, config } = getBackendAndConfig(
|
||||
const { backend, config } = await getBackendAndConfig(
|
||||
opts.apiKey,
|
||||
opts.baseUrl,
|
||||
);
|
||||
@@ -444,7 +522,7 @@ program
|
||||
// ── Dispatch: --entity ──
|
||||
if (opts.entity) {
|
||||
const { cmdEntitiesDelete } = await import("./commands/entities.js");
|
||||
const backend = getBackendOnly(opts.apiKey, opts.baseUrl);
|
||||
const backend = await getBackendOnly(opts.apiKey, opts.baseUrl);
|
||||
await cmdEntitiesDelete(backend, { ...opts, output });
|
||||
return;
|
||||
}
|
||||
@@ -519,7 +597,7 @@ entityCmd
|
||||
.action(async (entityType, opts) => {
|
||||
const { cmdEntitiesList } = await import("./commands/entities.js");
|
||||
const isAgent = checkAgentMode();
|
||||
const backend = getBackendOnly(opts.apiKey, opts.baseUrl);
|
||||
const backend = await getBackendOnly(opts.apiKey, opts.baseUrl);
|
||||
const output = isAgent ? "agent" : opts.output;
|
||||
await cmdEntitiesList(backend, entityType, { output });
|
||||
});
|
||||
@@ -543,7 +621,7 @@ entityCmd
|
||||
.action(async (opts) => {
|
||||
const { cmdEntitiesDelete } = await import("./commands/entities.js");
|
||||
const isAgent = checkAgentMode();
|
||||
const backend = getBackendOnly(opts.apiKey, opts.baseUrl);
|
||||
const backend = await getBackendOnly(opts.apiKey, opts.baseUrl);
|
||||
const output = isAgent ? "agent" : opts.output;
|
||||
await cmdEntitiesDelete(backend, { ...opts, output });
|
||||
});
|
||||
@@ -569,7 +647,7 @@ eventCmd
|
||||
.action(async (opts) => {
|
||||
const { cmdEventList } = await import("./commands/events.js");
|
||||
const isAgent = checkAgentMode();
|
||||
const backend = getBackendOnly(opts.apiKey, opts.baseUrl);
|
||||
const backend = await getBackendOnly(opts.apiKey, opts.baseUrl);
|
||||
const output = isAgent ? "agent" : opts.output;
|
||||
await cmdEventList(backend, { output });
|
||||
});
|
||||
@@ -587,7 +665,7 @@ eventCmd
|
||||
.action(async (eventId, opts) => {
|
||||
const { cmdEventStatus } = await import("./commands/events.js");
|
||||
const isAgent = checkAgentMode();
|
||||
const backend = getBackendOnly(opts.apiKey, opts.baseUrl);
|
||||
const backend = await getBackendOnly(opts.apiKey, opts.baseUrl);
|
||||
const output = isAgent ? "agent" : opts.output;
|
||||
await cmdEventStatus(backend, eventId, { output });
|
||||
});
|
||||
@@ -604,7 +682,10 @@ program
|
||||
.action(async (opts) => {
|
||||
const { cmdStatus } = await import("./commands/utils.js");
|
||||
const isAgent = checkAgentMode();
|
||||
const { backend, config } = getBackendAndConfig(opts.apiKey, opts.baseUrl);
|
||||
const { backend, config } = await getBackendAndConfig(
|
||||
opts.apiKey,
|
||||
opts.baseUrl,
|
||||
);
|
||||
const output = isAgent ? "agent" : opts.output;
|
||||
await cmdStatus(backend, {
|
||||
userId: config.defaults.userId || undefined,
|
||||
@@ -628,7 +709,10 @@ program
|
||||
.action(async (filePath, opts) => {
|
||||
const { cmdImport } = await import("./commands/utils.js");
|
||||
const isAgent = checkAgentMode();
|
||||
const { backend, config } = getBackendAndConfig(opts.apiKey, opts.baseUrl);
|
||||
const { backend, config } = await getBackendAndConfig(
|
||||
opts.apiKey,
|
||||
opts.baseUrl,
|
||||
);
|
||||
const ids = resolveIds(config, opts);
|
||||
const output = isAgent ? "agent" : opts.output;
|
||||
await cmdImport(backend, filePath, {
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* CLI telemetry — anonymous usage tracking via PostHog.
|
||||
*
|
||||
* Sends fire-and-forget events by spawning a detached child process
|
||||
* (telemetry-sender.cjs). The parent CLI process exits immediately;
|
||||
* the child handles email resolution, caching, and the HTTP POST.
|
||||
*
|
||||
* Disable with: MEM0_TELEMETRY=false
|
||||
*/
|
||||
|
||||
import { spawn } from "node:child_process";
|
||||
import { createHash } from "node:crypto";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { CONFIG_FILE, loadConfig } from "./config.js";
|
||||
import { CLI_VERSION } from "./version.js";
|
||||
|
||||
const POSTHOG_API_KEY = "phc_hgJkUVJFYtmaJqrvf6CYN67TIQ8yhXAkWzUn9AMU4yX";
|
||||
const POSTHOG_HOST = "https://us.i.posthog.com/i/v0/e/";
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const SENDER_SCRIPT = path.join(__dirname, "..", "telemetry-sender.cjs");
|
||||
|
||||
function isTelemetryEnabled(): boolean {
|
||||
try {
|
||||
return process.env.MEM0_TELEMETRY !== "false";
|
||||
} catch {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a stable anonymous identifier for the current user.
|
||||
*
|
||||
* Priority: cached user_email (from /v1/ping/) > MD5(api_key) > fallback.
|
||||
* Matches the SDK pattern in mem0-ts/src/client/mem0.ts.
|
||||
*/
|
||||
function getDistinctId(): string {
|
||||
try {
|
||||
const config = loadConfig();
|
||||
if (config.platform.userEmail) {
|
||||
return config.platform.userEmail;
|
||||
}
|
||||
if (config.platform.apiKey) {
|
||||
return createHash("md5").update(config.platform.apiKey).digest("hex");
|
||||
}
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
return "anonymous-cli";
|
||||
}
|
||||
|
||||
/**
|
||||
* Fire a PostHog event (non-blocking, returns void, never throws).
|
||||
* Spawns telemetry-sender.cjs as a detached subprocess.
|
||||
*
|
||||
* When `preResolvedEmail` is provided (e.g. from an upfront ping
|
||||
* validation), it is used directly as the PostHog distinct ID and the
|
||||
* subprocess skips its own `/v1/ping/` call.
|
||||
*/
|
||||
export function captureEvent(
|
||||
eventName: string,
|
||||
properties: Record<string, unknown> = {},
|
||||
preResolvedEmail?: string,
|
||||
): void {
|
||||
if (!isTelemetryEnabled()) return;
|
||||
|
||||
try {
|
||||
const config = loadConfig();
|
||||
const distinctId = preResolvedEmail || getDistinctId();
|
||||
|
||||
const payload = {
|
||||
api_key: POSTHOG_API_KEY,
|
||||
distinct_id: distinctId,
|
||||
event: eventName,
|
||||
properties: {
|
||||
source: "CLI",
|
||||
language: "node",
|
||||
cli_version: CLI_VERSION,
|
||||
node_version: process.version,
|
||||
os: process.platform,
|
||||
...properties,
|
||||
$process_person_profile: false,
|
||||
$lib: "posthog-node",
|
||||
},
|
||||
};
|
||||
|
||||
const context = {
|
||||
payload,
|
||||
posthogHost: POSTHOG_HOST,
|
||||
needsEmail: !distinctId || !distinctId.includes("@"),
|
||||
mem0ApiKey: config.platform.apiKey || "",
|
||||
mem0BaseUrl: config.platform.baseUrl || "https://api.mem0.ai",
|
||||
configPath: CONFIG_FILE,
|
||||
};
|
||||
|
||||
const child = spawn(
|
||||
process.execPath,
|
||||
[SENDER_SCRIPT, JSON.stringify(context)],
|
||||
{ detached: true, stdio: "ignore" },
|
||||
);
|
||||
child.unref();
|
||||
} catch {
|
||||
/* silently swallow */
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* Standalone telemetry sender — runs as a detached child process.
|
||||
*
|
||||
* Usage: node telemetry-sender.cjs '<json context>'
|
||||
*
|
||||
* This script is spawned by telemetry.captureEvent() and runs independently
|
||||
* of the parent CLI process. It:
|
||||
*
|
||||
* 1. Resolves the user's email via /v1/ping/ if not already cached
|
||||
* 2. Caches the email in ~/.mem0/config.json for future runs
|
||||
* 3. Sends the PostHog event
|
||||
*
|
||||
* All errors are silently swallowed — this process must never produce output
|
||||
* or affect the user experience.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const https = require("https");
|
||||
const fs = require("fs");
|
||||
|
||||
function httpsRequest(url, method, headers, body) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const u = new URL(url);
|
||||
const opts = {
|
||||
hostname: u.hostname,
|
||||
path: u.pathname + u.search,
|
||||
method,
|
||||
headers,
|
||||
timeout: 10000,
|
||||
};
|
||||
const req = https.request(opts, (res) => {
|
||||
let data = "";
|
||||
res.on("data", (chunk) => (data += chunk));
|
||||
res.on("end", () => {
|
||||
try {
|
||||
resolve(JSON.parse(data));
|
||||
} catch {
|
||||
resolve({});
|
||||
}
|
||||
});
|
||||
});
|
||||
req.on("error", reject);
|
||||
req.on("timeout", () => {
|
||||
req.destroy();
|
||||
reject(new Error("timeout"));
|
||||
});
|
||||
if (body) {
|
||||
req.end(body);
|
||||
} else {
|
||||
req.end();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function resolveAndCacheEmail(ctx, payload) {
|
||||
try {
|
||||
const pingUrl = ctx.mem0BaseUrl.replace(/\/+$/, "") + "/v1/ping/";
|
||||
const data = await httpsRequest(pingUrl, "GET", {
|
||||
Authorization: "Token " + ctx.mem0ApiKey,
|
||||
"Content-Type": "application/json",
|
||||
});
|
||||
if (data.user_email) {
|
||||
payload.distinct_id = data.user_email;
|
||||
cacheEmail(ctx.configPath, data.user_email);
|
||||
}
|
||||
} catch {
|
||||
// silently swallow
|
||||
}
|
||||
}
|
||||
|
||||
function cacheEmail(configPath, email) {
|
||||
if (!configPath) return;
|
||||
try {
|
||||
const raw = fs.readFileSync(configPath, "utf-8");
|
||||
const cfg = JSON.parse(raw);
|
||||
if (!cfg.platform) cfg.platform = {};
|
||||
cfg.platform.user_email = email;
|
||||
fs.writeFileSync(configPath, JSON.stringify(cfg, null, 2));
|
||||
} catch {
|
||||
// silently swallow
|
||||
}
|
||||
}
|
||||
|
||||
async function sendPosthogEvent(posthogHost, payload) {
|
||||
try {
|
||||
const body = JSON.stringify(payload);
|
||||
await httpsRequest(posthogHost, "POST", {
|
||||
"Content-Type": "application/json",
|
||||
"Content-Length": Buffer.byteLength(body),
|
||||
}, body);
|
||||
} catch {
|
||||
// silently swallow
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const ctx = JSON.parse(process.argv[2]);
|
||||
const payload = ctx.payload;
|
||||
|
||||
if (ctx.needsEmail && ctx.mem0ApiKey) {
|
||||
await resolveAndCacheEmail(ctx, payload);
|
||||
}
|
||||
|
||||
await sendPosthogEvent(ctx.posthogHost, payload);
|
||||
}
|
||||
|
||||
main().catch(() => {});
|
||||
@@ -39,7 +39,7 @@ afterEach(() => {
|
||||
|
||||
describe("branding constants", () => {
|
||||
it("has correct brand color", () => {
|
||||
expect(BRAND_COLOR).toBe("#F1C96C");
|
||||
expect(BRAND_COLOR).toBe("#8b5cf6");
|
||||
});
|
||||
|
||||
it("has correct tagline", () => {
|
||||
|
||||
@@ -44,13 +44,6 @@ describe("CLI Integration — help and version", () => {
|
||||
expect(result.stdout).toContain("search");
|
||||
});
|
||||
|
||||
it("shows version with --version", () => {
|
||||
const result = run(["--version"]);
|
||||
expect(result.exitCode).toBe(0);
|
||||
expect(result.stdout).toContain("0.1.0");
|
||||
});
|
||||
|
||||
|
||||
it("help --json produces valid JSON", () => {
|
||||
const result = run(["help", "--json"]);
|
||||
expect(result.exitCode).toBe(0);
|
||||
|
||||
@@ -253,13 +253,6 @@ describe("cmdDeleteAll", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("cmdVersion", () => {
|
||||
it("shows version", async () => {
|
||||
const { cmdVersion } = await import("../src/commands/utils.js");
|
||||
cmdVersion();
|
||||
expect(output).toContain("0.1.0");
|
||||
});
|
||||
});
|
||||
|
||||
describe("cmdEntitiesList", () => {
|
||||
it("lists users in table mode", async () => {
|
||||
|
||||
+310
-7
@@ -1,6 +1,12 @@
|
||||
# mem0 CLI
|
||||
# mem0 CLI (Python)
|
||||
|
||||
The official command-line interface for [mem0](https://mem0.ai) — the memory layer for AI agents.
|
||||
The official command-line interface for [mem0](https://mem0.ai) — the memory layer for AI agents. Python implementation.
|
||||
|
||||
> **Built for AI agents.** Pass `--agent` (or `--json`) as a global flag on any command to get structured JSON output optimized for programmatic consumption — sanitized fields, no colors or spinners, and errors as JSON too.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Python **3.10+**
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -18,28 +24,325 @@ pip install mem0-cli
|
||||
|
||||
> **Note:** On macOS with Homebrew Python, `pip install` outside a virtual environment will fail with an `externally-managed-environment` error ([PEP 668](https://peps.python.org/pep-0668/)). Use `pipx` instead, or install inside a virtual environment.
|
||||
|
||||
## Quick Start
|
||||
## Quick start
|
||||
|
||||
```bash
|
||||
# Set up your configuration
|
||||
# Interactive setup wizard
|
||||
mem0 init
|
||||
|
||||
# Or login via email
|
||||
mem0 init --email alice@company.com
|
||||
|
||||
# Or authenticate with an existing API key
|
||||
mem0 init --api-key m0-xxx
|
||||
|
||||
# Add a memory
|
||||
mem0 add "I prefer dark mode and use vim keybindings" --user-id alice
|
||||
|
||||
# Search memories
|
||||
mem0 search "What are Alice's preferences?" --user-id alice
|
||||
|
||||
# List all memories
|
||||
# List all memories for a user
|
||||
mem0 list --user-id alice
|
||||
|
||||
# Get a specific memory
|
||||
mem0 get <memory-id>
|
||||
|
||||
# Update a memory
|
||||
mem0 update <memory-id> "I switched to light mode"
|
||||
|
||||
# Delete a memory
|
||||
mem0 delete <memory-id>
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
### `mem0 init`
|
||||
|
||||
Interactive setup wizard. Prompts for your API key and default user ID.
|
||||
|
||||
```bash
|
||||
mem0 init
|
||||
mem0 init --api-key m0-xxx --user-id alice
|
||||
mem0 init --email alice@company.com
|
||||
```
|
||||
|
||||
If an existing configuration is detected, the CLI asks for confirmation before overwriting. Use `--force` to skip the prompt (useful in CI/CD).
|
||||
|
||||
```bash
|
||||
mem0 init --api-key m0-xxx --user-id alice --force
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--api-key` | API key (skip prompt) |
|
||||
| `-u, --user-id` | Default user ID (skip prompt) |
|
||||
| `--email` | Login via email verification code |
|
||||
| `--code` | Verification code (use with `--email` for non-interactive login) |
|
||||
| `--force` | Overwrite existing config without confirmation |
|
||||
|
||||
### `mem0 add`
|
||||
|
||||
Add a memory from text, a JSON messages array, a file, or stdin.
|
||||
|
||||
```bash
|
||||
mem0 add "I prefer dark mode" --user-id alice
|
||||
mem0 add --file conversation.json --user-id alice
|
||||
echo "Loves hiking on weekends" | mem0 add --user-id alice
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `-u, --user-id` | Scope to a user |
|
||||
| `--agent-id` | Scope to an agent |
|
||||
| `--messages` | Conversation messages as JSON |
|
||||
| `-f, --file` | Read messages from a JSON file |
|
||||
| `-m, --metadata` | Custom metadata as JSON |
|
||||
| `--categories` | Categories (JSON array or comma-separated) |
|
||||
| `--graph / --no-graph` | Enable or disable graph memory extraction |
|
||||
| `-o, --output` | Output format: `text`, `json`, `quiet` |
|
||||
|
||||
### `mem0 search`
|
||||
|
||||
Search memories using natural language.
|
||||
|
||||
```bash
|
||||
mem0 search "dietary restrictions" --user-id alice
|
||||
mem0 search "preferred tools" --user-id alice --output json --top-k 5
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `-u, --user-id` | Filter by user |
|
||||
| `-k, --top-k` | Number of results (default: 10) |
|
||||
| `--threshold` | Minimum similarity score (default: 0.3) |
|
||||
| `--rerank` | Enable reranking |
|
||||
| `--keyword` | Use keyword search instead of semantic |
|
||||
| `--filter` | Advanced filter expression (JSON) |
|
||||
| `--graph / --no-graph` | Enable or disable graph in search |
|
||||
| `-o, --output` | Output format: `text`, `json`, `table` |
|
||||
|
||||
### `mem0 list`
|
||||
|
||||
List memories with optional filters and pagination.
|
||||
|
||||
```bash
|
||||
mem0 list --user-id alice
|
||||
mem0 list --user-id alice --category preferences --output json
|
||||
mem0 list --user-id alice --after 2024-01-01 --page-size 50
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `-u, --user-id` | Filter by user |
|
||||
| `--page` | Page number (default: 1) |
|
||||
| `--page-size` | Results per page (default: 100) |
|
||||
| `--category` | Filter by category |
|
||||
| `--after` | Created after date (YYYY-MM-DD) |
|
||||
| `--before` | Created before date (YYYY-MM-DD) |
|
||||
| `-o, --output` | Output format: `text`, `json`, `table` |
|
||||
|
||||
### `mem0 get`
|
||||
|
||||
Retrieve a specific memory by ID.
|
||||
|
||||
```bash
|
||||
mem0 get 7b3c1a2e-4d5f-6789-abcd-ef0123456789
|
||||
mem0 get 7b3c1a2e-4d5f-6789-abcd-ef0123456789 --output json
|
||||
```
|
||||
|
||||
### `mem0 update`
|
||||
|
||||
Update the text or metadata of an existing memory.
|
||||
|
||||
```bash
|
||||
mem0 update <memory-id> "Updated preference text"
|
||||
mem0 update <memory-id> --metadata '{"priority": "high"}'
|
||||
echo "new text" | mem0 update <memory-id>
|
||||
```
|
||||
|
||||
### `mem0 delete`
|
||||
|
||||
Delete a single memory, all memories for a scope, or an entire entity.
|
||||
|
||||
```bash
|
||||
# Delete a single memory
|
||||
mem0 delete <memory-id>
|
||||
|
||||
# Delete all memories for a user
|
||||
mem0 delete --all --user-id alice --force
|
||||
|
||||
# Delete all memories project-wide
|
||||
mem0 delete --all --project --force
|
||||
|
||||
# Preview what would be deleted
|
||||
mem0 delete --all --user-id alice --dry-run
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--all` | Delete all memories matching scope filters |
|
||||
| `--entity` | Delete the entity and all its memories |
|
||||
| `--project` | With `--all`: delete all memories project-wide |
|
||||
| `--dry-run` | Preview without deleting |
|
||||
| `--force` | Skip confirmation prompt |
|
||||
|
||||
### `mem0 import`
|
||||
|
||||
Bulk import memories from a JSON file.
|
||||
|
||||
```bash
|
||||
mem0 import data.json --user-id alice
|
||||
```
|
||||
|
||||
The file should be a JSON array where each item has a `memory` (or `text` or `content`) field and optional `user_id`, `agent_id`, and `metadata` fields.
|
||||
|
||||
### `mem0 config`
|
||||
|
||||
View or modify the local CLI configuration.
|
||||
|
||||
```bash
|
||||
mem0 config show # Display current config (secrets redacted)
|
||||
mem0 config get api_key # Get a specific value
|
||||
mem0 config set user_id bob # Set a value
|
||||
```
|
||||
|
||||
### `mem0 entity`
|
||||
|
||||
List or delete entities (users, agents, apps, runs).
|
||||
|
||||
```bash
|
||||
mem0 entity list users
|
||||
mem0 entity list agents --output json
|
||||
mem0 entity delete --user-id alice --force
|
||||
```
|
||||
|
||||
### `mem0 event`
|
||||
|
||||
Inspect background processing events created by async operations (e.g. bulk deletes, large add jobs).
|
||||
|
||||
```bash
|
||||
# List recent events
|
||||
mem0 event list
|
||||
|
||||
# Check the status of a specific event
|
||||
mem0 event status <event-id>
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `-o, --output` | Output format: `text`, `json` |
|
||||
|
||||
### `mem0 status`
|
||||
|
||||
Verify your API connection and display the current project.
|
||||
|
||||
```bash
|
||||
mem0 status
|
||||
```
|
||||
|
||||
### `mem0 version`
|
||||
|
||||
Print the CLI version.
|
||||
|
||||
```bash
|
||||
mem0 version
|
||||
```
|
||||
|
||||
## Agent mode
|
||||
|
||||
Pass `--agent` (or its alias `--json`) as a **global flag** on any command to get output designed for AI agent tool loops:
|
||||
|
||||
```bash
|
||||
mem0 --agent search "user preferences" --user-id alice
|
||||
mem0 --agent add "User prefers dark mode" --user-id alice
|
||||
mem0 --agent list --user-id alice
|
||||
mem0 --agent delete --all --user-id alice --force
|
||||
```
|
||||
|
||||
Every command returns the same envelope shape:
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"command": "search",
|
||||
"duration_ms": 134,
|
||||
"scope": { "user_id": "alice" },
|
||||
"count": 2,
|
||||
"data": [
|
||||
{ "id": "abc-123", "memory": "User prefers dark mode", "score": 0.97, "created_at": "2026-01-15", "categories": ["preferences"] }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
What agent mode does differently from `--output json`:
|
||||
|
||||
- **Sanitized `data`**: only the fields an agent needs (id, memory, score, etc.) — no internal API noise
|
||||
- **No human output**: spinners, colors, and banners are suppressed entirely
|
||||
- **Errors as JSON**: errors go to stdout as `{"status": "error", "command": "...", "error": "..."}` with a non-zero exit code
|
||||
|
||||
Use `mem0 help --json` to get the full command tree as JSON — useful for agents that need to self-discover available commands.
|
||||
|
||||
## Output formats
|
||||
|
||||
Control how results are displayed with `--output`:
|
||||
|
||||
| Format | Description |
|
||||
|--------|-------------|
|
||||
| `text` | Human-readable with colors and formatting (default) |
|
||||
| `json` | Structured JSON for piping to `jq` (raw API response) |
|
||||
| `table` | Tabular format (default for `list`) |
|
||||
| `quiet` | Minimal — just IDs or status codes |
|
||||
| `agent` | Structured JSON envelope with sanitized fields (set by `--agent`/`--json`) |
|
||||
|
||||
## Global flags
|
||||
|
||||
These flags are available on all commands:
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--json` | Enable agent mode: structured JSON envelope output, no colors or spinners |
|
||||
| `--agent` | Alias for `--json` |
|
||||
| `--api-key` | Override the configured API key for this request |
|
||||
| `--base-url` | Override the configured API base URL for this request |
|
||||
| `-o, --output` | Set the output format |
|
||||
|
||||
## Environment variables
|
||||
|
||||
| Variable | Description |
|
||||
|----------|-------------|
|
||||
| `MEM0_API_KEY` | API key (overrides config file) |
|
||||
| `MEM0_BASE_URL` | API base URL |
|
||||
| `MEM0_USER_ID` | Default user ID |
|
||||
| `MEM0_AGENT_ID` | Default agent ID |
|
||||
| `MEM0_APP_ID` | Default app ID |
|
||||
| `MEM0_RUN_ID` | Default run ID |
|
||||
| `MEM0_ENABLE_GRAPH` | Enable graph memory (`true` / `false`) |
|
||||
|
||||
Environment variables take precedence over values in the config file, which take precedence over defaults.
|
||||
|
||||
## Development
|
||||
|
||||
```bash
|
||||
cd cli/python
|
||||
python -m venv .venv && source .venv/bin/activate
|
||||
pip install -e ".[dev]"
|
||||
|
||||
# Run during development
|
||||
python -m mem0_cli --help
|
||||
mem0 add "test memory" --user-id alice
|
||||
```
|
||||
|
||||
## Releasing
|
||||
|
||||
1. Update `version` in `pyproject.toml`
|
||||
2. Create a GitHub Release with tag `cli-v<version>` (e.g. `cli-v0.2.0`)
|
||||
2. Create a GitHub Release with tag `cli-v<version>` (e.g. `cli-v0.2.1`)
|
||||
|
||||
For a pre-release, use a beta version like `0.2.0b1` and check the **pre-release** checkbox.
|
||||
For a pre-release, use a beta version like `0.2.1b1` and check the **pre-release** checkbox.
|
||||
|
||||
## Documentation
|
||||
|
||||
Full documentation is available at [docs.mem0.ai/platform/cli](https://docs.mem0.ai/platform/cli).
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "mem0-cli"
|
||||
version = "0.2.0b1"
|
||||
version = "0.2.2"
|
||||
description = "The official CLI for mem0 — the memory layer for AI agents"
|
||||
readme = "README.md"
|
||||
license = "Apache-2.0"
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
"""mem0 CLI — the command-line interface for the mem0 memory layer."""
|
||||
|
||||
__version__ = "0.1.0"
|
||||
__version__ = "0.2.2"
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import contextlib
|
||||
import json as _json
|
||||
import os
|
||||
import stat as _stat_mod
|
||||
@@ -12,7 +13,7 @@ import typer
|
||||
from rich.console import Console
|
||||
|
||||
from mem0_cli import __version__
|
||||
from mem0_cli.branding import BRAND_COLOR, print_error
|
||||
from mem0_cli.branding import BRAND_COLOR, print_error, print_warning
|
||||
|
||||
console = Console()
|
||||
err_console = Console(stderr=True)
|
||||
@@ -55,6 +56,44 @@ event_app = typer.Typer(
|
||||
# entity_app and event_app registered after Memory commands to control panel ordering
|
||||
|
||||
|
||||
# ── Validated user identity (set by _get_backend_and_config) ──────────────
|
||||
|
||||
_validated_user_email: str | None = None
|
||||
|
||||
# ── Telemetry helper ─────────────────────────────────────────────────────
|
||||
|
||||
|
||||
def _fire_telemetry(command_name: str, extra: dict | None = None) -> None:
|
||||
"""Fire a PostHog telemetry event (non-blocking, never fails)."""
|
||||
try:
|
||||
from mem0_cli.telemetry import capture_event
|
||||
|
||||
props = {"command": command_name}
|
||||
if extra:
|
||||
props.update(extra)
|
||||
capture_event(f"cli.{command_name}", props, pre_resolved_email=_validated_user_email)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
@config_app.callback(invoke_without_command=True)
|
||||
def _config_callback(ctx: typer.Context) -> None:
|
||||
if ctx.invoked_subcommand:
|
||||
_fire_telemetry(f"config.{ctx.invoked_subcommand}")
|
||||
|
||||
|
||||
@entity_app.callback(invoke_without_command=True)
|
||||
def _entity_callback(ctx: typer.Context) -> None:
|
||||
if ctx.invoked_subcommand:
|
||||
_fire_telemetry(f"entity.{ctx.invoked_subcommand}")
|
||||
|
||||
|
||||
@event_app.callback(invoke_without_command=True)
|
||||
def _event_callback(ctx: typer.Context) -> None:
|
||||
if ctx.invoked_subcommand:
|
||||
_fire_telemetry(f"event.{ctx.invoked_subcommand}")
|
||||
|
||||
|
||||
# ── Helpers ───────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
@@ -62,9 +101,16 @@ def _get_backend_and_config(
|
||||
api_key: str | None = None,
|
||||
base_url: str | None = None,
|
||||
):
|
||||
"""Build and return the Platform backend plus the loaded config."""
|
||||
"""Build and return the Platform backend plus the loaded config.
|
||||
|
||||
Validates the API key upfront via ``/v1/ping/`` and caches the
|
||||
resolved user email for telemetry.
|
||||
"""
|
||||
global _validated_user_email
|
||||
|
||||
from mem0_cli.backend import get_backend
|
||||
from mem0_cli.config import load_config
|
||||
from mem0_cli.backend.platform import AuthError
|
||||
from mem0_cli.config import load_config, save_config
|
||||
|
||||
config = load_config()
|
||||
|
||||
@@ -81,7 +127,29 @@ def _get_backend_and_config(
|
||||
)
|
||||
raise typer.Exit(1)
|
||||
|
||||
return get_backend(config), config
|
||||
backend = get_backend(config)
|
||||
|
||||
# Validate the API key upfront with a fast timeout
|
||||
try:
|
||||
ping_data = backend.ping(timeout=5.0)
|
||||
email = ping_data.get("user_email") if isinstance(ping_data, dict) else None
|
||||
if email:
|
||||
_validated_user_email = email
|
||||
if config.platform.user_email != email:
|
||||
config.platform.user_email = email
|
||||
with contextlib.suppress(Exception):
|
||||
save_config(config)
|
||||
except AuthError:
|
||||
print_error(
|
||||
err_console,
|
||||
"Invalid or expired API key.",
|
||||
hint="Run 'mem0 init' or set MEM0_API_KEY environment variable.",
|
||||
)
|
||||
raise typer.Exit(1) from None
|
||||
except Exception:
|
||||
print_warning(err_console, "Could not validate API key (network issue). Proceeding anyway.")
|
||||
|
||||
return backend, config
|
||||
|
||||
|
||||
def _get_backend(
|
||||
@@ -165,8 +233,11 @@ def main_callback(
|
||||
if version:
|
||||
from mem0_cli.commands.utils import cmd_version
|
||||
|
||||
_fire_telemetry("version")
|
||||
cmd_version()
|
||||
raise typer.Exit()
|
||||
if ctx.invoked_subcommand:
|
||||
_fire_telemetry(ctx.invoked_subcommand)
|
||||
|
||||
|
||||
# ── Memory: add ───────────────────────────────────────────────────────────
|
||||
@@ -571,12 +642,14 @@ def delete(
|
||||
|
||||
# ── Dispatch ─────────────────────────────────────────────────────
|
||||
if memory_id is not None:
|
||||
_fire_telemetry("delete", {"delete_mode": "single"})
|
||||
from mem0_cli.commands.memory import cmd_delete
|
||||
|
||||
backend = _get_backend(api_key, base_url)
|
||||
cmd_delete(backend, memory_id, dry_run=dry_run, force=force, output=output)
|
||||
|
||||
elif all_:
|
||||
_fire_telemetry("delete", {"delete_mode": "all"})
|
||||
from mem0_cli.commands.memory import cmd_delete_all
|
||||
|
||||
backend, config = _get_backend_and_config(api_key, base_url)
|
||||
@@ -584,6 +657,7 @@ def delete(
|
||||
cmd_delete_all(backend, force=force, dry_run=dry_run, all_=project, **ids, output=output)
|
||||
|
||||
else: # --entity
|
||||
_fire_telemetry("delete", {"delete_mode": "entity"})
|
||||
from mem0_cli.commands.entities import cmd_entities_delete
|
||||
|
||||
backend = _get_backend(api_key, base_url)
|
||||
|
||||
@@ -6,6 +6,7 @@ from typing import Any
|
||||
|
||||
import httpx
|
||||
|
||||
from mem0_cli import __version__
|
||||
from mem0_cli.backend.base import Backend
|
||||
from mem0_cli.config import PlatformConfig
|
||||
|
||||
@@ -21,11 +22,17 @@ class PlatformBackend(Backend):
|
||||
headers={
|
||||
"Authorization": f"Token {config.api_key}",
|
||||
"Content-Type": "application/json",
|
||||
"X-Mem0-Source": "cli",
|
||||
"X-Mem0-Client-Language": "python",
|
||||
"X-Mem0-Client-Version": __version__,
|
||||
},
|
||||
timeout=30.0,
|
||||
)
|
||||
|
||||
def _request(self, method: str, path: str, **kwargs: Any) -> Any:
|
||||
from mem0_cli.state import is_agent_mode
|
||||
|
||||
self._client.headers["X-Mem0-Caller-Type"] = "agent" if is_agent_mode() else "user"
|
||||
resp = self._client.request(method, path, **kwargs)
|
||||
if resp.status_code == 401:
|
||||
raise AuthError("Authentication failed. Your API key may be invalid or expired.")
|
||||
@@ -281,6 +288,20 @@ class PlatformBackend(Backend):
|
||||
result = self._request("DELETE", f"/v2/entities/{entity_type}/{entity_id}/")
|
||||
return result
|
||||
|
||||
def ping(self, timeout: float | None = None) -> dict:
|
||||
"""Call the ping endpoint and return the raw response.
|
||||
|
||||
When *timeout* is given it overrides the client-level timeout so that
|
||||
validation pings can fail fast without blocking the user.
|
||||
"""
|
||||
if timeout is not None:
|
||||
resp = self._client.get("/v1/ping/", timeout=timeout)
|
||||
if resp.status_code == 401:
|
||||
raise AuthError("Authentication failed. Your API key may be invalid or expired.")
|
||||
resp.raise_for_status()
|
||||
return resp.json()
|
||||
return self._request("GET", "/v1/ping/")
|
||||
|
||||
def status(
|
||||
self,
|
||||
*,
|
||||
@@ -289,7 +310,7 @@ class PlatformBackend(Backend):
|
||||
) -> dict[str, Any]:
|
||||
"""Check connectivity using the ping endpoint."""
|
||||
try:
|
||||
self._request("GET", "/v1/ping/")
|
||||
self.ping()
|
||||
return {"connected": True, "backend": "platform", "base_url": self.base_url}
|
||||
except Exception as e:
|
||||
return {"connected": False, "backend": "platform", "error": str(e)}
|
||||
|
||||
@@ -26,8 +26,8 @@ LOGO_MINI = "◆ mem0"
|
||||
|
||||
TAGLINE = "The Memory Layer for AI Agents"
|
||||
|
||||
BRAND_COLOR = "#F1C96C" # Golden
|
||||
ACCENT_COLOR = "#F5D78E"
|
||||
BRAND_COLOR = "#8b5cf6" # Purple
|
||||
ACCENT_COLOR = "#a78bfa"
|
||||
SUCCESS_COLOR = "#22c55e"
|
||||
ERROR_COLOR = "#ef4444"
|
||||
WARNING_COLOR = "#f59e0b"
|
||||
|
||||
@@ -108,6 +108,10 @@ def _email_login(
|
||||
The caller expects at minimum an ``api_key`` field.
|
||||
"""
|
||||
url = base_url.rstrip("/")
|
||||
_source_headers = {
|
||||
"X-Mem0-Source": "cli",
|
||||
"X-Mem0-Client-Language": "python",
|
||||
}
|
||||
|
||||
with httpx.Client(timeout=30.0) as client:
|
||||
# If code is already provided, skip sending — user already has a code
|
||||
@@ -116,6 +120,7 @@ def _email_login(
|
||||
resp = client.post(
|
||||
f"{url}/api/v1/auth/email_code/",
|
||||
json={"email": email},
|
||||
headers=_source_headers,
|
||||
)
|
||||
if resp.status_code == 429:
|
||||
print_error(err_console, "Too many attempts. Try again in a few minutes.")
|
||||
@@ -148,6 +153,7 @@ def _email_login(
|
||||
resp = client.post(
|
||||
f"{url}/api/v1/auth/email_code/verify/",
|
||||
json={"email": email, "code": code.strip()},
|
||||
headers=_source_headers,
|
||||
)
|
||||
if resp.status_code == 429:
|
||||
print_error(err_console, "Too many attempts. Try again in a few minutes.")
|
||||
@@ -229,6 +235,7 @@ def run_init(
|
||||
raise typer.Exit(1)
|
||||
config.platform.api_key = api_key_val
|
||||
config.platform.base_url = base_url
|
||||
config.platform.user_email = email
|
||||
config.defaults.user_id = (
|
||||
user_id or os.environ.get("USER") or os.environ.get("USERNAME") or "mem0-cli"
|
||||
)
|
||||
@@ -299,6 +306,7 @@ def run_init(
|
||||
raise typer.Exit(1)
|
||||
config.platform.api_key = api_key_val
|
||||
config.platform.base_url = base_url
|
||||
config.platform.user_email = email_addr
|
||||
config.defaults.user_id = (
|
||||
user_id or os.environ.get("USER") or os.environ.get("USERNAME") or "mem0-cli"
|
||||
)
|
||||
@@ -384,6 +392,14 @@ def _validate_platform(config: Mem0Config) -> None:
|
||||
)
|
||||
if status.get("connected"):
|
||||
print_success(console, "Connected to mem0 Platform!")
|
||||
# Cache user_email from ping response for telemetry distinct_id
|
||||
try:
|
||||
ping_data = backend.ping()
|
||||
user_email = ping_data.get("user_email") if isinstance(ping_data, dict) else None
|
||||
if user_email:
|
||||
config.platform.user_email = user_email
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
print_error(
|
||||
err_console,
|
||||
|
||||
@@ -27,6 +27,7 @@ CONFIG_VERSION = 1
|
||||
class PlatformConfig:
|
||||
api_key: str = ""
|
||||
base_url: str = DEFAULT_BASE_URL
|
||||
user_email: str = ""
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -48,6 +49,7 @@ class Mem0Config:
|
||||
SHORT_KEY_ALIASES: dict[str, str] = {
|
||||
"api_key": "platform.api_key",
|
||||
"base_url": "platform.base_url",
|
||||
"user_email": "platform.user_email",
|
||||
"user_id": "defaults.user_id",
|
||||
"agent_id": "defaults.agent_id",
|
||||
"app_id": "defaults.app_id",
|
||||
@@ -76,6 +78,7 @@ def load_config() -> Mem0Config:
|
||||
plat = data.get("platform", {})
|
||||
config.platform.api_key = plat.get("api_key", "")
|
||||
config.platform.base_url = plat.get("base_url", DEFAULT_BASE_URL)
|
||||
config.platform.user_email = plat.get("user_email", "")
|
||||
|
||||
defaults = data.get("defaults", {})
|
||||
config.defaults.user_id = defaults.get("user_id", "")
|
||||
@@ -132,6 +135,7 @@ def save_config(config: Mem0Config) -> None:
|
||||
"platform": {
|
||||
"api_key": config.platform.api_key,
|
||||
"base_url": config.platform.base_url,
|
||||
"user_email": config.platform.user_email,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
"""CLI telemetry — anonymous usage tracking via PostHog.
|
||||
|
||||
Sends fire-and-forget events to PostHog by spawning a detached subprocess
|
||||
(telemetry_sender.py). The parent CLI process exits immediately; the
|
||||
subprocess handles email resolution, caching, and the HTTP POST.
|
||||
|
||||
Disable with: MEM0_TELEMETRY=false
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import platform
|
||||
import subprocess
|
||||
import sys
|
||||
from typing import Any
|
||||
|
||||
POSTHOG_API_KEY = "phc_hgJkUVJFYtmaJqrvf6CYN67TIQ8yhXAkWzUn9AMU4yX"
|
||||
POSTHOG_HOST = "https://us.i.posthog.com/i/v0/e/"
|
||||
|
||||
|
||||
def _is_telemetry_enabled() -> bool:
|
||||
val = os.environ.get("MEM0_TELEMETRY", "true").lower()
|
||||
return val not in ("false", "0", "no")
|
||||
|
||||
|
||||
def _get_distinct_id() -> str:
|
||||
"""Return a stable anonymous identifier for the current user.
|
||||
|
||||
Priority: cached user_email (from /v1/ping/) > MD5(api_key) > fallback.
|
||||
Matches the SDK pattern in mem0/client/main.py.
|
||||
"""
|
||||
try:
|
||||
from mem0_cli.config import load_config
|
||||
|
||||
config = load_config()
|
||||
if config.platform.user_email:
|
||||
return config.platform.user_email
|
||||
if config.platform.api_key:
|
||||
return hashlib.md5(config.platform.api_key.encode()).hexdigest()
|
||||
except Exception:
|
||||
pass
|
||||
return "anonymous-cli"
|
||||
|
||||
|
||||
def capture_event(
|
||||
event_name: str,
|
||||
properties: dict[str, Any] | None = None,
|
||||
pre_resolved_email: str | None = None,
|
||||
) -> None:
|
||||
"""Fire a PostHog event via a detached subprocess (non-blocking).
|
||||
|
||||
When *pre_resolved_email* is provided (e.g. from an upfront ping
|
||||
validation), it is used directly as the PostHog distinct ID and the
|
||||
subprocess skips its own ``/v1/ping/`` call.
|
||||
"""
|
||||
if not _is_telemetry_enabled():
|
||||
return
|
||||
|
||||
try:
|
||||
from mem0_cli import __version__
|
||||
from mem0_cli.config import CONFIG_FILE, load_config
|
||||
from mem0_cli.state import is_agent_mode
|
||||
|
||||
config = load_config()
|
||||
distinct_id = pre_resolved_email or _get_distinct_id()
|
||||
|
||||
payload = {
|
||||
"api_key": POSTHOG_API_KEY,
|
||||
"distinct_id": distinct_id,
|
||||
"event": event_name,
|
||||
"properties": {
|
||||
"source": "CLI",
|
||||
"language": "python",
|
||||
"cli_version": __version__,
|
||||
"agent_mode": is_agent_mode(),
|
||||
"python_version": sys.version,
|
||||
"os": sys.platform,
|
||||
"os_version": platform.version(),
|
||||
"$process_person_profile": False,
|
||||
"$lib": "posthog-python",
|
||||
**(properties or {}),
|
||||
},
|
||||
}
|
||||
|
||||
context = {
|
||||
"payload": payload,
|
||||
"posthog_host": POSTHOG_HOST,
|
||||
"needs_email": not distinct_id or "@" not in distinct_id,
|
||||
"mem0_api_key": config.platform.api_key or "",
|
||||
"mem0_base_url": config.platform.base_url or "https://api.mem0.ai",
|
||||
"config_path": str(CONFIG_FILE),
|
||||
}
|
||||
|
||||
subprocess.Popen(
|
||||
[sys.executable, "-m", "mem0_cli.telemetry_sender", json.dumps(context)],
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
start_new_session=True,
|
||||
close_fds=True,
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
@@ -0,0 +1,86 @@
|
||||
"""Standalone telemetry sender — runs as a detached subprocess.
|
||||
|
||||
Usage: python -m mem0_cli.telemetry_sender '<json context>'
|
||||
|
||||
This module is spawned by telemetry.capture_event() and runs independently
|
||||
of the parent CLI process. It:
|
||||
|
||||
1. Resolves the user's email via /v1/ping/ if not already cached
|
||||
2. Caches the email in ~/.mem0/config.json for future runs
|
||||
3. Sends the PostHog event
|
||||
|
||||
All errors are silently swallowed — this process must never produce output
|
||||
or affect the user experience.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import sys
|
||||
import urllib.request
|
||||
|
||||
|
||||
def main() -> None:
|
||||
ctx = json.loads(sys.argv[1])
|
||||
payload = ctx["payload"]
|
||||
|
||||
if ctx.get("needs_email") and ctx.get("mem0_api_key"):
|
||||
_resolve_and_cache_email(ctx, payload)
|
||||
|
||||
_send_posthog_event(ctx["posthog_host"], payload)
|
||||
|
||||
|
||||
def _resolve_and_cache_email(ctx: dict, payload: dict) -> None:
|
||||
"""Call /v1/ping/ to get the user's email, update the payload, and cache it."""
|
||||
try:
|
||||
ping_url = ctx["mem0_base_url"].rstrip("/") + "/v1/ping/"
|
||||
req = urllib.request.Request(
|
||||
ping_url,
|
||||
headers={
|
||||
"Authorization": "Token " + ctx["mem0_api_key"],
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
)
|
||||
resp = urllib.request.urlopen(req, timeout=10)
|
||||
data = json.loads(resp.read())
|
||||
email = data.get("user_email")
|
||||
if email:
|
||||
payload["distinct_id"] = email
|
||||
_cache_email(ctx.get("config_path"), email)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def _cache_email(config_path: str | None, email: str) -> None:
|
||||
"""Write user_email into the config file for future runs."""
|
||||
if not config_path:
|
||||
return
|
||||
try:
|
||||
with open(config_path) as f:
|
||||
cfg = json.load(f)
|
||||
cfg.setdefault("platform", {})["user_email"] = email
|
||||
with open(config_path, "w") as f:
|
||||
json.dump(cfg, f, indent=2)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def _send_posthog_event(posthog_host: str, payload: dict) -> None:
|
||||
"""POST the event to PostHog."""
|
||||
try:
|
||||
body = json.dumps(payload).encode()
|
||||
req = urllib.request.Request(
|
||||
posthog_host,
|
||||
data=body,
|
||||
headers={"Content-Type": "application/json"},
|
||||
)
|
||||
urllib.request.urlopen(req, timeout=10)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import contextlib
|
||||
|
||||
with contextlib.suppress(Exception):
|
||||
main()
|
||||
@@ -83,11 +83,6 @@ class TestCLIIntegration:
|
||||
assert "add" in result.stdout
|
||||
assert "search" in result.stdout
|
||||
|
||||
def test_version_flag(self):
|
||||
result = _run(["--version"])
|
||||
assert result.returncode == 0
|
||||
assert "0.1.0" in result.stdout
|
||||
|
||||
def test_add_help(self):
|
||||
result = _run(["add", "--help"])
|
||||
assert result.returncode == 0
|
||||
|
||||
@@ -30,7 +30,6 @@ from mem0_cli.commands.memory import (
|
||||
from mem0_cli.commands.utils import (
|
||||
cmd_import,
|
||||
cmd_status,
|
||||
cmd_version,
|
||||
)
|
||||
|
||||
|
||||
@@ -742,15 +741,6 @@ class TestStatusCommand:
|
||||
assert '"status"' in output
|
||||
|
||||
|
||||
class TestVersionCommand:
|
||||
def test_version(self):
|
||||
console, buf = _make_console()
|
||||
with patch("mem0_cli.commands.utils.console", console):
|
||||
cmd_version()
|
||||
output = buf.getvalue()
|
||||
assert "0.1.0" in output
|
||||
|
||||
|
||||
class TestImportCommand:
|
||||
def test_import_json(self, mock_backend, tmp_path):
|
||||
file_path = tmp_path / "import.json"
|
||||
|
||||
@@ -10,7 +10,7 @@ description: "REST APIs for memory management, search, and entity operations"
|
||||
Mem0 provides a comprehensive REST API for integrating advanced memory capabilities into your applications. Create, search, update, and manage memories across users, agents, and custom entities with simple HTTP requests.
|
||||
|
||||
<Info>
|
||||
**Quick start:** Get your API key from the [Mem0 Dashboard](https://app.mem0.ai/dashboard/api-keys) and make your first memory operation in minutes.
|
||||
**Quick start:** Get your API key from the <a href="https://app.mem0.ai/dashboard/api-keys" rel="nofollow">Mem0 Dashboard</a> and make your first memory operation in minutes.
|
||||
</Info>
|
||||
|
||||
---
|
||||
@@ -87,7 +87,7 @@ All API requests require authentication using Token-based authentication. Includ
|
||||
Authorization: Token <your-api-key>
|
||||
```
|
||||
|
||||
Get your API key from the [Mem0 Dashboard](https://app.mem0.ai/dashboard/api-keys).
|
||||
Get your API key from the <a href="https://app.mem0.ai/dashboard/api-keys" rel="nofollow">Mem0 Dashboard</a>.
|
||||
|
||||
<Warning>
|
||||
**Keep your API key secure.** Never expose it in client-side code or public repositories. Use environment variables and server-side requests only.
|
||||
|
||||
@@ -82,7 +82,7 @@ new_project = client.project.create(
|
||||
|
||||
### Update Project Settings
|
||||
|
||||
Modify project configuration including custom instructions, categories, and graph settings:
|
||||
Modify project configuration including custom instructions, categories, graph settings, and language preferences:
|
||||
|
||||
```python
|
||||
# Update project with custom categories
|
||||
@@ -101,6 +101,9 @@ client.project.update(
|
||||
# Enable graph memory for the project
|
||||
client.project.update(enable_graph=True)
|
||||
|
||||
# Use the input language for memory storage and retrieval
|
||||
client.project.update(multilingual=True)
|
||||
|
||||
# Update multiple settings at once
|
||||
client.project.update(
|
||||
custom_instructions="...",
|
||||
@@ -108,7 +111,8 @@ client.project.update(
|
||||
{"personal_info": "User personal information and preferences"},
|
||||
{"work_context": "Professional context and work-related information"}
|
||||
],
|
||||
enable_graph=True
|
||||
enable_graph=True,
|
||||
multilingual=True
|
||||
)
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
---
|
||||
title: "Highlights"
|
||||
description: "Major product launches, headline features, and milestones for Mem0."
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
<Update label="2026-04-06" description="Mem0 Skill Graph">
|
||||
|
||||
**Mem0 Skill Graph — In-Context Documentation for AI Agents**
|
||||
|
||||
AI coding agents in Claude Code, Cursor, and Codex can now access Mem0 knowledge directly in their workflow — no doc searching required. Three interconnected skills launched:
|
||||
|
||||
- **mem0 Core Skill** — Complete Python and TypeScript SDK reference, REST API patterns, and integration guides for LangChain, CrewAI, Autogen, and more
|
||||
- **mem0-cli Skill** — Terminal command reference, configuration walkthroughs, and CI/CD recipes
|
||||
- **mem0-vercel-ai-sdk Skill** — Vercel AI SDK provider API, memory-augmented generation patterns, and multi-provider setup
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-04-06" description="Mem0 CLI v0.2.2">
|
||||
|
||||
**Official Mem0 CLI — Now on PyPI and npm**
|
||||
|
||||
A full-featured command-line interface for Mem0, available in both Python and Node.js:
|
||||
|
||||
- **Install:** `pip install mem0-cli` or `npm install -g @mem0/cli`
|
||||
- **Full command suite** — `add`, `search`, `list`, `get`, `update`, `delete`, `import`, `config`, `init`, `status`, `entity`, `event`
|
||||
- **Interactive setup** — `mem0 init` with email verification or direct API key entry
|
||||
- **Works everywhere** — Platform (Mem0 Cloud) and self-hosted OSS modes
|
||||
- **Scriptable** — `--json` flag for CI/CD pipelines and automation
|
||||
- **Dual SDK** — Same commands, same experience across Python and Node.js
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-04-04" description="OpenClaw v1.0.4">
|
||||
|
||||
**OpenClaw Plugin — Production-Ready**
|
||||
|
||||
The OpenClaw Mem0 plugin went from initial release to production-ready in one week (v1.0.0 → v1.0.4):
|
||||
|
||||
- **Skills-based memory architecture** — New extraction pipeline with skill-loader, batched extraction, and domain-aware memory triage
|
||||
- **Dream gate** — Automatic memory consolidation during idle periods for higher-quality long-term recall
|
||||
- **Interactive CLI** — `openclaw mem0 init`, `status`, `config`, `import`, and `event` commands
|
||||
- **Unified tool naming** — `memory_add` and `memory_delete` replace 4 legacy tools, matching the platform API
|
||||
- **Security hardened** — Path traversal protection, pinned dependencies, 329 tests across 10 files
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-04-02" description="Mem0 Plugin for AI Editors">
|
||||
|
||||
**Mem0 Plugin for Claude Code, Cursor, and Codex**
|
||||
|
||||
Launched a unified Mem0 plugin across three major AI development environments — Claude Code and Cursor first (March 25), then Codex (April 2):
|
||||
|
||||
- **9 MCP memory tools** — add, search, get, update, delete, bulk delete, entity management via `mcp.mem0.ai`
|
||||
- **Lifecycle hooks** — Automatic memory capture at session start, context compaction, task completion, and session end
|
||||
- **Cloud MCP server** — Managed endpoint replaces local MCP and Smithery setup
|
||||
- **Streamable HTTP transport** — New MCP transport protocol for real-time streaming
|
||||
- **Codex-specific skill** — Dedicated skill in `mem0-plugin/skills/mem0-codex` for Codex workflows
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-03-21" description="New Providers">
|
||||
|
||||
**Apache AGE, Turbopuffer, MiniMax, and pgvector for Node.js**
|
||||
|
||||
Major expansion of the provider ecosystem:
|
||||
|
||||
- **Apache AGE** — New graph store support, bringing the total to 4 graph store backends (Neo4j, Memgraph, Kuzu, Apache AGE)
|
||||
- **Turbopuffer** — New vector database provider for Python SDK
|
||||
- **MiniMax** — New LLM provider with dedicated AWS Bedrock support
|
||||
- **pgvector for Node.js** — PostgreSQL vector support added to the TypeScript OSS SDK
|
||||
- **Reasoning models** — `reasoning_effort` parameter for OpenAI o1/o3-style models
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-03-14" description="Mem0 Platform Skill">
|
||||
|
||||
**Mem0 Platform Skill on skills.sh**
|
||||
|
||||
First skill launch — a dedicated Mem0 skill providing platform API reference, quickstart patterns, and integration examples directly inside agent sessions. Available on [skills.sh](https://skills.sh) for any compatible AI coding agent.
|
||||
|
||||
</Update>
|
||||
@@ -0,0 +1,185 @@
|
||||
---
|
||||
title: "OpenClaw"
|
||||
description: "Release notes for the OpenClaw plugin and agent harness."
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
<Update label="2026-04-07" description="v1.0.5">
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Init interactive choice bug**: Fixed number selection in `openclaw mem0 init` — entering 1/2/3 now correctly selects the corresponding option (was broken by readline prefill concatenating with user input)
|
||||
- **OSS pgvector crash** ([#4727](https://github.com/mem0ai/mem0/issues/4727)): Fixed "Client has already been connected" cascade when using pgvector in OSS mode. The warmup call swallowed errors leaving a half-initialized pg client; concurrent recall/capture then all hit `client.connect()` on the same client. Fix: let warmup errors propagate (so `initPromise` resets and retries with a fresh Memory + fresh pg client) and build fresh config objects per attempt instead of mutating shared state.
|
||||
|
||||
**Removed:**
|
||||
- **`orgId` / `projectId` config parameters**: Removed from config schema, CLI (`config show/get/set`), init display, and providers. The API key is project-scoped, so separate org/project IDs are unnecessary and could cause access errors if mismatched.
|
||||
- **`enableGraph` config parameter**: Removed from all config surfaces, providers, backend, and tools. Graph memory is being deprecated — removing the flag avoids unnecessary exposure.
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-04-04" description="v1.0.4">
|
||||
|
||||
**New Features:**
|
||||
- **Interactive init flow**: `openclaw mem0 init` with interactive menu (email verification or direct API key). Non-interactive modes: `--api-key`, `--email`, `--email --code`
|
||||
- **`memory_add` tool**: Replaces `memory_store` — name now matches `mem0` CLI and platform API
|
||||
- **`memory_delete` tool**: Unified delete — single ID, search-then-delete, bulk, entity cascade. Replaces `memory_forget` and `memory_delete_all`
|
||||
- **CLI subcommands**: `openclaw mem0 init`, `openclaw mem0 status`, `openclaw mem0 config show`, `openclaw mem0 config set`
|
||||
- **`import` CLI command**: Bulk-import memories from a JSON file with `--user-id` and `--agent-id` overrides
|
||||
- **`event list` / `event status` CLI commands**: Monitor background processing events
|
||||
- **`fs-safe.ts` module**: Isolated filesystem wrappers in a separate entry point
|
||||
- **`backend/` module**: `PlatformBackend` with direct HTTP API access for CLI commands
|
||||
- **Plugin manifest**: Added `contracts.tools`, `configSchema`, and `uiHints` to `openclaw.plugin.json`
|
||||
- **Test suite**: 329 tests across 10 test files
|
||||
|
||||
**Changes:**
|
||||
- **Modular architecture**: Extracted tools into `tools/` directory (6 files) and CLI into `cli/commands.ts`
|
||||
- **Code splitting**: tsup builds with `splitting: true` and two entry points
|
||||
- **Skills updated**: All SKILL.md files reference new tool names (`memory_add`, `memory_delete`)
|
||||
- **Auto-recall timeout**: Recall wrapped in 8-second `Promise.race`
|
||||
- **Auto-capture fire-and-forget**: `provider.add()` runs in background via `.then()/.catch()`
|
||||
- **Auto-capture minimum content gate**: Skips extraction when total user content is fewer than 50 chars
|
||||
|
||||
**Removed:**
|
||||
- `memory_store` tool — replaced by `memory_add`
|
||||
- `memory_forget` tool — replaced by `memory_delete`
|
||||
- `memory_delete_all` tool — merged into `memory_delete`
|
||||
- `memory_history` tool and `history` CLI command — deprecated
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-04-03" description="v1.0.3">
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Security**: Added `safePath()` containment helper to `readSkillFile` and `readDomainOverlay` in `skill-loader.ts` — prevents directory traversal
|
||||
- **Noise filter**: Reverted incorrect `After-Compaction` regex rename back to `Post-Compaction`
|
||||
|
||||
**Changes:**
|
||||
- **Supply-chain hardening**: Pinned `mem0ai` dependency to exact `2.3.0` (was `^2.3.0`)
|
||||
|
||||
**Tests:**
|
||||
- 12 new tests covering `safePath`, `readSkillFile`, `readDomainOverlay`, and `loadSkill` with traversal inputs
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-04-02" description="v1.0.2">
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Security**: Removed `resolveEnvVars()` and `resolveEnvVarsDeep()` from `config.ts` — plugin-side env resolution was redundant and triggered static analysis warnings ([#4676](https://github.com/mem0ai/mem0/pull/4676))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-04-02" description="v1.0.1">
|
||||
|
||||
**New Features:**
|
||||
- **CD workflow**: Added continuous deployment workflow with OIDC trusted publishing ([#4672](https://github.com/mem0ai/mem0/pull/4672))
|
||||
- **Plugin configuration manifest**: Added `compat` and `build` metadata to `package.json` ([#4667](https://github.com/mem0ai/mem0/pull/4667))
|
||||
- **LICENSE**: Added Apache-2.0 license file ([#4667](https://github.com/mem0ai/mem0/pull/4667))
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Dream gate**: Fixed cheap-first ordering, session isolation, and verified completion ([#4666](https://github.com/mem0ai/mem0/pull/4666))
|
||||
- **Graceful startup**: Plugin now starts gracefully when no API key is configured ([#4669](https://github.com/mem0ai/mem0/pull/4669))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-04-01" description="v1.0.0">
|
||||
|
||||
**New Features:**
|
||||
- **Skills-based memory architecture**: New skill-loader and skill-based extraction pipeline with batched extraction ([#4624](https://github.com/mem0ai/mem0/pull/4624))
|
||||
- **Dream gate**: Memory consolidation and dream-cycle processing during idle periods
|
||||
- **Enhanced recall**: New `recall.ts` module with improved recall logic and skill-aware retrieval
|
||||
- **Memory triage skill**: Domain-aware memory triage with companion domain support and recall protocol
|
||||
- **Memory dream skill**: Skill for memory consolidation during idle periods
|
||||
- **Plugin configuration**: Added `openclaw.plugin.json` manifest and `scripts/configure.py` setup helper
|
||||
|
||||
**Changes:**
|
||||
- Extraction pipeline refactored to use skills-based architecture for more contextual and higher quality memory capture
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-03-26" description="v0.4.1">
|
||||
|
||||
**New Features:**
|
||||
- **Improved extraction quality**: Enhanced noise filtering, deduplication, and better extraction instructions
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Credential detection**: Improved detection of credentials, API keys, and secrets in extraction instructions (#4552)
|
||||
- **Standalone timestamps**: Prevented extraction of standalone timestamps as memories (#4550)
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-03-16" description="v0.4.0">
|
||||
|
||||
**New Features:**
|
||||
- **Non-interactive trigger filtering**: Skips recall and capture for `cron`, `heartbeat`, `automation`, and `schedule` triggers
|
||||
- **Subagent hallucination prevention**: Detects ephemeral subagent sessions and routes recall to parent namespace
|
||||
- **Dynamic recall thresholding**: Memories scoring less than 50% of top result are dropped
|
||||
- **SQLite resilience**: Init error recovery with automatic retry for OSS mode
|
||||
- **`disableHistory` config option**: New `oss.disableHistory` flag
|
||||
- 78 unit tests covering filtering, isolation, trigger filtering, subagent detection, and SQLite resilience
|
||||
|
||||
**Changes:**
|
||||
- Auto-recall threshold raised from 0.5 to 0.6 for stricter precision
|
||||
- Recall candidate pool increased to `topK * 2` for better filtering headroom
|
||||
- Relaxed extraction instructions: related facts kept together to preserve context
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Concurrent session race condition**: Lifecycle hooks now use `ctx.sessionKey` directly instead of a shared mutable variable
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-03-12" description="v0.3.1">
|
||||
|
||||
**New Features:**
|
||||
- **Message filtering pipeline**: Multi-stage noise removal before extraction
|
||||
- **Broad recall for new sessions**: Short or new-session prompts trigger secondary broad search
|
||||
- **Client-side threshold filtering**: Safety net that drops low-relevance results
|
||||
- **Temporal anchoring**: Extraction instructions now include current date
|
||||
- 55 unit tests covering filtering and isolation helpers
|
||||
|
||||
**Changes:**
|
||||
- Extraction window expanded from last 10 to last 20 messages
|
||||
- Rewritten custom extraction instructions for conciseness and deduplication
|
||||
- Refactored monolithic `index.ts` (1772 lines) into 6 focused modules
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-03-10" description="v0.3.0">
|
||||
|
||||
**Bug Fixes:**
|
||||
- Updated `mem0ai` dependency with sqlite3 to better-sqlite3 migration (#4270)
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-03-09" description="v0.2.0">
|
||||
|
||||
**New Features:**
|
||||
- Per-agent memory isolation for multi-agent setups via `agentId`
|
||||
- "Understanding userId" section in docs
|
||||
|
||||
**Changes:**
|
||||
- Updated config examples to use concrete `userId` values instead of placeholders
|
||||
|
||||
**Bug Fixes:**
|
||||
- Migrated platform search to Mem0 v2 API
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-02-19" description="v0.1.2">
|
||||
|
||||
**New Features:**
|
||||
- Source field for openclaw memory entries
|
||||
|
||||
**Bug Fixes:**
|
||||
- Auto-recall injection and auto-capture message drop
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-02-02" description="v0.1.0">
|
||||
|
||||
**New Features:**
|
||||
- Initial release of the OpenClaw Mem0 plugin
|
||||
- Platform mode (Mem0 Cloud) and open-source mode support
|
||||
- Auto-recall: inject relevant memories before each turn
|
||||
- Auto-capture: store facts after each turn
|
||||
- Configurable `topK`, `threshold`, and `apiVersion` options
|
||||
|
||||
</Update>
|
||||
@@ -0,0 +1,290 @@
|
||||
---
|
||||
title: "Platform"
|
||||
description: "Release notes for the Mem0 hosted platform — backend, dashboard, billing, and infrastructure changes."
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
<Update label="2025-07-23" description="">
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Memory:** Fixed ADD functionality
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-19" description="">
|
||||
|
||||
**New Features:**
|
||||
- **UI:** Added Settings UI and latency display
|
||||
- **Performance:** Neo4j query optimization
|
||||
|
||||
**Bug Fixes:**
|
||||
- **OpenMemory:** Fixed OMM raising unnecessary exceptions
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-18" description="">
|
||||
|
||||
**Improvements:**
|
||||
- **UI:** Updated Event UI
|
||||
- **Performance:** Fixed N+1 query issue in semantic_search_v2 by optimizing MemorySerializer field selection
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Memory:** Fixed duplicate memory index sentry error
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-17" description="">
|
||||
|
||||
**New Features:**
|
||||
- **UI:** New Settings Page
|
||||
- **Memory:** Duplicate memories entities support
|
||||
|
||||
**Improvements:**
|
||||
- **Performance:** Optimized semantic search and get_all APIs by eliminating N+1 queries
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-16" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Database:** Implemented read replica routing with enhanced logging and app-specific DB routing
|
||||
|
||||
**Improvements:**
|
||||
- **Performance:** Improved query performance in search v2 and get all v2 endpoints
|
||||
|
||||
**Bug Fixes:**
|
||||
- **API:** Fixed pagination for get all API
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-12" description="">
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Graph:** Fixed social graph bugs and connection issues
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-11" description="">
|
||||
|
||||
**Improvements:**
|
||||
- **Rate Limiting:** New rate limit for V2 Search
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Slack:** Fixed Slack rate limit error with backend improvements
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-10" description="">
|
||||
|
||||
**Improvements:**
|
||||
- **Performance:**
|
||||
- Changed connection pooling time to 5 minutes
|
||||
- Separated graph lambdas for better performance
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-09" description="">
|
||||
|
||||
**Improvements:**
|
||||
- **Graph:** Graph Optimizations V2 and memory improvements
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-08" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Database:** Added read replica support for improved database performance
|
||||
- **UI:** Implemented UI changes for Users Page
|
||||
- **Feedback:** Enabled feedback functionality
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Serializer:** Fixed GET ALL Serializer
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-05" description="">
|
||||
|
||||
**New Features:**
|
||||
- **UI:** User Page Revamp and New Users Page
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-04" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Users:** New Users Page implementation
|
||||
- **Tools:** Added script to backfill memory categories
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Filters:** Fixed Filters Get All functionality
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-03" description="">
|
||||
|
||||
**Improvements:**
|
||||
- **Graph:** Graph Memory optimization
|
||||
- **Memory:** Fixed exact memories and semantically similar memories retrieval
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-02" description="">
|
||||
|
||||
**Improvements:**
|
||||
- **Categorization:** Refactored categorization logic to utilize Gemini 2.5 Flash and improve message handling
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-01" description="">
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Memory:** Fixed old_memory issue in Async memory addition lambda
|
||||
- **Events:** Fixed missing events
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-30" description="">
|
||||
|
||||
**Improvements:**
|
||||
- **Graph:** Improvements to graph memory and added user to LTM-STM
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-28" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Graph:** Added support for SQS in graph memory addition
|
||||
- **Testing:** Added Locust load testing script and Grafana Dashboard
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-27" description="">
|
||||
|
||||
**Improvements:**
|
||||
- **Rate Limiting:** Updated rate limiting for ADD API to 1000/min
|
||||
- **Performance:** Improved Neo4j performance
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-26" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Memory:** Edit Memory From Drawer functionality
|
||||
- **API:** Added Topic Suggestions API Endpoint
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-25" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Group Chat:** Group-Chat v2 with Actor-Aware Memories
|
||||
- **Memory:** Editable Metadata in Memories
|
||||
- **UI:** Memory Actions Badges
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-19" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Rate Limiting:** Implemented comprehensive rate limiting system
|
||||
|
||||
**Improvements:**
|
||||
- **Performance:** Added performance indexes for memory stats query
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Search:** Fixed search events not respecting top-k parameter
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-18" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Memory Management:** Implemented OpenAI Batch API for Memory Cleaning with fallback
|
||||
- **Playground:** Added Claude 4 support on Playground
|
||||
|
||||
**Improvements:**
|
||||
- **Memory:** Added ability to update memory metadata
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-17" description="">
|
||||
|
||||
**New Features:**
|
||||
- **UI:** New Memories Page UI design
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-16" description="">
|
||||
|
||||
**Improvements:**
|
||||
- **Infrastructure:** Migrated to Application Load Balancer (ALB)
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-13" description="">
|
||||
|
||||
**Improvements:**
|
||||
- **Memory Management:** Enhanced Memory Management with Cosine Similarity Fallback
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-11" description="">
|
||||
|
||||
**New Features:**
|
||||
- **OMM:** Added OMM Script and UI functionality
|
||||
|
||||
**Improvements:**
|
||||
- **API:** Added filters validation to semantic_search_v2 endpoint
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-09" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Intercom:** Set Intercom events for ADD and SEARCH operations
|
||||
- **OpenMemory:** Added Posthog integration and feedback functionality
|
||||
- **MCP:** New JavaScript MCP Server with feedback support
|
||||
|
||||
**Improvements:**
|
||||
- **Structured Data:** Enhanced structured data handling in memory management
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-06" description="">
|
||||
|
||||
**New Features:**
|
||||
- **OAuth:** Added Mem0 OAuth integration
|
||||
- **OMM:** Added OMM-Mem0 sync for deleted memories
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-05" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Filters:** Implemented Wildcard Filters and refactored filter logic in V2 Views
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-02" description="">
|
||||
|
||||
**New Features:**
|
||||
- **OpenMemory Cloud:** Added OpenMemory Cloud support
|
||||
- **Structured Data:** Added 'structured_attributes' field to Memory model
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-05-30" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Projects:** Added version and enable_graph to project views
|
||||
- **OpenMemory:** Added Postgres support for OpenMemory
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-05-19" description="">
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Core:** Fixed unicode error in user_id, agent_id, run_id and app_id
|
||||
|
||||
</Update>
|
||||
|
||||
@@ -1,13 +1,25 @@
|
||||
---
|
||||
title: "Product Updates"
|
||||
description: "Latest releases, bug fixes, and improvements for the Mem0 Python and TypeScript SDKs."
|
||||
title: "SDK & Tools"
|
||||
description: "Release notes for the Mem0 Python SDK, TypeScript SDK, Vercel AI SDK, CLI, and editor plugins."
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Python">
|
||||
|
||||
<Update label="2026-04-04" description="v1.0.11">
|
||||
|
||||
**New Features & Updates:**
|
||||
- **SDK:** Added `multilingual` parameter to project update ([#4314](https://github.com/mem0ai/mem0/pull/4314))
|
||||
|
||||
**Bug Fixes:**
|
||||
- **LLMs:** Fixed Groq model configuration ([#4700](https://github.com/mem0ai/mem0/pull/4700))
|
||||
- **Core:** Prevented thread and memory leaks from PostHog telemetry ([#4535](https://github.com/mem0ai/mem0/pull/4535))
|
||||
- **Vector Stores:** Used `DatetimeRange` for datetime string values in Qdrant range filters ([#4659](https://github.com/mem0ai/mem0/pull/4659))
|
||||
- **Configs:** Added missing `ConfigDict` to vector store configs (Elasticsearch, MongoDB, Neptune, OpenSearch, PGVector, Supabase, Valkey) ([#4656](https://github.com/mem0ai/mem0/pull/4656))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-04-01" description="v1.0.10">
|
||||
|
||||
**New Features & Updates:**
|
||||
@@ -831,6 +843,12 @@ mode: "wide"
|
||||
</Tab>
|
||||
|
||||
<Tab title="TypeScript">
|
||||
<Update label="2026-04-04" description="v2.4.6">
|
||||
|
||||
**New Features & Updates:**
|
||||
- **Client:** Added `multilingual` parameter to project update types ([#4314](https://github.com/mem0ai/mem0/pull/4314))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-04-01" description="v2.4.5">
|
||||
|
||||
@@ -1140,352 +1158,141 @@ mode: "wide"
|
||||
|
||||
</Tab>
|
||||
|
||||
<Tab title="Platform">
|
||||
<Tab title="CLI">
|
||||
|
||||
<Update label="2025-07-23" description="">
|
||||
<Update label="2026-04-06" description="Python v0.2.2 / Node v0.2.2">
|
||||
|
||||
**New Features:**
|
||||
- **Telemetry:** Added PostHog telemetry and source tracking to both Python and Node CLIs ([#4699](https://github.com/mem0ai/mem0/pull/4699))
|
||||
- **Validation:** API key validated upfront via `/v1/ping/` on startup — fail-fast with a helpful error instead of cryptic 401s ([#4701](https://github.com/mem0ai/mem0/pull/4701))
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Memory:** Fixed ADD functionality
|
||||
- **CD:** Fixed OIDC trusted publishing with `npx npm@latest` ([#4724](https://github.com/mem0ai/mem0/pull/4724))
|
||||
- **CD:** Removed npm self-upgrade from CD workflows ([#4723](https://github.com/mem0ai/mem0/pull/4723))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-19" description="">
|
||||
<Update label="2026-04-03" description="Python v0.2.1 / Node v0.2.1">
|
||||
|
||||
**New Features:**
|
||||
- **UI:** Added Settings UI and latency display
|
||||
- **Performance:** Neo4j query optimization
|
||||
- **Docs:** Comprehensive README with installation, usage examples, and purple branding ([#4680](https://github.com/mem0ai/mem0/pull/4680))
|
||||
|
||||
**Bug Fixes:**
|
||||
- **OpenMemory:** Fixed OMM raising unnecessary exceptions
|
||||
- **npm:** Added `repository` field to Node packages for npm provenance ([#4671](https://github.com/mem0ai/mem0/pull/4671))
|
||||
- **CD:** Added CD workflows for Node SDK packages with OIDC trusted publishing ([#4670](https://github.com/mem0ai/mem0/pull/4670))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-18" description="">
|
||||
<Update label="2026-04-02" description="Python v0.2.0 / Node v0.1.1">
|
||||
|
||||
**Improvements:**
|
||||
- **UI:** Updated Event UI
|
||||
- **Performance:** Fixed N+1 query issue in semantic_search_v2 by optimizing MemorySerializer field selection
|
||||
**New Features:**
|
||||
- **`event` commands:** `mem0 event list` shows recent background processing events in a table; `mem0 event status <id>` shows full detail including nested memory results ([#4649](https://github.com/mem0ai/mem0/pull/4649))
|
||||
- **`--json` / `--agent` flag:** Root-level flag switches all command output to a structured JSON envelope for programmatic/agent consumption. Envelope format: `{"status", "command", "duration_ms", "scope", "count", "data"}` ([#4649](https://github.com/mem0ai/mem0/pull/4649))
|
||||
- **Agent output sanitization:** Raw API responses projected to only relevant fields per command (e.g., `add` → `{id, memory, event}`, `search` → `{id, memory, score, created_at, categories}`) ([#4649](https://github.com/mem0ai/mem0/pull/4649))
|
||||
- **Email login:** Added email verification code login to `mem0 init` ([#4623](https://github.com/mem0ai/mem0/pull/4623))
|
||||
- **Brand update:** Updated color palette from purple to golden ([#4664](https://github.com/mem0ai/mem0/pull/4664))
|
||||
- **CI/CD:** Added CI pipelines and CD workflows for both CLIs ([#4640](https://github.com/mem0ai/mem0/pull/4640), [#4653](https://github.com/mem0ai/mem0/pull/4653))
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Memory:** Fixed duplicate memory index sentry error
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-17" description="">
|
||||
|
||||
**New Features:**
|
||||
- **UI:** New Settings Page
|
||||
- **Memory:** Duplicate memories entities support
|
||||
- **Node:** Fixed critical `MODULE_NOT_FOUND` crash on `status`, `import`, and all commands when installed globally — replaced runtime `createRequire` with build-time version injection ([#4636](https://github.com/mem0ai/mem0/pull/4636))
|
||||
- **Node:** API errors now show full response detail instead of bare "Bad Request" ([#4636](https://github.com/mem0ai/mem0/pull/4636))
|
||||
- **Python:** Fixed double error printing on all commands ([#4636](https://github.com/mem0ai/mem0/pull/4636))
|
||||
- **`status` command:** Replaced heavyweight `/v1/entities/` check with dedicated `GET /v1/ping/` endpoint ([#4649](https://github.com/mem0ai/mem0/pull/4649))
|
||||
- **`add` command:** Deduplicated PENDING results from API; changed misleading count message ([#4649](https://github.com/mem0ai/mem0/pull/4649))
|
||||
- **`init` command:** Partial flags now work in non-TTY; warns before overwriting existing config; added `--force` flag ([#4649](https://github.com/mem0ai/mem0/pull/4649))
|
||||
- **`delete` command:** Fixed entity delete via v2 API for all entity types ([#4649](https://github.com/mem0ai/mem0/pull/4649))
|
||||
|
||||
**Improvements:**
|
||||
- **Performance:** Optimized semantic search and get_all APIs by eliminating N+1 queries
|
||||
- Tables now show full UUIDs (was truncated to 8 chars, making `mem0 get <id>` fail) ([#4636](https://github.com/mem0ai/mem0/pull/4636))
|
||||
- Search table includes Score column ([#4636](https://github.com/mem0ai/mem0/pull/4636))
|
||||
- `config get api_key` short-form aliases added ([#4636](https://github.com/mem0ai/mem0/pull/4636))
|
||||
- Client-side validation for `--expires`, `--page-size`, `--page`, `--top-k`, `--threshold`, and empty content ([#4636](https://github.com/mem0ai/mem0/pull/4636))
|
||||
- `printInfo` / `printScope` moved to stderr to avoid contaminating JSON piping ([#4636](https://github.com/mem0ai/mem0/pull/4636))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-16" description="">
|
||||
<Update label="2026-03-26" description="Python v0.1.0 / Node v0.1.0">
|
||||
|
||||
**New Features:**
|
||||
- **Database:** Implemented read replica routing with enhanced logging and app-specific DB routing
|
||||
**Initial Release — Official Mem0 CLI**
|
||||
|
||||
**Improvements:**
|
||||
- **Performance:** Improved query performance in search v2 and get all v2 endpoints
|
||||
A full-featured command-line interface for Mem0, available in both Python and Node.js:
|
||||
|
||||
**Bug Fixes:**
|
||||
- **API:** Fixed pagination for get all API
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-12" description="">
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Graph:** Fixed social graph bugs and connection issues
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-11" description="">
|
||||
|
||||
**Improvements:**
|
||||
- **Rate Limiting:** New rate limit for V2 Search
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Slack:** Fixed Slack rate limit error with backend improvements
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-10" description="">
|
||||
|
||||
**Improvements:**
|
||||
- **Performance:**
|
||||
- Changed connection pooling time to 5 minutes
|
||||
- Separated graph lambdas for better performance
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-09" description="">
|
||||
|
||||
**Improvements:**
|
||||
- **Graph:** Graph Optimizations V2 and memory improvements
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-08" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Database:** Added read replica support for improved database performance
|
||||
- **UI:** Implemented UI changes for Users Page
|
||||
- **Feedback:** Enabled feedback functionality
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Serializer:** Fixed GET ALL Serializer
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-05" description="">
|
||||
|
||||
**New Features:**
|
||||
- **UI:** User Page Revamp and New Users Page
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-04" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Users:** New Users Page implementation
|
||||
- **Tools:** Added script to backfill memory categories
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Filters:** Fixed Filters Get All functionality
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-03" description="">
|
||||
|
||||
**Improvements:**
|
||||
- **Graph:** Graph Memory optimization
|
||||
- **Memory:** Fixed exact memories and semantically similar memories retrieval
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-02" description="">
|
||||
|
||||
**Improvements:**
|
||||
- **Categorization:** Refactored categorization logic to utilize Gemini 2.5 Flash and improve message handling
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-01" description="">
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Memory:** Fixed old_memory issue in Async memory addition lambda
|
||||
- **Events:** Fixed missing events
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-30" description="">
|
||||
|
||||
**Improvements:**
|
||||
- **Graph:** Improvements to graph memory and added user to LTM-STM
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-28" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Graph:** Added support for SQS in graph memory addition
|
||||
- **Testing:** Added Locust load testing script and Grafana Dashboard
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-27" description="">
|
||||
|
||||
**Improvements:**
|
||||
- **Rate Limiting:** Updated rate limiting for ADD API to 1000/min
|
||||
- **Performance:** Improved Neo4j performance
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-26" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Memory:** Edit Memory From Drawer functionality
|
||||
- **API:** Added Topic Suggestions API Endpoint
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-25" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Group Chat:** Group-Chat v2 with Actor-Aware Memories
|
||||
- **Memory:** Editable Metadata in Memories
|
||||
- **UI:** Memory Actions Badges
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-19" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Rate Limiting:** Implemented comprehensive rate limiting system
|
||||
|
||||
**Improvements:**
|
||||
- **Performance:** Added performance indexes for memory stats query
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Search:** Fixed search events not respecting top-k parameter
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-18" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Memory Management:** Implemented OpenAI Batch API for Memory Cleaning with fallback
|
||||
- **Playground:** Added Claude 4 support on Playground
|
||||
|
||||
**Improvements:**
|
||||
- **Memory:** Added ability to update memory metadata
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-17" description="">
|
||||
|
||||
**New Features:**
|
||||
- **UI:** New Memories Page UI design
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-16" description="">
|
||||
|
||||
**Improvements:**
|
||||
- **Infrastructure:** Migrated to Application Load Balancer (ALB)
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-13" description="">
|
||||
|
||||
**Improvements:**
|
||||
- **Memory Management:** Enhanced Memory Management with Cosine Similarity Fallback
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-11" description="">
|
||||
|
||||
**New Features:**
|
||||
- **OMM:** Added OMM Script and UI functionality
|
||||
|
||||
**Improvements:**
|
||||
- **API:** Added filters validation to semantic_search_v2 endpoint
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-09" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Intercom:** Set Intercom events for ADD and SEARCH operations
|
||||
- **OpenMemory:** Added Posthog integration and feedback functionality
|
||||
- **MCP:** New JavaScript MCP Server with feedback support
|
||||
|
||||
**Improvements:**
|
||||
- **Structured Data:** Enhanced structured data handling in memory management
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-06" description="">
|
||||
|
||||
**New Features:**
|
||||
- **OAuth:** Added Mem0 OAuth integration
|
||||
- **OMM:** Added OMM-Mem0 sync for deleted memories
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-05" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Filters:** Implemented Wildcard Filters and refactored filter logic in V2 Views
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-02" description="">
|
||||
|
||||
**New Features:**
|
||||
- **OpenMemory Cloud:** Added OpenMemory Cloud support
|
||||
- **Structured Data:** Added 'structured_attributes' field to Memory model
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-05-30" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Projects:** Added version and enable_graph to project views
|
||||
- **OpenMemory:** Added Postgres support for OpenMemory
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-05-19" description="">
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Core:** Fixed unicode error in user_id, agent_id, run_id and app_id
|
||||
- **Install:** `pip install mem0-cli` (Python) or `npm install -g @mem0/cli` (Node.js)
|
||||
- **Full command suite:** `add`, `search`, `list`, `get`, `update`, `delete`, `import`, `config`, `init`, `status`, `entity`
|
||||
- **Interactive setup:** `mem0 init` with API key entry and user ID configuration
|
||||
- **Works everywhere:** Platform (Mem0 Cloud) and self-hosted OSS modes
|
||||
- **Scriptable:** `-o json` flag for CI/CD pipelines and automation
|
||||
- **Dual SDK:** Same commands, same experience across Python and Node.js
|
||||
- **Shared spec:** Both implementations driven by a single `cli-spec.json` ensuring identical behavior ([#4575](https://github.com/mem0ai/mem0/pull/4575))
|
||||
|
||||
</Update>
|
||||
|
||||
</Tab>
|
||||
|
||||
<Tab title="Vercel AI SDK">
|
||||
<Tab title="Plugins">
|
||||
|
||||
<Update label="2025-12-26" description="v2.0.5">
|
||||
<Update label="2026-04-02" description="mem0-plugin v1.0.0">
|
||||
|
||||
**Mem0 Plugin for Claude Code, Cursor, and Codex**
|
||||
|
||||
The unified Mem0 plugin for AI development environments:
|
||||
|
||||
- **9 MCP memory tools:** `add_memory`, `search_memories`, `get_memories`, `get_memory`, `update_memory`, `delete_memory`, `delete_all_memories`, `delete_entities`, `list_entities` — all via `mcp.mem0.ai`
|
||||
- **Lifecycle hooks:** Automatic memory capture at session start, context compaction, task completion, and session end
|
||||
- **Cloud MCP server:** Managed endpoint replaces local MCP and Smithery setup
|
||||
- **Streamable HTTP transport:** New MCP transport protocol for real-time streaming
|
||||
- **Codex-specific skill:** Dedicated skill in `mem0-plugin/skills/mem0-codex` for Codex workflows
|
||||
- **Supported editors:** Claude Code, Claude Cowork, Cursor, Codex
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-12-26" description="Vercel AI SDK v2.0.5">
|
||||
**Bug Fix:**
|
||||
- **Vercel AI SDK:** Removed unnecessary dependencies to make the package lighter.
|
||||
- Removed unnecessary dependencies to make the package lighter.
|
||||
</Update>
|
||||
|
||||
<Update label="2025-09-25" description="v2.0.4">
|
||||
<Update label="2025-09-25" description="Vercel AI SDK v2.0.3 – v2.0.4">
|
||||
**New Features:**
|
||||
- Added file support for multimodal capabilities with memory context (v2.0.3)
|
||||
|
||||
**Bug Fix:**
|
||||
- **Vercel AI SDK:** Fixed version parameter in the AI SDK to use V2 for addition.
|
||||
- Fixed version parameter to use V2 for addition (v2.0.4)
|
||||
</Update>
|
||||
|
||||
<Update label="2025-09-25" description="v2.0.3">
|
||||
**New Features:**
|
||||
- **Vercel AI SDK:** Added file support for multimodal capabilities with memory context
|
||||
</Update>
|
||||
|
||||
<Update label="2025-09-03" description="v2.0.2">
|
||||
<Update label="2025-09-03" description="Vercel AI SDK v2.0.2">
|
||||
**Bug Fix:**
|
||||
- **Vercel AI SDK:** Fixed streaming response in the AI SDK.
|
||||
- Fixed streaming response in the AI SDK.
|
||||
</Update>
|
||||
|
||||
<Update label="2025-08-05" description="v2.0.1">
|
||||
<Update label="2025-08-05" description="Vercel AI SDK v2.0.0 – v2.0.1">
|
||||
**New Features:**
|
||||
- **Vercel AI SDK:** Added a new param `host` to the config.
|
||||
- Migration to AI SDK V5 (v2.0.0)
|
||||
- Added `host` param to the config (v2.0.1)
|
||||
</Update>
|
||||
|
||||
<Update label="2025-08-05" description="v2.0.0">
|
||||
<Update label="2025-06-15" description="Vercel AI SDK v1.0.6">
|
||||
**New Features:**
|
||||
- **Vercel AI SDK:** Migration to AI SDK V5.
|
||||
- Added `filter_memories` param.
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-15" description="v1.0.6">
|
||||
<Update label="2025-05-23" description="Vercel AI SDK v1.0.5">
|
||||
**New Features:**
|
||||
- **Vercel AI SDK:** Added param `filter_memories`.
|
||||
- Added support for Google provider.
|
||||
</Update>
|
||||
|
||||
<Update label="2025-05-23" description="v1.0.5">
|
||||
<Update label="2025-05-10" description="Vercel AI SDK v1.0.3 – v1.0.4">
|
||||
**New Features:**
|
||||
- **Vercel AI SDK:** Added support for Google provider.
|
||||
</Update>
|
||||
- Added support for `output_format` param (v1.0.4)
|
||||
|
||||
<Update label="2025-05-10" description="v1.0.4">
|
||||
**New Features:**
|
||||
- **Vercel AI SDK:** Added support for new param `output_format`.
|
||||
</Update>
|
||||
|
||||
<Update label="2025-05-08" description="v1.0.3">
|
||||
**Improvements:**
|
||||
- **Vercel AI SDK:** Added support for graceful failure in cases services are down.
|
||||
- Added graceful failure handling when services are down (v1.0.3)
|
||||
</Update>
|
||||
|
||||
<Update label="2025-05-01" description="v1.0.1">
|
||||
<Update label="2025-05-01" description="Vercel AI SDK v1.0.1">
|
||||
**New Features:**
|
||||
- **Vercel AI SDK:** Added support for graph memories
|
||||
- Added support for graph memories.
|
||||
</Update>
|
||||
|
||||
</Tab>
|
||||
|
||||
</Tabs>
|
||||
|
||||
@@ -24,6 +24,7 @@ config = {
|
||||
"provider": "gemini",
|
||||
"config": {
|
||||
"model": "gemini-2.0-flash-001",
|
||||
"api_key": "your-gemini-api-key",
|
||||
"temperature": 0.2,
|
||||
"max_tokens": 2000,
|
||||
"top_p": 1.0
|
||||
@@ -52,6 +53,7 @@ const config = {
|
||||
provider: "gemini",
|
||||
config: {
|
||||
model: "gemini-2.0-flash-001",
|
||||
apiKey: process.env.GOOGLE_API_KEY || '',
|
||||
temperature: 0.1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ Before you begin, follow these steps to set up the demo application:
|
||||
OPENAI_API_KEY=your_openai_api_key
|
||||
MEM0_API_KEY=your_mem0_api_key
|
||||
```
|
||||
You can obtain your `MEM0_API_KEY` by signing up at [Mem0 API Dashboard](https://app.mem0.ai/dashboard/api-keys).
|
||||
You can obtain your `MEM0_API_KEY` by signing up at <a href="https://app.mem0.ai/dashboard/api-keys" rel="nofollow">Mem0 API Dashboard</a>.
|
||||
|
||||
5. Start the development server:
|
||||
```bash
|
||||
|
||||
@@ -38,7 +38,7 @@ client = MemoryClient(api_key="your-api-key")
|
||||
```
|
||||
|
||||
<Note>
|
||||
Replace `your-api-key` with your actual Mem0 API key from the [dashboard](https://app.mem0.ai). Without proper API authentication, memory operations will fail.
|
||||
Replace `your-api-key` with your actual Mem0 API key from the <a href="https://app.mem0.ai" rel="nofollow">dashboard</a>. Without proper API authentication, memory operations will fail.
|
||||
</Note>
|
||||
|
||||
---
|
||||
|
||||
@@ -17,7 +17,7 @@ from mem0 import MemoryClient
|
||||
client = MemoryClient(api_key="m0-...")
|
||||
```
|
||||
|
||||
Grab an API key from the <Link href="https://app.mem0.ai/">Mem0 dashboard</Link> to get started.
|
||||
Grab an API key from the <a href="https://app.mem0.ai/" rel="nofollow">Mem0 dashboard</a> to get started.
|
||||
|
||||
## Store and Retrieve Scoped Memories
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ client = MemoryClient(api_key="your-api-key")
|
||||
```
|
||||
|
||||
<Note>
|
||||
Your API key needs export permissions to download memory data. Check your project settings on the [dashboard](https://app.mem0.ai) if export operations fail with authentication errors.
|
||||
Your API key needs export permissions to download memory data. Check your project settings on the <a href="https://app.mem0.ai" rel="nofollow">dashboard</a> if export operations fail with authentication errors.
|
||||
</Note>
|
||||
|
||||
Let's add some sample memories to work with:
|
||||
|
||||
@@ -55,7 +55,7 @@ GEMINI_API_KEY=your-gemini-api-key-here
|
||||
```
|
||||
|
||||
<Note>
|
||||
Ensure you have your Mem0 API key from the [Mem0 Dashboard](https://app.mem0.ai) and your Gemini API key from the [Google AI Studio](https://ai.studio/app/api-keys).
|
||||
Ensure you have your Mem0 API key from the <a href="https://app.mem0.ai" rel="nofollow">Mem0 Dashboard</a> and your Gemini API key from the [Google AI Studio](https://ai.studio/app/api-keys).
|
||||
</Note>
|
||||
|
||||
## Gemini Memory Agent
|
||||
|
||||
@@ -41,7 +41,7 @@ Set up your environment variables:
|
||||
- `MEM0_API_KEY`: Your Mem0 Platform API key
|
||||
- `OPENAI_API_KEY`: Your OpenAI API key
|
||||
|
||||
You can obtain your Mem0 Platform API key from the [Mem0 Platform](https://app.mem0.ai).
|
||||
You can obtain your Mem0 Platform API key from the <a href="https://app.mem0.ai" rel="nofollow">Mem0 Platform</a>.
|
||||
|
||||
## Complete Implementation
|
||||
|
||||
@@ -357,7 +357,7 @@ Based on our previous session, I remember we covered Vision Language Models and
|
||||
## Help & Resources
|
||||
|
||||
- [LlamaIndex Agent Workflows](https://docs.llamaindex.ai/en/stable/use_cases/agents/)
|
||||
- [Mem0 Platform](https://app.mem0.ai/)
|
||||
- <a href="https://app.mem0.ai/" rel="nofollow">Mem0 Platform</a>
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ os.environ["OPENAI_API_KEY"] = "<your-openai-api-key>"
|
||||
llm = OpenAI(model="gpt-4.1-nano-2025-04-14")
|
||||
```
|
||||
|
||||
Initialize the Mem0 client. You can find your API key [here](https://app.mem0.ai/dashboard/api-keys). Read about Mem0 [Open Source](https://docs.mem0.ai/open-source/overview).
|
||||
Initialize the Mem0 client. You can find your API key <a href="https://app.mem0.ai/dashboard/api-keys" rel="nofollow">here</a>. Read about Mem0 [Open Source](https://docs.mem0.ai/open-source/overview).
|
||||
```python
|
||||
os.environ["MEM0_API_KEY"] = "<your-mem0-api-key>"
|
||||
|
||||
|
||||
@@ -754,7 +754,7 @@ Exact output varies as Mem0 automatically extracts and deduplicates entities. Th
|
||||
- [MiroFish GitHub](https://github.com/666ghj/MiroFish) — Source code and setup guide
|
||||
- [MiroFish Documentation](https://deepwiki.com/666ghj/MiroFish) — Full framework docs
|
||||
- [Mem0 Graph Memory](/open-source/features/graph-memory) — Graph Memory documentation
|
||||
- [Mem0 Documentation](https://docs.mem0.ai/) — Full API reference
|
||||
- [Mem0 Documentation](https://docs.mem0.ai/introduction) — Full API reference
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Graph Memory" icon="network-wired" href="/open-source/features/graph-memory">
|
||||
|
||||
@@ -222,8 +222,8 @@ context = Mem0Context(user_id="user123")
|
||||
|
||||
## Resources
|
||||
|
||||
- [Mem0 Documentation](https://docs.mem0.ai)
|
||||
- [Mem0 Dashboard](https://app.mem0.ai/dashboard)
|
||||
- [Mem0 Documentation](https://docs.mem0.ai/introduction)
|
||||
- <a href="https://app.mem0.ai/dashboard" rel="nofollow">Mem0 Dashboard</a>
|
||||
- [API Reference](https://docs.mem0.ai/api-reference)
|
||||
|
||||
---
|
||||
|
||||
@@ -23,7 +23,7 @@ MEM0_API_KEY=your_mem0_api_key
|
||||
OPENAI_API_KEY=your_openai_api_key
|
||||
```
|
||||
|
||||
Get your Mem0 API key from the [Mem0 Dashboard](https://app.mem0.ai/dashboard/api-keys).
|
||||
Get your Mem0 API key from the <a href="https://app.mem0.ai/dashboard/api-keys" rel="nofollow">Mem0 Dashboard</a>.
|
||||
|
||||
### Configuration
|
||||
|
||||
@@ -308,8 +308,8 @@ run().catch(console.error);
|
||||
|
||||
## Resources
|
||||
|
||||
- [Mem0 Documentation](https://docs.mem0.ai)
|
||||
- [Mem0 Dashboard](https://app.mem0.ai/dashboard)
|
||||
- [Mem0 Documentation](https://docs.mem0.ai/introduction)
|
||||
- <a href="https://app.mem0.ai/dashboard" rel="nofollow">Mem0 Dashboard</a>
|
||||
- [API Reference](https://docs.mem0.ai/api-reference)
|
||||
- [OpenAI Documentation](https://platform.openai.com/docs)
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ Adding memory is how Mem0 captures useful details from a conversation so your ag
|
||||
- **Messages** – The ordered list of user/assistant turns you send to `add`.
|
||||
- **Infer** – Controls whether Mem0 extracts structured memories (`infer=True`, default) or stores raw messages.
|
||||
- **Metadata** – Optional filters (e.g., `{"category": "movie_recommendations"}`) that improve retrieval later.
|
||||
- **User / Session identifiers** – `user_id`, `session_id`, or `run_id` that scope the memory for future searches.
|
||||
- **User / Session identifiers** – `user_id`, `agent_id`, or `run_id` that scope the memory for future searches.
|
||||
|
||||
## How does it work?
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ Mem0 maps these classic categories onto its layered storage so you can decide wh
|
||||
Mem0 stores each layer separately and merges them when you query:
|
||||
|
||||
1. **Capture** – Messages enter the conversation layer while the turn is active.
|
||||
2. **Promote** – Relevant details persist to session or user memory based on your `user_id`, `session_id`, and metadata.
|
||||
2. **Promote** – Relevant details persist to session or user memory based on your `user_id`, `run_id`, and metadata.
|
||||
3. **Retrieve** – The search pipeline pulls from all layers, ranking user memories first, then session notes, then raw history.
|
||||
|
||||
```python
|
||||
@@ -66,19 +66,19 @@ memory = Memory(api_key=os.environ["MEM0_API_KEY"])
|
||||
memory.add(
|
||||
["I'm Alex and I prefer boutique hotels."],
|
||||
user_id="alex",
|
||||
session_id="trip-planning-2025",
|
||||
run_id="trip-planning-2025",
|
||||
)
|
||||
|
||||
# Later in the session, pull long-term + session context
|
||||
results = memory.search(
|
||||
"Any hotel preferences?",
|
||||
user_id="alex",
|
||||
session_id="trip-planning-2025",
|
||||
run_id="trip-planning-2025",
|
||||
)
|
||||
```
|
||||
|
||||
<Tip>
|
||||
Use `session_id` when you want short-term context to expire automatically; rely on `user_id` for lasting personalization.
|
||||
Use `run_id` when you want short-term context to expire automatically; rely on `user_id` for lasting personalization.
|
||||
</Tip>
|
||||
|
||||
## When should you use each layer?
|
||||
|
||||
+52
-15
@@ -12,7 +12,7 @@
|
||||
"logo": {
|
||||
"light": "/logo/light.svg",
|
||||
"dark": "/logo/dark.svg",
|
||||
"href": "https://app.mem0.ai/"
|
||||
"href": "https://mem0.ai"
|
||||
},
|
||||
"navigation": {
|
||||
"anchors": [
|
||||
@@ -133,6 +133,29 @@
|
||||
"pages": [
|
||||
"platform/contribute"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Release Notes",
|
||||
"icon": "rocket",
|
||||
"pages": [
|
||||
"changelog/highlights",
|
||||
"changelog/sdk",
|
||||
"changelog/platform",
|
||||
"changelog/openclaw"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tab": "OpenClaw",
|
||||
"groups": [
|
||||
{
|
||||
"group": "Agent Harness",
|
||||
"icon": "robot",
|
||||
"pages": [
|
||||
"integrations/openclaw",
|
||||
"integrations/hermes"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -393,11 +416,11 @@
|
||||
"integrations/autogen",
|
||||
"integrations/agno",
|
||||
"integrations/camel-ai",
|
||||
"integrations/openclaw",
|
||||
"integrations/openai-agents-sdk",
|
||||
"integrations/google-ai-adk",
|
||||
"integrations/mastra",
|
||||
"integrations/vercel-ai-sdk"
|
||||
"integrations/vercel-ai-sdk",
|
||||
"integrations/chatdev"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -430,6 +453,28 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tab": "Agent Plugins",
|
||||
"groups": [
|
||||
{
|
||||
"group": "Coding Agents",
|
||||
"icon": "terminal",
|
||||
"pages": [
|
||||
"integrations/claude-code",
|
||||
"integrations/cursor",
|
||||
"integrations/codex"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Agent Harness",
|
||||
"icon": "robot",
|
||||
"pages": [
|
||||
"integrations/openclaw",
|
||||
"integrations/hermes"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tab": "API Reference",
|
||||
"groups": [
|
||||
@@ -517,18 +562,6 @@
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tab": "Release Notes",
|
||||
"groups": [
|
||||
{
|
||||
"group": "Changelog",
|
||||
"icon": "rocket",
|
||||
"pages": [
|
||||
"changelog"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -579,6 +612,10 @@
|
||||
]
|
||||
},
|
||||
"redirects": [
|
||||
{
|
||||
"source": "/changelog",
|
||||
"destination": "/changelog/highlights"
|
||||
},
|
||||
{
|
||||
"source": "/api-reference/memory/v2-search-memories",
|
||||
"destination": "/api-reference/memory/search-memories"
|
||||
|
||||
@@ -381,4 +381,39 @@ Here are the available integrations for Mem0:
|
||||
>
|
||||
Build AI agents with persistent memory using Mastra's framework and tools.
|
||||
</Card>
|
||||
<Card
|
||||
title="OpenAI Agents SDK"
|
||||
icon="robot"
|
||||
href="/integrations/openai-agents-sdk"
|
||||
>
|
||||
Integrate Mem0 with the OpenAI Agents SDK for persistent memory across multi-agent workflows.
|
||||
</Card>
|
||||
<Card
|
||||
title="Google ADK"
|
||||
icon="google"
|
||||
href="/integrations/google-ai-adk"
|
||||
>
|
||||
Integrate Mem0 with Google Agent Development Kit for persistent memory across multi-agent workflows.
|
||||
</Card>
|
||||
<Card
|
||||
title="Flowise"
|
||||
icon="diagram-project"
|
||||
href="/integrations/flowise"
|
||||
>
|
||||
Add persistent Mem0 memory to Flowise chatflows for context-aware conversations in the low-code builder.
|
||||
</Card>
|
||||
<Card
|
||||
title="AWS Bedrock"
|
||||
icon="cloud"
|
||||
href="/integrations/aws-bedrock"
|
||||
>
|
||||
Use Mem0 with AWS Bedrock and OpenSearch Service for cloud-native persistent semantic memory storage.
|
||||
</Card>
|
||||
<Card
|
||||
title="ChatDev"
|
||||
icon="comments"
|
||||
href="/integrations/chatdev"
|
||||
>
|
||||
Add persistent cloud-managed memory to ChatDev multi-agent workflows with zero-code YAML configuration.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -24,7 +24,7 @@ pip install mem0ai agentops python-dotenv
|
||||
2. Valid API keys:
|
||||
- [AgentOps API Key](https://app.agentops.ai/dashboard/api-keys)
|
||||
- OpenAI API Key (for LLM operations)
|
||||
- [Mem0 API Key](https://app.mem0.ai/dashboard/api-keys) (optional, for cloud operations)
|
||||
- <a href="https://app.mem0.ai/dashboard/api-keys" rel="nofollow">Mem0 API Key</a> (optional, for cloud operations)
|
||||
|
||||
## Basic Integration Example
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ pip install agno mem0ai python-dotenv
|
||||
```
|
||||
|
||||
2. Valid API keys:
|
||||
- [Mem0 API Key](https://app.mem0.ai/dashboard/api-keys)
|
||||
- <a href="https://app.mem0.ai/dashboard/api-keys" rel="nofollow">Mem0 API Key</a>
|
||||
- OpenAI API Key (for the agent model)
|
||||
|
||||
## Quick Integration (Using `Mem0Tools`)
|
||||
|
||||
@@ -19,7 +19,7 @@ pip install autogen mem0ai openai python-dotenv
|
||||
|
||||
First, we'll import the necessary libraries and set up our configurations.
|
||||
|
||||
<Note>Remember to get the Mem0 API key from [Mem0 Platform](https://app.mem0.ai).</Note>
|
||||
<Note>Remember to get the Mem0 API key from <a href="https://app.mem0.ai" rel="nofollow">Mem0 Platform</a>.</Note>
|
||||
|
||||
```python
|
||||
import os
|
||||
|
||||
@@ -0,0 +1,243 @@
|
||||
---
|
||||
title: ChatDev
|
||||
description: "Add persistent, cloud-managed memory to ChatDev multi-agent workflows with Mem0 — no code required, just YAML configuration."
|
||||
---
|
||||
|
||||
Build multi-agent workflows in [ChatDev](https://github.com/OpenBMB/ChatDev) with persistent memory powered by Mem0. ChatDev is a zero-code multi-agent platform where agents, tools, and workflows are defined entirely in YAML. Mem0 integrates as a built-in memory store (`type: mem0`), giving your agents cloud-managed semantic search and cross-session persistence — all without writing any code.
|
||||
|
||||
## Overview
|
||||
|
||||
In this guide, you'll:
|
||||
1. Set up ChatDev with the Mem0 memory store
|
||||
2. Configure agents with persistent memory using YAML
|
||||
3. Enable automatic memory retrieval and storage across conversations
|
||||
4. Leverage cross-session persistence for personalized multi-agent interactions
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- **Python 3.12+**
|
||||
- **[uv](https://docs.astral.sh/uv/)** — Python package manager
|
||||
- **Node.js 18+** and **npm** — only needed if using the web console
|
||||
- A **Mem0 API key** from <a href="https://app.mem0.ai" rel="nofollow">app.mem0.ai</a>
|
||||
- An **OpenAI API key** (or another LLM provider supported by ChatDev)
|
||||
|
||||
## Setup and Configuration
|
||||
|
||||
Install ChatDev and its dependencies (includes `mem0ai`):
|
||||
|
||||
```bash
|
||||
git clone https://github.com/OpenBMB/ChatDev.git
|
||||
cd ChatDev
|
||||
uv sync
|
||||
```
|
||||
|
||||
If you plan to use the web console, also install the frontend:
|
||||
|
||||
```bash
|
||||
cd frontend && npm install && cd ..
|
||||
```
|
||||
|
||||
Set up your environment variables in a `.env` file:
|
||||
|
||||
<Note>Get your Mem0 API key from <a href="https://app.mem0.ai" rel="nofollow">Mem0 Platform</a>.</Note>
|
||||
|
||||
```bash
|
||||
MEM0_API_KEY=your-mem0-api-key
|
||||
API_KEY=your-openai-api-key
|
||||
BASE_URL=https://api.openai.com/v1
|
||||
```
|
||||
|
||||
## Configure Mem0 Memory Store
|
||||
|
||||
In your ChatDev workflow YAML, add a Mem0 memory store in the `memory` section:
|
||||
|
||||
```yaml
|
||||
memory:
|
||||
- name: mem0_store
|
||||
type: mem0
|
||||
config:
|
||||
api_key: ${MEM0_API_KEY}
|
||||
user_id: my-user-123 # optional: scope memories to a user
|
||||
agent_id: my-agent # optional: scope memories to an agent
|
||||
```
|
||||
|
||||
Mem0 handles all storage, embeddings, and search server-side — no local vector databases or embedding models are needed.
|
||||
|
||||
## Attach Memory to an Agent
|
||||
|
||||
Reference the memory store in your agent node's `memories` list:
|
||||
|
||||
```yaml
|
||||
nodes:
|
||||
- id: writer
|
||||
type: agent
|
||||
config:
|
||||
role: |
|
||||
You are a knowledgeable writer. Use your memories to build
|
||||
on past interactions.
|
||||
memories:
|
||||
- name: mem0_store
|
||||
top_k: 5
|
||||
similarity_threshold: 0.5 # minimum relevance score (0.0–1.0); set to -1.0 to disable
|
||||
retrieve_stage:
|
||||
- gen
|
||||
read: true
|
||||
write: true
|
||||
```
|
||||
|
||||
- **`read: true`** — Agent retrieves relevant memories before generating a response
|
||||
- **`write: true`** — Agent stores new memories from user input after each interaction
|
||||
- **`top_k`** — Number of memories to retrieve per query
|
||||
- **`similarity_threshold`** — Minimum relevance score for retrieved memories. Set to `-1.0` to return all results regardless of score
|
||||
- **`retrieve_stage`** — When to retrieve memories. Options: `pre_gen_thinking` (before generation), `gen` (during generation), `post_gen_thinking` (after generation), `finished` (after completion)
|
||||
|
||||
## Full Example Workflow
|
||||
|
||||
Here's a complete workflow YAML that creates a memory-backed conversational agent:
|
||||
|
||||
```yaml
|
||||
version: 0.4.0
|
||||
graph:
|
||||
description: Memory-backed conversation using Mem0
|
||||
|
||||
nodes:
|
||||
- id: writer
|
||||
type: agent
|
||||
config:
|
||||
base_url: ${BASE_URL}
|
||||
api_key: ${API_KEY}
|
||||
provider: openai
|
||||
name: gpt-5.4
|
||||
role: |
|
||||
You are a knowledgeable writer. Use your memories to build
|
||||
on past interactions. If memory sections are provided
|
||||
(wrapped by ===== Related Memories =====), incorporate
|
||||
relevant context from those memories into your response.
|
||||
params:
|
||||
temperature: 0.7
|
||||
max_tokens: 2000
|
||||
memories:
|
||||
- name: mem0_store
|
||||
top_k: 5
|
||||
retrieve_stage:
|
||||
- gen
|
||||
read: true
|
||||
write: true
|
||||
|
||||
memory:
|
||||
- name: mem0_store
|
||||
type: mem0
|
||||
config:
|
||||
api_key: ${MEM0_API_KEY}
|
||||
user_id: project-user-123
|
||||
agent_id: writer-agent
|
||||
|
||||
start:
|
||||
- writer
|
||||
end: []
|
||||
```
|
||||
|
||||
Run the workflow:
|
||||
|
||||
```bash
|
||||
# Option 1: CLI (recommended for quick testing)
|
||||
uv run python run.py --path yaml_instance/demo_mem0_memory.yaml --name my_project
|
||||
|
||||
# Option 2: Web console
|
||||
make dev
|
||||
# Backend starts at http://localhost:6400, frontend at http://localhost:5173
|
||||
```
|
||||
|
||||
To use the web console, open `http://localhost:5173`, create a new workflow, and paste your YAML configuration into the editor. The web console provides a visual chat interface for interacting with your memory-backed agents.
|
||||
|
||||
## How It Works
|
||||
|
||||
When an agent with Mem0 memory receives input, the following cycle runs automatically:
|
||||
|
||||
**1. Retrieve** — Before generating a response, ChatDev queries Mem0 with the user's input using semantic search. Relevant memories are injected into the agent's context in this format:
|
||||
|
||||
```
|
||||
===== Related Memories =====
|
||||
--- mem0_store ---
|
||||
1. User's favorite language is Rust
|
||||
2. User lives in San Francisco
|
||||
===== End of Memory =====
|
||||
```
|
||||
|
||||
This is why the role prompt in the example references `===== Related Memories =====` — the agent needs to know how to use this injected context.
|
||||
|
||||
**2. Generate** — The agent produces a response using the retrieved memories as additional context.
|
||||
|
||||
**3. Store** — After generation, the user's input is sent to Mem0 via `client.add()`. Mem0's extraction model automatically identifies and stores facts, preferences, and key information. Only user input is stored — agent output is excluded to keep memories clean.
|
||||
|
||||
Memories persist in Mem0's cloud across all sessions. The next time the same `user_id` or `agent_id` is used, previous memories are automatically retrieved.
|
||||
|
||||
## Dual-Scope Memory (User + Agent)
|
||||
|
||||
When both `user_id` and `agent_id` are configured, Mem0 uses an OR filter to search across both scopes in a single query:
|
||||
|
||||
```yaml
|
||||
memory:
|
||||
- name: shared_store
|
||||
type: mem0
|
||||
config:
|
||||
api_key: ${MEM0_API_KEY}
|
||||
user_id: alice # stores user preferences ("Alice prefers dark mode")
|
||||
agent_id: support-bot # stores agent-learned context ("Resolved Alice's billing issue")
|
||||
```
|
||||
|
||||
This means retrieval returns memories from **both** the user's scope and the agent's scope. Writes include both IDs, so each memory is accessible from either dimension. Use this when you want an agent to remember both what the user told it *and* what the agent learned across sessions.
|
||||
|
||||
## Configuration Reference
|
||||
|
||||
### Memory Store Config
|
||||
|
||||
| Field | Required | Description |
|
||||
|-------|----------|-------------|
|
||||
| `api_key` | Yes | Mem0 API key from <a href="https://app.mem0.ai" rel="nofollow">app.mem0.ai</a> |
|
||||
| `user_id` | No | Scope memories to a specific user |
|
||||
| `agent_id` | No | Scope memories to a specific agent |
|
||||
|
||||
### Memory Attachment Config
|
||||
|
||||
| Field | Default | Description |
|
||||
|-------|---------|-------------|
|
||||
| `top_k` | `3` | Number of memories to retrieve |
|
||||
| `similarity_threshold` | `-1.0` (disabled) | Minimum relevance score. Set a value between `0.0` and `1.0` to filter low-relevance results. Default (`-1.0`) returns all matches without filtering |
|
||||
| `retrieve_stage` | `["gen"]` | When to retrieve: `pre_gen_thinking`, `gen`, `post_gen_thinking`, or `finished` |
|
||||
| `read` | `true` | Whether the agent retrieves memories |
|
||||
| `write` | `true` | Whether the agent stores new memories |
|
||||
|
||||
## Tips and Common Pitfalls
|
||||
|
||||
<Info>
|
||||
**Indexing delay** — Freshly stored memories may take a few seconds to become searchable. If a memory isn't retrieved immediately after being stored, wait a moment and try again.
|
||||
</Info>
|
||||
|
||||
- **No memories returned on first run** — This is expected. Memories are stored *after* the agent responds, so the first interaction has no prior context. Memories appear starting from the second interaction onward.
|
||||
- **`mem0ai` not installed** — If you see `ImportError: mem0ai is required for Mem0Memory`, run `uv add mem0ai` or `pip install mem0ai` to add the dependency.
|
||||
- **Invalid API key** — A wrong or expired `MEM0_API_KEY` will log errors like `Mem0 search failed` or `Mem0 add failed` but won't crash the agent. Check your key at <a href="https://app.mem0.ai" rel="nofollow">app.mem0.ai</a>.
|
||||
- **Pipeline headers in memories** — ChatDev automatically strips internal pipeline headers (e.g., `=== INPUT FROM TASK (user) ===`) before sending text to Mem0, so your memories stay clean.
|
||||
- **Clearing test memories** — To delete memories created during testing, use the Mem0 dashboard at <a href="https://app.mem0.ai" rel="nofollow">app.mem0.ai</a> or the Python SDK: `MemoryClient().delete_all(user_id="your-test-user")`.
|
||||
|
||||
## Key Features
|
||||
|
||||
1. **Zero-Code Integration** — Configure Mem0 entirely through YAML, no Python code required
|
||||
2. **Cloud-Managed Storage** — Mem0 handles embeddings, persistence, and search server-side
|
||||
3. **Semantic Search** — Retrieve contextually relevant memories, not just keyword matches
|
||||
4. **Cross-Session Persistence** — Memories survive across runs, sessions, and restarts
|
||||
5. **Multi-Agent Memory Sharing** — Multiple agents can share memories through common `user_id` or `agent_id` scopes
|
||||
6. **Intelligent Input Processing** — Only user input is stored; agent output is excluded to prevent noisy memories
|
||||
|
||||
## Conclusion
|
||||
|
||||
By adding Mem0 as a memory store in ChatDev, your multi-agent workflows gain persistent, intelligent memory with zero code changes. Agents automatically remember past interactions and use that context to provide personalized, coherent responses across sessions.
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="CrewAI Integration" icon="users" href="/integrations/crewai">
|
||||
Build multi-agent systems with CrewAI and Mem0
|
||||
</Card>
|
||||
<Card title="AutoGen Integration" icon="robot" href="/integrations/autogen">
|
||||
Build conversational agents with AutoGen and Mem0
|
||||
</Card>
|
||||
</CardGroup>
|
||||
@@ -0,0 +1,156 @@
|
||||
---
|
||||
title: Claude Code
|
||||
description: "Add persistent memory to Claude Code and Claude Cowork with the Mem0 plugin — MCP server, lifecycle hooks, and SDK skill."
|
||||
---
|
||||
|
||||
Add persistent memory to [**Claude Code**](https://docs.anthropic.com/en/docs/claude-code) (CLI) and **Claude Cowork** (desktop app) with the Mem0 plugin. Your agent forgets everything between sessions — this plugin fixes that by connecting to Mem0's cloud memory layer via MCP, automatically capturing learnings at key lifecycle points, and retrieving relevant context before every response.
|
||||
|
||||
## Overview
|
||||
|
||||
1. **MCP Server** — Connect to Mem0's remote MCP server for memory tools (add, search, update, delete)
|
||||
2. **Lifecycle Hooks** — Automatic memory capture at session start, context compaction, task completion, and session end
|
||||
3. **SDK Skill** — Teaches the agent how to integrate the Mem0 SDK into your applications
|
||||
4. **Zero local dependencies** — Cloud-hosted MCP server, no local setup required
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before setting up Mem0 with Claude Code, ensure you have:
|
||||
|
||||
1. A Mem0 Platform account and API key:
|
||||
- <a href="https://app.mem0.ai" rel="nofollow">Sign up at app.mem0.ai</a>
|
||||
- <a href="https://app.mem0.ai/dashboard/api-keys" rel="nofollow">Get your API key</a> (starts with `m0-`)
|
||||
|
||||
2. Claude Code CLI or Claude Cowork desktop app installed
|
||||
|
||||
3. Your API key exported in your shell:
|
||||
|
||||
```bash
|
||||
export MEM0_API_KEY="m0-your-api-key"
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
### Option A — Plugin Marketplace (Recommended)
|
||||
|
||||
Install the full plugin including MCP server, lifecycle hooks, and SDK skill:
|
||||
|
||||
```
|
||||
/plugin marketplace add mem0ai/mem0
|
||||
/plugin install mem0@mem0-plugins
|
||||
```
|
||||
|
||||
**Claude Cowork desktop app:** Open the Cowork tab, click **Customize** in the sidebar, click **Browse plugins**, and install Mem0.
|
||||
|
||||
### Option B — MCP Only
|
||||
|
||||
Add the Mem0 MCP server directly with a single command:
|
||||
|
||||
```bash
|
||||
npx mcp-add \
|
||||
--name mem0-mcp \
|
||||
--type http \
|
||||
--url "https://mcp.mem0.ai/mcp" \
|
||||
--clients "claude code"
|
||||
```
|
||||
|
||||
This gives you the MCP tools but not the lifecycle hooks or SDK skill.
|
||||
|
||||
### Option C — Manual MCP Configuration
|
||||
|
||||
Add to your Claude Code MCP config (`.mcp.json`):
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"mem0": {
|
||||
"type": "http",
|
||||
"url": "https://mcp.mem0.ai/mcp/",
|
||||
"headers": {
|
||||
"Authorization": "Token ${MEM0_API_KEY}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<Info icon="check">
|
||||
Start a new session and ask: *"List my mem0 entities"* or *"Search my memories for hello"*. If the `mem0` tools appear and respond, you're all set.
|
||||
</Info>
|
||||
|
||||
## What's Included
|
||||
|
||||
| Component | Plugin Install | MCP Only |
|
||||
|-----------|:--------------:|:--------:|
|
||||
| MCP Server (9 memory tools) | Yes | Yes |
|
||||
| Lifecycle Hooks | Yes | No |
|
||||
| Mem0 SDK Skill | Yes | No |
|
||||
|
||||
## Available MCP Tools
|
||||
|
||||
Once installed, the following tools are available in every Claude Code session:
|
||||
|
||||
| Tool | Description |
|
||||
|------|-------------|
|
||||
| `add_memory` | Save text or conversation history for a user/agent |
|
||||
| `search_memories` | Semantic search across memories with filters |
|
||||
| `get_memories` | List memories with filters and pagination |
|
||||
| `get_memory` | Retrieve a specific memory by ID |
|
||||
| `update_memory` | Overwrite a memory's text by ID |
|
||||
| `delete_memory` | Delete a single memory by ID |
|
||||
| `delete_all_memories` | Bulk delete all memories in scope |
|
||||
| `delete_entities` | Delete a user/agent/app/run entity and its memories |
|
||||
| `list_entities` | List users/agents/apps/runs stored in Mem0 |
|
||||
|
||||
## Lifecycle Hooks
|
||||
|
||||
When installed via the plugin marketplace, Mem0 hooks into Claude Code's lifecycle to automatically manage memory:
|
||||
|
||||
### Session Start
|
||||
On every new session, the plugin prompts Claude to call `search_memories` to load relevant context from prior sessions. On resumed or post-compaction sessions, it adjusts the prompt accordingly.
|
||||
|
||||
### User Prompt
|
||||
Before processing each user message, the plugin searches Mem0 for memories relevant to the current prompt and injects them into context. Short prompts (< 20 characters) are skipped to minimize latency.
|
||||
|
||||
### Pre-Compaction
|
||||
Before context compaction, the plugin prompts Claude to store a comprehensive session summary — including goals, accomplishments, decisions, modified files, and current state — so nothing is lost.
|
||||
|
||||
### Task Completed
|
||||
After each task completion, the plugin prompts Claude to extract and store key learnings: successful strategies, failed approaches, architectural decisions, and new conventions.
|
||||
|
||||
### Session End
|
||||
When Claude finishes responding, the plugin prompts for any unstored learnings and captures transcript state via the Mem0 REST API as a background safety net.
|
||||
|
||||
## Example Workflow
|
||||
|
||||
```text
|
||||
# Session 1: Working on a feature
|
||||
You: Let's refactor the auth module to use JWT tokens instead of sessions.
|
||||
|
||||
# Claude searches memories, finds nothing relevant, proceeds with the work.
|
||||
# After completing the task, Mem0 stores:
|
||||
# - Decision: "Migrated auth from sessions to JWT tokens"
|
||||
# - Files modified: auth/middleware.ts, auth/token.ts
|
||||
# - User preference: "Prefers TypeScript, uses ESLint"
|
||||
|
||||
# Session 2 (days later): Related work
|
||||
You: Add refresh token rotation to the auth system.
|
||||
|
||||
# Claude searches memories, retrieves the JWT migration context.
|
||||
# Knows the file structure, decisions made, and user preferences.
|
||||
# Continues seamlessly without re-explaining the codebase.
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **"Connection failed"** — Verify `MEM0_API_KEY` is set in your shell: `echo $MEM0_API_KEY`
|
||||
- **No tools appearing** — Restart your Claude Code session after installation
|
||||
- **Memories not being captured** — Ensure you installed via the plugin marketplace (Option A) for lifecycle hooks. MCP-only installs require manual memory operations.
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Mem0 MCP Setup" icon="puzzle-piece" href="/platform/mem0-mcp">
|
||||
Detailed MCP configuration for all clients
|
||||
</Card>
|
||||
<Card title="Codex Integration" icon={<svg width="24" height="25" viewBox="0 0 24 25" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M20.5565 10.6338C21.0009 9.27575 20.8528 7.76958 20.1367 6.53501C19.0503 4.63378 16.8528 3.67081 14.7046 4.11526C13.7663 3.05353 12.3836 2.46094 10.9515 2.46094C8.75399 2.46094 6.82807 3.86835 6.13671 5.94242C4.7293 6.23872 3.51943 7.10291 2.80338 8.36217C1.71696 10.2634 1.96387 12.6338 3.42066 14.2634C2.97622 15.6461 3.14906 17.1276 3.8651 18.3622C4.95152 20.2634 7.14906 21.2511 9.2972 20.7819C10.2602 21.8437 11.6182 22.4609 13.0503 22.4609C15.2478 22.4609 17.1737 21.0535 17.8651 18.9795C19.2725 18.6832 20.4824 17.819 21.1984 16.5597C22.2849 14.6585 22.0379 12.2634 20.5565 10.6338ZM13.0503 21.1523C12.1614 21.1523 11.3219 20.856 10.6552 20.2881C10.6799 20.2634 10.754 20.2387 10.7787 20.214L14.754 17.9177C14.9515 17.7943 15.075 17.5967 15.075 17.3498V11.7449L16.754 12.7079C16.7787 12.7079 16.7787 12.7325 16.7787 12.7572V17.3992C16.8034 19.4733 15.1244 21.1523 13.0503 21.1523ZM5.00091 17.7202C4.55646 16.9548 4.40831 16.0659 4.55646 15.2017C4.58115 15.2264 4.63054 15.2511 4.67992 15.2758L8.65523 17.572C8.85276 17.6955 9.09967 17.6955 9.2972 17.572L14.1614 14.7572V16.7079C14.1614 16.7325 14.1614 16.7572 14.1367 16.7572L10.112 19.0782C8.33424 20.1153 6.03794 19.498 5.00091 17.7202ZM3.96387 9.02884C4.40831 8.26341 5.09967 7.69551 5.91449 7.37452V12.1153C5.91449 12.3375 6.03794 12.5597 6.23548 12.6832L11.0997 15.498L9.42066 16.4609C9.39597 16.4609 9.37128 16.4856 9.37128 16.4609L5.34659 14.1399C3.51943 13.1029 2.92683 10.8066 3.96387 9.02884ZM17.791 12.2387L12.9268 9.4239L14.6058 8.46094C14.6305 8.46094 14.6552 8.43625 14.6552 8.46094L18.6799 10.7819C20.4824 11.819 21.075 14.1153 20.0379 15.893C19.5935 16.6585 18.9021 17.2264 18.0873 17.5227V12.8066C18.112 12.5844 17.9886 12.3622 17.791 12.2387ZM19.4454 9.7202C19.4207 9.69551 19.3713 9.67081 19.3219 9.64612L15.3466 7.34983C15.1491 7.22637 14.9021 7.22637 14.7046 7.34983L9.84041 10.1646V8.21402C9.84041 8.18933 9.84041 8.16464 9.86511 8.16464L13.8898 5.84365C15.6923 4.80662 17.9639 5.4239 19.0009 7.22637C19.4454 7.96711 19.5935 8.856 19.4454 9.7202ZM8.92683 13.177L7.24782 12.214C7.22313 12.214 7.22313 12.1893 7.22313 12.1646V7.52267C7.22313 5.44859 8.90214 3.76958 10.9762 3.76958C11.8651 3.76958 12.7046 4.06588 13.3713 4.63378C13.3466 4.65847 13.2972 4.68316 13.2478 4.70785L9.27251 7.00415C9.07498 7.1276 8.95152 7.32514 8.95152 7.57205V13.177H8.92683ZM9.84041 11.2017L12.0133 9.94242L14.1861 11.2017V13.6955L12.0133 14.9548L9.84041 13.6955V11.2017Z" fill="currentColor"/></svg>} href="/integrations/codex">
|
||||
Add Mem0 memory to OpenAI Codex workflows
|
||||
</Card>
|
||||
</CardGroup>
|
||||
@@ -0,0 +1,212 @@
|
||||
---
|
||||
title: Codex
|
||||
description: "Add persistent memory to OpenAI Codex with the Mem0 plugin — MCP server, memory protocol skill, and plugin marketplace support."
|
||||
---
|
||||
|
||||
Add persistent memory to [**OpenAI Codex**](https://openai.com/index/codex/) with the Mem0 plugin. Codex forgets everything between tasks — this plugin fixes that by connecting to Mem0's cloud memory layer via MCP and using a skill-based memory protocol to automatically retrieve context and store learnings.
|
||||
|
||||
## Overview
|
||||
|
||||
1. **MCP Server** — Connect to Mem0's remote MCP server for memory tools (add, search, update, delete)
|
||||
2. **Memory Protocol Skill** — Instructs the agent to retrieve memories at task start, store learnings on completion, and capture session state before context loss
|
||||
3. **Plugin Marketplace** — Install via Codex's repo-level or personal plugin marketplace
|
||||
4. **Zero local dependencies** — Cloud-hosted MCP server, no local setup required
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before setting up Mem0 with Codex, ensure you have:
|
||||
|
||||
1. A Mem0 Platform account and API key:
|
||||
- <a href="https://app.mem0.ai" rel="nofollow">Sign up at app.mem0.ai</a>
|
||||
- <a href="https://app.mem0.ai/dashboard/api-keys" rel="nofollow">Get your API key</a> (starts with `m0-`)
|
||||
|
||||
2. OpenAI Codex access
|
||||
|
||||
3. Your API key exported in your shell:
|
||||
|
||||
```bash
|
||||
export MEM0_API_KEY="m0-your-api-key"
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
### Option A — Repo Marketplace (Recommended for Teams)
|
||||
|
||||
Add a `.agents/plugins/marketplace.json` to your repository root:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "mem0-plugins",
|
||||
"interface": {
|
||||
"displayName": "Mem0 Plugins"
|
||||
},
|
||||
"plugins": [
|
||||
{
|
||||
"name": "mem0",
|
||||
"source": {
|
||||
"source": "local",
|
||||
"path": "./plugins/mem0"
|
||||
},
|
||||
"policy": {
|
||||
"installation": "AVAILABLE",
|
||||
"authentication": "ON_INSTALL"
|
||||
},
|
||||
"category": "Productivity"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Then in Codex, browse the repo's plugin directory and install Mem0.
|
||||
|
||||
### Option B — Personal Marketplace
|
||||
|
||||
Add to `~/.agents/plugins/marketplace.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "mem0-plugins",
|
||||
"interface": {
|
||||
"displayName": "Mem0 Plugins"
|
||||
},
|
||||
"plugins": [
|
||||
{
|
||||
"name": "mem0",
|
||||
"source": {
|
||||
"source": "local",
|
||||
"path": "/path/to/mem0-plugin"
|
||||
},
|
||||
"policy": {
|
||||
"installation": "AVAILABLE",
|
||||
"authentication": "ON_INSTALL"
|
||||
},
|
||||
"category": "Productivity"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Option C — Manual MCP Configuration
|
||||
|
||||
Add to your Codex MCP config:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"mem0": {
|
||||
"type": "http",
|
||||
"url": "https://mcp.mem0.ai/mcp/",
|
||||
"headers": {
|
||||
"Authorization": "Token ${MEM0_API_KEY}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<Info icon="check">
|
||||
Start a new Codex task and ask: *"List my mem0 entities"* or *"Search my memories for hello"*. If the `mem0` tools appear and respond, you're all set.
|
||||
</Info>
|
||||
|
||||
## What's Included
|
||||
|
||||
| Component | Plugin Install | MCP Only |
|
||||
|-----------|:--------------:|:--------:|
|
||||
| MCP Server (9 memory tools) | Yes | Yes |
|
||||
| Memory Protocol Skill | Yes | No |
|
||||
| Mem0 SDK Skill | Yes | No |
|
||||
|
||||
## Available MCP Tools
|
||||
|
||||
Once installed, the following tools are available in every Codex session:
|
||||
|
||||
| Tool | Description |
|
||||
|------|-------------|
|
||||
| `add_memory` | Save text or conversation history for a user/agent |
|
||||
| `search_memories` | Semantic search across memories with filters |
|
||||
| `get_memories` | List memories with filters and pagination |
|
||||
| `get_memory` | Retrieve a specific memory by ID |
|
||||
| `update_memory` | Overwrite a memory's text by ID |
|
||||
| `delete_memory` | Delete a single memory by ID |
|
||||
| `delete_all_memories` | Bulk delete all memories in scope |
|
||||
| `delete_entities` | Delete a user/agent/app/run entity and its memories |
|
||||
| `list_entities` | List users/agents/apps/runs stored in Mem0 |
|
||||
|
||||
## Memory Protocol Skill
|
||||
|
||||
Codex uses a skill-based approach instead of lifecycle hooks. When installed via the plugin marketplace, the memory protocol skill instructs the agent to:
|
||||
|
||||
### On Every New Task
|
||||
1. Call `search_memories` with a query related to the current task to load relevant context
|
||||
2. Review returned memories to understand what was learned in prior sessions
|
||||
3. Optionally call `get_memories` to browse all stored memories
|
||||
|
||||
### After Completing Significant Work
|
||||
Store key learnings using `add_memory` with structured metadata:
|
||||
|
||||
| What to store | Metadata type |
|
||||
|--------------|---------------|
|
||||
| Architectural decisions | `{"type": "decision"}` |
|
||||
| Strategies that worked | `{"type": "task_learning"}` |
|
||||
| Failed approaches | `{"type": "anti_pattern"}` |
|
||||
| User preferences observed | `{"type": "user_preference"}` |
|
||||
| Environment discoveries | `{"type": "environmental"}` |
|
||||
| Conventions established | `{"type": "convention"}` |
|
||||
|
||||
### Before Losing Context
|
||||
Store a comprehensive session summary including goals, accomplishments, decisions, files modified, and current state with metadata `{"type": "session_state"}`.
|
||||
|
||||
## Plugin Manifest
|
||||
|
||||
The Codex plugin manifest (`.codex-plugin/plugin.json`) follows the Codex plugin specification:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "mem0",
|
||||
"version": "0.1.0",
|
||||
"description": "Mem0 memory layer for AI applications.",
|
||||
"skills": "./skills/",
|
||||
"mcpServers": "./.codex-mcp.json",
|
||||
"interface": {
|
||||
"displayName": "Mem0",
|
||||
"shortDescription": "Persistent memory layer for AI coding workflows",
|
||||
"category": "Productivity",
|
||||
"capabilities": ["Read", "Write"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Example Workflow
|
||||
|
||||
```text
|
||||
# Task 1: Setting up a new service
|
||||
You: Create a REST API for the notifications service using Express and TypeScript.
|
||||
|
||||
# Codex searches memories, finds user preferences from prior tasks.
|
||||
# After completing the task, Mem0 stores:
|
||||
# - Decision: "Notifications service uses Express + TypeScript + Zod validation"
|
||||
# - Convention: "All API routes follow /api/v1/{resource} pattern"
|
||||
# - Preference: "User prefers explicit error types over generic catch-all"
|
||||
|
||||
# Task 2 (days later): Extending the service
|
||||
You: Add WebSocket support for real-time notification delivery.
|
||||
|
||||
# Codex searches memories, retrieves the architecture decisions and conventions.
|
||||
# Follows the same patterns established in the first task.
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **"Connection failed"** — Verify `MEM0_API_KEY` is set in your shell: `echo $MEM0_API_KEY`
|
||||
- **No tools appearing** — Restart your Codex session after plugin installation
|
||||
- **Plugin not found** — Ensure `.agents/plugins/marketplace.json` is at the repository root and `source.path` points to the correct plugin directory
|
||||
- **Skills not loading** — Verify the `skills` field in `plugin.json` points to a valid directory containing `SKILL.md` files
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Mem0 MCP Setup" icon="puzzle-piece" href="/platform/mem0-mcp">
|
||||
Detailed MCP configuration for all clients
|
||||
</Card>
|
||||
<Card title="Claude Code Integration" icon={<svg width="24" height="25" viewBox="0 0 24 25" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M5.92888 16.2181L9.86008 14.0122L9.92585 13.8199L9.86008 13.7137H9.66782L9.01009 13.6732L6.76369 13.6125L4.81581 13.5315L2.92863 13.4303L2.45304 13.3292L2.00781 12.7423L2.05335 12.4488L2.45304 12.1807L3.02476 12.2313L4.28962 12.3173L6.18692 12.4488L7.56309 12.5298L9.60204 12.7423H9.92585L9.97138 12.6107L9.86008 12.5298L9.77407 12.4488L7.811 11.1182L5.68603 9.71165L4.57295 8.90214L3.97088 8.49233L3.66731 8.10781L3.53577 7.26794L4.08219 6.66587L4.81581 6.71646L5.00301 6.76706L5.74674 7.33877L7.33541 8.56822L9.40979 10.0962L9.71335 10.3491L9.83478 10.2631L9.84996 10.2024L9.71335 9.97475L8.5851 7.93579L7.38095 5.86141L6.84465 5.00131L6.70298 4.48524C6.65239 4.27275 6.61697 4.09567 6.61697 3.87811L7.23928 3.03318L7.58332 2.92188L8.41307 3.03318L8.76218 3.33675L9.27824 4.5156L10.113 6.37242L11.4083 8.89708L11.7877 9.64588L11.9901 10.339L12.066 10.5515H12.1975V10.4301L12.3038 9.00839L12.5011 7.26288L12.6934 5.01649L12.7591 4.38406L13.0728 3.62514L13.6951 3.21532L14.1808 3.44806L14.5805 4.01978L14.5249 4.38912L14.2871 5.93225L13.8216 8.35066L13.5181 9.96969H13.6951L13.8975 9.76731L14.7171 8.67953L16.0933 6.95931L16.7005 6.27629L17.4088 5.52243L17.8641 5.16321H18.7242L19.3567 6.10427L19.0733 7.07568L18.1879 8.19888L17.4543 9.15006L16.4019 10.5667L15.7442 11.7L15.8049 11.7911L15.9618 11.7759L18.3397 11.27L19.6248 11.0372L21.1578 10.7741L21.851 11.0979L21.9269 11.4268L21.6537 12.0997L20.0144 12.5045L18.0918 12.889L15.2282 13.567L15.1927 13.5923L15.2332 13.6428L16.5234 13.7643L17.0749 13.7946H18.4257L20.9403 13.9818L21.598 14.4169L21.9926 14.9482L21.9269 15.3529L20.915 15.869L19.5489 15.5452L16.3615 14.7863L15.2686 14.5131H15.1168V14.6041L16.0275 15.4946L17.6972 17.0023L19.7867 18.9451L19.893 19.4258L19.6248 19.8053L19.3415 19.7648L17.5049 18.3835L16.7966 17.7612L15.1927 16.4104H15.0865V16.552L15.4558 17.0934L17.4088 20.0279L17.51 20.9285L17.3683 21.2219L16.8624 21.399L16.3058 21.2978L15.1624 19.6939L13.9835 17.8877L13.0324 16.2687L12.916 16.3345L12.3544 22.3805L12.0913 22.6891L11.4842 22.9219L10.9782 22.5374L10.7101 21.915L10.9782 20.6856L11.302 19.0818L11.5651 17.8068L11.8029 16.2232L11.9446 15.697L11.9345 15.6616L11.8181 15.6767L10.6241 17.316L8.80771 19.7698L7.37083 21.3079L7.02679 21.4445L6.42977 21.1359L6.48542 20.5844L6.81935 20.0936L8.80771 17.5639L10.0068 15.9955L10.7809 15.0898L10.7758 14.9583H10.7303L5.44824 18.3886L4.50718 18.51L4.10242 18.1306L4.15302 17.5083L4.34528 17.3059L5.93394 16.213L5.92888 16.2181Z" fill="currentColor"/></svg>} href="/integrations/claude-code">
|
||||
Add Mem0 memory to Claude Code workflows
|
||||
</Card>
|
||||
</CardGroup>
|
||||
@@ -22,7 +22,7 @@ pip install crewai crewai-tools mem0ai
|
||||
|
||||
Import required modules and set up configurations:
|
||||
|
||||
<Note>Remember to get your API keys from [Mem0 Platform](https://app.mem0.ai), [OpenAI](https://platform.openai.com) and [Serper Dev](https://serper.dev) for search capabilities.</Note>
|
||||
<Note>Remember to get your API keys from <a href="https://app.mem0.ai" rel="nofollow">Mem0 Platform</a>, [OpenAI](https://platform.openai.com) and [Serper Dev](https://serper.dev) for search capabilities.</Note>
|
||||
|
||||
```python
|
||||
import os
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
---
|
||||
title: Cursor
|
||||
description: "Add persistent memory to Cursor with the Mem0 plugin — MCP server, lifecycle hooks, and SDK skill for context-aware coding."
|
||||
---
|
||||
|
||||
Add persistent memory to [**Cursor**](https://cursor.com) with the Mem0 plugin. Your AI assistant forgets everything between sessions — this plugin fixes that by connecting to Mem0's cloud memory layer via MCP, automatically capturing learnings at key lifecycle points, and retrieving relevant context before every response.
|
||||
|
||||
## Overview
|
||||
|
||||
1. **MCP Server** — Connect to Mem0's remote MCP server for memory tools (add, search, update, delete)
|
||||
2. **Lifecycle Hooks** — Automatic memory capture at session start, compaction, and user prompts (Marketplace install)
|
||||
3. **SDK Skill** — Teaches the agent how to integrate the Mem0 SDK into your applications
|
||||
4. **Zero local dependencies** — Cloud-hosted MCP server, no local setup required
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before setting up Mem0 with Cursor, ensure you have:
|
||||
|
||||
1. A Mem0 Platform account and API key:
|
||||
- <a href="https://app.mem0.ai" rel="nofollow">Sign up at app.mem0.ai</a>
|
||||
- <a href="https://app.mem0.ai/dashboard/api-keys" rel="nofollow">Get your API key</a> (starts with `m0-`)
|
||||
|
||||
2. Cursor installed ([cursor.com](https://cursor.com))
|
||||
|
||||
3. Your API key exported in your shell:
|
||||
|
||||
```bash
|
||||
export MEM0_API_KEY="m0-your-api-key"
|
||||
```
|
||||
|
||||
<Warning>
|
||||
Already have `mem0` configured as an MCP server in Cursor? Remove the existing entry from your Cursor MCP settings before installing to avoid duplicate tools.
|
||||
</Warning>
|
||||
|
||||
## Installation
|
||||
|
||||
### Option A — One-Click Deeplink (MCP Only)
|
||||
|
||||
The fastest way to get started. Click the link below to install the Mem0 MCP server directly in Cursor:
|
||||
|
||||
[Install Mem0 MCP in Cursor](cursor://anysphere.cursor-deeplink/mcp/install?name=mem0&config=eyJtY3BTZXJ2ZXJzIjp7Im1lbTAiOnsidXJsIjoiaHR0cHM6Ly9tY3AubWVtMC5haS9tY3AvIiwiaGVhZGVycyI6eyJBdXRob3JpemF0aW9uIjoiVG9rZW4gJHtlbnY6TUVNMF9BUElfS0VZfSJ9fX19)
|
||||
|
||||
### Option B — npx (MCP Only)
|
||||
|
||||
```bash
|
||||
npx mcp-add \
|
||||
--name mem0-mcp \
|
||||
--type http \
|
||||
--url "https://mcp.mem0.ai/mcp" \
|
||||
--clients "cursor"
|
||||
```
|
||||
|
||||
### Option C — Manual Configuration (MCP Only)
|
||||
|
||||
Add the following to your `.cursor/mcp.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"mem0": {
|
||||
"url": "https://mcp.mem0.ai/mcp/",
|
||||
"headers": {
|
||||
"Authorization": "Token ${env:MEM0_API_KEY}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Option D — Cursor Marketplace (Full Plugin)
|
||||
|
||||
Install from the [Cursor Marketplace](https://cursor.com/marketplace) for the complete experience including lifecycle hooks, the Mem0 SDK skill, and automatic memory capture.
|
||||
|
||||
<Info icon="check">
|
||||
Start a new Cursor session and ask: *"List my mem0 entities"* or *"Search my memories for hello"*. If the `mem0` tools appear and respond, you're all set.
|
||||
</Info>
|
||||
|
||||
## What's Included
|
||||
|
||||
| Component | Marketplace Install | Deeplink / Manual / npx |
|
||||
|-----------|:-------------------:|:-----------------------:|
|
||||
| MCP Server (9 memory tools) | Yes | Yes |
|
||||
| Lifecycle Hooks | Yes | No |
|
||||
| Mem0 SDK Skill | Yes | No |
|
||||
|
||||
## Available MCP Tools
|
||||
|
||||
Once installed, the following tools are available in every Cursor session:
|
||||
|
||||
| Tool | Description |
|
||||
|------|-------------|
|
||||
| `add_memory` | Save text or conversation history for a user/agent |
|
||||
| `search_memories` | Semantic search across memories with filters |
|
||||
| `get_memories` | List memories with filters and pagination |
|
||||
| `get_memory` | Retrieve a specific memory by ID |
|
||||
| `update_memory` | Overwrite a memory's text by ID |
|
||||
| `delete_memory` | Delete a single memory by ID |
|
||||
| `delete_all_memories` | Bulk delete all memories in scope |
|
||||
| `delete_entities` | Delete a user/agent/app/run entity and its memories |
|
||||
| `list_entities` | List users/agents/apps/runs stored in Mem0 |
|
||||
|
||||
## Lifecycle Hooks (Marketplace Install)
|
||||
|
||||
When installed via the Cursor Marketplace, Mem0 hooks into Cursor's lifecycle:
|
||||
|
||||
### Session Start
|
||||
On every new session, the plugin prompts the agent to call `search_memories` to load relevant context from prior sessions.
|
||||
|
||||
### User Prompt
|
||||
Before processing each user message, the plugin searches Mem0 for relevant memories and injects them into context. Short prompts are skipped to minimize latency.
|
||||
|
||||
### Pre-Compaction
|
||||
Before context compaction, the plugin captures a comprehensive session summary so nothing is lost when the context window resets.
|
||||
|
||||
## Example Workflow
|
||||
|
||||
```text
|
||||
# Session 1: Debugging a performance issue
|
||||
You: The API endpoint /users is taking 3 seconds. Help me optimize it.
|
||||
|
||||
# Cursor agent searches memories, proceeds with investigation.
|
||||
# After completing the task, Mem0 stores:
|
||||
# - Learning: "N+1 query in UserService.getAll() — fixed with eager loading"
|
||||
# - Decision: "Added database index on users.email column"
|
||||
# - Preference: "User prefers query-level fixes over caching"
|
||||
|
||||
# Session 2 (next week): Similar issue
|
||||
You: The /orders endpoint is also slow, same pattern as before.
|
||||
|
||||
# Agent searches memories, retrieves the optimization learnings.
|
||||
# Immediately checks for N+1 queries and missing indexes.
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **"Connection failed"** — Verify `MEM0_API_KEY` is set: `echo $MEM0_API_KEY`
|
||||
- **Duplicate tools** — If you had a previous MCP config for `mem0`, remove it before installing the plugin
|
||||
- **No tools appearing** — Go to Cursor Settings > MCP and verify the `mem0` server shows as connected
|
||||
- **Hooks not running** — Hooks require the Marketplace install (Option D). Deeplink/manual installs only provide MCP tools.
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Mem0 MCP Setup" icon="puzzle-piece" href="/platform/mem0-mcp">
|
||||
Detailed MCP configuration for all clients
|
||||
</Card>
|
||||
<Card title="Claude Code Integration" icon={<svg width="24" height="25" viewBox="0 0 24 25" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M5.92888 16.2181L9.86008 14.0122L9.92585 13.8199L9.86008 13.7137H9.66782L9.01009 13.6732L6.76369 13.6125L4.81581 13.5315L2.92863 13.4303L2.45304 13.3292L2.00781 12.7423L2.05335 12.4488L2.45304 12.1807L3.02476 12.2313L4.28962 12.3173L6.18692 12.4488L7.56309 12.5298L9.60204 12.7423H9.92585L9.97138 12.6107L9.86008 12.5298L9.77407 12.4488L7.811 11.1182L5.68603 9.71165L4.57295 8.90214L3.97088 8.49233L3.66731 8.10781L3.53577 7.26794L4.08219 6.66587L4.81581 6.71646L5.00301 6.76706L5.74674 7.33877L7.33541 8.56822L9.40979 10.0962L9.71335 10.3491L9.83478 10.2631L9.84996 10.2024L9.71335 9.97475L8.5851 7.93579L7.38095 5.86141L6.84465 5.00131L6.70298 4.48524C6.65239 4.27275 6.61697 4.09567 6.61697 3.87811L7.23928 3.03318L7.58332 2.92188L8.41307 3.03318L8.76218 3.33675L9.27824 4.5156L10.113 6.37242L11.4083 8.89708L11.7877 9.64588L11.9901 10.339L12.066 10.5515H12.1975V10.4301L12.3038 9.00839L12.5011 7.26288L12.6934 5.01649L12.7591 4.38406L13.0728 3.62514L13.6951 3.21532L14.1808 3.44806L14.5805 4.01978L14.5249 4.38912L14.2871 5.93225L13.8216 8.35066L13.5181 9.96969H13.6951L13.8975 9.76731L14.7171 8.67953L16.0933 6.95931L16.7005 6.27629L17.4088 5.52243L17.8641 5.16321H18.7242L19.3567 6.10427L19.0733 7.07568L18.1879 8.19888L17.4543 9.15006L16.4019 10.5667L15.7442 11.7L15.8049 11.7911L15.9618 11.7759L18.3397 11.27L19.6248 11.0372L21.1578 10.7741L21.851 11.0979L21.9269 11.4268L21.6537 12.0997L20.0144 12.5045L18.0918 12.889L15.2282 13.567L15.1927 13.5923L15.2332 13.6428L16.5234 13.7643L17.0749 13.7946H18.4257L20.9403 13.9818L21.598 14.4169L21.9926 14.9482L21.9269 15.3529L20.915 15.869L19.5489 15.5452L16.3615 14.7863L15.2686 14.5131H15.1168V14.6041L16.0275 15.4946L17.6972 17.0023L19.7867 18.9451L19.893 19.4258L19.6248 19.8053L19.3415 19.7648L17.5049 18.3835L16.7966 17.7612L15.1927 16.4104H15.0865V16.552L15.4558 17.0934L17.4088 20.0279L17.51 20.9285L17.3683 21.2219L16.8624 21.399L16.3058 21.2978L15.1624 19.6939L13.9835 17.8877L13.0324 16.2687L12.916 16.3345L12.3544 22.3805L12.0913 22.6891L11.4842 22.9219L10.9782 22.5374L10.7101 21.915L10.9782 20.6856L11.302 19.0818L11.5651 17.8068L11.8029 16.2232L11.9446 15.697L11.9345 15.6616L11.8181 15.6767L10.6241 17.316L8.80771 19.7698L7.37083 21.3079L7.02679 21.4445L6.42977 21.1359L6.48542 20.5844L6.81935 20.0936L8.80771 17.5639L10.0068 15.9955L10.7809 15.0898L10.7758 14.9583H10.7303L5.44824 18.3886L4.50718 18.51L4.10242 18.1306L4.15302 17.5083L4.34528 17.3059L5.93394 16.213L5.92888 16.2181Z" fill="currentColor"/></svg>} href="/integrations/claude-code">
|
||||
Add Mem0 memory to Claude Code workflows
|
||||
</Card>
|
||||
</CardGroup>
|
||||
@@ -38,7 +38,7 @@ npx flowise start
|
||||
|
||||
### 2. Obtain Your Mem0 API Key
|
||||
|
||||
1. Navigate to the [Mem0 API Key dashboard](https://app.mem0.ai/dashboard/api-keys).
|
||||
1. Navigate to the <a href="https://app.mem0.ai/dashboard/api-keys" rel="nofollow">Mem0 API Key dashboard</a>.
|
||||
2. Generate or copy your existing Mem0 API Key.
|
||||
|
||||

|
||||
@@ -70,7 +70,7 @@ Test your memory configuration:
|
||||
|
||||
1. Save your Flowise configuration
|
||||
2. Run a test chat and store some information
|
||||
3. Verify the stored memories in the [Mem0 Dashboard](https://app.mem0.ai/dashboard/requests)
|
||||
3. Verify the stored memories in the <a href="https://app.mem0.ai/dashboard/requests" rel="nofollow">Mem0 Dashboard</a>
|
||||
|
||||

|
||||
|
||||
@@ -103,7 +103,7 @@ Available settings include:
|
||||
|
||||
### Platform Configuration
|
||||
|
||||
Additional settings available in [Mem0 Project Settings](https://app.mem0.ai/dashboard/project-settings):
|
||||
Additional settings available in <a href="https://app.mem0.ai/dashboard/project-settings" rel="nofollow">Mem0 Project Settings</a>:
|
||||
|
||||
1. **Custom Instructions**: Define memory extraction rules
|
||||
2. **Expiration Date**: Set automatic memory cleanup periods
|
||||
|
||||
@@ -22,7 +22,7 @@ pip install google-adk mem0ai python-dotenv
|
||||
```
|
||||
|
||||
2. Valid API keys:
|
||||
- [Mem0 API Key](https://app.mem0.ai/dashboard/api-keys)
|
||||
- <a href="https://app.mem0.ai/dashboard/api-keys" rel="nofollow">Mem0 API Key</a>
|
||||
- Google AI Studio API Key
|
||||
|
||||
## Basic Integration Example
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
---
|
||||
title: Hermes Agent
|
||||
description: "Add long-term memory to Hermes agents using Mem0 as a pluggable memory provider with automatic background sync and zero-latency prefetch."
|
||||
---
|
||||
|
||||
Add long-term memory to [Hermes Agent](https://github.com/NousResearch/hermes-agent) — a self-improving AI agent CLI by Nous Research. Hermes has a pluggable memory system, and Mem0 is one of the supported providers. Once enabled, Mem0 automatically learns facts from your conversations and surfaces relevant ones before each turn — all without slowing down the chat.
|
||||
|
||||
## Overview
|
||||
|
||||
Hermes runs a built-in memory system (file-based `MEMORY.md` and `USER.md`) alongside one external provider. When Mem0 is active, it works additively with the built-in system at three key moments in every conversation turn:
|
||||
|
||||
### 1. Before the Agent Responds (Prefetch)
|
||||
|
||||
When you send a message, Hermes checks if it already has cached Mem0 search results from the previous turn. If so, those memories are injected into the system prompt so the LLM can see them. This is **zero-latency** — no waiting for an API call.
|
||||
|
||||
### 2. After the Agent Responds (Sync)
|
||||
|
||||
Once the LLM finishes responding, Hermes sends the `(user message, assistant response)` pair to Mem0's API in a **background thread**. Mem0's server-side LLM automatically extracts facts (e.g., "user prefers Python", "user works at Acme Corp") — you don't have to tell it what to remember.
|
||||
|
||||
### 3. Background Prefetch for Next Turn
|
||||
|
||||
At the same time as sync, Hermes kicks off a background search on Mem0 to pre-load relevant memories for the next turn. By the time you type your next message, the memories are already cached.
|
||||
|
||||
## Agent Tools
|
||||
|
||||
When Mem0 is active, the LLM gets three extra tools it can call during conversations:
|
||||
|
||||
| Tool | Description |
|
||||
|------|-------------|
|
||||
| `mem0_profile` | Fetch all stored memories about the user |
|
||||
| `mem0_search` | Semantic search through memories (supports optional reranking via `rerank` and `top_k` parameters) |
|
||||
| `mem0_conclude` | Store a specific fact verbatim — uses `infer=False` so no server-side LLM extraction happens |
|
||||
|
||||
## Installation
|
||||
|
||||
Install Hermes Agent:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash
|
||||
source ~/.bashrc
|
||||
```
|
||||
|
||||
The `mem0ai` Python package is automatically installed when you enable the Mem0 provider — no manual pip install needed.
|
||||
|
||||
## Setup
|
||||
|
||||
### Option 1: Interactive Setup Wizard (Recommended)
|
||||
|
||||
```bash
|
||||
hermes memory setup
|
||||
```
|
||||
|
||||
Select **mem0** as the provider and enter your Mem0 API key when prompted. The wizard writes your config to `~/.hermes/mem0.json`.
|
||||
|
||||
<Note>Get your API key from <a href="https://app.mem0.ai" rel="nofollow">app.mem0.ai</a>.</Note>
|
||||
|
||||
### Option 2: Manual Configuration
|
||||
|
||||
```bash
|
||||
hermes config set memory.provider mem0
|
||||
echo "MEM0_API_KEY=your-api-key" >> ~/.hermes/.env
|
||||
```
|
||||
|
||||
Then in your `config.yaml`:
|
||||
|
||||
```yaml
|
||||
memory:
|
||||
provider: mem0
|
||||
```
|
||||
|
||||
That's it — Mem0 runs automatically from this point.
|
||||
|
||||
## Configuration Options
|
||||
|
||||
Configuration is stored in `~/.hermes/mem0.json`. Values can also be set via environment variables.
|
||||
|
||||
| Key | Env Variable | Default | Description |
|
||||
|-----|-------------|---------|-------------|
|
||||
| `api_key` | `MEM0_API_KEY` | — | **Required.** Mem0 Platform API key |
|
||||
| `user_id` | `MEM0_USER_ID` | `hermes-user` | User identifier for scoping memories |
|
||||
| `agent_id` | `MEM0_AGENT_ID` | `hermes` | Agent identifier |
|
||||
| `rerank` | — | `true` | Enable reranking for memory recall |
|
||||
|
||||
|
||||
## Reliability
|
||||
|
||||
- **Circuit Breaker** — If Mem0's API fails 5 times in a row, Hermes stops calling it for 2 minutes, then retries. The agent keeps working fine without memory during that time.
|
||||
- **Non-blocking** — All Mem0 API calls happen in background daemon threads. A slow or failed API call never blocks your conversation.
|
||||
- **Thread-safe** — The Mem0 client uses lazy initialization with locking, safe for concurrent access.
|
||||
|
||||
## Key Features
|
||||
|
||||
1. **Zero-Latency Recall** — Memories are prefetched in the background and cached, ready before you type
|
||||
2. **Server-side Extraction** — Mem0's API automatically extracts and deduplicates facts from each exchange
|
||||
3. **Non-blocking** — All API calls run in background daemon threads
|
||||
4. **Fault Tolerant** — Circuit breaker ensures the agent works even if Mem0 is temporarily unreachable
|
||||
5. **Additive Memory** — Works alongside Hermes' built-in file-based memory system (MEMORY.md, USER.md)
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="OpenClaw Integration" icon={<svg width="24" height="24" viewBox="0 0 500 500" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="m153.5 173.5q24.62 1.46 46 13.5 12.11 8.1 17.5 21.5 0.74 2.45 0.5 5 0.09 0.81 1 1 1.48-4.9 1-10 5.04 10.48 1.5 22-9.81 27.86-35.5 42.5-26.17 14.97-56 19.5-2.77-0.4-2 1 2.86 1.27 6 1 25.64 1.53 48.5-10 0.34 10.08 2 20 1.08 5.76 5 10 1 1.5 0 3-31.11 20.84-68.5 17.5-23.7-5.7-32.5-28.5-4.39-9.18-3.5-19 15.41 6.23 32 4.5-20.68-6.39-39-18-34.81-27.22-12.5-65.5 11.84-14.83 29-23 4.21 7.66 11.5 12.5 3 1 6 0-26.04-34.62-29-78-0.13-8.46 2-16.5 1 6.5 2 13 3.43 39.53 24.5 73 2.03 2.28 4.5 4 0.5-1.25 1-2.5-1.27-6.54-5-12 0.5-0.75 1-1.5 9.72-3.43 20-4 0.55 10.34 8 17.5 1.94 0.74 4 0.5-17.8-64.6 16.5-122 0.98-1.79 1.5 0-28.21 56.64-13.5 118 1.08 1.43 2.5 0.5 2.21-4.98 2-10.5z" fill="currentColor"/><path fill-rule="evenodd" d="m454.5 97.5q-1.33 11.18-8.5 20-21.81 26.28-55.5 32-1.11-0.2-2 0.5 2.31 2.82 5.5 4.5 1 2 0 4-9.56 11.3-19.5 20 19.71-8.72 31-27 2.68-0.43 5 1-14.24 30.97-48 36.5-9.93 1.71-20 1.5-6.8-0.48-13 1 5.81 6.92 14 11-10.78 16.03-27 26.5 27.16-7.4 38-33.5 4.34 1.35 9 1-9.08 23.84-33 33.5-18.45 6.41-38 7 22.59 8.92 45-1 12.05-5.52 24-11 9.01-1.79 17 2.5 5.28-4.38 11-8 12.8-6.07 27-5 0 0.5 0 1-19.34 2.69-34 15.5 0.5 0.25 1 0.5 17.79-8.09 36-15 2.71-0.79 5-2 2.5-1 5-2 5.53-4.04 11-8 11.7-4.18 24-6.5 7.78-1.36 15 1.5-2.97 18.45-13.5 34-34.92 49.37-94.5 62.5-59.27 12.45-108-23-15.53-12.52-21.5-31.5-2.47-14.26 4-27-3.15 24.41 14 42-4.92-10.28-7-22-1.97-17.63 7-33 47.28-69.5 125.5-100 15.86-3.42 32-5.5 18.63-1.47 37 1.5z" fill="currentColor"/><path fill-rule="evenodd" d="m231.5 238.5q1.31-0.2 2 1-3.13 28.62 15 51-16.25 6.75-27-7.5-1-1-2 0 14.73 29.34 46 18.5 1.79 0.52 0 1.5-37.63 16.82-50.5-22.5-5.1-26.48 16.5-42z" fill="currentColor"/><path fill-rule="evenodd" d="m203.5 266.5q1.31-0.2 2 1-2.48 22.08 12 39-6.99 1.35-14 0.5 4.59 4.08 10 7-8.71 0.28-14.5-6.5-16.98-22.76 4.5-41z" fill="currentColor"/><path fill-rule="evenodd" d="m58.5 284.5q9.6-2.17 14.5 6 5.15 14.18-1 28-11.05-13.14-27.5-17.5 5.15-9.9 14-16.5z" fill="currentColor"/><path fill-rule="evenodd" d="m56.5 313.5q3.43 5.43 8 10-4.88 0.44-8 4-1.11-0.2-2 0.5 28.91 1.65 38 28.5 0.45 3.16-1 6-11.02-7.01-23-12.5-4.75-3.75-9.5-7.5 1.47 7.42 7 13 8.34 27.18 32 43 0.99 2.41-1.5 3.5-40.25 5.58-66.5-25.5-15.67-22.01-8-48 10.46-23.87 34.5-15z" fill="currentColor"/><path fill-rule="evenodd" d="m198.5 319.5q1.44 0.68 2.5 2 2.41 8.23 6 16 1.2 2.64-0.5 5-30.65 21.41-68 18.5-25.16-6.17-32.5-30.5 6.96 4.99 15.5 6.5 8.99 0.75 18 0.5 16.25 2.38 32-2.5 15.9-3.94 27-15.5z" fill="currentColor"/><path fill-rule="evenodd" d="m239.5 342.5q7.02-0.25 14 0.5 4.46 1.06 8 3.5-5.2 2.35-10 5.5-3.88 4.65-9 7.5-9.89-3.09-9.5-13 2.36-3.63 6.5-4z" fill="currentColor"/><path fill-rule="evenodd" d="m214.5 349.5q5.96 7.2 13.5 13 1 1 0 2-28.58 23.34-65.5 20.5-18.15-4.24-27.5-19.5 1.13 0.94 2.5 1.5 14.7 1.42 29-1.5 26.57-0.52 48-16z" fill="currentColor"/><path fill-rule="evenodd" d="m302.5 373.5q0.21 2.44-2 3.5-28.69 7.6-50.5-12.5-0.06-6.71 6.5-9 4.45-0.75 9-1 22.26 2.27 37 19z" fill="currentColor"/><path fill-rule="evenodd" d="m232.5 365.5q17.6 6.19 10.5 23-10.6 10.42-25.5 11.5-25.94 3.21-49-9 36.75-1.65 64-25.5z" fill="currentColor"/><path fill-rule="evenodd" d="m113.5 367.5q7.7-0.01 9.5 7-9.69 7.19-18.5 15.5-7.23 5.76-5.5-3.5 3.12-12.84 14.5-19z" fill="currentColor"/><path fill-rule="evenodd" d="m126.5 380.5q7.88-0.4 12 6.5-8.5 7.25-17 14.5-5.62-12.55 5-21z" fill="currentColor"/><path fill-rule="evenodd" d="m283.5 385.5q3.22 2.95 7 5.5 2.8 4.03 6 7.5 0.42 2.77-2 4-15.5-9.75-31-19.5-1.79-0.98 0-1.5 9.96 2.49 20 4z" fill="currentColor"/></svg>} href="/integrations/openclaw">
|
||||
Add memory to OpenClaw agents with auto-recall and auto-capture
|
||||
</Card>
|
||||
<Card title="Mem0 Platform" icon="rocket" href="/platform/overview">
|
||||
Get your API key and explore the Mem0 dashboard
|
||||
</Card>
|
||||
</CardGroup>
|
||||
@@ -16,7 +16,7 @@ Combining Mem0 with Keywords AI allows you to:
|
||||
4. Optimize token usage and reduce costs
|
||||
|
||||
<Note>
|
||||
You can get your Mem0 API key, user_id, and org_id from the [Mem0 dashboard](https://app.mem0.ai/). These are required for proper integration.
|
||||
You can get your Mem0 API key, user_id, and org_id from the <a href="https://app.mem0.ai/" rel="nofollow">Mem0 dashboard</a>. These are required for proper integration.
|
||||
</Note>
|
||||
|
||||
## Setup and Configuration
|
||||
|
||||
@@ -22,7 +22,7 @@ pip install langchain langchain_openai mem0ai python-dotenv
|
||||
|
||||
Import required modules and set up configurations:
|
||||
|
||||
<Note>Remember to get the Mem0 API key from [Mem0 Platform](https://app.mem0.ai).</Note>
|
||||
<Note>Remember to get the Mem0 API key from <a href="https://app.mem0.ai" rel="nofollow">Mem0 Platform</a>.</Note>
|
||||
|
||||
```python
|
||||
import os
|
||||
|
||||
@@ -23,7 +23,7 @@ pip install langgraph langchain-openai mem0ai python-dotenv
|
||||
|
||||
Import required modules and set up configurations:
|
||||
|
||||
<Note>Remember to get the Mem0 API key from [Mem0 Platform](https://app.mem0.ai).</Note>
|
||||
<Note>Remember to get the Mem0 API key from <a href="https://app.mem0.ai" rel="nofollow">Mem0 Platform</a>.</Note>
|
||||
|
||||
```python
|
||||
from typing import Annotated, TypedDict, List
|
||||
|
||||
@@ -22,7 +22,7 @@ pip install llama-index-core llama-index-memory-mem0 python-dotenv
|
||||
Set your Mem0 Platform API key as an environment variable. You can replace `<your-mem0-api-key>` with your actual API key:
|
||||
|
||||
<Note type="info">
|
||||
You can obtain your Mem0 Platform API key from the [Mem0 Platform](https://app.mem0.ai/login).
|
||||
You can obtain your Mem0 Platform API key from the <a href="https://app.mem0.ai/login" rel="nofollow">Mem0 Platform</a>.
|
||||
</Note>
|
||||
|
||||
```python
|
||||
|
||||
@@ -23,7 +23,7 @@ npm install @mastra/core @mastra/mem0 @ai-sdk/openai zod
|
||||
|
||||
Set up your environment variables:
|
||||
|
||||
<Note>Remember to get the Mem0 API key from [Mem0 Platform](https://app.mem0.ai).</Note>
|
||||
<Note>Remember to get the Mem0 API key from <a href="https://app.mem0.ai" rel="nofollow">Mem0 Platform</a>.</Note>
|
||||
|
||||
```bash
|
||||
MEM0_API_KEY=your-mem0-api-key
|
||||
|
||||
@@ -22,7 +22,7 @@ pip install openai-agents mem0ai
|
||||
```
|
||||
|
||||
2. Valid API keys:
|
||||
- [Mem0 API Key](https://app.mem0.ai/dashboard/api-keys)
|
||||
- <a href="https://app.mem0.ai/dashboard/api-keys" rel="nofollow">Mem0 API Key</a>
|
||||
- [OpenAI API Key](https://platform.openai.com/api-keys)
|
||||
|
||||
## Basic Integration Example
|
||||
|
||||
@@ -42,7 +42,7 @@ All memories are scoped to this `userId` — different values create separate me
|
||||
|
||||
### Platform Mode (Mem0 Cloud)
|
||||
|
||||
<Note>Get your API key from [app.mem0.ai](https://app.mem0.ai).</Note>
|
||||
<Note>Get your API key from <a href="https://app.mem0.ai" rel="nofollow">app.mem0.ai</a>.</Note>
|
||||
|
||||
Add to your `openclaw.json`:
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ Mem0 is a self-improving memory layer for LLM applications, enabling personalize
|
||||
|
||||
**Get your API Key**: You'll need a Mem0 API key to use this extension:
|
||||
|
||||
a. Sign up at [app.mem0.ai](https://app.mem0.ai)
|
||||
a. Sign up at <a href="https://app.mem0.ai" rel="nofollow">app.mem0.ai</a>
|
||||
|
||||
b. Navigate to your API Keys page
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ npm install @mem0/vercel-ai-provider
|
||||
|
||||
### Setting Up Mem0
|
||||
|
||||
1. Get your **Mem0 API Key** from the [Mem0 Dashboard](https://app.mem0.ai/dashboard/api-keys).
|
||||
1. Get your **Mem0 API Key** from the <a href="https://app.mem0.ai/dashboard/api-keys" rel="nofollow">Mem0 Dashboard</a>.
|
||||
|
||||
2. Initialize the Mem0 Client in your application:
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ Move your Mem0 implementation to managed infrastructure with enterprise features
|
||||
|
||||
## Plan
|
||||
|
||||
1. **Sign up**: Create an account on [Mem0 Platform](https://app.mem0.ai).
|
||||
1. **Sign up**: Create an account on <a href="https://app.mem0.ai" rel="nofollow">Mem0 Platform</a>.
|
||||
2. **Get API Key**: Navigate to **Settings > API Keys** and generate a new key.
|
||||
3. **Review Usage**: Identify where you instantiate `Memory` and where you call `search` or `get_all`.
|
||||
|
||||
@@ -368,7 +368,7 @@ If you encounter issues, you can revert immediately by switching your import bac
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Platform Dashboard](https://app.mem0.ai) - Monitor usage and manage settings.
|
||||
- <a href="https://app.mem0.ai" rel="nofollow">Platform Dashboard</a> - Monitor usage and manage settings.
|
||||
- [Webhooks Setup](/platform/features/webhooks) - Configure real-time event notifications.
|
||||
- [Organizations & Projects](/api-reference/organizations-projects) - Set up multi-tenancy for your team.
|
||||
|
||||
|
||||
@@ -3686,6 +3686,10 @@
|
||||
"type": "object"
|
||||
},
|
||||
"description": "List of custom categories to be used for memory categorization."
|
||||
},
|
||||
"multilingual": {
|
||||
"type": "boolean",
|
||||
"description": "Whether to use the input language for memory storage and retrieval."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,8 +7,8 @@ estimatedTime: "~2 minutes"
|
||||
|
||||
<Info>
|
||||
**Prerequisites**
|
||||
- Mem0 Platform account ([Sign up here](https://app.mem0.ai))
|
||||
- API key ([Get one from dashboard](https://app.mem0.ai/settings/api-keys))
|
||||
- Mem0 Platform account (<a href="https://app.mem0.ai" rel="nofollow">Sign up here</a>)
|
||||
- API key (<a href="https://app.mem0.ai/settings/api-keys" rel="nofollow">Get one from dashboard</a>)
|
||||
- Node.js 14+ (for npx)
|
||||
- An MCP-compatible client (Claude, Claude Code, Cursor, Windsurf, VS Code, OpenCode)
|
||||
</Info>
|
||||
@@ -163,7 +163,7 @@ Agent: Updated your project status successfully.
|
||||
```
|
||||
|
||||
<Info icon="check">
|
||||
If you get "Connection failed", ensure you have a valid API key from [Mem0 Dashboard](https://app.mem0.ai/settings/api-keys).
|
||||
If you get "Connection failed", ensure you have a valid API key from <a href="https://app.mem0.ai/settings/api-keys" rel="nofollow">Mem0 Dashboard</a>.
|
||||
</Info>
|
||||
|
||||
---
|
||||
@@ -171,7 +171,7 @@ Agent: Updated your project status successfully.
|
||||
## Quick Recovery
|
||||
|
||||
- **"Connection refused"** → Check your internet connection and ensure the MCP client is correctly configured
|
||||
- **"Invalid API key"** → Get a new key from [Mem0 Dashboard](https://app.mem0.ai/settings/api-keys)
|
||||
- **"Invalid API key"** → Get a new key from <a href="https://app.mem0.ai/settings/api-keys" rel="nofollow">Mem0 Dashboard</a>
|
||||
- **"npx command not found"** → Install Node.js from [nodejs.org](https://nodejs.org)
|
||||
|
||||
---
|
||||
|
||||
@@ -64,7 +64,7 @@ Mem0 is the memory engine that keeps conversations contextual so users never rep
|
||||
<Card title="Connect Integrations" icon="plug" href="/integrations">
|
||||
LangChain, CrewAI, Vercel AI SDK.
|
||||
</Card>
|
||||
<Card title="Monitor in the Dashboard" icon="presentation" href="https://app.mem0.ai">
|
||||
<Card title="Monitor in the Dashboard" icon="presentation" href="https://app.mem0.ai/login">
|
||||
Track activity and manage workspaces.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -150,7 +150,7 @@ Mem0 offers two powerful ways to add memory to your AI applications. Choose base
|
||||
<Card
|
||||
title="Try Platform Free"
|
||||
icon="rocket"
|
||||
href="https://app.mem0.ai"
|
||||
href="https://app.mem0.ai/login"
|
||||
>
|
||||
Sign up and test the Platform with our free tier. No credit card required.
|
||||
</Card>
|
||||
|
||||
@@ -9,8 +9,8 @@ Get started with Mem0 Platform's hosted API in under 5 minutes. This guide shows
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Mem0 Platform account ([Sign up here](https://app.mem0.ai))
|
||||
- API key ([Get one from dashboard](https://app.mem0.ai/dashboard/settings?tab=api-keys&subtab=configuration))
|
||||
- Mem0 Platform account (<a href="https://app.mem0.ai" rel="nofollow">Sign up here</a>)
|
||||
- API key (<a href="https://app.mem0.ai/dashboard/settings?tab=api-keys&subtab=configuration" rel="nofollow">Get one from dashboard</a>)
|
||||
- Python 3.10+, Node.js 14+, or cURL
|
||||
|
||||
## Installation
|
||||
|
||||
+2
-2
@@ -12,7 +12,7 @@ We follow the llms.txt standard:
|
||||
- [llms.txt](https://docs.mem0.ai/llms.txt)
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Get an API Key" icon="key" href="https://app.mem0.ai">
|
||||
<Card title="Get an API Key" icon="key" href="https://app.mem0.ai/login">
|
||||
Sign up for Mem0 Platform and start building
|
||||
</Card>
|
||||
<Card title="Quickstart" icon="rocket" href="/platform/quickstart">
|
||||
@@ -34,7 +34,7 @@ Works with Claude Code, Cursor, Windsurf, and any assistant that supports skills
|
||||
|
||||
Connect Claude, Claude Code, Cursor, Windsurf, VS Code, OpenCode, or any MCP-compatible client to Mem0.
|
||||
|
||||
Get your API key from [app.mem0.ai](https://app.mem0.ai), then add Mem0 MCP with a single command:
|
||||
Get your API key from <a href="https://app.mem0.ai" rel="nofollow">app.mem0.ai</a>, then add Mem0 MCP with a single command:
|
||||
|
||||
```bash
|
||||
npx mcp-add \
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"mem0": {
|
||||
"url": "https://mcp.mem0.ai/mcp/",
|
||||
"bearer_token_env_var": "MEM0_API_KEY"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"name": "mem0",
|
||||
"version": "0.1.0",
|
||||
"description": "Mem0 memory layer for AI applications. Add persistent memory, personalization, and semantic search to Codex workflows using the Mem0 Platform MCP server.",
|
||||
"author": {
|
||||
"name": "Mem0",
|
||||
"email": "support@mem0.ai"
|
||||
},
|
||||
"homepage": "https://mem0.ai",
|
||||
"repository": "https://github.com/mem0ai/mem0",
|
||||
"license": "Apache-2.0",
|
||||
"skills": "./skills/",
|
||||
"mcpServers": "./.codex-mcp.json",
|
||||
"interface": {
|
||||
"displayName": "Mem0",
|
||||
"shortDescription": "Persistent memory layer for AI coding workflows",
|
||||
"longDescription": "Mem0 adds long-term memory to Codex. Store decisions, user preferences, project context, and session state across conversations. Memories are automatically retrieved via semantic search so Codex always has the right context.",
|
||||
"developerName": "Mem0",
|
||||
"category": "Productivity",
|
||||
"capabilities": [
|
||||
"Read",
|
||||
"Write"
|
||||
],
|
||||
"websiteURL": "https://mem0.ai",
|
||||
"privacyPolicyURL": "https://mem0.ai/privacy",
|
||||
"termsOfServiceURL": "https://mem0.ai/terms",
|
||||
"defaultPrompt": [
|
||||
"Search my memories for recent project decisions",
|
||||
"Remember that I prefer TypeScript over JavaScript",
|
||||
"What do you know about my coding preferences?"
|
||||
],
|
||||
"brandColor": "#FBBF24",
|
||||
"logo": "./logo.svg"
|
||||
}
|
||||
}
|
||||
+69
-8
@@ -1,6 +1,6 @@
|
||||
# Mem0 Plugin for Claude Code, Claude Cowork & Cursor
|
||||
# Mem0 Plugin for Claude Code, Claude Cowork, Cursor & Codex
|
||||
|
||||
Add persistent memory to your AI workflows. Store, retrieve, and manage memories across sessions using the Mem0 Platform. Works with **Claude Code** (CLI), **Claude Cowork** (desktop app), and **Cursor**.
|
||||
Add persistent memory to your AI workflows. Store, retrieve, and manage memories across sessions using the Mem0 Platform. Works with **Claude Code** (CLI), **Claude Cowork** (desktop app), **Cursor**, and **Codex**.
|
||||
|
||||
## Step 1: Set your API key
|
||||
|
||||
@@ -47,6 +47,65 @@ Claude Code and Claude Cowork share the same plugin system.
|
||||
|
||||
This installs the full plugin including the MCP server, lifecycle hooks (automatic memory capture), and the Mem0 SDK skill.
|
||||
|
||||
### Codex
|
||||
|
||||
**Option A — Repo marketplace** (recommended for teams):
|
||||
|
||||
Add the plugin marketplace to your repo root (already included in this repository):
|
||||
|
||||
```
|
||||
.agents/plugins/marketplace.json
|
||||
```
|
||||
|
||||
Then in Codex, browse the repo's plugin directory and install Mem0.
|
||||
|
||||
**Option B — Personal marketplace**:
|
||||
|
||||
Add to `~/.agents/plugins/marketplace.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "mem0-plugins",
|
||||
"interface": {
|
||||
"displayName": "Mem0 Plugins"
|
||||
},
|
||||
"plugins": [
|
||||
{
|
||||
"name": "mem0",
|
||||
"source": {
|
||||
"source": "local",
|
||||
"path": "/path/to/mem0/mem0-plugin"
|
||||
},
|
||||
"policy": {
|
||||
"installation": "AVAILABLE",
|
||||
"authentication": "ON_INSTALL"
|
||||
},
|
||||
"category": "Productivity"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Option C — Manual MCP configuration**:
|
||||
|
||||
Add to your Codex MCP config:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"mem0": {
|
||||
"type": "http",
|
||||
"url": "https://mcp.mem0.ai/mcp/",
|
||||
"headers": {
|
||||
"Authorization": "Token ${MEM0_API_KEY}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This installs the MCP server and the Mem0 SDK skill. Codex uses the skill-based memory protocol instead of lifecycle hooks.
|
||||
|
||||
### Cursor
|
||||
|
||||
> **Already have `mem0` configured as an MCP server?** Remove the existing entry from your Cursor MCP settings before installing to avoid duplicate tools.
|
||||
@@ -86,15 +145,17 @@ After installing, confirm the MCP server is connected:
|
||||
|
||||
## What's included
|
||||
|
||||
| Component | Claude Code / Cowork | Cursor (Marketplace) | Cursor (Deeplink/Manual) |
|
||||
|-----------|:--------------------:|:--------------------:|:------------------------:|
|
||||
| MCP Server | Yes | Yes | Yes |
|
||||
| Lifecycle Hooks | Yes | Yes | No |
|
||||
| Mem0 SDK Skill | Yes | Yes | No |
|
||||
| Component | Claude Code / Cowork | Cursor (Marketplace) | Cursor (Deeplink/Manual) | Codex |
|
||||
|-----------|:--------------------:|:--------------------:|:------------------------:|:-----:|
|
||||
| MCP Server | Yes | Yes | Yes | Yes |
|
||||
| Lifecycle Hooks | Yes | Yes | No | No |
|
||||
| Mem0 SDK Skill | Yes | Yes | No | Yes |
|
||||
| Memory Protocol Skill | No | No | No | Yes |
|
||||
|
||||
- **MCP Server** — Connects to the Mem0 remote MCP server (`mcp.mem0.ai`), providing tools to add, search, update, and delete memories. No local dependencies required.
|
||||
- **Lifecycle Hooks** — Automatic memory capture at key points: session start, context compaction, task completion, and session end.
|
||||
- **Lifecycle Hooks** — Automatic memory capture at key points: session start, context compaction, task completion, and session end. (Claude Code/Cursor only)
|
||||
- **Mem0 SDK Skill** — Guides the AI on how to integrate the Mem0 SDK (Python & TypeScript) into your applications.
|
||||
- **Memory Protocol Skill** — Codex-specific skill that instructs the agent to retrieve relevant memories at task start, store learnings on completion, and capture session state before context loss. Replaces lifecycle hooks on platforms that don't support them.
|
||||
|
||||
## MCP Tools
|
||||
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
---
|
||||
name: mem0-codex
|
||||
description: >
|
||||
Mem0 persistent memory integration for Codex. Automatically retrieve relevant
|
||||
memories at the start of each task, store key learnings when tasks complete,
|
||||
and capture session state before context is lost. Use the mem0 MCP tools
|
||||
(add_memory, search_memories, get_memories, etc.) for all memory operations.
|
||||
---
|
||||
|
||||
# Mem0 Memory Protocol for Codex
|
||||
|
||||
You have access to persistent memory via the mem0 MCP tools. Follow this protocol to maintain context across sessions.
|
||||
|
||||
## On every new task
|
||||
|
||||
1. Call `search_memories` with a query related to the current task or project to load relevant context.
|
||||
2. Review returned memories to understand what has been learned in prior sessions.
|
||||
3. If appropriate, call `get_memories` to browse all stored memories for this user.
|
||||
|
||||
## After completing significant work
|
||||
|
||||
Extract key learnings and store them using the `add_memory` tool:
|
||||
|
||||
- **Decisions made** -> Include metadata `{"type": "decision"}`
|
||||
- **Strategies that worked** -> Include metadata `{"type": "task_learning"}`
|
||||
- **Failed approaches** -> Include metadata `{"type": "anti_pattern"}`
|
||||
- **User preferences observed** -> Include metadata `{"type": "user_preference"}`
|
||||
- **Environment/setup discoveries** -> Include metadata `{"type": "environmental"}`
|
||||
- **Conventions established** -> Include metadata `{"type": "convention"}`
|
||||
|
||||
Memories can be as detailed as needed -- include full context, reasoning, code snippets, file paths, and examples. Longer, searchable memories are more valuable than vague one-liners.
|
||||
|
||||
## Before losing context
|
||||
|
||||
If context is about to be compacted or the session is ending, store a comprehensive session summary:
|
||||
|
||||
```
|
||||
## Session Summary
|
||||
|
||||
### User's Goal
|
||||
[What the user originally asked for]
|
||||
|
||||
### What Was Accomplished
|
||||
[Numbered list of tasks completed]
|
||||
|
||||
### Key Decisions Made
|
||||
[Architectural choices, trade-offs discussed]
|
||||
|
||||
### Files Created or Modified
|
||||
[Important file paths with what changed]
|
||||
|
||||
### Current State
|
||||
[What is in progress, pending items, next steps]
|
||||
```
|
||||
|
||||
Include metadata: `{"type": "session_state"}`
|
||||
|
||||
## Memory hygiene
|
||||
|
||||
- Do NOT write to MEMORY.md or any file-based memory. Use mem0 MCP tools exclusively.
|
||||
- Only store genuinely useful learnings. Skip trivial interactions.
|
||||
- Use specific, searchable language in memory content.
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mem0ai",
|
||||
"version": "2.4.5",
|
||||
"version": "2.4.6",
|
||||
"description": "The Memory Layer For Your AI Apps",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.mjs",
|
||||
@@ -68,6 +68,11 @@
|
||||
"!src/community/**"
|
||||
]
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mem0ai/mem0",
|
||||
"directory": "mem0-ts"
|
||||
},
|
||||
"keywords": [
|
||||
"mem0",
|
||||
"api",
|
||||
|
||||
@@ -167,6 +167,7 @@ export interface PromptUpdatePayload {
|
||||
exclusion_prompt?: string;
|
||||
memory_depth?: string | null;
|
||||
usecase_setting?: string | number;
|
||||
multilingual?: boolean;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import { OpenAILLM } from "./openai";
|
||||
import { LLMConfig, Message } from "../types";
|
||||
import { LLMResponse } from "./base";
|
||||
|
||||
export class DeepSeekLLM extends OpenAILLM {
|
||||
constructor(config: LLMConfig) {
|
||||
const apiKey = config.apiKey || process.env.DEEPSEEK_API_KEY;
|
||||
if (!apiKey) {
|
||||
throw new Error("DeepSeek API key is required");
|
||||
}
|
||||
super({
|
||||
...config,
|
||||
apiKey,
|
||||
baseURL:
|
||||
config.baseURL ||
|
||||
process.env.DEEPSEEK_API_BASE ||
|
||||
"https://api.deepseek.com",
|
||||
model: config.model || "deepseek-chat",
|
||||
});
|
||||
}
|
||||
|
||||
async generateResponse(
|
||||
messages: Message[],
|
||||
responseFormat?: { type: string },
|
||||
tools?: any[],
|
||||
): Promise<string | LLMResponse> {
|
||||
try {
|
||||
return await super.generateResponse(messages, responseFormat, tools);
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
throw new Error(`DeepSeek LLM failed: ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async generateChat(messages: Message[]): Promise<LLMResponse> {
|
||||
try {
|
||||
return await super.generateChat(messages);
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
throw new Error(`DeepSeek LLM failed: ${message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,7 @@ import { LangchainEmbedder } from "../embeddings/langchain";
|
||||
import { LangchainVectorStore } from "../vector_stores/langchain";
|
||||
import { AzureAISearch } from "../vector_stores/azure_ai_search";
|
||||
import { PGVector } from "../vector_stores/pgvector";
|
||||
import { DeepSeekLLM } from "../llms/deepseek";
|
||||
|
||||
export class EmbedderFactory {
|
||||
static create(provider: string, config: EmbeddingConfig): Embedder {
|
||||
@@ -82,6 +83,8 @@ export class LLMFactory {
|
||||
return new MistralLLM(config);
|
||||
case "langchain":
|
||||
return new LangchainLLM(config);
|
||||
case "deepseek":
|
||||
return new DeepSeekLLM(config);
|
||||
default:
|
||||
throw new Error(`Unsupported LLM provider: ${provider}`);
|
||||
}
|
||||
|
||||
@@ -14,6 +14,25 @@ try {
|
||||
const POSTHOG_API_KEY = "phc_hgJkUVJFYtmaJqrvf6CYN67TIQ8yhXAkWzUn9AMU4yX";
|
||||
const POSTHOG_HOST = "https://us.i.posthog.com/i/v0/e/";
|
||||
|
||||
// Default sampling rate for hot-path OSS events. Lifecycle events always fire at 100%.
|
||||
// Override via MEM0_TELEMETRY_SAMPLE_RATE env var. Mirrors mem0/memory/telemetry.py.
|
||||
const DEFAULT_SAMPLE_RATE = 0.1;
|
||||
const MEM0_TELEMETRY_SAMPLE_RATE: number = ((): number => {
|
||||
try {
|
||||
const raw = process?.env?.MEM0_TELEMETRY_SAMPLE_RATE;
|
||||
if (raw !== undefined) {
|
||||
const parsed = Number(raw);
|
||||
if (Number.isFinite(parsed) && parsed >= 0 && parsed <= 1) {
|
||||
return parsed;
|
||||
}
|
||||
}
|
||||
} catch {}
|
||||
return DEFAULT_SAMPLE_RATE;
|
||||
})();
|
||||
|
||||
// Events that bypass sampling. Keep in sync with _captureEvent call sites in memory/index.ts.
|
||||
const LIFECYCLE_EVENTS: ReadonlySet<string> = new Set(["init", "reset"]);
|
||||
|
||||
class UnifiedTelemetry implements TelemetryClient {
|
||||
private apiKey: string;
|
||||
private host: string;
|
||||
@@ -78,6 +97,12 @@ async function captureClientEvent(
|
||||
return;
|
||||
}
|
||||
|
||||
// >= so that rate=0 drops everything and rate=1 keeps everything (Math.random() ∈ [0, 1)).
|
||||
const isLifecycle = LIFECYCLE_EVENTS.has(eventName);
|
||||
if (!isLifecycle && Math.random() >= MEM0_TELEMETRY_SAMPLE_RATE) {
|
||||
return;
|
||||
}
|
||||
|
||||
const eventData: TelemetryEventData = {
|
||||
function: `${instance.constructor.name}`,
|
||||
method: eventName,
|
||||
@@ -86,6 +111,8 @@ async function captureClientEvent(
|
||||
client_version: version,
|
||||
client_source: "nodejs",
|
||||
...additionalData,
|
||||
// sample_rate set AFTER the spread so callers can never override it
|
||||
sample_rate: isLifecycle ? 1.0 : MEM0_TELEMETRY_SAMPLE_RATE,
|
||||
};
|
||||
|
||||
await telemetry.captureEvent(
|
||||
|
||||
@@ -23,6 +23,8 @@ export interface TelemetryEventData {
|
||||
timestamp?: string;
|
||||
client_source: "browser" | "nodejs";
|
||||
client_version: string;
|
||||
/** Set by the sampling layer so PostHog dashboards can extrapolate via 1/sample_rate. */
|
||||
sample_rate?: number;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
/// <reference types="jest" />
|
||||
/**
|
||||
* DeepSeek LLM — unit tests (mocked OpenAI).
|
||||
*/
|
||||
|
||||
import { DeepSeekLLM } from "../src/llms/deepseek";
|
||||
|
||||
const mockCreate = jest.fn();
|
||||
|
||||
jest.mock("openai", () => {
|
||||
return jest.fn().mockImplementation(() => ({
|
||||
chat: { completions: { create: mockCreate } },
|
||||
}));
|
||||
});
|
||||
|
||||
describe("DeepSeekLLM (unit)", () => {
|
||||
beforeEach(() => mockCreate.mockClear());
|
||||
|
||||
it("throws when no API key is provided", () => {
|
||||
const original = process.env.DEEPSEEK_API_KEY;
|
||||
delete process.env.DEEPSEEK_API_KEY;
|
||||
try {
|
||||
expect(() => new DeepSeekLLM({})).toThrow("DeepSeek API key is required");
|
||||
} finally {
|
||||
if (original !== undefined) process.env.DEEPSEEK_API_KEY = original;
|
||||
}
|
||||
});
|
||||
|
||||
it("generateResponse() returns a text response", async () => {
|
||||
mockCreate.mockResolvedValueOnce({
|
||||
choices: [
|
||||
{
|
||||
message: {
|
||||
content: "Hello, world!",
|
||||
role: "assistant",
|
||||
tool_calls: null,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const llm = new DeepSeekLLM({ apiKey: "test-key" });
|
||||
const result = await llm.generateResponse([
|
||||
{ role: "user", content: "Hi" },
|
||||
]);
|
||||
|
||||
expect(mockCreate).toHaveBeenCalledTimes(1);
|
||||
expect(result).toBe("Hello, world!");
|
||||
});
|
||||
|
||||
it("generateResponse() handles tool calls", async () => {
|
||||
mockCreate.mockResolvedValueOnce({
|
||||
choices: [
|
||||
{
|
||||
message: {
|
||||
content: "",
|
||||
role: "assistant",
|
||||
tool_calls: [
|
||||
{
|
||||
function: {
|
||||
name: "get_weather",
|
||||
arguments: '{"city": "London"}',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const llm = new DeepSeekLLM({ apiKey: "test-key" });
|
||||
const result = await llm.generateResponse(
|
||||
[{ role: "user", content: "What is the weather?" }],
|
||||
undefined,
|
||||
[{ type: "function", function: { name: "get_weather" } }],
|
||||
);
|
||||
|
||||
expect(result).toEqual({
|
||||
content: "",
|
||||
role: "assistant",
|
||||
toolCalls: [{ name: "get_weather", arguments: '{"city": "London"}' }],
|
||||
});
|
||||
});
|
||||
|
||||
it("generateResponse() wraps API errors with a clear message", async () => {
|
||||
mockCreate.mockRejectedValueOnce(new Error("Connection refused"));
|
||||
|
||||
const llm = new DeepSeekLLM({ apiKey: "test-key" });
|
||||
|
||||
await expect(
|
||||
llm.generateResponse([{ role: "user", content: "Hi" }]),
|
||||
).rejects.toThrow("DeepSeek LLM failed: Connection refused");
|
||||
});
|
||||
|
||||
it("generateChat() returns LLMResponse shape", async () => {
|
||||
mockCreate.mockResolvedValueOnce({
|
||||
choices: [
|
||||
{
|
||||
message: { content: "I can help with that.", role: "assistant" },
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const llm = new DeepSeekLLM({ apiKey: "test-key" });
|
||||
const result = await llm.generateChat([
|
||||
{ role: "user", content: "Help me" },
|
||||
]);
|
||||
|
||||
expect(result).toEqual({
|
||||
content: "I can help with that.",
|
||||
role: "assistant",
|
||||
});
|
||||
});
|
||||
|
||||
it("generateChat() wraps API errors with a clear message", async () => {
|
||||
mockCreate.mockRejectedValueOnce(new Error("Timeout"));
|
||||
|
||||
const llm = new DeepSeekLLM({ apiKey: "test-key" });
|
||||
|
||||
await expect(
|
||||
llm.generateChat([{ role: "user", content: "Hi" }]),
|
||||
).rejects.toThrow("DeepSeek LLM failed: Timeout");
|
||||
});
|
||||
});
|
||||
@@ -87,6 +87,11 @@ jest.mock("../src/llms/lmstudio", () => ({
|
||||
.fn()
|
||||
.mockImplementation((config) => ({ type: "lmstudio-llm", config })),
|
||||
}));
|
||||
jest.mock("../src/llms/deepseek", () => ({
|
||||
DeepSeekLLM: jest
|
||||
.fn()
|
||||
.mockImplementation((config) => ({ type: "deepseek-llm", config })),
|
||||
}));
|
||||
|
||||
jest.mock("../src/vector_stores/qdrant", () => ({
|
||||
Qdrant: jest
|
||||
@@ -200,6 +205,7 @@ describe("LLMFactory", () => {
|
||||
["mistral"],
|
||||
["langchain"],
|
||||
["lmstudio"],
|
||||
["deepseek"],
|
||||
])("creates LLM for provider '%s'", (provider) => {
|
||||
expect(() => LLMFactory.create(provider, dummyLLMConfig)).not.toThrow();
|
||||
});
|
||||
|
||||
@@ -0,0 +1,211 @@
|
||||
/// <reference types="jest" />
|
||||
/**
|
||||
* Telemetry sampling — unit tests.
|
||||
*
|
||||
* Sampling lives inside captureClientEvent in src/utils/telemetry.ts. It uses
|
||||
* Math.random() compared against MEM0_TELEMETRY_SAMPLE_RATE (default 0.1) to
|
||||
* drop hot-path events; lifecycle events ('init', 'reset') always fire.
|
||||
*
|
||||
* These tests target captureClientEvent directly. Existing OSS tests that mock
|
||||
* captureClientEvent (vector-stores-compat, dimension-autodetect, config-manager)
|
||||
* are unaffected because the function signature and contract are unchanged.
|
||||
*/
|
||||
|
||||
import type { TelemetryInstance } from "../src/utils/telemetry.types";
|
||||
|
||||
// Helper to make a fake TelemetryInstance.
|
||||
function makeInstance(
|
||||
overrides: Partial<TelemetryInstance> = {},
|
||||
): TelemetryInstance {
|
||||
return {
|
||||
telemetryId: "test-id",
|
||||
constructor: { name: "Memory" },
|
||||
host: "https://test.example.com",
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
describe("telemetry sampling", () => {
|
||||
let originalFetch: typeof global.fetch;
|
||||
let fetchMock: jest.Mock;
|
||||
let randomSpy: jest.SpyInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
originalFetch = global.fetch;
|
||||
fetchMock = jest.fn().mockResolvedValue({
|
||||
ok: true,
|
||||
text: jest.fn().mockResolvedValue(""),
|
||||
});
|
||||
global.fetch = fetchMock as any;
|
||||
randomSpy = jest.spyOn(Math, "random");
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
global.fetch = originalFetch;
|
||||
randomSpy.mockRestore();
|
||||
jest.resetModules();
|
||||
});
|
||||
|
||||
describe("lifecycle events always fire", () => {
|
||||
it("init event fires even at the highest random value", async () => {
|
||||
randomSpy.mockReturnValue(0.999);
|
||||
const { captureClientEvent } = await import("../src/utils/telemetry");
|
||||
await captureClientEvent("init", makeInstance());
|
||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("reset event fires even at the highest random value", async () => {
|
||||
randomSpy.mockReturnValue(0.999);
|
||||
const { captureClientEvent } = await import("../src/utils/telemetry");
|
||||
await captureClientEvent("reset", makeInstance());
|
||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("init event payload has sample_rate: 1.0", async () => {
|
||||
randomSpy.mockReturnValue(0.999);
|
||||
const { captureClientEvent } = await import("../src/utils/telemetry");
|
||||
await captureClientEvent("init", makeInstance());
|
||||
const body = JSON.parse(fetchMock.mock.calls[0][1].body);
|
||||
expect(body.properties.sample_rate).toBe(1.0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("hot-path events are sampled", () => {
|
||||
it("add event is dropped when random > sample_rate", async () => {
|
||||
randomSpy.mockReturnValue(0.99); // > 0.1 default rate
|
||||
const { captureClientEvent } = await import("../src/utils/telemetry");
|
||||
await captureClientEvent("add", makeInstance());
|
||||
expect(fetchMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("search event is dropped when random > sample_rate", async () => {
|
||||
randomSpy.mockReturnValue(0.99);
|
||||
const { captureClientEvent } = await import("../src/utils/telemetry");
|
||||
await captureClientEvent("search", makeInstance());
|
||||
expect(fetchMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("add event passes when random < sample_rate", async () => {
|
||||
randomSpy.mockReturnValue(0.05); // < 0.1 default rate
|
||||
const { captureClientEvent } = await import("../src/utils/telemetry");
|
||||
await captureClientEvent("add", makeInstance());
|
||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("hot-path event payload has sample_rate: 0.1", async () => {
|
||||
randomSpy.mockReturnValue(0.05);
|
||||
const { captureClientEvent } = await import("../src/utils/telemetry");
|
||||
await captureClientEvent("add", makeInstance());
|
||||
const body = JSON.parse(fetchMock.mock.calls[0][1].body);
|
||||
expect(body.properties.sample_rate).toBe(0.1);
|
||||
});
|
||||
|
||||
it("sample_rate cannot be overridden by additionalData", async () => {
|
||||
randomSpy.mockReturnValue(0.05);
|
||||
const { captureClientEvent } = await import("../src/utils/telemetry");
|
||||
await captureClientEvent("add", makeInstance(), { sample_rate: 0.99 });
|
||||
const body = JSON.parse(fetchMock.mock.calls[0][1].body);
|
||||
expect(body.properties.sample_rate).toBe(0.1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("env var override", () => {
|
||||
afterEach(() => {
|
||||
delete process.env.MEM0_TELEMETRY_SAMPLE_RATE;
|
||||
});
|
||||
|
||||
it("rate 1.0 sends every event including hot-path at high random", async () => {
|
||||
process.env.MEM0_TELEMETRY_SAMPLE_RATE = "1.0";
|
||||
jest.resetModules();
|
||||
randomSpy.mockReturnValue(0.999);
|
||||
const { captureClientEvent } = await import("../src/utils/telemetry");
|
||||
await captureClientEvent("add", makeInstance());
|
||||
// 0.999 > 1.0 is false, so the gate never trips
|
||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("rate 0.0 drops every hot-path event including at random 0", async () => {
|
||||
// The gate is `random >= rate`, so rate=0 drops at random=0 (0 >= 0 is true).
|
||||
process.env.MEM0_TELEMETRY_SAMPLE_RATE = "0.0";
|
||||
jest.resetModules();
|
||||
randomSpy.mockReturnValue(0.0);
|
||||
const { captureClientEvent } = await import("../src/utils/telemetry");
|
||||
await captureClientEvent("add", makeInstance());
|
||||
expect(fetchMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("rate 0.0 drops at any random value", async () => {
|
||||
process.env.MEM0_TELEMETRY_SAMPLE_RATE = "0.0";
|
||||
jest.resetModules();
|
||||
randomSpy.mockReturnValue(0.5);
|
||||
const { captureClientEvent } = await import("../src/utils/telemetry");
|
||||
await captureClientEvent("add", makeInstance());
|
||||
expect(fetchMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("rate 0.0 still passes lifecycle events", async () => {
|
||||
process.env.MEM0_TELEMETRY_SAMPLE_RATE = "0.0";
|
||||
jest.resetModules();
|
||||
randomSpy.mockReturnValue(0.999);
|
||||
const { captureClientEvent } = await import("../src/utils/telemetry");
|
||||
await captureClientEvent("init", makeInstance());
|
||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("rate 0.5 passes events at random below 0.5", async () => {
|
||||
process.env.MEM0_TELEMETRY_SAMPLE_RATE = "0.5";
|
||||
jest.resetModules();
|
||||
randomSpy.mockReturnValue(0.3);
|
||||
const { captureClientEvent } = await import("../src/utils/telemetry");
|
||||
await captureClientEvent("add", makeInstance());
|
||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("invalid env var falls back to default rate", async () => {
|
||||
process.env.MEM0_TELEMETRY_SAMPLE_RATE = "not a number";
|
||||
jest.resetModules();
|
||||
randomSpy.mockReturnValue(0.05);
|
||||
const { captureClientEvent } = await import("../src/utils/telemetry");
|
||||
await captureClientEvent("add", makeInstance());
|
||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("out-of-range env var (negative) falls back to default rate", async () => {
|
||||
process.env.MEM0_TELEMETRY_SAMPLE_RATE = "-0.5";
|
||||
jest.resetModules();
|
||||
randomSpy.mockReturnValue(0.05);
|
||||
const { captureClientEvent } = await import("../src/utils/telemetry");
|
||||
await captureClientEvent("add", makeInstance());
|
||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("out-of-range env var (> 1) falls back to default rate", async () => {
|
||||
process.env.MEM0_TELEMETRY_SAMPLE_RATE = "5";
|
||||
jest.resetModules();
|
||||
randomSpy.mockReturnValue(0.05);
|
||||
const { captureClientEvent } = await import("../src/utils/telemetry");
|
||||
await captureClientEvent("add", makeInstance());
|
||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("contract preservation", () => {
|
||||
it("lifecycle event includes additionalData", async () => {
|
||||
const { captureClientEvent } = await import("../src/utils/telemetry");
|
||||
await captureClientEvent("init", makeInstance(), {
|
||||
api_version: "v1.1",
|
||||
client_type: "Memory",
|
||||
});
|
||||
const body = JSON.parse(fetchMock.mock.calls[0][1].body);
|
||||
expect(body.properties.api_version).toBe("v1.1");
|
||||
expect(body.properties.client_type).toBe("Memory");
|
||||
expect(body.properties.sample_rate).toBe(1.0);
|
||||
});
|
||||
|
||||
it("captureClientEvent without telemetryId is a no-op", async () => {
|
||||
const { captureClientEvent } = await import("../src/utils/telemetry");
|
||||
await captureClientEvent("add", makeInstance({ telemetryId: "" }));
|
||||
expect(fetchMock).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -676,6 +676,7 @@ class MemoryClient:
|
||||
exclusion_prompt: Optional[str] = None,
|
||||
memory_depth: Optional[str] = None,
|
||||
usecase_setting: Optional[str] = None,
|
||||
multilingual: Optional[bool] = None,
|
||||
) -> Dict[str, Any]:
|
||||
"""Update the project settings.
|
||||
|
||||
@@ -689,6 +690,7 @@ class MemoryClient:
|
||||
exclusion_prompt: Exclusion prompt for the project
|
||||
memory_depth: Memory depth for the project
|
||||
usecase_setting: Usecase setting for the project
|
||||
multilingual: Whether to use the input language for memory storage and retrieval
|
||||
|
||||
Returns:
|
||||
Dictionary containing the API response.
|
||||
@@ -718,6 +720,7 @@ class MemoryClient:
|
||||
and exclusion_prompt is None
|
||||
and memory_depth is None
|
||||
and usecase_setting is None
|
||||
and multilingual is None
|
||||
):
|
||||
raise ValueError(
|
||||
"Currently we only support updating custom_instructions or "
|
||||
@@ -736,6 +739,7 @@ class MemoryClient:
|
||||
"exclusion_prompt": exclusion_prompt,
|
||||
"memory_depth": memory_depth,
|
||||
"usecase_setting": usecase_setting,
|
||||
"multilingual": multilingual,
|
||||
}
|
||||
)
|
||||
response = self.client.patch(
|
||||
@@ -756,6 +760,7 @@ class MemoryClient:
|
||||
"exclusion_prompt": exclusion_prompt,
|
||||
"memory_depth": memory_depth,
|
||||
"usecase_setting": usecase_setting,
|
||||
"multilingual": multilingual,
|
||||
"sync_type": "sync",
|
||||
},
|
||||
)
|
||||
@@ -1554,6 +1559,7 @@ class AsyncMemoryClient:
|
||||
retrieval_criteria: Optional[List[Dict[str, Any]]] = None,
|
||||
enable_graph: Optional[bool] = None,
|
||||
version: Optional[str] = None,
|
||||
multilingual: Optional[bool] = None,
|
||||
) -> Dict[str, Any]:
|
||||
"""Update the project settings.
|
||||
|
||||
@@ -1563,6 +1569,7 @@ class AsyncMemoryClient:
|
||||
retrieval_criteria: New retrieval criteria for the project
|
||||
enable_graph: Enable or disable the graph for the project
|
||||
version: Version of the project
|
||||
multilingual: Whether to use the input language for memory storage and retrieval
|
||||
|
||||
Returns:
|
||||
Dictionary containing the API response.
|
||||
@@ -1588,6 +1595,7 @@ class AsyncMemoryClient:
|
||||
and retrieval_criteria is None
|
||||
and enable_graph is None
|
||||
and version is None
|
||||
and multilingual is None
|
||||
):
|
||||
raise ValueError(
|
||||
"Currently we only support updating custom_instructions or custom_categories or retrieval_criteria, so you must provide at least one of them"
|
||||
@@ -1600,6 +1608,7 @@ class AsyncMemoryClient:
|
||||
"retrieval_criteria": retrieval_criteria,
|
||||
"enable_graph": enable_graph,
|
||||
"version": version,
|
||||
"multilingual": multilingual,
|
||||
}
|
||||
)
|
||||
response = await self.async_client.patch(
|
||||
@@ -1616,6 +1625,7 @@ class AsyncMemoryClient:
|
||||
"retrieval_criteria": retrieval_criteria,
|
||||
"enable_graph": enable_graph,
|
||||
"version": version,
|
||||
"multilingual": multilingual,
|
||||
"sync_type": "async",
|
||||
},
|
||||
)
|
||||
|
||||
+12
-2
@@ -399,6 +399,7 @@ class Project(BaseProject):
|
||||
custom_categories: Optional[List[str]] = None,
|
||||
retrieval_criteria: Optional[List[Dict[str, Any]]] = None,
|
||||
enable_graph: Optional[bool] = None,
|
||||
multilingual: Optional[bool] = None,
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Update project settings.
|
||||
@@ -408,6 +409,7 @@ class Project(BaseProject):
|
||||
custom_categories: New categories for the project
|
||||
retrieval_criteria: New retrieval criteria for the project
|
||||
enable_graph: Enable or disable the graph for the project
|
||||
multilingual: Whether to use the input language for memory storage and retrieval
|
||||
|
||||
Returns:
|
||||
Dictionary containing the API response.
|
||||
@@ -424,11 +426,12 @@ class Project(BaseProject):
|
||||
and custom_categories is None
|
||||
and retrieval_criteria is None
|
||||
and enable_graph is None
|
||||
and multilingual is None
|
||||
):
|
||||
raise ValueError(
|
||||
"At least one parameter must be provided for update: "
|
||||
"custom_instructions, custom_categories, retrieval_criteria, "
|
||||
"enable_graph"
|
||||
"enable_graph, multilingual"
|
||||
)
|
||||
|
||||
payload = self._prepare_params(
|
||||
@@ -437,6 +440,7 @@ class Project(BaseProject):
|
||||
"custom_categories": custom_categories,
|
||||
"retrieval_criteria": retrieval_criteria,
|
||||
"enable_graph": enable_graph,
|
||||
"multilingual": multilingual,
|
||||
}
|
||||
)
|
||||
response = self._client.patch(
|
||||
@@ -452,6 +456,7 @@ class Project(BaseProject):
|
||||
"custom_categories": custom_categories,
|
||||
"retrieval_criteria": retrieval_criteria,
|
||||
"enable_graph": enable_graph,
|
||||
"multilingual": multilingual,
|
||||
"sync_type": "sync",
|
||||
},
|
||||
)
|
||||
@@ -716,6 +721,7 @@ class AsyncProject(BaseProject):
|
||||
custom_categories: Optional[List[str]] = None,
|
||||
retrieval_criteria: Optional[List[Dict[str, Any]]] = None,
|
||||
enable_graph: Optional[bool] = None,
|
||||
multilingual: Optional[bool] = None,
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Update project settings.
|
||||
@@ -725,6 +731,7 @@ class AsyncProject(BaseProject):
|
||||
custom_categories: New categories for the project
|
||||
retrieval_criteria: New retrieval criteria for the project
|
||||
enable_graph: Enable or disable the graph for the project
|
||||
multilingual: Whether to use the input language for memory storage and retrieval
|
||||
|
||||
Returns:
|
||||
Dictionary containing the API response.
|
||||
@@ -741,11 +748,12 @@ class AsyncProject(BaseProject):
|
||||
and custom_categories is None
|
||||
and retrieval_criteria is None
|
||||
and enable_graph is None
|
||||
and multilingual is None
|
||||
):
|
||||
raise ValueError(
|
||||
"At least one parameter must be provided for update: "
|
||||
"custom_instructions, custom_categories, retrieval_criteria, "
|
||||
"enable_graph"
|
||||
"enable_graph, multilingual"
|
||||
)
|
||||
|
||||
payload = self._prepare_params(
|
||||
@@ -754,6 +762,7 @@ class AsyncProject(BaseProject):
|
||||
"custom_categories": custom_categories,
|
||||
"retrieval_criteria": retrieval_criteria,
|
||||
"enable_graph": enable_graph,
|
||||
"multilingual": multilingual,
|
||||
}
|
||||
)
|
||||
response = await self._client.patch(
|
||||
@@ -769,6 +778,7 @@ class AsyncProject(BaseProject):
|
||||
"custom_categories": custom_categories,
|
||||
"retrieval_criteria": retrieval_criteria,
|
||||
"enable_graph": enable_graph,
|
||||
"multilingual": multilingual,
|
||||
"sync_type": "async",
|
||||
},
|
||||
)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from collections.abc import Callable
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from pydantic import BaseModel, Field, model_validator
|
||||
from pydantic import BaseModel, ConfigDict, Field, model_validator
|
||||
|
||||
|
||||
class ElasticsearchConfig(BaseModel):
|
||||
@@ -63,3 +63,5 @@ class ElasticsearchConfig(BaseModel):
|
||||
f"Please input only the following fields: {', '.join(allowed_fields)}"
|
||||
)
|
||||
return values
|
||||
|
||||
model_config = ConfigDict(arbitrary_types_allowed=True)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
from pydantic import BaseModel, Field, model_validator
|
||||
from pydantic import BaseModel, ConfigDict, Field, model_validator
|
||||
|
||||
|
||||
class MongoDBConfig(BaseModel):
|
||||
@@ -23,3 +23,5 @@ class MongoDBConfig(BaseModel):
|
||||
f"Please provide only the following fields: {', '.join(allowed_fields)}."
|
||||
)
|
||||
return values
|
||||
|
||||
model_config = ConfigDict(arbitrary_types_allowed=False)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user