Compare commits
195 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6ddf1669f4 | |||
| d3d2e89fd5 | |||
| 43175d85f2 | |||
| 661ecb9f0f | |||
| 09f181c577 | |||
| 3497f26a00 | |||
| e9c0547423 | |||
| 25bc1b7426 | |||
| fee344db85 | |||
| b611f69381 | |||
| c2862831db | |||
| 1678e682ee | |||
| ced4af681f | |||
| 565db27121 | |||
| c0ac9f81fa | |||
| 879c68555c | |||
| c2e723352e | |||
| 716f021df8 | |||
| 7fa996261d | |||
| 87bd2d91e0 | |||
| 15a930dac2 | |||
| fa9abc77a6 | |||
| 4e448269bc | |||
| 29d131f7aa | |||
| 42fe129330 | |||
| bd5996f41e | |||
| 299c423213 | |||
| ce0531a13e | |||
| 513b56159f | |||
| 1676b3168d | |||
| 8a786bf72d | |||
| a48f34cf77 | |||
| 650b734b1b | |||
| 871a1de7d2 | |||
| e615cc66de | |||
| ca86a164bd | |||
| 2ac3f3956a | |||
| 7a9f03af3f | |||
| 48f1d6f010 | |||
| f0ccd99924 | |||
| c5971193a2 | |||
| ff53fd60b7 | |||
| ffa334537a | |||
| bd7ce2c13c | |||
| 5d767219ff | |||
| 6b744845c3 | |||
| 5b4478458b | |||
| 1751e7bff9 | |||
| 7ae6a8c36a | |||
| 1dcee153b9 | |||
| 4065e846f6 | |||
| 466249113c | |||
| 3e2ae734e7 | |||
| 96b31c4bc0 | |||
| 0117d5838b | |||
| 42a3b4043c | |||
| 158e9111cb | |||
| 9ed1983b85 | |||
| 703e8a035d | |||
| 7ed2faab84 | |||
| 0d66d3d127 | |||
| 137b7519f7 | |||
| e34f5835bd | |||
| f122eb7c65 | |||
| a5123b8a5e | |||
| 6aa9bffa55 | |||
| d772f9a961 | |||
| 7c841a2bce | |||
| 6a6dfb4935 | |||
| 8b370def80 | |||
| d46464282c | |||
| bb4a239cb1 | |||
| e30f0d91fe | |||
| 9f34e858c7 | |||
| 94bbc13de0 | |||
| a2f01a8fcc | |||
| 30d172e826 | |||
| bb69b036b5 | |||
| b55c51e004 | |||
| 4492e75d04 | |||
| 4d949022f2 | |||
| 3ef034a9e4 | |||
| b90e3c0b76 | |||
| a8eeddde64 | |||
| 09a9e34382 | |||
| 66c4394b40 | |||
| 32575a65fc | |||
| 66901d7393 | |||
| a1eefc31bc | |||
| de471799d1 | |||
| 3951ad4705 | |||
| 9315e3036f | |||
| b3ede5b7c0 | |||
| 3553fc79dd | |||
| f322cf82b9 | |||
| 73c975ba68 | |||
| 931d579ba5 | |||
| f4773a0baf | |||
| 06d33f6cc4 | |||
| 8f3b60f3e1 | |||
| a6e27dcc9c | |||
| 4f10c986b5 | |||
| 821152bd14 | |||
| f48b133101 | |||
| 1d56f85705 | |||
| ced852033b | |||
| b9ad8fa8b2 | |||
| e3f5ce7b41 | |||
| f681889b14 | |||
| b5ec46be5b | |||
| 168ad358d5 | |||
| 2c796d144f | |||
| c676c2c458 | |||
| b36847622d | |||
| 32c8849044 | |||
| 2dd2872c08 | |||
| cf268da19d | |||
| 7a5df64746 | |||
| 4c41f6deeb | |||
| f84aa1eb31 | |||
| 9226ee2229 | |||
| 8399b088a5 | |||
| 437f0b5495 | |||
| 0ffaffa88c | |||
| 433ff494f1 | |||
| de03c52ed3 | |||
| b4a50e3dc8 | |||
| b819d95d18 | |||
| 3ac1c9452c | |||
| d6347f6660 | |||
| e769502baa | |||
| 652193d599 | |||
| a86c87236d | |||
| 2274b5acad | |||
| 9b0705c345 | |||
| d31fa168eb | |||
| f32eb4406b | |||
| 366945965d | |||
| 6702fa3e3e | |||
| a44855af9e | |||
| d817aa9c12 | |||
| 7ac8ab154b | |||
| b00a1a1065 | |||
| 2e90ed4f78 | |||
| 069ea0887c | |||
| ae7f406265 | |||
| 90f2d24e83 | |||
| 64b9646e7d | |||
| 866888df41 | |||
| 95b6f95f7b | |||
| 74771b4e76 | |||
| 8e65ce915d | |||
| a3154d59e5 | |||
| 1019f0e17c | |||
| 9328c36a46 | |||
| eb4afc6ef7 | |||
| fea748d7e6 | |||
| e83297f150 | |||
| eaca45dcdb | |||
| add6aad40b | |||
| 116c439b1d | |||
| 49b7953c44 | |||
| 3e6ab39429 | |||
| 75a37ec93d | |||
| 88934304c6 | |||
| 098a599579 | |||
| 5a2201d76b | |||
| ad736d9a06 | |||
| 7f6d46050e | |||
| f9c52baf21 | |||
| 0da3359a1a | |||
| 6b9707fee9 | |||
| 99beb007ab | |||
| 16a7702d09 | |||
| 53a3998873 | |||
| 08aa143db3 | |||
| ac141fdafe | |||
| b1188d6044 | |||
| 0d61af60c2 | |||
| 58696e4bd4 | |||
| 8b11e0787a | |||
| 09dc74d61a | |||
| 606ede7c0a | |||
| edd1b3e2f2 | |||
| 74d043731b | |||
| 843ab82905 | |||
| 79793b0d2e | |||
| 5f7ace2aef | |||
| 219b1a6f3d | |||
| 57c8468ce6 | |||
| ddee5f8671 | |||
| fbce5fab14 | |||
| 6a1597c6fb | |||
| c9e8482a35 | |||
| e602923751 |
@@ -8,7 +8,7 @@
|
||||
"name": "mem0",
|
||||
"source": {
|
||||
"source": "local",
|
||||
"path": "./mem0-plugin"
|
||||
"path": "./integrations/mem0-plugin"
|
||||
},
|
||||
"policy": {
|
||||
"installation": "AVAILABLE",
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
"plugins": [
|
||||
{
|
||||
"name": "mem0",
|
||||
"source": "./mem0-plugin",
|
||||
"source": "./integrations/mem0-plugin",
|
||||
"description": "Mem0 memory layer for AI applications. Add persistent memory, personalization, and semantic search to Claude workflows.",
|
||||
"version": "0.1.2"
|
||||
"version": "0.2.10"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "mem0-plugins",
|
||||
"interface": {
|
||||
"displayName": "Mem0 Plugins"
|
||||
},
|
||||
"plugins": [
|
||||
{
|
||||
"name": "mem0",
|
||||
"source": {
|
||||
"source": "local",
|
||||
"path": "./integrations/mem0-plugin"
|
||||
},
|
||||
"policy": {
|
||||
"installation": "AVAILABLE",
|
||||
"authentication": "ON_INSTALL"
|
||||
},
|
||||
"category": "Productivity"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -10,9 +10,9 @@
|
||||
"plugins": [
|
||||
{
|
||||
"name": "mem0",
|
||||
"source": "./mem0-plugin",
|
||||
"source": "./integrations/mem0-plugin",
|
||||
"description": "Mem0 memory layer for AI applications. Add persistent memory, personalization, and semantic search.",
|
||||
"version": "0.1.1"
|
||||
"version": "0.2.10"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,18 +1,33 @@
|
||||
name: Publish Python 🐍 distributions 📦 to PyPI and TestPyPI
|
||||
|
||||
# Dispatched by release.yml (Release Router) when a release tagged v* is
|
||||
# published. Can also be dispatched manually to re-publish a tag.
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: 'Release tag to build and publish (e.g. v1.2.3)'
|
||||
required: true
|
||||
type: string
|
||||
prerelease:
|
||||
description: 'Unused for PyPI (pre-releases are expressed in the version itself); accepted for router uniformity'
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
jobs:
|
||||
build-n-publish:
|
||||
name: Build and publish Python 🐍 distributions 📦 to PyPI and TestPyPI
|
||||
if: startsWith(github.event.release.tag_name, 'v')
|
||||
# Pure SDK version tags only (v1.2.3) — excludes package-prefixed tags
|
||||
# like vercel-ai-v* that also start with 'v'
|
||||
if: startsWith(inputs.tag, 'v') && !contains(inputs.tag, '-v')
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ inputs.tag }}
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
@@ -39,7 +54,6 @@ jobs:
|
||||
# packages_dir: dist/
|
||||
|
||||
- name: Publish distribution 📦 to PyPI
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
||||
with:
|
||||
packages_dir: dist/
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
name: CI Gate
|
||||
|
||||
# Single required status check for all PRs.
|
||||
#
|
||||
# Path-filtered CI workflows can't be marked as required in branch
|
||||
# protection: on a PR that doesn't touch their paths they never report, and
|
||||
# the required check hangs at "Expected" forever. This gate solves that. It
|
||||
# runs on every PR, detects which packages changed, calls only the relevant
|
||||
# package CI workflows (as reusable workflows), and the final "CI Gate" job
|
||||
# reports the aggregate result — success when every invoked pipeline passed
|
||||
# (skipped pipelines are fine), failure when any failed.
|
||||
#
|
||||
# Branch protection should require exactly one status check: "CI Gate".
|
||||
#
|
||||
# Package CI workflows keep their own push-to-main and workflow_dispatch
|
||||
# triggers; only their pull_request triggers moved here. To wire in a new
|
||||
# package: add a filter under the `changes` job, a call job that `uses:` the
|
||||
# package workflow, and list the call job in the gate's `needs`.
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
concurrency:
|
||||
group: ci-gate-${{ github.event.pull_request.number }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
name: Detect changed packages
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
python_sdk: ${{ steps.filter.outputs.python_sdk }}
|
||||
ts_sdk: ${{ steps.filter.outputs.ts_sdk }}
|
||||
cli_python: ${{ steps.filter.outputs.cli_python }}
|
||||
cli_node: ${{ steps.filter.outputs.cli_node }}
|
||||
openclaw: ${{ steps.filter.outputs.openclaw }}
|
||||
opencode_plugin: ${{ steps.filter.outputs.opencode_plugin }}
|
||||
pi_agent_plugin: ${{ steps.filter.outputs.pi_agent_plugin }}
|
||||
docs_llms_txt: ${{ steps.filter.outputs.docs_llms_txt }}
|
||||
steps:
|
||||
- uses: dorny/paths-filter@v3
|
||||
id: filter
|
||||
with:
|
||||
# Each filter mirrors the package workflow's old pull_request
|
||||
# paths, plus the package workflow file itself and this gate file
|
||||
# (changing either must re-exercise the pipeline).
|
||||
filters: |
|
||||
python_sdk:
|
||||
- 'mem0/**'
|
||||
- 'tests/**'
|
||||
- 'pyproject.toml'
|
||||
- '.github/workflows/ci.yml'
|
||||
- '.github/workflows/ci-gate.yml'
|
||||
ts_sdk:
|
||||
- 'mem0-ts/**'
|
||||
- '.github/workflows/ts-sdk-ci.yml'
|
||||
- '.github/workflows/ci-gate.yml'
|
||||
cli_python:
|
||||
- 'cli/python/**'
|
||||
- '.github/workflows/cli-python-ci.yml'
|
||||
- '.github/workflows/ci-gate.yml'
|
||||
cli_node:
|
||||
- 'cli/node/**'
|
||||
- '.github/workflows/cli-node-ci.yml'
|
||||
- '.github/workflows/ci-gate.yml'
|
||||
openclaw:
|
||||
- 'integrations/openclaw/**'
|
||||
- '.github/workflows/openclaw-checks.yml'
|
||||
- '.github/workflows/ci-gate.yml'
|
||||
opencode_plugin:
|
||||
- 'integrations/mem0-plugin/.opencode-plugin/**'
|
||||
- '.github/workflows/opencode-plugin-checks.yml'
|
||||
- '.github/workflows/ci-gate.yml'
|
||||
pi_agent_plugin:
|
||||
- 'integrations/pi-agent-plugin/**'
|
||||
- '.github/workflows/pi-agent-plugin-checks.yml'
|
||||
- '.github/workflows/ci-gate.yml'
|
||||
docs_llms_txt:
|
||||
- 'docs/**/*.mdx'
|
||||
- 'docs/llms.txt'
|
||||
- 'scripts/check-llms-txt-coverage.py'
|
||||
- 'scripts/llms-txt-ignore.txt'
|
||||
- '.github/workflows/docs-llms-txt-check.yml'
|
||||
- '.github/workflows/ci-gate.yml'
|
||||
|
||||
python-sdk:
|
||||
name: Python SDK
|
||||
needs: changes
|
||||
if: needs.changes.outputs.python_sdk == 'true'
|
||||
uses: ./.github/workflows/ci.yml
|
||||
secrets: inherit
|
||||
|
||||
ts-sdk:
|
||||
name: TypeScript SDK
|
||||
needs: changes
|
||||
if: needs.changes.outputs.ts_sdk == 'true'
|
||||
uses: ./.github/workflows/ts-sdk-ci.yml
|
||||
secrets: inherit
|
||||
|
||||
cli-python:
|
||||
name: Python CLI
|
||||
needs: changes
|
||||
if: needs.changes.outputs.cli_python == 'true'
|
||||
uses: ./.github/workflows/cli-python-ci.yml
|
||||
secrets: inherit
|
||||
|
||||
cli-node:
|
||||
name: Node CLI
|
||||
needs: changes
|
||||
if: needs.changes.outputs.cli_node == 'true'
|
||||
uses: ./.github/workflows/cli-node-ci.yml
|
||||
secrets: inherit
|
||||
|
||||
openclaw:
|
||||
name: OpenClaw
|
||||
needs: changes
|
||||
if: needs.changes.outputs.openclaw == 'true'
|
||||
uses: ./.github/workflows/openclaw-checks.yml
|
||||
secrets: inherit
|
||||
|
||||
opencode-plugin:
|
||||
name: OpenCode Plugin
|
||||
needs: changes
|
||||
if: needs.changes.outputs.opencode_plugin == 'true'
|
||||
uses: ./.github/workflows/opencode-plugin-checks.yml
|
||||
secrets: inherit
|
||||
|
||||
pi-agent-plugin:
|
||||
name: Pi Agent Plugin
|
||||
needs: changes
|
||||
if: needs.changes.outputs.pi_agent_plugin == 'true'
|
||||
uses: ./.github/workflows/pi-agent-plugin-checks.yml
|
||||
secrets: inherit
|
||||
|
||||
docs-llms-txt:
|
||||
name: docs llms.txt
|
||||
needs: changes
|
||||
if: needs.changes.outputs.docs_llms_txt == 'true'
|
||||
uses: ./.github/workflows/docs-llms-txt-check.yml
|
||||
secrets: inherit
|
||||
|
||||
gate:
|
||||
name: CI Gate
|
||||
needs:
|
||||
- changes
|
||||
- python-sdk
|
||||
- ts-sdk
|
||||
- cli-python
|
||||
- cli-node
|
||||
- openclaw
|
||||
- opencode-plugin
|
||||
- pi-agent-plugin
|
||||
- docs-llms-txt
|
||||
if: always()
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Evaluate pipeline results
|
||||
env:
|
||||
NEEDS: ${{ toJSON(needs) }}
|
||||
run: |
|
||||
echo "$NEEDS" | jq -r 'to_entries[] | "\(.key): \(.value.result)"'
|
||||
failed=$(echo "$NEEDS" | jq -r '[to_entries[] | select(.value.result == "failure" or .value.result == "cancelled") | .key] | join(", ")')
|
||||
if [ -n "$failed" ]; then
|
||||
echo "::error::Failing pipelines: $failed"
|
||||
exit 1
|
||||
fi
|
||||
echo "All pipelines relevant to this change passed."
|
||||
+18
-59
@@ -1,20 +1,11 @@
|
||||
name: ci
|
||||
|
||||
# On PRs this is invoked by ci-gate.yml (the single required check);
|
||||
# push-to-main runs remain standalone.
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'mem0/**'
|
||||
- 'tests/**'
|
||||
- 'embedchain/**'
|
||||
- '.github/workflows/**'
|
||||
- 'pyproject.toml'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'mem0/**'
|
||||
- 'tests/**'
|
||||
- 'embedchain/**'
|
||||
- 'pyproject.toml'
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
changelog_check:
|
||||
@@ -60,9 +51,8 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
mem0_changed: ${{ steps.filter.outputs.mem0 }}
|
||||
embedchain_changed: ${{ steps.filter.outputs.embedchain }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dorny/paths-filter@v2
|
||||
id: filter
|
||||
with:
|
||||
@@ -70,25 +60,28 @@ jobs:
|
||||
mem0:
|
||||
- 'mem0/**'
|
||||
- 'tests/**'
|
||||
- '.github/workflows/**'
|
||||
- '.github/workflows/ci.yml'
|
||||
- 'pyproject.toml'
|
||||
embedchain:
|
||||
- 'embedchain/**'
|
||||
|
||||
build_mem0:
|
||||
needs: check_changes
|
||||
if: needs.check_changes.outputs.mem0_changed == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.10", "3.11", "3.12"]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Skip — no relevant changes
|
||||
if: needs.check_changes.outputs.mem0_changed != 'true'
|
||||
run: echo "No changes in mem0/, tests/, pyproject.toml, or ci.yml — skipping"
|
||||
- uses: actions/checkout@v4
|
||||
if: needs.check_changes.outputs.mem0_changed == 'true'
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
if: needs.check_changes.outputs.mem0_changed == 'true'
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Clean up disk space
|
||||
if: needs.check_changes.outputs.mem0_changed == 'true'
|
||||
run: |
|
||||
df -h
|
||||
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc /opt/hostedtoolcache/CodeQL
|
||||
@@ -96,61 +89,27 @@ jobs:
|
||||
sudo docker builder prune -a
|
||||
df -h
|
||||
- name: Install Hatch
|
||||
if: needs.check_changes.outputs.mem0_changed == 'true'
|
||||
run: pip install hatch
|
||||
- name: Load cached venv
|
||||
if: needs.check_changes.outputs.mem0_changed == 'true'
|
||||
id: cached-hatch-dependencies
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: .venv
|
||||
key: venv-mem0-${{ runner.os }}-${{ hashFiles('**/pyproject.toml') }}
|
||||
- name: Install GEOS Libraries
|
||||
if: needs.check_changes.outputs.mem0_changed == 'true'
|
||||
run: sudo apt-get update && sudo apt-get install -y libgeos-dev
|
||||
- name: Install dependencies
|
||||
if: needs.check_changes.outputs.mem0_changed == 'true' && steps.cached-hatch-dependencies.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
pip install --upgrade pip
|
||||
pip install -e ".[test,graph,vector_stores,llms,extras]"
|
||||
pip install ruff
|
||||
if: steps.cached-hatch-dependencies.outputs.cache-hit != 'true'
|
||||
- name: Run Linting
|
||||
if: needs.check_changes.outputs.mem0_changed == 'true'
|
||||
run: make lint
|
||||
- name: Run tests and generate coverage report
|
||||
if: needs.check_changes.outputs.mem0_changed == 'true'
|
||||
run: make test
|
||||
|
||||
build_embedchain:
|
||||
needs: check_changes
|
||||
if: needs.check_changes.outputs.embedchain_changed == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.9", "3.10", "3.11", "3.12"]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Install Hatch
|
||||
run: pip install hatch
|
||||
- name: Load cached venv
|
||||
id: cached-hatch-dependencies
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: .venv
|
||||
key: venv-embedchain-${{ runner.os }}-${{ hashFiles('**/pyproject.toml') }}
|
||||
- name: Install dependencies
|
||||
run: cd embedchain && make install_all
|
||||
if: steps.cached-hatch-dependencies.outputs.cache-hit != 'true'
|
||||
- name: Run Formatting
|
||||
run: |
|
||||
mkdir -p embedchain/.ruff_cache && chmod -R 777 embedchain/.ruff_cache
|
||||
cd embedchain && hatch run format
|
||||
- name: Lint with ruff
|
||||
run: cd embedchain && make lint
|
||||
- name: Run tests and generate coverage report
|
||||
run: cd embedchain && make coverage
|
||||
- name: Upload coverage reports to Codecov
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
file: coverage.xml
|
||||
env:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
@@ -1,13 +1,25 @@
|
||||
name: Publish @mem0/cli 📦 to npm
|
||||
|
||||
# Dispatched by release.yml (Release Router) when a release tagged
|
||||
# cli-node-v* is published. Can also be dispatched manually to re-publish
|
||||
# a tag.
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: 'Release tag to build and publish (e.g. cli-node-v0.2.0)'
|
||||
required: true
|
||||
type: string
|
||||
prerelease:
|
||||
description: 'Publish under the version preid dist-tag instead of latest'
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
jobs:
|
||||
build-n-publish:
|
||||
name: Build and publish @mem0/cli 📦 to npm
|
||||
if: startsWith(github.event.release.tag_name, 'cli-node-v')
|
||||
if: startsWith(inputs.tag, 'cli-node-v')
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write
|
||||
@@ -16,6 +28,8 @@ jobs:
|
||||
working-directory: cli/node
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ inputs.tag }}
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
@@ -38,7 +52,7 @@ jobs:
|
||||
|
||||
- name: Publish to npm
|
||||
run: |
|
||||
if [ "${{ github.event.release.prerelease }}" = "true" ]; then
|
||||
if [ "${{ inputs.prerelease }}" = "true" ]; then
|
||||
PREID=$(node -p "require('./package.json').version.split('-')[1].split('.')[0]")
|
||||
npx npm@latest publish --provenance --access public --tag "$PREID"
|
||||
else
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
name: CLI Node CI
|
||||
|
||||
# On PRs this is invoked by ci-gate.yml (the single required check);
|
||||
# push-to-main and manual runs remain standalone.
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
@@ -7,10 +9,7 @@ on:
|
||||
paths:
|
||||
- 'cli/node/**'
|
||||
- '.github/workflows/cli-node-ci.yml'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'cli/node/**'
|
||||
- '.github/workflows/cli-node-ci.yml'
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
|
||||
@@ -1,13 +1,24 @@
|
||||
name: Publish mem0-cli 🐍 distributions 📦 to PyPI
|
||||
|
||||
# Dispatched by release.yml (Release Router) when a release tagged cli-v* is
|
||||
# published. Can also be dispatched manually to re-publish a tag.
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: 'Release tag to build and publish (e.g. cli-v0.2.0)'
|
||||
required: true
|
||||
type: string
|
||||
prerelease:
|
||||
description: 'Unused for PyPI (pre-releases are expressed in the version itself); accepted for router uniformity'
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
jobs:
|
||||
build-n-publish:
|
||||
name: Build and publish mem0-cli 📦 to PyPI
|
||||
if: startsWith(github.event.release.tag_name, 'cli-v')
|
||||
if: startsWith(inputs.tag, 'cli-v')
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write
|
||||
@@ -16,6 +27,8 @@ jobs:
|
||||
working-directory: cli/python
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ inputs.tag }}
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
name: CLI Python CI
|
||||
|
||||
# On PRs this is invoked by ci-gate.yml (the single required check);
|
||||
# push-to-main and manual runs remain standalone.
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
@@ -7,10 +9,7 @@ on:
|
||||
paths:
|
||||
- 'cli/python/**'
|
||||
- '.github/workflows/cli-python-ci.yml'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'cli/python/**'
|
||||
- '.github/workflows/cli-python-ci.yml'
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
|
||||
@@ -6,13 +6,10 @@ name: docs - llms.txt check
|
||||
# python scripts/check-llms-txt-coverage.py # read-only
|
||||
# python scripts/check-llms-txt-coverage.py --write # scaffold placeholders
|
||||
|
||||
# On PRs this is invoked by ci-gate.yml (the single required check);
|
||||
# manual runs remain standalone.
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- 'docs/**/*.mdx'
|
||||
- 'docs/llms.txt'
|
||||
- 'scripts/check-llms-txt-coverage.py'
|
||||
- 'scripts/llms-txt-ignore.txt'
|
||||
workflow_call:
|
||||
workflow_dispatch: {}
|
||||
|
||||
permissions:
|
||||
|
||||
@@ -1,21 +1,35 @@
|
||||
name: Publish @mem0/openclaw-mem0 📦 to npm
|
||||
|
||||
# Dispatched by release.yml (Release Router) when a release tagged
|
||||
# openclaw-v* is published. Can also be dispatched manually to re-publish
|
||||
# a tag.
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: 'Release tag to build and publish (e.g. openclaw-v0.5.0)'
|
||||
required: true
|
||||
type: string
|
||||
prerelease:
|
||||
description: 'Publish under the version preid dist-tag instead of latest'
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
jobs:
|
||||
build-n-publish:
|
||||
name: Build and publish @mem0/openclaw-mem0 📦 to npm
|
||||
if: startsWith(github.event.release.tag_name, 'openclaw-v')
|
||||
if: startsWith(inputs.tag, 'openclaw-v')
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write
|
||||
defaults:
|
||||
run:
|
||||
working-directory: openclaw
|
||||
working-directory: integrations/openclaw
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ inputs.tag }}
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
@@ -28,7 +42,7 @@ jobs:
|
||||
node-version: '22'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
cache: 'pnpm'
|
||||
cache-dependency-path: openclaw/pnpm-lock.yaml
|
||||
cache-dependency-path: integrations/openclaw/pnpm-lock.yaml
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
@@ -38,7 +52,7 @@ jobs:
|
||||
|
||||
- name: Publish to npm
|
||||
run: |
|
||||
if [ "${{ github.event.release.prerelease }}" = "true" ]; then
|
||||
if [ "${{ inputs.prerelease }}" = "true" ]; then
|
||||
PREID=$(node -p "require('./package.json').version.split('-')[1].split('.')[0]")
|
||||
npx npm@latest publish --provenance --access public --tag "$PREID"
|
||||
else
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
name: openclaw checks
|
||||
|
||||
# On PRs this is invoked by ci-gate.yml (the single required check);
|
||||
# push-to-main and manual runs remain standalone.
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'openclaw/**'
|
||||
- '.github/workflows/openclaw-checks.yml'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'openclaw/**'
|
||||
- 'integrations/openclaw/**'
|
||||
- '.github/workflows/openclaw-checks.yml'
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
@@ -28,13 +27,13 @@ jobs:
|
||||
with:
|
||||
node-version: 20
|
||||
cache: 'pnpm'
|
||||
cache-dependency-path: openclaw/pnpm-lock.yaml
|
||||
cache-dependency-path: integrations/openclaw/pnpm-lock.yaml
|
||||
|
||||
- name: Install dependencies
|
||||
run: cd openclaw && pnpm install --frozen-lockfile
|
||||
run: cd integrations/openclaw && pnpm install --frozen-lockfile
|
||||
|
||||
- name: Type check
|
||||
run: cd openclaw && pnpm exec tsc --noEmit
|
||||
run: cd integrations/openclaw && pnpm exec tsc --noEmit
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -54,20 +53,20 @@ jobs:
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: 'pnpm'
|
||||
cache-dependency-path: openclaw/pnpm-lock.yaml
|
||||
cache-dependency-path: integrations/openclaw/pnpm-lock.yaml
|
||||
|
||||
- name: Install dependencies
|
||||
run: cd openclaw && pnpm install --frozen-lockfile
|
||||
run: cd integrations/openclaw && pnpm install --frozen-lockfile
|
||||
|
||||
- name: Run tests with coverage
|
||||
run: cd openclaw && pnpm exec vitest run --coverage
|
||||
run: cd integrations/openclaw && pnpm exec vitest run --coverage
|
||||
|
||||
- name: Upload coverage to Codecov
|
||||
if: matrix.node-version == 20
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
flags: openclaw
|
||||
directory: openclaw/coverage
|
||||
directory: integrations/openclaw/coverage
|
||||
env:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
@@ -86,15 +85,15 @@ jobs:
|
||||
with:
|
||||
node-version: 20
|
||||
cache: 'pnpm'
|
||||
cache-dependency-path: openclaw/pnpm-lock.yaml
|
||||
cache-dependency-path: integrations/openclaw/pnpm-lock.yaml
|
||||
|
||||
- name: Install dependencies
|
||||
run: cd openclaw && pnpm install --frozen-lockfile
|
||||
run: cd integrations/openclaw && pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build
|
||||
run: cd openclaw && pnpm build
|
||||
run: cd integrations/openclaw && pnpm build
|
||||
|
||||
- name: Verify dist output exists
|
||||
run: |
|
||||
test -f openclaw/dist/index.js || (echo "Build output missing: dist/index.js" && exit 1)
|
||||
test -f openclaw/dist/index.d.ts || (echo "Build output missing: dist/index.d.ts" && exit 1)
|
||||
test -f integrations/openclaw/dist/index.js || (echo "Build output missing: dist/index.js" && exit 1)
|
||||
test -f integrations/openclaw/dist/index.d.ts || (echo "Build output missing: dist/index.d.ts" && exit 1)
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
name: Publish @mem0/opencode-plugin 📦 to npm
|
||||
|
||||
# Dispatched by release.yml (Release Router) when a release tagged
|
||||
# opencode-v* is published. Can also be dispatched manually to re-publish
|
||||
# a tag.
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: 'Release tag to build and publish (e.g. opencode-v0.2.0)'
|
||||
required: true
|
||||
type: string
|
||||
prerelease:
|
||||
description: 'Publish under the version preid dist-tag instead of latest'
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
jobs:
|
||||
build-n-publish:
|
||||
name: Build and publish @mem0/opencode-plugin 📦 to npm
|
||||
if: startsWith(inputs.tag, 'opencode-v')
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write
|
||||
defaults:
|
||||
run:
|
||||
working-directory: integrations/mem0-plugin/.opencode-plugin
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ inputs.tag }}
|
||||
|
||||
- name: Install Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: latest
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '22'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install --frozen-lockfile
|
||||
|
||||
- name: Build
|
||||
run: bun run build
|
||||
|
||||
- name: Publish to npm
|
||||
run: |
|
||||
if [ "${{ inputs.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,39 @@
|
||||
name: opencode-plugin checks
|
||||
|
||||
# On PRs this is invoked by ci-gate.yml (the single required check);
|
||||
# push-to-main and manual runs remain standalone.
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'integrations/mem0-plugin/.opencode-plugin/**'
|
||||
- '.github/workflows/opencode-plugin-checks.yml'
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: integrations/mem0-plugin/.opencode-plugin
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: latest
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install --frozen-lockfile
|
||||
|
||||
- name: Type check
|
||||
run: bun run type-check
|
||||
|
||||
- name: Build
|
||||
run: bun run build
|
||||
|
||||
- name: Verify dist output exists
|
||||
run: |
|
||||
test -f dist/index.js || (echo "Build output missing: dist/index.js" && exit 1)
|
||||
@@ -0,0 +1,60 @@
|
||||
name: Publish @mem0/pi-agent-plugin 📦 to npm
|
||||
|
||||
# Dispatched by release.yml (Release Router) when a release tagged
|
||||
# pi-agent-v* is published. Can also be dispatched manually to re-publish
|
||||
# a tag.
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: 'Release tag to build and publish (e.g. pi-agent-v0.1.1)'
|
||||
required: true
|
||||
type: string
|
||||
prerelease:
|
||||
description: 'Publish under the version preid dist-tag instead of latest'
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
jobs:
|
||||
build-n-publish:
|
||||
name: Build and publish @mem0/pi-agent-plugin 📦 to npm
|
||||
if: startsWith(inputs.tag, 'pi-agent-v')
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write
|
||||
defaults:
|
||||
run:
|
||||
working-directory: integrations/pi-agent-plugin
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ inputs.tag }}
|
||||
|
||||
- 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: integrations/pi-agent-plugin/pnpm-lock.yaml
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build
|
||||
run: pnpm build
|
||||
|
||||
- name: Publish to npm
|
||||
run: |
|
||||
if [ "${{ inputs.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,92 @@
|
||||
name: pi-agent-plugin checks
|
||||
|
||||
# On PRs this is invoked by ci-gate.yml (the single required check);
|
||||
# push-to-main and manual runs remain standalone.
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'integrations/pi-agent-plugin/**'
|
||||
- '.github/workflows/pi-agent-plugin-checks.yml'
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: 'pnpm'
|
||||
cache-dependency-path: integrations/pi-agent-plugin/pnpm-lock.yaml
|
||||
|
||||
- name: Install dependencies
|
||||
run: cd integrations/pi-agent-plugin && pnpm install --frozen-lockfile
|
||||
|
||||
- name: Type check
|
||||
run: cd integrations/pi-agent-plugin && pnpm exec tsc --noEmit
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [20, 22]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
|
||||
- name: Setup Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: 'pnpm'
|
||||
cache-dependency-path: integrations/pi-agent-plugin/pnpm-lock.yaml
|
||||
|
||||
- name: Install dependencies
|
||||
run: cd integrations/pi-agent-plugin && pnpm install --frozen-lockfile
|
||||
|
||||
- name: Run tests
|
||||
run: cd integrations/pi-agent-plugin && pnpm exec vitest run
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: 'pnpm'
|
||||
cache-dependency-path: integrations/pi-agent-plugin/pnpm-lock.yaml
|
||||
|
||||
- name: Install dependencies
|
||||
run: cd integrations/pi-agent-plugin && pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build
|
||||
run: cd integrations/pi-agent-plugin && pnpm build
|
||||
|
||||
- name: Verify dist output exists
|
||||
run: |
|
||||
test -f integrations/pi-agent-plugin/dist/index.js || (echo "Build output missing: dist/index.js" && exit 1)
|
||||
test -f integrations/pi-agent-plugin/dist/index.d.ts || (echo "Build output missing: dist/index.d.ts" && exit 1)
|
||||
test -f integrations/pi-agent-plugin/dist/entry.js || (echo "Build output missing: dist/entry.js" && exit 1)
|
||||
test -f integrations/pi-agent-plugin/dist/entry.d.ts || (echo "Build output missing: dist/entry.d.ts" && exit 1)
|
||||
@@ -0,0 +1,68 @@
|
||||
name: Release Router 🚦
|
||||
|
||||
# Single entry point for all release publishing.
|
||||
#
|
||||
# Package CD workflows no longer listen to release events themselves — this
|
||||
# router inspects the release tag and dispatches only the matching pipeline,
|
||||
# so each release produces one routed run instead of one real run plus seven
|
||||
# skipped ones.
|
||||
#
|
||||
# Re-publishing a release (e.g. after fixing registry settings) does NOT
|
||||
# require deleting and recreating it anymore — manually dispatch the
|
||||
# package's CD workflow from the tag instead:
|
||||
#
|
||||
# gh workflow run <package>-cd.yml --ref refs/tags/<tag> -f tag=<tag>
|
||||
#
|
||||
# Note: dispatching runs the workflow file as it exists at the given ref, so
|
||||
# this router can only dispatch tags created after the workflow_dispatch
|
||||
# conversion landed on main. For older tags, dispatch manually from main.
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
permissions:
|
||||
actions: write
|
||||
|
||||
jobs:
|
||||
route:
|
||||
name: Route ${{ github.event.release.tag_name }} to its CD pipeline
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Match tag prefix to CD workflow
|
||||
id: match
|
||||
env:
|
||||
TAG: ${{ github.event.release.tag_name }}
|
||||
run: |
|
||||
# Specific package prefixes first; the bare v* (Python SDK) arm
|
||||
# must stay last so prefixed tags that also start with 'v'
|
||||
# (vercel-ai-v*) can never be routed to the Python pipeline.
|
||||
case "$TAG" in
|
||||
ts-v*) workflow="ts-sdk-cd.yml" ;;
|
||||
cli-node-v*) workflow="cli-node-cd.yml" ;;
|
||||
cli-v*) workflow="cli-python-cd.yml" ;;
|
||||
vercel-ai-v*) workflow="vercel-ai-cd.yml" ;;
|
||||
openclaw-v*) workflow="openclaw-cd.yml" ;;
|
||||
opencode-v*) workflow="opencode-plugin-cd.yml" ;;
|
||||
pi-agent-v*) workflow="pi-agent-plugin-cd.yml" ;;
|
||||
v*) workflow="cd.yml" ;;
|
||||
*)
|
||||
echo "::error::Release tag '$TAG' does not match any known package prefix — nothing will be published. See the tag prefix table in AGENTS.md."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
echo "workflow=$workflow" >> "$GITHUB_OUTPUT"
|
||||
echo ":outbox_tray: Routed \`$TAG\` → \`$workflow\`" >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
- name: Dispatch ${{ steps.match.outputs.workflow }}
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
TAG: ${{ github.event.release.tag_name }}
|
||||
run: |
|
||||
# --ref points at the tag so the dispatched run builds (and signs
|
||||
# provenance for) the exact tagged commit.
|
||||
gh workflow run "${{ steps.match.outputs.workflow }}" \
|
||||
--repo "$GITHUB_REPOSITORY" \
|
||||
--ref "refs/tags/$TAG" \
|
||||
-f tag="$TAG" \
|
||||
-f prerelease="${{ github.event.release.prerelease }}"
|
||||
@@ -1,13 +1,24 @@
|
||||
name: Publish mem0ai 📦 to npm
|
||||
|
||||
# Dispatched by release.yml (Release Router) when a release tagged ts-v* is
|
||||
# published. Can also be dispatched manually to re-publish a tag.
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: 'Release tag to build and publish (e.g. ts-v2.1.0)'
|
||||
required: true
|
||||
type: string
|
||||
prerelease:
|
||||
description: 'Publish under the version preid dist-tag instead of latest'
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
jobs:
|
||||
build-n-publish:
|
||||
name: Build and publish mem0ai 📦 to npm
|
||||
if: startsWith(github.event.release.tag_name, 'ts-v')
|
||||
if: startsWith(inputs.tag, 'ts-v')
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write
|
||||
@@ -16,6 +27,8 @@ jobs:
|
||||
working-directory: mem0-ts
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ inputs.tag }}
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
@@ -38,7 +51,7 @@ jobs:
|
||||
|
||||
- name: Publish to npm
|
||||
run: |
|
||||
if [ "${{ github.event.release.prerelease }}" = "true" ]; then
|
||||
if [ "${{ inputs.prerelease }}" = "true" ]; then
|
||||
PREID=$(node -p "require('./package.json').version.split('-')[1].split('.')[0]")
|
||||
npx npm@latest publish --provenance --access public --tag "$PREID"
|
||||
else
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
name: TypeScript SDK CI
|
||||
|
||||
# On PRs this is invoked by ci-gate.yml (the single required check);
|
||||
# push-to-main runs remain standalone.
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'mem0-ts/**'
|
||||
- '.github/workflows/ts-sdk-ci.yml'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'mem0-ts/**'
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
check_changes:
|
||||
|
||||
@@ -1,21 +1,35 @@
|
||||
name: Publish @mem0/vercel-ai-provider 📦 to npm
|
||||
|
||||
# Dispatched by release.yml (Release Router) when a release tagged
|
||||
# vercel-ai-v* is published. Can also be dispatched manually to re-publish
|
||||
# a tag.
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: 'Release tag to build and publish (e.g. vercel-ai-v2.0.7)'
|
||||
required: true
|
||||
type: string
|
||||
prerelease:
|
||||
description: 'Publish under the version preid dist-tag instead of latest'
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
jobs:
|
||||
build-n-publish:
|
||||
name: Build and publish @mem0/vercel-ai-provider 📦 to npm
|
||||
if: startsWith(github.event.release.tag_name, 'vercel-ai-v')
|
||||
if: startsWith(inputs.tag, 'vercel-ai-v')
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write
|
||||
defaults:
|
||||
run:
|
||||
working-directory: vercel-ai-sdk
|
||||
working-directory: integrations/vercel-ai-sdk
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ inputs.tag }}
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
@@ -28,7 +42,7 @@ jobs:
|
||||
node-version: '22'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
cache: 'pnpm'
|
||||
cache-dependency-path: vercel-ai-sdk/pnpm-lock.yaml
|
||||
cache-dependency-path: integrations/vercel-ai-sdk/pnpm-lock.yaml
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
@@ -38,7 +52,7 @@ jobs:
|
||||
|
||||
- name: Publish to npm
|
||||
run: |
|
||||
if [ "${{ github.event.release.prerelease }}" = "true" ]; then
|
||||
if [ "${{ inputs.prerelease }}" = "true" ]; then
|
||||
PREID=$(node -p "require('./package.json').version.split('-')[1].split('.')[0]")
|
||||
npx npm@latest publish --provenance --access public --tag "$PREID"
|
||||
else
|
||||
|
||||
+2
-1
@@ -170,7 +170,6 @@ cython_debug/
|
||||
# Database
|
||||
db
|
||||
test-db
|
||||
!embedchain/embedchain/core/db/
|
||||
|
||||
.vscode
|
||||
.idea/
|
||||
@@ -190,3 +189,5 @@ eval/
|
||||
qdrant_storage/
|
||||
.crossnote
|
||||
testing.ipynb
|
||||
.weave/
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
[submodule "evaluation"]
|
||||
path = evaluation
|
||||
url = https://github.com/mem0ai/memory-benchmarks
|
||||
branch = main
|
||||
@@ -12,7 +12,7 @@ This file provides context for AI coding assistants (Claude Code, Cursor, GitHub
|
||||
|
||||
## Repository Structure
|
||||
|
||||
This is a **polyglot monorepo** containing Python and TypeScript packages, CLIs, servers, plugins, documentation, and evaluation tooling.
|
||||
This is a **polyglot monorepo** containing Python and TypeScript packages, CLIs, servers, plugins, and documentation.
|
||||
|
||||
### Key Directories
|
||||
|
||||
@@ -22,18 +22,18 @@ This is a **polyglot monorepo** containing Python and TypeScript packages, CLIs,
|
||||
| `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 |
|
||||
| `integrations/` | **Agent & editor integrations**, one directory per integration (see "Adding a New Integration") |
|
||||
| `integrations/mem0-plugin/` | AI editor plugins (Claude Code, Cursor, Codex) — MCP server connection, lifecycle hooks, skills. Contains nested `.opencode-plugin/` (`@mem0/opencode-plugin`) |
|
||||
| `integrations/openclaw/` | `@mem0/openclaw-mem0` — OpenClaw plugin for Claude Code / AI editors |
|
||||
| `integrations/pi-agent-plugin/` | `@mem0/pi-agent-plugin` — Pi Agent plugin |
|
||||
| `integrations/vercel-ai-sdk/` | `@mem0/vercel-ai-provider` — Vercel AI SDK memory provider |
|
||||
| `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. Reference skills (SDK knowledge, always-on): `mem0/`, `mem0-cli/`, `mem0-vercel-ai-sdk/`. Pipeline skills (run on demand): `mem0-integrate/`, `mem0-test-integration/` |
|
||||
| `skills/` | Claude Code skill definitions. Reference skills (SDK knowledge, always-on): `mem0/`, `mem0-cli/`, `mem0-vercel-ai-sdk/`. Pipeline skills (run on demand): `mem0-integrate/`, `mem0-test-integration/`, `mem0-oss-to-platform/` |
|
||||
| `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) |
|
||||
| `evaluation/` | Submodule → [`mem0ai/memory-benchmarks`](https://github.com/mem0ai/memory-benchmarks) — benchmarking (LOCOMO, LongMemEval, BEAM) lives in that repo |
|
||||
| `examples/` | Sample projects & runnable demos — apps, Chrome extension, multi-agent patterns, and Jupyter notebooks (`notebooks/`) |
|
||||
| `pr-reviews/` | Pull request review materials |
|
||||
| `scripts/` | Repo-wide utility scripts (e.g., `check-llms-txt-coverage.py` for docs/llms.txt sync) |
|
||||
|
||||
@@ -50,8 +50,8 @@ mem0 (Python SDK) mem0-ts (TypeScript SDK)
|
||||
|
||||
cli/python/ ──▶ mem0ai (optional, for OSS mode)
|
||||
cli/node/ ──▶ mem0ai (npm, for API calls)
|
||||
vercel-ai-sdk/ ──▶ ai, @ai-sdk/* providers
|
||||
openclaw/ ──▶ mem0ai (npm)
|
||||
integrations/vercel-ai-sdk/ ──▶ ai, @ai-sdk/* providers
|
||||
integrations/openclaw/ ──▶ mem0ai (npm)
|
||||
```
|
||||
|
||||
## Development Setup
|
||||
@@ -74,8 +74,8 @@ 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
|
||||
cd integrations/vercel-ai-sdk && pnpm install # Vercel AI provider
|
||||
cd integrations/openclaw && pnpm install # OpenClaw plugin
|
||||
```
|
||||
|
||||
## Build, Lint, and Test Commands
|
||||
@@ -163,10 +163,10 @@ pnpm run dev # tsx src/index.ts (development)
|
||||
- **Test:** vitest (not jest)
|
||||
- **Framework:** Commander + Chalk + ora + cli-table3
|
||||
|
||||
### Vercel AI SDK Provider (`vercel-ai-sdk/`)
|
||||
### Vercel AI SDK Provider (`integrations/vercel-ai-sdk/`)
|
||||
|
||||
```bash
|
||||
cd vercel-ai-sdk
|
||||
cd integrations/vercel-ai-sdk
|
||||
pnpm install
|
||||
pnpm run build # tsup
|
||||
pnpm run lint # eslint
|
||||
@@ -181,10 +181,10 @@ pnpm run test:node # vitest (node runtime)
|
||||
- **Lint:** ESLint + Prettier
|
||||
- **Test:** jest + vitest (edge/node configs)
|
||||
|
||||
### OpenClaw Plugin (`openclaw/`)
|
||||
### OpenClaw Plugin (`integrations/openclaw/`)
|
||||
|
||||
```bash
|
||||
cd openclaw
|
||||
cd integrations/openclaw
|
||||
pnpm install
|
||||
pnpm run build # tsup
|
||||
pnpm run test # vitest run
|
||||
@@ -246,18 +246,19 @@ make docs # or: cd docs && mintlify dev
|
||||
- **API spec:** `docs/openapi.json`
|
||||
- **Structure:** `api-reference/`, `open-source/`, `platform/`, `integrations/`, `cookbooks/`, `core-concepts/`
|
||||
|
||||
### Evaluation (`evaluation/`)
|
||||
### Evaluation / Benchmarking
|
||||
|
||||
Benchmarking lives in the external [`mem0ai/memory-benchmarks`](https://github.com/mem0ai/memory-benchmarks) repo (LOCOMO + LongMemEval + BEAM). The in-repo `evaluation/` path is a **git submodule** pinned to that repo's `main` — populate it with `git submodule update --init evaluation` (or clone mem0 with `--recurse-submodules`), or clone the benchmarks repo standalone:
|
||||
|
||||
```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
|
||||
git clone https://github.com/mem0ai/memory-benchmarks.git
|
||||
cd memory-benchmarks
|
||||
pip install -r requirements.txt
|
||||
|
||||
# Run a benchmark (Mem0 Cloud; use docker compose for OSS)
|
||||
python -m benchmarks.locomo.run --project-name my-test --backend cloud --mem0-api-key $MEM0_API_KEY
|
||||
python -m benchmarks.longmemeval.run --project-name my-test --backend cloud --mem0-api-key $MEM0_API_KEY --all-questions
|
||||
python -m benchmarks.beam.run --project-name my-test --backend cloud --mem0-api-key $MEM0_API_KEY --chat-sizes 100K --conversations 0-9
|
||||
```
|
||||
|
||||
## Core APIs
|
||||
@@ -330,7 +331,7 @@ make run-openai # OpenAI comparison
|
||||
- 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.
|
||||
- Ruff excludes `openmemory/` from root config.
|
||||
|
||||
### TypeScript Conventions
|
||||
|
||||
@@ -343,8 +344,8 @@ make run-openai # OpenAI comparison
|
||||
|---------|--------|-----------|---------------|
|
||||
| `mem0-ts/` | — | Prettier | jest |
|
||||
| `cli/node/` | Biome | Biome | vitest |
|
||||
| `vercel-ai-sdk/` | ESLint | Prettier | jest + vitest |
|
||||
| `openclaw/` | — | — | vitest |
|
||||
| `integrations/vercel-ai-sdk/` | ESLint | Prettier | jest + vitest |
|
||||
| `integrations/openclaw/` | — | — | vitest |
|
||||
|
||||
### Type Checking
|
||||
|
||||
@@ -382,14 +383,14 @@ 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:** MCP tools in `integrations/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.
|
||||
- `integrations/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, split into two categories:
|
||||
- **Reference skills** (always-on SDK knowledge): `mem0` (Python + TS SDKs, framework integrations), `mem0-cli` (terminal workflows), `mem0-vercel-ai-sdk` (Vercel AI provider).
|
||||
- **Pipeline skills** (run on demand): `mem0-integrate` wires Mem0 into an existing repo via a TDD pipeline; `mem0-test-integration` verifies what the integrator produced on the same branch. The two are loosely coupled via `.mem0-integration/` artifacts.
|
||||
- **Pipeline skills** (run on demand): `mem0-integrate` wires Mem0 into an existing repo via a TDD pipeline; `mem0-test-integration` verifies what the integrator produced on the same branch (the two are loosely coupled via `.mem0-integration/` artifacts); `mem0-oss-to-platform` migrates an existing project from Mem0 OSS to the hosted Platform SDK (plan, then execute on approval).
|
||||
|
||||
### Adding a New Provider
|
||||
|
||||
@@ -403,32 +404,58 @@ To add a new LLM, embedding, vector store, or reranker provider:
|
||||
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
|
||||
|
||||
### Adding a New Integration
|
||||
|
||||
Agent/editor integrations live under `integrations/`. Each is a self-contained directory (its own `package.json`/lockfile, build, and tests). To add one:
|
||||
|
||||
1. Create `integrations/<name>/` and build the integration there.
|
||||
2. If it publishes to a registry, set `repository.directory: "integrations/<name>"` in its `package.json` so npm provenance links to the correct subdirectory.
|
||||
3. Add CI/CD under `.github/workflows/` (`<name>-checks.yml`, `<name>-cd.yml`). Use `integrations/<name>` in `paths:` triggers, `working-directory`, and `cache-dependency-path`. Register the release tag prefix in the `case` block in `release.yml` (keep the bare `v*` arm last). Keep workflow **filenames** stable — npm OIDC trusted publishing is pinned to repo + workflow filename.
|
||||
4. If it is a Claude Code / editor marketplace plugin, register its path in the five `marketplace.json` files (root + `.claude-plugin/`, `.cursor-plugin/`, `.codex-plugin/`, `.agents/plugins/`).
|
||||
5. Document it under `docs/integrations/` and add the page to `docs/docs.json` and `docs/llms.txt`.
|
||||
6. Add rows to the "Key Directories" table and the CI/CD tables in this file.
|
||||
|
||||
## 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 |
|
||||
PR testing is orchestrated by a single entry point: **`ci-gate.yml` (CI Gate)** runs on every PR, detects which packages changed, and invokes only the relevant package workflows below as reusable workflows (`workflow_call`). Its final **`CI Gate`** job aggregates the results (skipped pipelines pass; failed or cancelled ones fail) and is the **only status check that needs to be required** in branch protection. Package workflows keep their own push-to-main and manual triggers; their `pull_request` triggers moved into the gate's path filters.
|
||||
|
||||
| Workflow | File | Standalone Triggers | Tests |
|
||||
|----------|------|---------------------|-------|
|
||||
| CI Gate | `ci-gate.yml` | All PRs | Routes to and aggregates the workflows below |
|
||||
| Python SDK | `ci.yml` | Push to main | Ruff lint + pytest on Python 3.10, 3.11, 3.12 |
|
||||
| TypeScript SDK | `ts-sdk-ci.yml` | Push to main (on `mem0-ts/`) | Prettier + build + jest on Node 20, 22 |
|
||||
| Python CLI | `cli-python-ci.yml` | Push to main (on `cli/python/`), manual | Ruff lint + pytest + hatch build on Python 3.10, 3.11, 3.12 |
|
||||
| Node CLI | `cli-node-ci.yml` | Push to main (on `cli/node/`), manual | Biome lint + tsc + vitest + tsup build on Node 20, 22 |
|
||||
| OpenClaw | `openclaw-checks.yml` | Push to main (on `integrations/openclaw/`), manual | tsc + vitest (with Codecov) + tsup build on Node 20, 22 |
|
||||
| OpenCode Plugin | `opencode-plugin-checks.yml` | Push to main (on `integrations/mem0-plugin/.opencode-plugin/`), manual | Bun: tsc type-check + build + dist artifact check |
|
||||
| Pi Agent Plugin | `pi-agent-plugin-checks.yml` | Push to main (on `integrations/pi-agent-plugin/`), manual | tsc + vitest + tsup build (dist artifact check) on Node 20, 22 |
|
||||
| docs llms.txt | `docs-llms-txt-check.yml` | Manual | `docs/llms.txt` coverage check |
|
||||
|
||||
When adding a new package CI workflow: give it `workflow_call` (plus `push`/`workflow_dispatch` as needed, but no `pull_request` trigger), then register it in `ci-gate.yml` — a path filter under the `changes` job, a call job, and an entry in the gate job's `needs` list.
|
||||
|
||||
### CD Workflows (automated publishing)
|
||||
|
||||
Publishing is routed through a single entry point: **`release.yml` (Release Router)** is the only workflow that listens to `release: published` events. It matches the release tag prefix and dispatches the corresponding package workflow via `workflow_dispatch`, so each release produces exactly one routed run (no skipped runs from the other pipelines).
|
||||
|
||||
| Workflow | File | Tag Prefix | Target |
|
||||
|----------|------|------------|--------|
|
||||
| Release Router | `release.yml` | (all releases) | dispatches the matching workflow below |
|
||||
| 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`) |
|
||||
| OpenCode Plugin | `opencode-plugin-cd.yml` | `opencode-v*` | npm (`@mem0/opencode-plugin`) |
|
||||
| Pi Agent Plugin | `pi-agent-plugin-cd.yml` | `pi-agent-v*` | npm (`@mem0/pi-agent-plugin`) |
|
||||
|
||||
- Package CD workflows are `workflow_dispatch`-only (inputs: `tag`, `prerelease`); they check out and build the given tag. Registry trusted-publisher settings stay pinned to each package's own workflow filename.
|
||||
- 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.
|
||||
- To re-publish a release (e.g. after a registry settings fix), do **not** delete/recreate the GitHub release — manually dispatch the package workflow instead: `gh workflow run <package>-cd.yml --ref refs/tags/<tag> -f tag=<tag>`.
|
||||
- When adding a new package: add its CD workflow (`workflow_dispatch` with `tag`/`prerelease` inputs), then register its tag prefix in the `case` block in `release.yml`. Keep the bare `v*` arm last.
|
||||
|
||||
### Utility Workflows
|
||||
|
||||
@@ -576,7 +603,6 @@ N/A
|
||||
- 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.
|
||||
|
||||
@@ -1026,7 +1026,8 @@ def get_user_preferences(user_id: str):
|
||||
### AutoGen Integration
|
||||
|
||||
```python
|
||||
from cookbooks.helper.mem0_teachability import Mem0Teachability
|
||||
# Mem0Teachability lives in examples/notebooks/helper/ — see examples/notebooks/mem0-autogen.ipynb
|
||||
from helper.mem0_teachability import Mem0Teachability
|
||||
from mem0 import Memory
|
||||
|
||||
# Add memory capability to AutoGen agents
|
||||
|
||||
@@ -1,221 +0,0 @@
|
||||
# Migration Guide: Upgrading to mem0 1.0.0
|
||||
|
||||
## TL;DR
|
||||
|
||||
**What changed?** We simplified the API by removing confusing version parameters. Now everything returns a consistent format: `{"results": [...]}`.
|
||||
|
||||
**What you need to do:**
|
||||
1. Upgrade: `pip install mem0ai==1.0.0`
|
||||
2. Remove `version` and `output_format` parameters from your code
|
||||
3. Update response handling to use `result["results"]` instead of treating responses as lists
|
||||
|
||||
**Time needed:** ~5-10 minutes for most projects
|
||||
|
||||
---
|
||||
|
||||
## Quick Migration Guide
|
||||
|
||||
### 1. Install the Update
|
||||
|
||||
```bash
|
||||
pip install mem0ai==1.0.0
|
||||
```
|
||||
|
||||
### 2. Update Your Code
|
||||
|
||||
**If you're using the Memory API:**
|
||||
|
||||
```python
|
||||
# Before
|
||||
memory = Memory(config=MemoryConfig(version="v1.1"))
|
||||
result = memory.add("I like pizza")
|
||||
|
||||
# After
|
||||
memory = Memory() # That's it - version is automatic now
|
||||
result = memory.add("I like pizza")
|
||||
```
|
||||
|
||||
**If you're using the Client API:**
|
||||
|
||||
```python
|
||||
# Before
|
||||
client.add(messages, output_format="v1.1")
|
||||
client.search(query, version="v2", output_format="v1.1")
|
||||
|
||||
# After
|
||||
client.add(messages) # Just remove those extra parameters
|
||||
client.search(query)
|
||||
```
|
||||
|
||||
### 3. Update How You Handle Responses
|
||||
|
||||
All responses now use the same format: a dictionary with `"results"` key.
|
||||
|
||||
```python
|
||||
# Before - you might have done this
|
||||
result = memory.add("I like pizza")
|
||||
for item in result: # Treating it as a list
|
||||
print(item)
|
||||
|
||||
# After - do this instead
|
||||
result = memory.add("I like pizza")
|
||||
for item in result["results"]: # Access the results key
|
||||
print(item)
|
||||
|
||||
# Graph relations (if you use them)
|
||||
if "relations" in result:
|
||||
for relation in result["relations"]:
|
||||
print(relation)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Enhanced Message Handling
|
||||
|
||||
The platform client (MemoryClient) now supports the same flexible message formats as the OSS version:
|
||||
|
||||
```python
|
||||
from mem0 import MemoryClient
|
||||
|
||||
client = MemoryClient(api_key="your-key")
|
||||
|
||||
# All three formats now work:
|
||||
|
||||
# 1. Single string (automatically converted to user message)
|
||||
client.add("I like pizza", user_id="alice")
|
||||
|
||||
# 2. Single message dictionary
|
||||
client.add({"role": "user", "content": "I like pizza"}, user_id="alice")
|
||||
|
||||
# 3. List of messages (conversation)
|
||||
client.add([
|
||||
{"role": "user", "content": "I like pizza"},
|
||||
{"role": "assistant", "content": "I'll remember that!"}
|
||||
], user_id="alice")
|
||||
```
|
||||
|
||||
### Async Mode Configuration
|
||||
|
||||
The `async_mode` parameter now defaults to `True` but can be configured:
|
||||
|
||||
```python
|
||||
# Default behavior (async_mode=True)
|
||||
client.add(messages, user_id="alice")
|
||||
|
||||
# Explicitly set async mode
|
||||
client.add(messages, user_id="alice", async_mode=True)
|
||||
|
||||
# Disable async mode if needed
|
||||
client.add(messages, user_id="alice", async_mode=False)
|
||||
```
|
||||
|
||||
**Note:** `async_mode=True` provides better performance for most use cases. Only set it to `False` if you have specific synchronous processing requirements.
|
||||
|
||||
---
|
||||
|
||||
## That's It!
|
||||
|
||||
For most users, that's all you need to know. The changes are:
|
||||
- ✅ No more `version` or `output_format` parameters
|
||||
- ✅ Consistent `{"results": [...]}` response format
|
||||
- ✅ Cleaner, simpler API
|
||||
|
||||
---
|
||||
|
||||
## Common Issues
|
||||
|
||||
**Getting `KeyError: 'results'`?**
|
||||
|
||||
Your code is still treating the response as a list. Update it:
|
||||
```python
|
||||
# Change this:
|
||||
for memory in response:
|
||||
|
||||
# To this:
|
||||
for memory in response["results"]:
|
||||
```
|
||||
|
||||
**Getting `TypeError: unexpected keyword argument`?**
|
||||
|
||||
You're still passing old parameters. Remove them:
|
||||
```python
|
||||
# Change this:
|
||||
client.add(messages, output_format="v1.1")
|
||||
|
||||
# To this:
|
||||
client.add(messages)
|
||||
```
|
||||
|
||||
**Seeing deprecation warnings?**
|
||||
|
||||
Remove any explicit `version="v1.0"` from your config:
|
||||
```python
|
||||
# Change this:
|
||||
memory = Memory(config=MemoryConfig(version="v1.0"))
|
||||
|
||||
# To this:
|
||||
memory = Memory()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## What's New in 1.0.0
|
||||
|
||||
- **Better vector stores:** Fixed OpenSearch and improved reliability across all stores
|
||||
- **Cleaner API:** One way to do things, no more confusing options
|
||||
- **Enhanced GCP support:** Better Vertex AI configuration options
|
||||
- **Flexible message input:** Platform client now accepts strings, dicts, and lists (aligned with OSS)
|
||||
- **Configurable async_mode:** Now defaults to `True` but users can override if needed
|
||||
|
||||
---
|
||||
|
||||
## Need Help?
|
||||
|
||||
- Check [GitHub Issues](https://github.com/mem0ai/mem0/issues)
|
||||
- Read the [documentation](https://docs.mem0.ai/)
|
||||
- Open a new issue if you're stuck
|
||||
|
||||
---
|
||||
|
||||
## Advanced: Configuration Changes
|
||||
|
||||
**If you configured vector stores with version:**
|
||||
|
||||
```python
|
||||
# Before
|
||||
config = MemoryConfig(
|
||||
version="v1.1",
|
||||
vector_store=VectorStoreConfig(...)
|
||||
)
|
||||
|
||||
# After
|
||||
config = MemoryConfig(
|
||||
vector_store=VectorStoreConfig(...)
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Testing Your Migration
|
||||
|
||||
Quick sanity check:
|
||||
|
||||
```python
|
||||
from mem0 import Memory
|
||||
|
||||
memory = Memory()
|
||||
|
||||
# Add should return a dict with "results"
|
||||
result = memory.add("I like pizza", user_id="test")
|
||||
assert "results" in result
|
||||
|
||||
# Search should return a dict with "results"
|
||||
search = memory.search("food", user_id="test")
|
||||
assert "results" in search
|
||||
|
||||
# Get all should return a dict with "results"
|
||||
all_memories = memory.get_all(user_id="test")
|
||||
assert "results" in all_memories
|
||||
|
||||
print("✅ Migration successful!")
|
||||
```
|
||||
@@ -86,7 +86,25 @@ See the [migration guide](https://docs.mem0.ai/migration/oss-v2-to-v3) for upgra
|
||||
|
||||
## 🚀 Quickstart Guide <a name="quickstart"></a>
|
||||
|
||||
> **Agent Mode — for AI agents setting up Mem0 autonomously.** Run `mem0 init --agent --agent-caller <your-name> --json` (after `pip install mem0-cli` or `npm install -g @mem0/cli`), replacing `<your-name>` with your AI agent identity (e.g. `claude-code`, `cursor`, `codex`). This mints an evaluation Mem0 API key in <5 seconds — no email, no dashboard, no OTP. If you forgot to pass `--agent-caller`, run `mem0 identify <your-name>` after init. Use the key immediately against the Platform or the MCP server. The human owner can claim ownership later with `mem0 init --email <their-email>`: memories transfer, the same key keeps working, and the agent isn't disrupted.
|
||||
### Sign up as an agent
|
||||
|
||||
AI agents can mint a working Mem0 API key in under five seconds — no email, no dashboard, no OTP. Four commands end-to-end:
|
||||
|
||||
```bash
|
||||
# 1. Install
|
||||
npm install -g @mem0/cli # or: pip install mem0-cli
|
||||
|
||||
# 2. Sign up as an agent (replace `claude-code` with your name)
|
||||
mem0 init --agent --agent-caller claude-code
|
||||
|
||||
# 3. Add a memory
|
||||
mem0 add "I am using mem0"
|
||||
|
||||
# 4. Search
|
||||
mem0 search "am I using mem0"
|
||||
```
|
||||
|
||||
The human owner can claim the account later with `mem0 init --email <their-email>` — same key, memories preserved. Full guide: [Sign up as an agent](https://docs.mem0.ai/platform/agent-signup).
|
||||
|
||||
| | Library | Self-Hosted Server | Cloud Platform |
|
||||
|---|---------|-------------------|----------------|
|
||||
@@ -135,6 +153,7 @@ See the [self-hosted docs](https://docs.mem0.ai/open-source/overview) for config
|
||||
|
||||
1. Sign up on [Mem0 Platform](https://app.mem0.ai?utm_source=oss&utm_medium=readme)
|
||||
2. Embed the memory layer via SDK or API keys
|
||||
3. Using hosted Qdrant vectors? See the [Platform migration guide](https://docs.mem0.ai/migration/oss-to-platform) to import them into Mem0 Platform.
|
||||
|
||||
### CLI
|
||||
|
||||
@@ -167,9 +186,10 @@ npx skills add https://github.com/mem0ai/mem0 --skill mem0-vercel-ai-sdk
|
||||
```bash
|
||||
npx skills add https://github.com/mem0ai/mem0 --skill mem0-integrate
|
||||
npx skills add https://github.com/mem0ai/mem0 --skill mem0-test-integration
|
||||
npx skills add https://github.com/mem0ai/mem0 --skill mem0-oss-to-platform
|
||||
```
|
||||
|
||||
Use `/mem0-integrate` to wire Mem0 into an existing repo via a test-first pipeline, then `/mem0-test-integration` to verify. See the [skills catalog](./skills/) or [Vibecoding with Mem0](https://docs.mem0.ai/vibecoding) for the full picture.
|
||||
Use `/mem0-integrate` to wire Mem0 into an existing repo via a test-first pipeline, then `/mem0-test-integration` to verify. Use `/mem0-oss-to-platform` to migrate an existing project from Mem0 OSS to the hosted Platform SDK. See the [skills catalog](./skills/) or [Vibecoding with Mem0](https://docs.mem0.ai/vibecoding) for the full picture.
|
||||
|
||||
### Basic Usage
|
||||
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to `@mem0/cli` are documented here.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.2.9] — 2026-06-19
|
||||
|
||||
### Security
|
||||
|
||||
- Telemetry no longer passes the Mem0 API key to its child process via
|
||||
command-line arguments. The context is now sent over stdin, so the key is no
|
||||
longer visible in the process list (`ps`, `/proc/<pid>/cmdline`, Activity
|
||||
Monitor). Fixes #4862.
|
||||
|
||||
## [0.2.8] — 2026-06-01
|
||||
|
||||
### Security
|
||||
|
||||
- Pinned transitive dependencies via pnpm overrides to remediate high-severity CVEs:
|
||||
- `jws` → 4.0.1 (CVE-2025-65945)
|
||||
- `langsmith` → ^0.6.0 (CVE-2026-45134)
|
||||
- `tar-fs` → ^2.1.4 (CVE-2025-48387, CVE-2025-59343)
|
||||
- `picomatch` → ^2.3.2 (CVE-2026-33671)
|
||||
- `minimatch` → ^3.1.3 / ^5.1.8 / ^9.0.7 (CVE-2026-27903, CVE-2026-27904, CVE-2026-26996)
|
||||
- `path-to-regexp` → ^8.4.0 (CVE-2026-4926)
|
||||
- `rollup` → ^4.59.0 (CVE-2026-27606)
|
||||
- `glob` → ^10.5.0 (CVE-2025-64756)
|
||||
- `@modelcontextprotocol/sdk` → ^1.25.4 (CVE-2025-66414, CVE-2026-0621)
|
||||
|
||||
## [0.2.7] — 2026-05-20
|
||||
|
||||
### Added
|
||||
|
||||
- `mem0 whoami` — print the active agent's `default_user_id` (the AGENTRUSH
|
||||
leaderboard identifier). Reads from local config, no network call.
|
||||
- `mem0 agent-rush <add | search>` — subcommand group that wraps the new
|
||||
`/v1/agent-rush/` platform endpoints for the 7-day AGENTRUSH game. Project
|
||||
routing is implicit (resolved server-side); no flags exposed. Pretty-prints
|
||||
platform error codes into actionable hints (e.g. `agentrush_search_first`
|
||||
→ "Run 3 'mem0 agent-rush search' commands before adding.").
|
||||
- PII safety prompt on first `mem0 agent-rush add`. Interactive runs require
|
||||
explicit `y` to acknowledge that AGENTRUSH memories are public; the
|
||||
acknowledgement is persisted in `~/.mem0/config.json` under
|
||||
`agent_rush.acknowledged_at` so the prompt only appears once per machine.
|
||||
Non-interactive (agent) invocations surface the warning to stderr without
|
||||
blocking.
|
||||
- New config schema field: `agent_rush.acknowledged_at` (ISO timestamp,
|
||||
empty until first interactive acknowledgement).
|
||||
|
||||
### Changed
|
||||
|
||||
- HTTP requests from the new agent-rush commands send `X-Mem0-Mode: agent-rush`
|
||||
in addition to the existing source headers, so platform telemetry can split
|
||||
game traffic from regular CLI usage.
|
||||
|
||||
## [0.2.6] and earlier
|
||||
|
||||
Unlogged historical releases. See git history under `cli/node/`.
|
||||
+13
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mem0/cli",
|
||||
"version": "0.2.5",
|
||||
"version": "0.2.9",
|
||||
"description": "The official CLI for mem0 — the memory layer for AI agents",
|
||||
"type": "module",
|
||||
"bin": {
|
||||
@@ -40,8 +40,19 @@
|
||||
"typescript": "^5.4.0",
|
||||
"tsup": "^8.0.0",
|
||||
"tsx": "^4.7.0",
|
||||
"vitest": "^1.5.0",
|
||||
"vite": "^6.0.0",
|
||||
"vitest": "^4.1.0",
|
||||
"@biomejs/biome": "^1.7.0",
|
||||
"@types/node": "^20.0.0"
|
||||
},
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"jws@4.0.0": "4.0.1",
|
||||
"langsmith@<0.6.0": "^0.6.0",
|
||||
"tar-fs@>=2.0.0 <2.1.4": "^2.1.4",
|
||||
"picomatch@<2.3.2": "^2.3.2",
|
||||
"postcss@<8.5.10": ">=8.5.10",
|
||||
"esbuild": ">=0.28.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+310
-723
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,14 @@
|
||||
packages:
|
||||
- '.'
|
||||
|
||||
onlyBuiltDependencies:
|
||||
- "@biomejs/biome"
|
||||
- esbuild
|
||||
|
||||
overrides:
|
||||
jws@4.0.0: 4.0.1
|
||||
langsmith@<0.6.0: ^0.6.0
|
||||
tar-fs@>=2.0.0 <2.1.4: ^2.1.4
|
||||
picomatch@<2.3.2: ^2.3.2
|
||||
"postcss@<8.5.10": ">=8.5.10"
|
||||
"esbuild": ">=0.28.1"
|
||||
@@ -247,7 +247,7 @@ export async function claimViaOtp(
|
||||
printError(`Claim failed: ${detail}`);
|
||||
if (errCode === "email_already_claimed") {
|
||||
console.log(
|
||||
` ${dim("Tip: this email already has a Mem0 account. Sign in there and run `mem0 link <key>` to attach this agent.")}`,
|
||||
` ${dim("Tip: this email already has a Mem0 account. Sign in at app.mem0.ai with your existing credentials.")}`,
|
||||
);
|
||||
}
|
||||
process.exit(1);
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
/**
|
||||
* `mem0 agent-rush <add|search> "..."` — wraps the AGENTRUSH platform endpoints.
|
||||
* Project routing is implicit (server-side); zero flags needed.
|
||||
*/
|
||||
|
||||
import readline from "node:readline";
|
||||
import { colors, printError, printSuccess } from "../branding.js";
|
||||
import { loadConfig, saveConfig } from "../config.js";
|
||||
import { CLI_VERSION } from "../version.js";
|
||||
|
||||
const PII_WARNING = [
|
||||
"",
|
||||
"⚠️ AGENTRUSH memories are PUBLIC — visible to any other player.",
|
||||
" Do not include real names, emails, secrets, work content, or PII.",
|
||||
"",
|
||||
].join("\n");
|
||||
|
||||
const ERROR_HINTS: Record<string, string> = {
|
||||
agentrush_search_first:
|
||||
"Run 3 'mem0 agent-rush search' commands before adding.",
|
||||
agentrush_search_quota: "You've used your 3 lifetime searches.",
|
||||
agentrush_add_quota: "You've used your 3 lifetime adds.",
|
||||
agentrush_not_agent_mode:
|
||||
"Re-run 'mem0 init --agent' to bootstrap an agent-mode key.",
|
||||
agentrush_length: "Memory text must be 50-1000 characters.",
|
||||
agentrush_no_urls: "URLs are not allowed.",
|
||||
agentrush_blocklist: "Content contains a blocked term.",
|
||||
agentrush_global_quota: "Event-wide cap reached. Try again later.",
|
||||
agentrush_not_provisioned:
|
||||
"AGENTRUSH is not provisioned in this environment.",
|
||||
};
|
||||
|
||||
async function callEndpoint(
|
||||
path: string,
|
||||
body: Record<string, unknown>,
|
||||
): Promise<unknown> {
|
||||
const config = loadConfig();
|
||||
const baseUrl = (config.platform?.baseUrl ?? "https://api.mem0.ai").replace(
|
||||
/\/+$/,
|
||||
"",
|
||||
);
|
||||
|
||||
if (!config.platform?.apiKey) {
|
||||
printError("Not initialized. Run `mem0 init --agent` first.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const resp = await fetch(`${baseUrl}${path}`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
Authorization: `Token ${config.platform.apiKey}`,
|
||||
"Content-Type": "application/json",
|
||||
"X-Mem0-Source": "cli",
|
||||
"X-Mem0-Client-Language": "node",
|
||||
"X-Mem0-Client-Version": CLI_VERSION,
|
||||
"X-Mem0-Mode": "agent-rush",
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
signal: AbortSignal.timeout(30_000),
|
||||
});
|
||||
|
||||
const json = await resp.json().catch(() => ({}));
|
||||
|
||||
if (!resp.ok) {
|
||||
const code =
|
||||
(json as { error?: { code?: string } }).error?.code ?? "unknown";
|
||||
printError(`AGENTRUSH error: ${code}`);
|
||||
if (ERROR_HINTS[code]) {
|
||||
console.log(` ${colors.dim(ERROR_HINTS[code])}`);
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
function promptLine(question: string): Promise<string> {
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout,
|
||||
});
|
||||
return new Promise((resolve) => {
|
||||
rl.question(question, (answer) => {
|
||||
rl.close();
|
||||
resolve(answer.trim());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure the human has acknowledged that AGENTRUSH memories are PUBLIC.
|
||||
*
|
||||
* Interactive (TTY): show the prompt; on "y" persist `agentRush.acknowledgedAt`
|
||||
* so we never ask the same machine twice. On anything else, abort.
|
||||
*
|
||||
* Non-interactive (agent invocation, no TTY): print the warning to stderr
|
||||
* for the human reading the agent's transcript and proceed — agents can't
|
||||
* answer y/N prompts.
|
||||
*/
|
||||
async function ensureWarningAcknowledged(): Promise<void> {
|
||||
const config = loadConfig();
|
||||
if (config.agentRush?.acknowledgedAt) return;
|
||||
|
||||
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
||||
// Agent context: surface the warning to stderr, don't block.
|
||||
console.error(PII_WARNING);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(PII_WARNING);
|
||||
const answer = (await promptLine(" Continue? [y/N]: ")).toLowerCase();
|
||||
if (answer !== "y" && answer !== "yes") {
|
||||
printError("Aborted.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
config.agentRush.acknowledgedAt = new Date().toISOString();
|
||||
saveConfig(config);
|
||||
}
|
||||
|
||||
export async function cmdAgentRushAdd(content: string): Promise<void> {
|
||||
await ensureWarningAcknowledged();
|
||||
const result = await callEndpoint("/v1/agent-rush/memories/", { content });
|
||||
printSuccess(
|
||||
`Memory submitted (event_id: ${(result as { event_id?: string }).event_id ?? "?"})`,
|
||||
);
|
||||
}
|
||||
|
||||
export async function cmdAgentRushSearch(query: string): Promise<void> {
|
||||
const result = (await callEndpoint("/v1/agent-rush/memories/search/", {
|
||||
query,
|
||||
})) as {
|
||||
results?: Array<{ memory?: string }>;
|
||||
memories?: Array<{ memory?: string }>;
|
||||
};
|
||||
|
||||
const memories = result.results ?? result.memories ?? [];
|
||||
|
||||
if (memories.length === 0) {
|
||||
console.log(colors.dim("(no results)"));
|
||||
return;
|
||||
}
|
||||
|
||||
memories.slice(0, 5).forEach((m, i) => {
|
||||
console.log(` ${i + 1}. ${m.memory ?? JSON.stringify(m)}`);
|
||||
});
|
||||
}
|
||||
@@ -46,7 +46,7 @@ export async function cmdAdd(
|
||||
file?: string;
|
||||
metadata?: string;
|
||||
immutable: boolean;
|
||||
noInfer: boolean;
|
||||
infer?: boolean;
|
||||
expires?: string;
|
||||
categories?: string;
|
||||
output: string;
|
||||
@@ -136,7 +136,7 @@ export async function cmdAdd(
|
||||
runId: opts.runId,
|
||||
metadata: meta,
|
||||
immutable: opts.immutable,
|
||||
infer: !opts.noInfer,
|
||||
infer: opts.infer !== false,
|
||||
expires: opts.expires,
|
||||
categories: cats,
|
||||
});
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* `mem0 whoami` — print the active agent's default_user_id (AGENTRUSH identifier).
|
||||
* Reads from local config; no network call.
|
||||
*/
|
||||
|
||||
import { colors, printError, printInfo } from "../branding.js";
|
||||
import { loadConfig } from "../config.js";
|
||||
|
||||
export async function cmdWhoami(): Promise<void> {
|
||||
const config = loadConfig();
|
||||
const sessionId = config.platform?.defaultUserId;
|
||||
if (!sessionId) {
|
||||
printError("No default_user_id found. Run `mem0 init --agent` first.");
|
||||
process.exit(1);
|
||||
}
|
||||
console.log(`Your AGENTRUSH identifier: ${colors.brand(sessionId)}`);
|
||||
printInfo("Find your row at https://mem0.ai/agentrush");
|
||||
}
|
||||
@@ -40,11 +40,18 @@ export interface TelemetryConfig {
|
||||
anonymousId: string;
|
||||
}
|
||||
|
||||
export interface AgentRushConfig {
|
||||
// ISO timestamp the human acknowledged the "memories are public" warning.
|
||||
// Empty until first interactive `mem0 agent-rush add`.
|
||||
acknowledgedAt: string;
|
||||
}
|
||||
|
||||
export interface Mem0Config {
|
||||
version: number;
|
||||
defaults: DefaultsConfig;
|
||||
platform: PlatformConfig;
|
||||
telemetry: TelemetryConfig;
|
||||
agentRush: AgentRushConfig;
|
||||
}
|
||||
|
||||
export function createDefaultConfig(): Mem0Config {
|
||||
@@ -69,6 +76,9 @@ export function createDefaultConfig(): Mem0Config {
|
||||
telemetry: {
|
||||
anonymousId: "",
|
||||
},
|
||||
agentRush: {
|
||||
acknowledgedAt: "",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -103,6 +113,8 @@ export function loadConfig(): Mem0Config {
|
||||
config.defaults.runId = defaults.run_id ?? "";
|
||||
const telemetry = data.telemetry ?? {};
|
||||
config.telemetry.anonymousId = telemetry.anonymous_id ?? "";
|
||||
const agentRush = data.agent_rush ?? {};
|
||||
config.agentRush.acknowledgedAt = agentRush.acknowledged_at ?? "";
|
||||
}
|
||||
|
||||
// Environment variable overrides
|
||||
@@ -143,6 +155,9 @@ export function saveConfig(config: Mem0Config): void {
|
||||
telemetry: {
|
||||
anonymous_id: config.telemetry.anonymousId,
|
||||
},
|
||||
agent_rush: {
|
||||
acknowledged_at: config.agentRush.acknowledgedAt,
|
||||
},
|
||||
};
|
||||
|
||||
fs.writeFileSync(CONFIG_FILE, JSON.stringify(data, null, 2));
|
||||
|
||||
@@ -262,6 +262,48 @@ program
|
||||
await runIdentify(name);
|
||||
});
|
||||
|
||||
// ── Setup: whoami (print active agent identifier) ────────────────────────
|
||||
|
||||
program
|
||||
.command("whoami")
|
||||
.description("Print the active agent's AGENTRUSH identifier.")
|
||||
.action(async () => {
|
||||
const { cmdWhoami } = await import("./commands/whoami.js");
|
||||
await cmdWhoami();
|
||||
});
|
||||
|
||||
// ── AGENTRUSH subcommand group ────────────────────────────────────────────
|
||||
|
||||
const agentRush = program
|
||||
.command("agent-rush")
|
||||
.description("AGENTRUSH game commands.")
|
||||
.addHelpCommand(false)
|
||||
.configureHelp({ formatHelp: richFormatHelp });
|
||||
|
||||
agentRush
|
||||
.command("add <content...>")
|
||||
.description("Submit a memory to AGENTRUSH.")
|
||||
.addHelpText(
|
||||
"after",
|
||||
'\nExamples:\n $ mem0 agent-rush add "I used mem0 to build a coding agent"\n $ mem0 agent-rush add "Agents that remember are better agents"',
|
||||
)
|
||||
.action(async (parts: string[]) => {
|
||||
const { cmdAgentRushAdd } = await import("./commands/agent-rush.js");
|
||||
await cmdAgentRushAdd(parts.join(" "));
|
||||
});
|
||||
|
||||
agentRush
|
||||
.command("search <query...>")
|
||||
.description("Search AGENTRUSH memories.")
|
||||
.addHelpText(
|
||||
"after",
|
||||
'\nExamples:\n $ mem0 agent-rush search "agents and memory and tools"\n $ mem0 agent-rush search "coding assistant"',
|
||||
)
|
||||
.action(async (parts: string[]) => {
|
||||
const { cmdAgentRushSearch } = await import("./commands/agent-rush.js");
|
||||
await cmdAgentRushSearch(parts.join(" "));
|
||||
});
|
||||
|
||||
// ── Memory: add ───────────────────────────────────────────────────────────
|
||||
|
||||
program
|
||||
|
||||
@@ -145,11 +145,11 @@ export function captureEvent(
|
||||
anonDistinctIdToAlias: anonIdToAlias,
|
||||
};
|
||||
|
||||
const child = spawn(
|
||||
process.execPath,
|
||||
[SENDER_SCRIPT, JSON.stringify(context)],
|
||||
{ detached: true, stdio: "ignore" },
|
||||
);
|
||||
const child = spawn(process.execPath, [SENDER_SCRIPT], {
|
||||
detached: true,
|
||||
stdio: ["pipe", "ignore", "ignore"],
|
||||
});
|
||||
child.stdin?.end(JSON.stringify(context));
|
||||
child.unref();
|
||||
} catch {
|
||||
/* silently swallow */
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/**
|
||||
* Standalone telemetry sender — runs as a detached child process.
|
||||
*
|
||||
* Usage: node telemetry-sender.cjs '<json context>'
|
||||
* Usage: node telemetry-sender.cjs (JSON context is read from stdin; a single
|
||||
* argv argument is still accepted as a legacy fallback)
|
||||
*
|
||||
* This script is spawned by telemetry.captureEvent() and runs independently
|
||||
* of the parent CLI process. It:
|
||||
@@ -19,6 +20,31 @@
|
||||
const https = require("https");
|
||||
const fs = require("fs");
|
||||
|
||||
function loadContext() {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (process.argv[2]) {
|
||||
try {
|
||||
resolve(JSON.parse(process.argv[2]));
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let data = "";
|
||||
process.stdin.setEncoding("utf8");
|
||||
process.stdin.on("data", (chunk) => (data += chunk));
|
||||
process.stdin.on("end", () => {
|
||||
try {
|
||||
resolve(JSON.parse(data));
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
process.stdin.on("error", reject);
|
||||
});
|
||||
}
|
||||
|
||||
function httpsRequest(url, method, headers, body) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const u = new URL(url);
|
||||
@@ -108,7 +134,7 @@ async function sendIdentifyEvent(ctx, payload, anonId) {
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const ctx = JSON.parse(process.argv[2]);
|
||||
const ctx = await loadContext();
|
||||
const payload = ctx.payload;
|
||||
|
||||
if (ctx.needsEmail && ctx.mem0ApiKey) {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*/
|
||||
|
||||
import { describe, it, expect, vi, beforeEach } from "vitest";
|
||||
import { Command } from "commander";
|
||||
import { createMockBackend } from "./setup.js";
|
||||
import type { Backend } from "../src/backend/base.js";
|
||||
import { setAgentMode } from "../src/state.js";
|
||||
@@ -41,8 +42,6 @@ describe("cmdAdd", () => {
|
||||
await cmdAdd(mockBackend, "I prefer dark mode", {
|
||||
userId: "alice",
|
||||
immutable: false,
|
||||
noInfer: false,
|
||||
|
||||
output: "text",
|
||||
});
|
||||
expect(mockBackend.add).toHaveBeenCalledOnce();
|
||||
@@ -54,8 +53,6 @@ describe("cmdAdd", () => {
|
||||
userId: "alice",
|
||||
messages: JSON.stringify([{ role: "user", content: "I love Python" }]),
|
||||
immutable: false,
|
||||
noInfer: false,
|
||||
|
||||
output: "text",
|
||||
});
|
||||
expect(mockBackend.add).toHaveBeenCalledOnce();
|
||||
@@ -66,8 +63,6 @@ describe("cmdAdd", () => {
|
||||
await cmdAdd(mockBackend, "test", {
|
||||
userId: "alice",
|
||||
immutable: false,
|
||||
noInfer: false,
|
||||
|
||||
output: "json",
|
||||
});
|
||||
expect(output).toContain("results");
|
||||
@@ -78,14 +73,59 @@ describe("cmdAdd", () => {
|
||||
await cmdAdd(mockBackend, "test", {
|
||||
userId: "alice",
|
||||
immutable: false,
|
||||
noInfer: false,
|
||||
|
||||
output: "quiet",
|
||||
});
|
||||
expect(output).not.toContain("dark mode");
|
||||
});
|
||||
});
|
||||
|
||||
describe("cmdAdd forwards --no-infer (regression for #5261)", () => {
|
||||
it("forwards infer: false when --no-infer is set", async () => {
|
||||
const { cmdAdd } = await import("../src/commands/memory.js");
|
||||
// `infer: false` is the shape Commander produces for `--no-infer`.
|
||||
await cmdAdd(mockBackend, "store me verbatim", {
|
||||
userId: "alice",
|
||||
immutable: false,
|
||||
infer: false,
|
||||
output: "text",
|
||||
});
|
||||
expect(mockBackend.add).toHaveBeenCalledWith(
|
||||
"store me verbatim",
|
||||
undefined,
|
||||
expect.objectContaining({ infer: false }),
|
||||
);
|
||||
});
|
||||
|
||||
it("forwards infer: true by default (flag absent)", async () => {
|
||||
const { cmdAdd } = await import("../src/commands/memory.js");
|
||||
await cmdAdd(mockBackend, "infer me", {
|
||||
userId: "alice",
|
||||
immutable: false,
|
||||
output: "text",
|
||||
});
|
||||
expect(mockBackend.add).toHaveBeenCalledWith(
|
||||
"infer me",
|
||||
undefined,
|
||||
expect.objectContaining({ infer: true }),
|
||||
);
|
||||
});
|
||||
|
||||
it("Commander stores --no-infer as opts.infer, not opts.noInfer", () => {
|
||||
// Pins the assumption the fix relies on: Commander's `--no-X` option
|
||||
// populates the positive camelCase key (`infer`), never `noInfer`.
|
||||
const withFlag = new Command();
|
||||
withFlag.option("--no-infer", "Skip inference, store raw.").action(() => {});
|
||||
withFlag.parse(["--no-infer"], { from: "user" });
|
||||
expect(withFlag.opts().infer).toBe(false);
|
||||
expect(withFlag.opts().noInfer).toBeUndefined();
|
||||
|
||||
const withoutFlag = new Command();
|
||||
withoutFlag.option("--no-infer", "Skip inference, store raw.").action(() => {});
|
||||
withoutFlag.parse([], { from: "user" });
|
||||
expect(withoutFlag.opts().infer).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("cmdAdd deduplicates PENDING", () => {
|
||||
const DUPLICATE_PENDING = {
|
||||
results: [
|
||||
@@ -100,8 +140,6 @@ describe("cmdAdd deduplicates PENDING", () => {
|
||||
await cmdAdd(mockBackend, "test", {
|
||||
userId: "alice",
|
||||
immutable: false,
|
||||
noInfer: false,
|
||||
|
||||
output: "text",
|
||||
});
|
||||
expect(output.match(/Queued/g)?.length).toBe(1);
|
||||
@@ -113,8 +151,6 @@ describe("cmdAdd deduplicates PENDING", () => {
|
||||
await cmdAdd(mockBackend, "test", {
|
||||
userId: "alice",
|
||||
immutable: false,
|
||||
noInfer: false,
|
||||
|
||||
output: "json",
|
||||
});
|
||||
const data = JSON.parse(output);
|
||||
@@ -129,8 +165,6 @@ describe("cmdAdd deduplicates PENDING", () => {
|
||||
await cmdAdd(mockBackend, "test", {
|
||||
userId: "alice",
|
||||
immutable: false,
|
||||
noInfer: false,
|
||||
|
||||
output: "agent",
|
||||
});
|
||||
const data = JSON.parse(output);
|
||||
@@ -315,8 +349,6 @@ describe("agent mode", () => {
|
||||
await cmdAdd(mockBackend, "test preference", {
|
||||
userId: "alice",
|
||||
immutable: false,
|
||||
noInfer: false,
|
||||
|
||||
output: "agent",
|
||||
});
|
||||
const parsed = JSON.parse(output.trim());
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const mockLoadConfig = vi.fn();
|
||||
const mockSaveConfig = vi.fn();
|
||||
const mockSpawn = vi.fn();
|
||||
|
||||
vi.mock("../src/config.js", () => ({
|
||||
CONFIG_FILE: "/tmp/mem0-config.json",
|
||||
loadConfig: mockLoadConfig,
|
||||
saveConfig: mockSaveConfig,
|
||||
}));
|
||||
|
||||
vi.mock("node:child_process", () => ({
|
||||
spawn: mockSpawn,
|
||||
}));
|
||||
|
||||
describe("captureEvent", () => {
|
||||
beforeEach(() => {
|
||||
vi.resetModules();
|
||||
mockLoadConfig.mockReset();
|
||||
mockSaveConfig.mockReset();
|
||||
mockSpawn.mockReset();
|
||||
delete process.env.MEM0_TELEMETRY;
|
||||
});
|
||||
|
||||
it("pipes the telemetry context through stdin instead of argv", async () => {
|
||||
mockLoadConfig.mockReturnValue({
|
||||
platform: {
|
||||
apiKey: "m0-node-secret",
|
||||
baseUrl: "https://api.mem0.ai",
|
||||
userEmail: "",
|
||||
},
|
||||
telemetry: {
|
||||
anonymousId: "cli-anon-node",
|
||||
},
|
||||
});
|
||||
|
||||
const stdin = { end: vi.fn() };
|
||||
const child = { stdin, unref: vi.fn() };
|
||||
mockSpawn.mockReturnValue(child);
|
||||
|
||||
const { captureEvent } = await import("../src/telemetry.js");
|
||||
captureEvent("node_test_event", { case: "stdin-secret" });
|
||||
|
||||
expect(mockSpawn).toHaveBeenCalledTimes(1);
|
||||
const [execPath, args, options] = mockSpawn.mock.calls[0];
|
||||
expect(execPath).toBe(process.execPath);
|
||||
expect(args).toHaveLength(1);
|
||||
expect(String(args[0])).toContain("telemetry-sender.cjs");
|
||||
expect(JSON.stringify(args)).not.toContain("m0-node-secret");
|
||||
expect(options).toMatchObject({ detached: true, stdio: ["pipe", "ignore", "ignore"] });
|
||||
|
||||
expect(stdin.end).toHaveBeenCalledTimes(1);
|
||||
const payload = JSON.parse(stdin.end.mock.calls[0][0]);
|
||||
expect(payload.mem0ApiKey).toBe("m0-node-secret");
|
||||
expect(payload.payload.event).toBe("node_test_event");
|
||||
expect(child.unref).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
@@ -8,4 +8,10 @@ export default defineConfig({
|
||||
define: {
|
||||
__CLI_VERSION__: JSON.stringify(pkg.version),
|
||||
},
|
||||
test: {
|
||||
// Integration tests spawn the CLI via `npx tsx` (15s subprocess
|
||||
// timeout); the first spawn in a file pays a cold-start cost that can
|
||||
// exceed vitest's 5s default on CI runners.
|
||||
testTimeout: 30_000,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to `mem0-cli` (Python) are documented here.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.2.8] — 2026-06-19
|
||||
|
||||
### Security
|
||||
|
||||
- Telemetry no longer passes the Mem0 API key to its child process via
|
||||
command-line arguments. The context is now sent over stdin, so the key is no
|
||||
longer visible in the process list (`ps`, `/proc/<pid>/cmdline`, Activity
|
||||
Monitor). Fixes #4862.
|
||||
|
||||
### Fixed
|
||||
|
||||
- `__version__` now matches the packaged version (was stale at 0.2.4).
|
||||
|
||||
## [0.2.7] — 2026-05-20
|
||||
|
||||
### Added
|
||||
|
||||
- `mem0 whoami` — print the active agent's `default_user_id` (the AGENTRUSH
|
||||
leaderboard identifier). Reads from local config, no network call.
|
||||
- `mem0 agent-rush <add | search>` — subcommand group that wraps the new
|
||||
`/v1/agent-rush/` platform endpoints for the 7-day AGENTRUSH game. Project
|
||||
routing is implicit (resolved server-side); no flags exposed. Pretty-prints
|
||||
platform error codes into actionable hints (e.g. `agentrush_search_first`
|
||||
→ "Run 3 'mem0 agent-rush search' commands before adding.").
|
||||
- PII safety prompt on first `mem0 agent-rush add`. Interactive runs require
|
||||
explicit `y` to acknowledge that AGENTRUSH memories are public; the
|
||||
acknowledgement is persisted in `~/.mem0/config.json` under
|
||||
`agent_rush.acknowledged_at` so the prompt only appears once per machine.
|
||||
Non-interactive (agent) invocations surface the warning to stderr without
|
||||
blocking.
|
||||
- New config schema field: `agent_rush.acknowledged_at` (ISO timestamp,
|
||||
empty until first interactive acknowledgement).
|
||||
|
||||
### Changed
|
||||
|
||||
- HTTP requests from the new agent-rush commands send `X-Mem0-Mode: agent-rush`
|
||||
in addition to the existing source headers, so platform telemetry can split
|
||||
game traffic from regular CLI usage.
|
||||
|
||||
## [0.2.6] and earlier
|
||||
|
||||
Unlogged historical releases. See git history under `cli/python/`.
|
||||
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "mem0-cli"
|
||||
version = "0.2.5"
|
||||
version = "0.2.8"
|
||||
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.2.4"
|
||||
__version__ = "0.2.8"
|
||||
|
||||
@@ -914,6 +914,65 @@ def identify(
|
||||
run_identify(name)
|
||||
|
||||
|
||||
@app.command(name="whoami", rich_help_panel="Setup")
|
||||
def whoami_cmd() -> None:
|
||||
"""Print your AGENTRUSH identifier (default_user_id).
|
||||
|
||||
Example:
|
||||
mem0 whoami
|
||||
"""
|
||||
from mem0_cli.commands.whoami_cmd import run_whoami
|
||||
|
||||
run_whoami()
|
||||
|
||||
|
||||
# ── AGENTRUSH sub-app ─────────────────────────────────────────────────────
|
||||
|
||||
agent_rush_app = typer.Typer(
|
||||
name="agent-rush",
|
||||
help="AGENTRUSH game commands",
|
||||
no_args_is_help=True,
|
||||
rich_markup_mode="rich",
|
||||
)
|
||||
|
||||
|
||||
@agent_rush_app.callback(invoke_without_command=True)
|
||||
def _agent_rush_callback(ctx: typer.Context) -> None:
|
||||
if ctx.invoked_subcommand:
|
||||
_fire_telemetry(f"agent-rush.{ctx.invoked_subcommand}")
|
||||
|
||||
|
||||
@agent_rush_app.command(name="add")
|
||||
def agent_rush_add(
|
||||
content: str = typer.Argument(..., help="Memory content (50-1000 characters, no URLs)."),
|
||||
) -> None:
|
||||
"""Submit a memory to AGENTRUSH.
|
||||
|
||||
Example:
|
||||
mem0 agent-rush add "I enjoy solving constraint-satisfaction problems."
|
||||
"""
|
||||
from mem0_cli.commands.agent_rush_cmd import run_agent_rush_add
|
||||
|
||||
run_agent_rush_add(content)
|
||||
|
||||
|
||||
@agent_rush_app.command(name="search")
|
||||
def agent_rush_search(
|
||||
query: str = typer.Argument(..., help="Search query."),
|
||||
) -> None:
|
||||
"""Search AGENTRUSH memories.
|
||||
|
||||
Example:
|
||||
mem0 agent-rush search "constraint satisfaction"
|
||||
"""
|
||||
from mem0_cli.commands.agent_rush_cmd import run_agent_rush_search
|
||||
|
||||
run_agent_rush_search(query)
|
||||
|
||||
|
||||
app.add_typer(agent_rush_app, name="agent-rush", rich_help_panel="Setup")
|
||||
|
||||
|
||||
# (entity_app registered at module level, below sub-group definitions)
|
||||
|
||||
|
||||
|
||||
@@ -218,7 +218,7 @@ def claim_via_otp(config: Mem0Config, *, email: str, code: str | None = None) ->
|
||||
print_error(err_console, f"Claim failed: {detail}")
|
||||
if code_str == "email_already_claimed":
|
||||
console.print(
|
||||
f" [{DIM_COLOR}]Tip: this email already has a Mem0 account. Sign in there and run `mem0 link <key>` to attach this agent.[/]"
|
||||
f" [{DIM_COLOR}]Tip: this email already has a Mem0 account. Sign in at app.mem0.ai with your existing credentials.[/]"
|
||||
)
|
||||
raise typer.Exit(1)
|
||||
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
"""mem0 agent-rush — AGENTRUSH game commands.
|
||||
|
||||
Wraps the platform's /v1/agent-rush/{memories/, memories/search/} endpoints.
|
||||
Hardcoded routing; no flags needed.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from datetime import datetime, timezone
|
||||
|
||||
import httpx
|
||||
import typer
|
||||
from rich.console import Console
|
||||
|
||||
from mem0_cli.branding import print_error, print_success
|
||||
from mem0_cli.config import load_config, save_config
|
||||
|
||||
console = Console()
|
||||
err_console = Console(stderr=True)
|
||||
|
||||
_PII_WARNING_LINES = (
|
||||
"",
|
||||
"[yellow]⚠️ AGENTRUSH memories are PUBLIC — visible to any other player.[/yellow]",
|
||||
"[yellow] Do not include real names, emails, secrets, work content, or PII.[/yellow]",
|
||||
"",
|
||||
)
|
||||
|
||||
_SOURCE_HEADERS = {
|
||||
"X-Mem0-Source": "cli",
|
||||
"X-Mem0-Client-Language": "python",
|
||||
"X-Mem0-Mode": "agent-rush",
|
||||
}
|
||||
|
||||
_ERROR_HINTS = {
|
||||
"agentrush_search_first": "Run 3 'mem0 agent-rush search' commands before adding.",
|
||||
"agentrush_search_quota": "You've used your 3 lifetime searches.",
|
||||
"agentrush_add_quota": "You've used your 3 lifetime adds.",
|
||||
"agentrush_not_agent_mode": "Re-run 'mem0 init --agent' to bootstrap an agent-mode key.",
|
||||
"agentrush_length": "Memory text must be 50-1000 characters.",
|
||||
"agentrush_no_urls": "URLs are not allowed.",
|
||||
"agentrush_blocklist": "Content contains a blocked term.",
|
||||
"agentrush_global_quota": "Event-wide cap reached. Try again later.",
|
||||
"agentrush_not_provisioned": "AGENTRUSH is not provisioned in this environment.",
|
||||
}
|
||||
|
||||
|
||||
def _call(path: str, body: dict) -> dict:
|
||||
config = load_config()
|
||||
if not config.platform.api_key:
|
||||
print_error(err_console, "Not initialized. Run `mem0 init --agent` first.")
|
||||
raise typer.Exit(1)
|
||||
base_url = (config.platform.base_url or "https://api.mem0.ai").rstrip("/")
|
||||
try:
|
||||
with httpx.Client(timeout=30.0) as client:
|
||||
resp = client.post(
|
||||
f"{base_url}{path}",
|
||||
headers={
|
||||
**_SOURCE_HEADERS,
|
||||
"Authorization": f"Token {config.platform.api_key}",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
json=body,
|
||||
)
|
||||
except httpx.HTTPError as exc:
|
||||
print_error(err_console, f"Network error: {exc}")
|
||||
raise typer.Exit(1) from exc
|
||||
try:
|
||||
data = resp.json()
|
||||
except Exception:
|
||||
data = {}
|
||||
if resp.status_code >= 400:
|
||||
code = (
|
||||
(data.get("error") or {}).get("code", "unknown")
|
||||
if isinstance(data, dict)
|
||||
else "unknown"
|
||||
)
|
||||
print_error(err_console, f"AGENTRUSH error: {code}")
|
||||
hint = _ERROR_HINTS.get(code)
|
||||
if hint:
|
||||
console.print(f" [dim]{hint}[/dim]")
|
||||
raise typer.Exit(1)
|
||||
return data
|
||||
|
||||
|
||||
def _ensure_warning_acknowledged() -> None:
|
||||
"""Block the first interactive add on the PII warning; pass-through for agents.
|
||||
|
||||
Interactive (TTY): show prompt, require explicit 'y', persist
|
||||
`agent_rush.acknowledged_at` so we never ask the same machine twice.
|
||||
|
||||
Non-interactive (no TTY — typical when an agent runs the CLI): surface
|
||||
the warning to stderr for the human reading the agent transcript and
|
||||
proceed without prompting (agents can't answer y/N).
|
||||
"""
|
||||
config = load_config()
|
||||
if config.agent_rush.acknowledged_at:
|
||||
return
|
||||
|
||||
is_tty = sys.stdin.isatty() and sys.stdout.isatty()
|
||||
if not is_tty:
|
||||
for line in _PII_WARNING_LINES:
|
||||
err_console.print(line)
|
||||
return
|
||||
|
||||
for line in _PII_WARNING_LINES:
|
||||
console.print(line)
|
||||
answer = typer.prompt(" Continue? [y/N]", default="N", show_default=False).strip().lower()
|
||||
if answer not in ("y", "yes"):
|
||||
print_error(err_console, "Aborted.")
|
||||
raise typer.Exit(1)
|
||||
|
||||
config.agent_rush.acknowledged_at = datetime.now(timezone.utc).isoformat()
|
||||
save_config(config)
|
||||
|
||||
|
||||
def run_agent_rush_add(content: str) -> None:
|
||||
_ensure_warning_acknowledged()
|
||||
result = _call("/v1/agent-rush/memories/", {"content": content})
|
||||
event_id = result.get("event_id", "?")
|
||||
print_success(console, f"Memory submitted (event_id: {event_id})")
|
||||
|
||||
|
||||
def run_agent_rush_search(query: str) -> None:
|
||||
result = _call("/v1/agent-rush/memories/search/", {"query": query})
|
||||
memories = result.get("results") or result.get("memories") or []
|
||||
if not memories:
|
||||
console.print("[dim](no results)[/dim]")
|
||||
return
|
||||
for i, m in enumerate(memories[:5], start=1):
|
||||
text = m.get("memory") if isinstance(m, dict) else str(m)
|
||||
console.print(f" {i}. {text}")
|
||||
@@ -0,0 +1,25 @@
|
||||
"""mem0 whoami — print the active agent's default_user_id (AGENTRUSH identifier)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import typer
|
||||
from rich.console import Console
|
||||
|
||||
from mem0_cli.branding import BRAND_COLOR, print_error, print_info
|
||||
from mem0_cli.config import load_config
|
||||
|
||||
console = Console()
|
||||
err_console = Console(stderr=True)
|
||||
|
||||
|
||||
def run_whoami() -> None:
|
||||
config = load_config()
|
||||
session_id = config.platform.default_user_id if config.platform else None
|
||||
if not session_id:
|
||||
print_error(
|
||||
err_console,
|
||||
"No default_user_id found. Run `mem0 init --agent` first.",
|
||||
)
|
||||
raise typer.Exit(1)
|
||||
console.print(f"Your AGENTRUSH identifier: [{BRAND_COLOR}]{session_id}[/{BRAND_COLOR}]")
|
||||
print_info(console, "Find your row at https://mem0.ai/agentrush")
|
||||
@@ -51,12 +51,20 @@ class TelemetryConfig:
|
||||
anonymous_id: str = ""
|
||||
|
||||
|
||||
@dataclass
|
||||
class AgentRushConfig:
|
||||
# ISO timestamp the human acknowledged the "memories are public" warning.
|
||||
# Empty until first interactive `mem0 agent-rush add`.
|
||||
acknowledged_at: str = ""
|
||||
|
||||
|
||||
@dataclass
|
||||
class Mem0Config:
|
||||
version: int = CONFIG_VERSION
|
||||
defaults: DefaultsConfig = field(default_factory=DefaultsConfig)
|
||||
platform: PlatformConfig = field(default_factory=PlatformConfig)
|
||||
telemetry: TelemetryConfig = field(default_factory=TelemetryConfig)
|
||||
agent_rush: AgentRushConfig = field(default_factory=AgentRushConfig)
|
||||
|
||||
|
||||
SHORT_KEY_ALIASES: dict[str, str] = {
|
||||
@@ -105,6 +113,9 @@ def load_config() -> Mem0Config:
|
||||
telemetry = data.get("telemetry", {})
|
||||
config.telemetry.anonymous_id = telemetry.get("anonymous_id", "")
|
||||
|
||||
agent_rush = data.get("agent_rush", {})
|
||||
config.agent_rush.acknowledged_at = agent_rush.get("acknowledged_at", "")
|
||||
|
||||
# Environment variable overrides
|
||||
env_key = os.environ.get("MEM0_API_KEY")
|
||||
if env_key:
|
||||
@@ -158,6 +169,9 @@ def save_config(config: Mem0Config) -> None:
|
||||
"telemetry": {
|
||||
"anonymous_id": config.telemetry.anonymous_id,
|
||||
},
|
||||
"agent_rush": {
|
||||
"acknowledged_at": config.agent_rush.acknowledged_at,
|
||||
},
|
||||
}
|
||||
|
||||
with open(CONFIG_FILE, "w") as f:
|
||||
|
||||
@@ -137,12 +137,19 @@ def capture_event(
|
||||
"anon_distinct_id_to_alias": anon_id_to_alias,
|
||||
}
|
||||
|
||||
subprocess.Popen(
|
||||
[sys.executable, "-m", "mem0_cli.telemetry_sender", json.dumps(context)],
|
||||
child = subprocess.Popen(
|
||||
[sys.executable, "-m", "mem0_cli.telemetry_sender"],
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
start_new_session=True,
|
||||
close_fds=True,
|
||||
text=True,
|
||||
)
|
||||
if child.stdin:
|
||||
with contextlib.suppress(Exception):
|
||||
child.stdin.write(json.dumps(context))
|
||||
with contextlib.suppress(Exception):
|
||||
child.stdin.close()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""Standalone telemetry sender — runs as a detached subprocess.
|
||||
|
||||
Usage: python -m mem0_cli.telemetry_sender '<json context>'
|
||||
Usage: python -m mem0_cli.telemetry_sender (JSON context is read from stdin;
|
||||
a single argv argument is still accepted as a legacy fallback)
|
||||
|
||||
This module is spawned by telemetry.capture_event() and runs independently
|
||||
of the parent CLI process. It:
|
||||
@@ -20,8 +21,18 @@ import sys
|
||||
import urllib.request
|
||||
|
||||
|
||||
def _load_context() -> dict:
|
||||
"""Load telemetry context from stdin, falling back to argv for compatibility."""
|
||||
raw = ""
|
||||
if not sys.stdin.isatty():
|
||||
raw = sys.stdin.read().strip()
|
||||
if not raw and len(sys.argv) > 1:
|
||||
raw = sys.argv[1]
|
||||
return json.loads(raw)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
ctx = json.loads(sys.argv[1])
|
||||
ctx = _load_context()
|
||||
payload = ctx["payload"]
|
||||
|
||||
if ctx.get("needs_email") and ctx.get("mem0_api_key"):
|
||||
|
||||
@@ -32,12 +32,13 @@ def _run(args: list[str], home_dir: str | None = None) -> subprocess.CompletedPr
|
||||
if key.startswith("MEM0_"):
|
||||
del env[key]
|
||||
env.pop("FORCE_COLOR", None)
|
||||
env["PYTHONIOENCODING"] = "utf-8"
|
||||
if home_dir:
|
||||
env["HOME"] = home_dir
|
||||
result = subprocess.run(
|
||||
[sys.executable, "-m", "mem0_cli", *args],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
env=env,
|
||||
timeout=15,
|
||||
)
|
||||
@@ -99,12 +100,13 @@ class TestArgvPreprocessing:
|
||||
result = subprocess.run(
|
||||
[sys.executable, "-m", "mem0_cli", "init", "--agent"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
env={
|
||||
**{k: v for k, v in os.environ.items() if not k.startswith("MEM0_")},
|
||||
"HOME": clean_home,
|
||||
"MEM0_BASE_URL": "http://127.0.0.1:1", # blackhole
|
||||
"FORCE_COLOR": "0",
|
||||
"PYTHONIOENCODING": "utf-8",
|
||||
},
|
||||
timeout=15,
|
||||
)
|
||||
@@ -133,12 +135,13 @@ class TestJsonEnvelopeParity:
|
||||
result = subprocess.run(
|
||||
[sys.executable, "-m", "mem0_cli", "init", "--agent", "--json"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
env={
|
||||
**{k: v for k, v in os.environ.items() if not k.startswith("MEM0_")},
|
||||
"HOME": clean_home,
|
||||
"MEM0_BASE_URL": "http://127.0.0.1:1",
|
||||
"FORCE_COLOR": "0",
|
||||
"PYTHONIOENCODING": "utf-8",
|
||||
},
|
||||
timeout=15,
|
||||
)
|
||||
|
||||
@@ -49,6 +49,7 @@ def _run(
|
||||
if key.startswith("MEM0_"):
|
||||
del env[key]
|
||||
env.pop("FORCE_COLOR", None)
|
||||
env["PYTHONIOENCODING"] = "utf-8"
|
||||
if home_dir:
|
||||
env["HOME"] = home_dir
|
||||
if env_override:
|
||||
@@ -56,7 +57,7 @@ def _run(
|
||||
result = subprocess.run(
|
||||
[sys.executable, "-m", "mem0_cli", *args],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
env=env,
|
||||
)
|
||||
return subprocess.CompletedProcess(
|
||||
|
||||
@@ -8,8 +8,8 @@ from io import StringIO
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
from click.exceptions import Exit as ClickExit
|
||||
from rich.console import Console
|
||||
from typer import Exit as TyperExit
|
||||
|
||||
from mem0_cli.commands.config_cmd import (
|
||||
cmd_config_get,
|
||||
@@ -181,7 +181,7 @@ class TestAddCommand:
|
||||
patch("mem0_cli.commands.memory.console", console),
|
||||
patch("mem0_cli.commands.memory.err_console", err_console),
|
||||
patch("mem0_cli.commands.memory._stdin_is_piped", return_value=False),
|
||||
pytest.raises((SystemExit, ClickExit)),
|
||||
pytest.raises((SystemExit, TyperExit)),
|
||||
):
|
||||
cmd_add(
|
||||
mock_backend,
|
||||
@@ -206,7 +206,7 @@ class TestAddCommand:
|
||||
with (
|
||||
patch("mem0_cli.commands.memory.console", console),
|
||||
patch("mem0_cli.commands.memory.err_console", err_console),
|
||||
pytest.raises((SystemExit, ClickExit)),
|
||||
pytest.raises((SystemExit, TyperExit)),
|
||||
):
|
||||
cmd_add(
|
||||
mock_backend,
|
||||
@@ -764,7 +764,7 @@ class TestImportCommand:
|
||||
with (
|
||||
patch("mem0_cli.commands.utils.console", console),
|
||||
patch("mem0_cli.commands.utils.err_console", err_console),
|
||||
pytest.raises((SystemExit, ClickExit)),
|
||||
pytest.raises((SystemExit, TyperExit)),
|
||||
):
|
||||
cmd_import(mock_backend, "/nonexistent/file.json", user_id=None, agent_id=None)
|
||||
|
||||
@@ -801,7 +801,7 @@ class TestEntitiesListCommand:
|
||||
with (
|
||||
patch("mem0_cli.commands.entities.console", console),
|
||||
patch("mem0_cli.commands.entities.err_console", err_console),
|
||||
pytest.raises((SystemExit, ClickExit)),
|
||||
pytest.raises((SystemExit, TyperExit)),
|
||||
):
|
||||
cmd_entities_list(mock_backend, "invalid", output="table")
|
||||
|
||||
@@ -944,7 +944,7 @@ class TestEntitiesDeleteCommand:
|
||||
with (
|
||||
patch("mem0_cli.commands.entities.console", console),
|
||||
patch("mem0_cli.commands.entities.err_console", err_console),
|
||||
pytest.raises((SystemExit, ClickExit)),
|
||||
pytest.raises((SystemExit, TyperExit)),
|
||||
):
|
||||
cmd_entities_delete(
|
||||
mock_backend,
|
||||
@@ -1308,7 +1308,7 @@ class TestAgentMode:
|
||||
patch("mem0_cli.commands.memory.console", console),
|
||||
patch("mem0_cli.commands.memory.err_console", err_console),
|
||||
patch("sys.stdout", captured_stdout),
|
||||
pytest.raises((SystemExit, ClickExit)),
|
||||
pytest.raises((SystemExit, TyperExit)),
|
||||
):
|
||||
cmd_get(mock_backend, "bad-id", output="text")
|
||||
|
||||
|
||||
@@ -67,7 +67,8 @@ class TestConfig:
|
||||
from mem0_cli.config import CONFIG_FILE
|
||||
|
||||
mode = os.stat(CONFIG_FILE).st_mode & 0o777
|
||||
assert mode == 0o600
|
||||
if os.name != "nt":
|
||||
assert mode == 0o600
|
||||
|
||||
def test_defaults_save_and_load(self, isolate_config):
|
||||
config = Mem0Config()
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
"""Tests for telemetry subprocess secret handling."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import io
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from mem0_cli.config import Mem0Config, save_config
|
||||
from mem0_cli.telemetry import capture_event
|
||||
from mem0_cli.telemetry_sender import _load_context
|
||||
|
||||
|
||||
class _CaptureStdin:
|
||||
def __init__(self):
|
||||
self.buffer = ""
|
||||
self.closed = False
|
||||
|
||||
def write(self, value: str) -> None:
|
||||
self.buffer += value
|
||||
|
||||
def close(self) -> None:
|
||||
self.closed = True
|
||||
|
||||
|
||||
class _DummyProcess:
|
||||
def __init__(self):
|
||||
self.stdin = _CaptureStdin()
|
||||
|
||||
|
||||
def test_capture_event_writes_context_to_stdin_not_argv(isolate_config, monkeypatch):
|
||||
config = Mem0Config()
|
||||
config.platform.api_key = "m0-test-secret"
|
||||
config.telemetry.anonymous_id = "cli-anon-test"
|
||||
save_config(config)
|
||||
|
||||
captured: dict[str, object] = {}
|
||||
proc = _DummyProcess()
|
||||
|
||||
def fake_popen(args, **kwargs):
|
||||
captured["args"] = args
|
||||
captured["kwargs"] = kwargs
|
||||
return proc
|
||||
|
||||
monkeypatch.setattr("mem0_cli.telemetry.subprocess.Popen", fake_popen)
|
||||
|
||||
capture_event("unit_test_event", {"case": "stdin-secret"})
|
||||
|
||||
argv = captured["args"]
|
||||
assert argv == [sys.executable, "-m", "mem0_cli.telemetry_sender"]
|
||||
assert all("m0-test-secret" not in arg for arg in argv)
|
||||
|
||||
kwargs = captured["kwargs"]
|
||||
assert kwargs["stdin"] == subprocess.PIPE
|
||||
assert kwargs["text"] is True
|
||||
|
||||
ctx = json.loads(proc.stdin.buffer)
|
||||
assert ctx["mem0_api_key"] == "m0-test-secret"
|
||||
assert ctx["payload"]["event"] == "unit_test_event"
|
||||
|
||||
assert proc.stdin.closed
|
||||
|
||||
|
||||
def test_load_context_reads_from_stdin(monkeypatch):
|
||||
monkeypatch.setattr("sys.argv", ["telemetry_sender"])
|
||||
monkeypatch.setattr("sys.stdin", io.StringIO('{"payload": {"event": "stdin"}}'))
|
||||
|
||||
ctx = _load_context()
|
||||
|
||||
assert ctx["payload"]["event"] == "stdin"
|
||||
|
||||
|
||||
def test_load_context_falls_back_to_argv(monkeypatch):
|
||||
monkeypatch.setattr("sys.argv", ["telemetry_sender", '{"payload": {"event": "argv"}}'])
|
||||
monkeypatch.setattr("sys.stdin", io.StringIO(""))
|
||||
|
||||
ctx = _load_context()
|
||||
|
||||
assert ctx["payload"]["event"] == "argv"
|
||||
@@ -79,7 +79,7 @@ new_project = client.project.create(
|
||||
|
||||
### Update Project Settings
|
||||
|
||||
Modify project configuration including custom instructions, categories, graph settings, and language preferences:
|
||||
Modify project configuration including custom instructions, categories, and language preferences:
|
||||
|
||||
```python
|
||||
# Update project with custom categories
|
||||
|
||||
@@ -46,9 +46,9 @@ Ground-up rewrite of the memory pipeline with 20+ point benchmark improvements:
|
||||
- **~3-4x fewer tokens** — Under 7K tokens per retrieval vs 25K+ for full-context approaches
|
||||
- **ADD-only extraction** — Memories accumulate; nothing is overwritten or deleted
|
||||
- **Hybrid retrieval** — Semantic + BM25 keyword + entity boost, scored in parallel
|
||||
- **Entity linking** — Entities extracted, embedded, and linked across memories
|
||||
- **Graph memory (built-in)**: entities extracted, embedded, and linked across memories, with no external graph store required
|
||||
|
||||
Breaking changes: Graph memory removed from OSS, `search()` defaults changed, deprecated params removed. See [migration guide](/migration/oss-v2-to-v3).
|
||||
Breaking changes: external graph stores removed from OSS (replaced by built-in graph memory), `search()` defaults changed, deprecated params removed. See [migration guide](/migration/oss-v2-to-v3).
|
||||
|
||||
</Update>
|
||||
|
||||
|
||||
@@ -4,6 +4,39 @@ description: "Release notes for the OpenClaw plugin and agent harness."
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
<Update label="2026-06-12" description="v1.0.13">
|
||||
|
||||
**Fixes:**
|
||||
- **Custom categories payload:** `customCategories` (a `Record<string, string>` map) is now converted via the new `customCategoryMapToList()` helper into the `Array<Record<string, string>>` shape the Mem0 SDK expects on `add` calls — previously the raw object was passed as `custom_categories` and silently ignored ([#5345](https://github.com/mem0ai/mem0/pull/5345))
|
||||
- **Skip runtime setup during metadata registration:** `register()` now detects `registrationMode === "cli-metadata"`, registers only the CLI commands, and returns early — avoiding backend initialization, service/tool registration, and hook installation during OpenClaw's metadata-only registration pass ([#5383](https://github.com/mem0ai/mem0/pull/5383))
|
||||
|
||||
**Security:**
|
||||
- Bumped `mem0ai` from `3.0.3` to `3.0.7` (latest Node SDK) — includes the transitive axios CVE remediation shipped in `3.0.6` ([#5460](https://github.com/mem0ai/mem0/pull/5460))
|
||||
- Added pnpm override `uuid@<11.1.1` → `>=11.1.1` to resolve an open MEDIUM Dependabot alert ([#5489](https://github.com/mem0ai/mem0/pull/5489))
|
||||
|
||||
**Improvements:**
|
||||
- **Repo consolidation:** Plugin moved from repo-root `openclaw/` to `integrations/openclaw/`; `package.json` `repository.directory` updated to match so npm provenance links to the correct subdirectory ([#5491](https://github.com/mem0ai/mem0/pull/5491))
|
||||
|
||||
**Tests:**
|
||||
- Added `customCategoryMapToList` unit tests and a `PlatformProvider` test asserting `custom_categories` is passed to the Mem0 SDK as a list ([#5345](https://github.com/mem0ai/mem0/pull/5345))
|
||||
- Added a regression test asserting `cli-metadata` registration registers only CLI commands and triggers no runtime side effects ([#5383](https://github.com/mem0ai/mem0/pull/5383))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-06-02" description="v1.0.12">
|
||||
|
||||
**Docs:**
|
||||
- **Agent Mode onboarding:** README now documents an autonomous setup path for AI agents — `mem0 init --agent --json` mints an evaluation Mem0 API key with no email, OTP, or browser and exports it as `MEM0_API_KEY` for `openclaw mem0 init`; a human owner can later run `mem0 init --email <email>` to claim ownership without disrupting the agent ([#5123](https://github.com/mem0ai/mem0/pull/5123))
|
||||
|
||||
**Security:**
|
||||
- Added pnpm overrides to remediate advisories in transitive dependencies: `langsmith@<0.6.0` → `^0.6.0`, `picomatch@<2.3.2` → `^2.3.2`, `vite` → `^8.0.5`, and `@qdrant/js-client-rest` → `^1.18.0` ([#5294](https://github.com/mem0ai/mem0/pull/5294))
|
||||
|
||||
**Dependencies:**
|
||||
- Bumped `mem0ai` from `3.0.2` to `3.0.3` ([#5212](https://github.com/mem0ai/mem0/pull/5212))
|
||||
- Bumped dev dependencies `@vitest/coverage-v8` and `vitest` from `^4.0.18` to `^4.1.7`; added `vite@^8.0.5` and `@qdrant/js-client-rest@^1.18.0` ([#5294](https://github.com/mem0ai/mem0/pull/5294))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-04-29" description="v1.0.11">
|
||||
|
||||
**New Features:**
|
||||
|
||||
@@ -25,7 +25,7 @@ mode: "wide"
|
||||
<Update label="2026-04-16" description="">
|
||||
|
||||
**Improvements:**
|
||||
- **UI:** Removed Graph Memory tab, page, and all references from dashboard, sidebar, project settings, playground, and billing
|
||||
- **UI:** Removed the legacy external-graph-store visualization tab, page, and its references from dashboard, sidebar, project settings, playground, and billing
|
||||
|
||||
</Update>
|
||||
|
||||
|
||||
+199
-4
@@ -7,6 +7,92 @@ mode: "wide"
|
||||
<Tabs>
|
||||
<Tab title="Python">
|
||||
|
||||
<Update label="2026-06-17" description="v2.0.7">
|
||||
|
||||
**New Features:**
|
||||
- **LLMs:** Add Gemini via Vertex AI as LLM provider ([#4030](https://github.com/mem0ai/mem0/pull/4030))
|
||||
- **Embeddings:** Add native `embed_batch` to `OllamaEmbedding` for batched embedding requests ([#5415](https://github.com/mem0ai/mem0/pull/5415))
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Core:** Fix `api_error_handler` silently dropping return values from async methods ([#5540](https://github.com/mem0ai/mem0/pull/5540))
|
||||
- **Core:** Fix `AsyncMemory.reset()` not resetting the entity store ([#5535](https://github.com/mem0ai/mem0/pull/5535))
|
||||
- **Core:** Fix `async delete_all` aborting on first error, leaving partial deletion ([#5529](https://github.com/mem0ai/mem0/pull/5529))
|
||||
- **Core:** Skip messages without a `content` key in message parsers to prevent `KeyError` crashes ([#5575](https://github.com/mem0ai/mem0/pull/5575))
|
||||
- **Core:** Preserve custom metadata fields during memory update ([#5480](https://github.com/mem0ai/mem0/pull/5480))
|
||||
- **LLMs:** Fix Anthropic `tool_choice` format and tool response parsing ([#5537](https://github.com/mem0ai/mem0/pull/5537))
|
||||
- **LLMs:** Fix Ollama `json` format mutating the caller's messages list in-place ([#5539](https://github.com/mem0ai/mem0/pull/5539))
|
||||
- **LLMs:** Omit `None` config values from Gemini `GenerateContentConfig` to prevent validation errors ([#5528](https://github.com/mem0ai/mem0/pull/5528))
|
||||
- **LLMs:** Honor reasoning-model params in `AzureOpenAIStructuredLLM` ([#5548](https://github.com/mem0ai/mem0/pull/5548))
|
||||
- **LLMs:** Honor reasoning-model params in `OpenAIStructuredLLM` ([#5458](https://github.com/mem0ai/mem0/pull/5458))
|
||||
- **LLMs:** Send `max_completion_tokens` for the GPT-5 family across all providers ([#5547](https://github.com/mem0ai/mem0/pull/5547))
|
||||
- **LLMs:** Accept and forward `**kwargs` in Together, LangChain, and Sarvam providers ([#5556](https://github.com/mem0ai/mem0/pull/5556))
|
||||
- **LLMs:** Fix Bedrock AI21 response parse default using `dict` literal instead of `set` ([#5527](https://github.com/mem0ai/mem0/pull/5527))
|
||||
- **LLMs:** Fix LiteLLM function-calling check blocking all calls on non-tool models ([#5536](https://github.com/mem0ai/mem0/pull/5536))
|
||||
- **LLMs:** Fix HuggingFace provider using `self.config` instead of raw `config` parameter ([#5538](https://github.com/mem0ai/mem0/pull/5538))
|
||||
- **Embeddings:** Honor `aws_session_token` in AWS Bedrock embeddings ([#5566](https://github.com/mem0ai/mem0/pull/5566))
|
||||
- **Rerankers:** Respect `config.top_k` in Cohere and ZeroEntropy fallback paths ([#5560](https://github.com/mem0ai/mem0/pull/5560))
|
||||
- **Vector Stores:** Fix FAISS filtered search dropping over-fetched candidates before filtering ([#5453](https://github.com/mem0ai/mem0/pull/5453))
|
||||
- **Vector Stores:** Fix Weaviate `reset()` crashing with missing `vector_size` argument ([#5531](https://github.com/mem0ai/mem0/pull/5531))
|
||||
- **Vector Stores:** Pass embedding dims in Weaviate `reset()` to avoid re-init crash ([#5570](https://github.com/mem0ai/mem0/pull/5570))
|
||||
- **Vector Stores:** Fix MongoDB `reset()` passing wrong argument to `create_col()` ([#5532](https://github.com/mem0ai/mem0/pull/5532))
|
||||
- **Vector Stores:** Fix Pinecone hybrid search crashing when `filters` is `None` ([#5533](https://github.com/mem0ai/mem0/pull/5533))
|
||||
- **Vector Stores:** Fix Redis crashing on empty or `None` filters in `search()` and `list()` ([#5446](https://github.com/mem0ai/mem0/pull/5446))
|
||||
- **Vector Stores:** Return `None` from `get()` for missing IDs in Milvus, Weaviate, and Supabase ([#5562](https://github.com/mem0ai/mem0/pull/5562))
|
||||
- **Vector Stores:** Return `None` from ChromaDB `get()` for missing IDs ([#5561](https://github.com/mem0ai/mem0/pull/5561))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-06-13" description="v2.0.6">
|
||||
|
||||
**New Features:**
|
||||
- **Memory:** Add a contextual OSS-to-Platform notices system that surfaces occasional, situation-aware messages (first run, scale/performance thresholds, slow queries, and when temporal/decay features are relevant) pointing to the corresponding Mem0 Platform capabilities; disable via `MEM0_TELEMETRY=false` ([#5494](https://github.com/mem0ai/mem0/pull/5494))
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Memory:** Prevent a crash in `parse_vision_messages` when vision support is disabled ([#5487](https://github.com/mem0ai/mem0/pull/5487))
|
||||
- **Vector Stores:** Expose the `https` option on the Qdrant vector store configuration so TLS endpoints can be targeted explicitly ([#5380](https://github.com/mem0ai/mem0/pull/5380))
|
||||
- **Vector Stores:** Use valid S3 Vectors entity index names, fixing index operations that failed on invalid names ([#5416](https://github.com/mem0ai/mem0/pull/5416))
|
||||
- **Vector Stores:** Fix `search()` crashing with a `TypeError` in the LangChain vector store when a result score is `None` ([#5072](https://github.com/mem0ai/mem0/pull/5072))
|
||||
- **Vector Stores:** Use `is not None` instead of a truthiness check for vector/payload in the PGVector `update()` path, so valid empty/zero values are no longer skipped ([#5488](https://github.com/mem0ai/mem0/pull/5488))
|
||||
- **Vector Stores:** Index the Valkey `memory` field as `TEXT` rather than `TAG` so full-text search behaves correctly ([#5443](https://github.com/mem0ai/mem0/pull/5443))
|
||||
- **Vector Stores:** Implement `$not` filter support in the ChromaDB vector store ([#5485](https://github.com/mem0ai/mem0/pull/5485))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-06-10" description="v2.0.5">
|
||||
|
||||
**New Features:**
|
||||
- **Memory:** Warn at init time when hybrid/BM25 search silently degrades to semantic-only because the configured vector store does not implement `keyword_search`. Affected stores: Chroma, FAISS, Cassandra, LangChain, Neptune Analytics, S3 Vectors, Supabase, TurboPuffer, Valkey ([#5444](https://github.com/mem0ai/mem0/pull/5444))
|
||||
- **Memory:** Add opt-in `explain=True` parameter to `Memory.search()` and `AsyncMemory.search()`. When enabled, each result includes a `score_breakdown` dict with `semantic`, `keyword` (normalized BM25), `entity_boost`, and `temporal_boost` signals so callers can understand and tune retrieval ranking ([#5102](https://github.com/mem0ai/mem0/pull/5102))
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Vector Stores:** Normalize similarity scores to `[0, 1]` (higher = better) consistently across all backends. 11 adapters previously returned raw distance metrics (lower = better) — FAISS, Chroma, Milvus, Redis, Cassandra, PGVector, S3 Vectors, Supabase, Valkey, Azure MySQL, and Vertex AI Vector Search — causing incorrect ranking in multi-store setups ([#5391](https://github.com/mem0ai/mem0/pull/5391))
|
||||
- **Memory:** Parallelize entity boost searches in `Memory.search()` and `AsyncMemory.search()`. Previously up to 8 entities were embedded and queried sequentially (16 serial round-trips with remote embedders); all entity lookups now run concurrently, eliminating multi-second latency on entity-rich queries ([#5377](https://github.com/mem0ai/mem0/pull/5377))
|
||||
- **Memory:** Reject empty or whitespace-only queries in `Memory.search()`, `AsyncMemory.search()`, `MemoryClient.search()`, and `AsyncMemoryClient.search()` before any embedding or API call is made. Also strips leading/trailing whitespace from valid queries ([#5258](https://github.com/mem0ai/mem0/pull/5258))
|
||||
- **LLMs:** Add `is_reasoning_model: Optional[bool]` override to `BaseLlmConfig` (surfaced on `OpenAILlmConfig` and `AzureOpenAILlmConfig`). Fixes silent zero-extraction when using Azure deployments with versioned `gpt-5.x` names that the automatic name-based heuristic cannot recognize ([#5327](https://github.com/mem0ai/mem0/pull/5327))
|
||||
- **LLMs:** Fix xAI LLM provider: add `XAIConfig` with `xai_base_url`, forward `tools`/`tool_choice` in `generate_response()`, and parse `tool_calls` in the response. Previously the provider raised `AttributeError` at init and silently dropped tool results ([#5190](https://github.com/mem0ai/mem0/pull/5190))
|
||||
- **Vector Stores:** Fix PGVector `ConnectionPool` hang in Docker Compose environments where the app container starts before Postgres is DNS-resolvable — switched to `open=False` to avoid blocking constructor or silent zombie pool ([#5155](https://github.com/mem0ai/mem0/pull/5155))
|
||||
- **Vector Stores:** Fix PGVector `sslmode` handling for PostgreSQL URIs — the `sslmode` query parameter is now correctly extracted and forwarded when building the async connection pool ([#5308](https://github.com/mem0ai/mem0/pull/5308))
|
||||
- **Vector Stores:** Fix S3 Vectors `list()` not applying metadata filters — filtering is now done client-side after fetching, with pagination preserved and `top_k` applied after filtering to prevent pre-truncation of matching rows ([#5018](https://github.com/mem0ai/mem0/pull/5018))
|
||||
- **Vector Stores:** Fix Upstash Vector `search()` routing all queries to the default namespace — `namespace` is now passed as a top-level keyword argument to `query_many()` instead of inside the per-query dict where it was silently ignored ([#5202](https://github.com/mem0ai/mem0/pull/5202))
|
||||
- **Core:** Replace mutable default arguments with `None` sentinels in embedder configs and the proxy module, preventing cross-request state contamination ([#5302](https://github.com/mem0ai/mem0/pull/5302))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-05-27" description="v2.0.4">
|
||||
|
||||
**New Features:**
|
||||
- **Client:** `delete()` and async `delete()` accept `delete_linked` (default `False`). When `True`, deleting a memory also removes the older memories it superseded (the v3 `linked_memory_ids` chain), transitively — the delete-side counterpart of `latest_only`, so a superseded memory does not resurface after the current one is deleted ([#5270](https://github.com/mem0ai/mem0/pull/5270))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-05-26" description="v2.0.3">
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Vector Stores:** PGVector adapter now supports rich filter operators (`eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `in`, `nin`, `contains`, `icontains`, wildcard `*`, `$or`, `$not`) in `search()`, `keyword_search()`, and `list()`. Previously only exact-equality filters worked — operator dicts were silently stringified and returned zero results ([#5263](https://github.com/mem0ai/mem0/pull/5263))
|
||||
- **Server:** Fixed `/search` endpoint returning 502 when `user_id`, `agent_id`, or `run_id` are sent as top-level request fields. The server now maps these into the `filters` dict before calling `Memory.search()`, matching the v3 API contract. Top-level entity ID fields are marked as deprecated in the OpenAPI schema and emit a warning log — clients should migrate to `filters={"user_id": "..."}` ([#5263](https://github.com/mem0ai/mem0/pull/5263))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-05-08" description="v2.0.2">
|
||||
|
||||
**Bug Fixes:**
|
||||
@@ -63,8 +149,8 @@ mode: "wide"
|
||||
- **`messages` in `Memory.add()` rejects invalid types:** Passing `None` or non-`(str | dict | list)` values raises `Mem0ValidationError` (`error_code="VALIDATION_003"`) ([#4843](https://github.com/mem0ai/mem0/pull/4843))
|
||||
- **`qdrant-client>=1.12.0` required** — Upgrade from `>=1.9.1` ([#4805](https://github.com/mem0ai/mem0/pull/4805))
|
||||
- **`org_id` and `project_id` removed** — Removed from `MemoryClient` constructor and all method signatures ([#4740](https://github.com/mem0ai/mem0/pull/4740))
|
||||
- **Graph Memory Removed (OSS):** `mem0/memory/graph_memory.py`, `memgraph_memory.py`, `kuzu_memory.py`, `apache_age_memory.py`, and `mem0/graphs/` (Neo4j / Memgraph / Kuzu / Apache AGE / Neptune drivers) deleted — ~4,000 lines. Graph memory is no longer supported in the OSS SDK; graph drivers (neo4j, memgraph, kuzu, etc.) can be uninstalled. Use the Platform API for graph features. Remove `enable_graph` and `graph_store` from your config ([#4805](https://github.com/mem0ai/mem0/pull/4805))
|
||||
- **`enable_graph` removed from Client SDK** — Graph memory is now a project-level setting on the Platform. Remove `enable_graph` from `MemoryClient.add()` / `search()` / `get_all()` / `update_project()` calls ([#4776](https://github.com/mem0ai/mem0/pull/4776))
|
||||
- **External Graph Store Removed (OSS):** `mem0/memory/graph_memory.py`, `memgraph_memory.py`, `kuzu_memory.py`, `apache_age_memory.py`, and `mem0/graphs/` (Neo4j / Memgraph / Kuzu / Apache AGE / Neptune drivers) deleted, about 4,000 lines. The external graph store integration is no longer part of the OSS SDK; graph drivers (neo4j, memgraph, kuzu, etc.) can be uninstalled. Graph memory now runs natively as built-in entity linking. Remove `enable_graph` and `graph_store` from your config ([#4805](https://github.com/mem0ai/mem0/pull/4805))
|
||||
- **`enable_graph` removed from Client SDK:** Graph memory now runs automatically and no longer needs a flag. Remove `enable_graph` from `MemoryClient.add()` / `search()` / `get_all()` / `update_project()` calls ([#4776](https://github.com/mem0ai/mem0/pull/4776))
|
||||
- **`custom_fact_extraction_prompt` renamed to `custom_instructions`** — Update config and memory module references ([#4740](https://github.com/mem0ai/mem0/pull/4740))
|
||||
- **Typed option classes** — Added Pydantic v2 typed classes: `AddMemoryOptions`, `SearchMemoryOptions`, `GetAllMemoryOptions`, `DeleteAllMemoryOptions`, `UpdateMemoryOptions`, `ProjectUpdateOptions` ([#4740](https://github.com/mem0ai/mem0/pull/4740))
|
||||
|
||||
@@ -924,6 +1010,64 @@ See the [OSS v1 to v2 migration guide](https://docs.mem0.ai/migration/oss-v1-to-
|
||||
</Tab>
|
||||
|
||||
<Tab title="TypeScript">
|
||||
|
||||
<Update label="2026-06-17" description="v3.0.9">
|
||||
|
||||
**Bug Fixes:**
|
||||
- **LLMs:** Fix Anthropic `tool_choice` format — was incorrectly sent as a bare string `"auto"` (rejected by the API); now correctly sent as `{ type: "auto" }`. Also fixes tool response parsing: `tool_use` blocks are now parsed into `toolCalls` objects instead of throwing. Updated default model to `claude-sonnet-4-6` and default `max_tokens` to `2000` to match the Python provider. Added `temperature`, `topP`, and `maxTokens` to `LLMConfig` so Anthropic params can be configured ([#5537](https://github.com/mem0ai/mem0/pull/5537))
|
||||
- **Memory (OSS):** Preserve custom metadata fields during `update()` — fields such as `category`, `priority`, and other user-defined keys were previously dropped on update; the existing payload is now spread before applying the new data ([#5480](https://github.com/mem0ai/mem0/pull/5480))
|
||||
- **Client:** Preserve user-defined schema keys in `createMemoryExport` ([#5594](https://github.com/mem0ai/mem0/pull/5594))
|
||||
|
||||
**Security:**
|
||||
- **Dependencies:** Bump `esbuild` to `>=0.28.1` across all npm packages via pnpm overrides to remediate upstream vulnerability ([#5563](https://github.com/mem0ai/mem0/pull/5563))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-06-13" description="v3.0.8">
|
||||
|
||||
**New Features:**
|
||||
- **Memory:** Add a contextual OSS-to-Platform notices system that surfaces occasional, situation-aware messages (first run, scale/performance thresholds, slow queries, and when temporal/decay features are relevant) pointing to the corresponding Mem0 Platform capabilities; disable via `MEM0_TELEMETRY=false` ([#5494](https://github.com/mem0ai/mem0/pull/5494))
|
||||
|
||||
**Security:**
|
||||
- **Dependencies:** Upgrade `@langchain/community` to `^1.1.18` to remediate CVE-2026-27795 and CVE-2026-26019 ([#5510](https://github.com/mem0ai/mem0/pull/5510))
|
||||
- **Dependencies:** Resolve all open MEDIUM Dependabot alerts via pnpm overrides ([#5489](https://github.com/mem0ai/mem0/pull/5489))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-06-10" description="v3.0.7">
|
||||
|
||||
**New Features:**
|
||||
- **Embeddings:** Add `LMStudioEmbedding` provider for local embeddings via the LM Studio server ([#5377](https://github.com/mem0ai/mem0/pull/5377))
|
||||
- **Memory:** Add opt-in `explain: true` option to `Memory.search()`. When enabled, each result includes a `scoreBreakdown` object with `semantic`, `keyword`, `entityBoost`, and `temporalBoost` fields so callers can inspect and tune retrieval ranking ([#5102](https://github.com/mem0ai/mem0/pull/5102))
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Memory:** Parallelize entity boost searches in `Memory.search()`. All entity embed + store lookups now run concurrently instead of sequentially, eliminating multi-second latency on entity-rich queries with remote embedding providers ([#5377](https://github.com/mem0ai/mem0/pull/5377))
|
||||
- **Vector Stores:** Normalize similarity scores to `[0, 1]` (higher = better) — fixed score inversion in the Redis vector store adapter ([#5391](https://github.com/mem0ai/mem0/pull/5391))
|
||||
- **Embeddings:** Request `encoding_format: "float"` from the OpenAI embedder in both `embed()` and `embedBatch()`. Fixes incorrect vector dimensions when using OpenAI-compatible proxies that default to base64 encoding ([#5170](https://github.com/mem0ai/mem0/pull/5170))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-06-01" description="v3.0.6">
|
||||
|
||||
**Security:**
|
||||
- **Dependencies:** Bumped `axios` to `^1.16.0` to remediate high-severity prototype-pollution CVEs (credential theft, MITM, DoS). Pinned transitive dependencies via pnpm overrides: `jws` → 4.0.1 (CVE-2025-65945), `langsmith` → ^0.6.0 (CVE-2026-45134), `tar-fs` → ^2.1.4 (CVE-2025-48387, CVE-2025-59343), `picomatch` → ^2.3.2 (CVE-2026-33671), `minimatch` → ^3.1.3 / ^5.1.8 / ^9.0.7 (CVE-2026-27903, CVE-2026-27904, CVE-2026-26996), `path-to-regexp` → ^8.4.0 (CVE-2026-4926), `rollup` → ^4.59.0 (CVE-2026-27606), `glob` → ^10.5.0 (CVE-2025-64756), `@modelcontextprotocol/sdk` → ^1.25.4 (CVE-2025-66414, CVE-2026-0621)
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-05-27" description="v3.0.5">
|
||||
|
||||
**New Features:**
|
||||
- **Client:** `delete()` accepts an options object with `deleteLinked` (serialized as `delete_linked`, default `false`). When `true`, deleting a memory also removes the older memories it superseded (the v3 linked chain), transitively — the delete-side counterpart of `latestOnly`, so a superseded memory does not resurface after the current one is deleted ([#5270](https://github.com/mem0ai/mem0/pull/5270))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-05-26" description="v3.0.4">
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Vector Stores:** PGVector adapter now supports rich filter operators (`eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `in`, `nin`, `contains`, `icontains`, wildcard `*`, `$or`, `$not`) in `search()`, `keywordSearch()`, and `list()`. Previously only exact-equality filters worked — operator objects were passed as raw values and returned incorrect results ([#5263](https://github.com/mem0ai/mem0/pull/5263))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-05-08" description="v3.0.3">
|
||||
|
||||
**Bug Fixes:**
|
||||
@@ -969,7 +1113,7 @@ See the [OSS v1 to v2 migration guide](https://docs.mem0.ai/migration/oss-v1-to-
|
||||
- **Default model:** `gpt-5-mini` is now the default in `OpenAI`, `OpenAIStructured`, and `Azure` LLM providers ([#4829](https://github.com/mem0ai/mem0/pull/4829))
|
||||
|
||||
**Breaking Changes:**
|
||||
- **Graph Memory Removed (OSS):** `graph_memory.ts` (675 lines), `graphs/tools.ts` (267 lines), `graphs/utils.ts` (116 lines), `graphs/configs.ts` (30 lines) deleted. Graph memory is no longer supported in the OSS SDK — use Platform API for graph features ([#4805](https://github.com/mem0ai/mem0/pull/4805))
|
||||
- **External Graph Store Removed (OSS):** `graph_memory.ts` (675 lines), `graphs/tools.ts` (267 lines), `graphs/utils.ts` (116 lines), `graphs/configs.ts` (30 lines) deleted. The external graph store integration is no longer part of the OSS SDK; graph memory now runs natively as built-in entity linking ([#4805](https://github.com/mem0ai/mem0/pull/4805))
|
||||
- **camelCase Parameters (Client SDK):** All user-facing parameters converted from snake_case to camelCase. Mapping is transparent at API boundary via `camelToSnakeKeys()` / `snakeToCamelKeys()` ([#4776](https://github.com/mem0ai/mem0/pull/4776))
|
||||
```typescript
|
||||
// Before
|
||||
@@ -1323,10 +1467,24 @@ See the [TypeScript SDK migration guide](https://docs.mem0.ai/migration/ts-v2-to
|
||||
|
||||
<Tab title="CLI">
|
||||
|
||||
<Update label="2026-06-01" description="Node v0.2.8">
|
||||
|
||||
**Security:**
|
||||
- **Dependencies:** Pinned transitive dependencies via pnpm overrides to remediate high-severity CVEs: `jws` → 4.0.1 (CVE-2025-65945), `langsmith` → ^0.6.0 (CVE-2026-45134), `tar-fs` → ^2.1.4 (CVE-2025-48387, CVE-2025-59343), `picomatch` → ^2.3.2 (CVE-2026-33671), `minimatch` → ^3.1.3 / ^5.1.8 / ^9.0.7 (CVE-2026-27903, CVE-2026-27904, CVE-2026-26996), `path-to-regexp` → ^8.4.0 (CVE-2026-4926), `rollup` → ^4.59.0 (CVE-2026-27606), `glob` → ^10.5.0 (CVE-2025-64756), `@modelcontextprotocol/sdk` → ^1.25.4 (CVE-2025-66414, CVE-2026-0621)
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-05-16" description="Python v0.2.6 / Node v0.2.6">
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Claim flow error message:** The `email_already_claimed` tip in `mem0 init --email` previously suggested running `mem0 link <key>` — a command that doesn't exist. Replaced with honest copy pointing the user to sign in at app.mem0.ai with their existing credentials ([#5152](https://github.com/mem0ai/mem0/pull/5152))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-05-14" description="Python v0.2.5 / Node v0.2.5">
|
||||
|
||||
**New Features:**
|
||||
- **Agent Mode (`mem0 init --agent`):** Zero-friction signup for AI agents — mints a working Mem0 API key in <5s with no email, no dashboard, no OTP. Returns an unclaimed shadow account the human can later claim with `mem0 init --email <their-email>` (memories preserved, same key keeps working) ([#5123](https://github.com/mem0ai/mem0/pull/5123))
|
||||
- **Agent Mode (`mem0 init --agent`):** Zero-friction signup for AI agents — mints a working Mem0 API key in under 5 seconds with no email, no dashboard, no OTP. Returns an unclaimed shadow account the human can later claim with `mem0 init --email <their-email>` (memories preserved, same key keeps working) ([#5123](https://github.com/mem0ai/mem0/pull/5123))
|
||||
- **Self-declared agent identity:** Agents pass `--agent-caller <name>` (e.g. `claude-code`, `cursor`, `codex`) on `mem0 init --agent` so signups attribute to the right tool in analytics. Proof Editor-style — the agent declares itself rather than the CLI sniffing it from env vars ([#5123](https://github.com/mem0ai/mem0/pull/5123))
|
||||
- **`mem0 identify <name>`:** New subcommand to self-tag an Agent Mode key after the fact when the agent forgot to pass `--agent-caller` on init. Idempotent — re-running just overwrites ([#5123](https://github.com/mem0ai/mem0/pull/5123))
|
||||
- **Plugin sync:** `~/.claude/settings.json::env::MEM0_API_KEY` and `~/.zshrc`/`.bashrc` `export MEM0_API_KEY=` lines stay in sync with `~/.mem0/config.json` automatically. Idempotent — only updates EXISTING entries, never creates new ones ([#5123](https://github.com/mem0ai/mem0/pull/5123))
|
||||
@@ -1432,6 +1590,43 @@ A full-featured command-line interface for Mem0, available in both Python and No
|
||||
|
||||
<Tab title="Plugins">
|
||||
|
||||
<Update label="2026-06-01" description="openclaw-mem0 v1.0.12">
|
||||
|
||||
**Security:**
|
||||
- **Dependencies:** Pinned transitive dependencies via pnpm overrides to remediate high-severity CVEs: `protobufjs` → ^7.5.5, `vite` → ^8.0.5, `langsmith` → ^0.6.0 (CVE-2026-45134), `picomatch` → ^2.3.2 (CVE-2026-33671), `@qdrant/js-client-rest` → ^1.18.0
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-06-10" description="Vercel AI SDK v3.0.0">
|
||||
|
||||
**Major Release** — Migrated to Vercel AI SDK v6 (`LanguageModelV3` / `ProviderV3`) and Mem0 v3 API.
|
||||
|
||||
**Breaking Changes:**
|
||||
- **AI SDK v6:** Upgraded from AI SDK v5 (`LanguageModelV2`) to v6 (`LanguageModelV3`). Users must upgrade `ai` to `^6.0.199` and all `@ai-sdk/*` provider packages to `^3.x` ([#4741](https://github.com/mem0ai/mem0/pull/4741))
|
||||
- **Mem0 v3 API:** Memory endpoints migrated from `/v1/memories/` and `/v2/memories/search/` to `/v3/memories/add/` and `/v3/memories/search/`. Entity IDs (`user_id`, `agent_id`, `run_id`) now go inside the `filters` object for search requests ([#4741](https://github.com/mem0ai/mem0/pull/4741))
|
||||
- **Graph memory removed:** All `enable_graph`, graph prompts, and relation-extraction code removed. Graph memory is now a project-level setting on the Platform ([#4741](https://github.com/mem0ai/mem0/pull/4741))
|
||||
- **Deprecated params removed:** `org_id`, `project_id`, `org_name`, `project_name`, `output_format`, `filter_memories`, `async_mode`, `enable_graph`, `version`, `api_version` removed from `Mem0ConfigSettings` ([#4741](https://github.com/mem0ai/mem0/pull/4741))
|
||||
|
||||
**New Features:**
|
||||
- **V3 provider contract:** `specificationVersion: 'v3'`, `supportedUrls` property, V3 content array in `doGenerate`, V3 stream lifecycle events in `doStream` ([#4741](https://github.com/mem0ai/mem0/pull/4741))
|
||||
- **Mem0 source in responses:** Memories are attached as a `source` in `generateText`/`streamText` responses with `providerMetadata.mem0.memories` for programmatic access ([#4741](https://github.com/mem0ai/mem0/pull/4741))
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Async memory storage:** `addMemories` is now properly `await`ed — memories no longer silently fail to store ([#4741](https://github.com/mem0ai/mem0/pull/4741))
|
||||
- **Prompt mutation:** Prompt array is now cloned before injecting memory context, preventing side effects on the caller's array ([#4741](https://github.com/mem0ai/mem0/pull/4741))
|
||||
- **Null guard on content:** `doGenerate` guards against null `content` from upstream providers ([#4741](https://github.com/mem0ai/mem0/pull/4741))
|
||||
- **Stream response:** `doStream` now returns the full `LanguageModelV3StreamResult` object preserving all V3 fields ([#4741](https://github.com/mem0ai/mem0/pull/4741))
|
||||
- **Response normalization:** `getMemories` and `retrieveMemories` now handle both array and `{results: [...]}` envelope responses from the v3 API ([#4741](https://github.com/mem0ai/mem0/pull/4741))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-06-01" description="Vercel AI SDK v2.0.6">
|
||||
|
||||
**Security:**
|
||||
- **Dependencies:** Pinned transitive dependencies via pnpm overrides to remediate high-severity CVEs: `glob` → ^10.5.0 (CVE-2025-64756), `minimatch` → ^3.1.3 / ^5.1.8 / ^9.0.7 (CVE-2026-27903, CVE-2026-27904, CVE-2026-26996), `picomatch` → ^2.3.2 (CVE-2026-33671), `rollup` → ^4.59.0 (CVE-2026-27606)
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-04-02" description="mem0-plugin v1.0.0">
|
||||
|
||||
**Mem0 Plugin for Claude Code, Cursor, and Codex**
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
---
|
||||
title: "Neon"
|
||||
description: "Use Neon as a vector store in Mem0, powered by PostgreSQL and pgvector."
|
||||
---
|
||||
|
||||
Use [Neon](https://neon.com/) as a vector store in Mem0, powered by PostgreSQL and the
|
||||
[pgvector extension](https://neon.com/docs/extensions/pgvector).
|
||||
|
||||
Neon is a serverless Postgres platform. Since Mem0 supports Postgres through the
|
||||
`pgvector` provider, Neon can be used with a standard Postgres connection string.
|
||||
|
||||
## Usage
|
||||
|
||||
<CodeGroup>
|
||||
```python Python
|
||||
import os
|
||||
|
||||
from dotenv import load_dotenv
|
||||
from mem0 import Memory
|
||||
|
||||
load_dotenv()
|
||||
|
||||
config = {
|
||||
"vector_store": {
|
||||
"provider": "pgvector",
|
||||
"config": {
|
||||
"connection_string": os.environ["DATABASE_URL"],
|
||||
"collection_name": "memories",
|
||||
"embedding_model_dims": 1536,
|
||||
"hnsw": True,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
m = Memory.from_config(config)
|
||||
messages = [
|
||||
{"role": "user", "content": "I'm planning to watch a movie tonight. Any recommendations?"},
|
||||
{"role": "assistant", "content": "How about thriller movies? They can be quite engaging."},
|
||||
{"role": "user", "content": "I'm not a big fan of thriller movies but I love sci-fi movies."},
|
||||
{"role": "assistant", "content": "Got it! I'll avoid thriller recommendations and suggest sci-fi movies in the future."},
|
||||
]
|
||||
m.add(messages, user_id="alice", metadata={"category": "movies"})
|
||||
|
||||
results = m.search(
|
||||
"What movies should I recommend?",
|
||||
filters={"user_id": "alice"},
|
||||
)
|
||||
|
||||
print(results)
|
||||
```
|
||||
|
||||
```typescript TypeScript
|
||||
import "dotenv/config";
|
||||
import { Memory } from "mem0ai/oss";
|
||||
|
||||
const databaseUrl = new URL(process.env.DATABASE_URL!);
|
||||
|
||||
const m = new Memory({
|
||||
vectorStore: {
|
||||
provider: "pgvector",
|
||||
config: {
|
||||
user: decodeURIComponent(databaseUrl.username),
|
||||
password: decodeURIComponent(databaseUrl.password),
|
||||
host: databaseUrl.hostname,
|
||||
port: Number(databaseUrl.port || 5432),
|
||||
dbname: databaseUrl.pathname.slice(1) || "neondb",
|
||||
collectionName: "memories",
|
||||
dimension: 1536,
|
||||
embeddingModelDims: 1536,
|
||||
hnsw: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const messages = [
|
||||
{ role: "user" as const, content: "I'm planning to watch a movie tonight. Any recommendations?" },
|
||||
{ role: "assistant" as const, content: "How about thriller movies? They can be quite engaging." },
|
||||
{ role: "user" as const, content: "I'm not a big fan of thriller movies but I love sci-fi movies." },
|
||||
{ role: "assistant" as const, content: "Got it! I'll avoid thriller recommendations and suggest sci-fi movies in the future." },
|
||||
];
|
||||
|
||||
await m.add(messages, {
|
||||
userId: "alice",
|
||||
metadata: { category: "movies" },
|
||||
});
|
||||
|
||||
const results = await m.search("What movies should I recommend?", {
|
||||
filters: { user_id: "alice" },
|
||||
});
|
||||
|
||||
console.log(results);
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
## SQL Migration
|
||||
|
||||
You don't need to run any SQL migrations. Mem0 creates the collection table when it initializes the `pgvector` store.
|
||||
|
||||
## Environment
|
||||
|
||||
```env
|
||||
OPENAI_API_KEY=sk-xx...
|
||||
DATABASE_URL=postgresql://user:password@ep-example.us-east-2.aws.neon.tech/neondb?sslmode=require
|
||||
```
|
||||
|
||||
## Config
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Python">
|
||||
| Parameter | Description | Default Value |
|
||||
| --- | --- | --- |
|
||||
| `connection_string` | Neon Postgres connection string. | Required |
|
||||
| `collection_name` | Name for the vector collection. | `mem0` |
|
||||
| `embedding_model_dims` | Embedding model dimensions. | `1536` |
|
||||
| `hnsw` | Enables HNSW indexing. | `False` |
|
||||
| `sslmode` | PostgreSQL SSL mode. Use `require` for Neon. | Driver default |
|
||||
</Tab>
|
||||
<Tab title="TypeScript">
|
||||
The current Mem0 TypeScript `pgvector` adapter takes individual Postgres fields,
|
||||
so parse `DATABASE_URL` before creating `Memory`.
|
||||
|
||||
| Parameter | Description | Default |
|
||||
| --- | --- | --- |
|
||||
| `user` | Database user. | Required |
|
||||
| `password` | Database password. | Required |
|
||||
| `host` | Database host. | Required |
|
||||
| `port` | Database port. | `5432` |
|
||||
| `dbname` | Database name. | `vector_store` |
|
||||
| `collectionName` | Name for the vector collection. | `memories` |
|
||||
| `dimension` | Vector dimension for Mem0 config. | Auto-detected |
|
||||
| `embeddingModelDims` | Embedding model dimensions for table creation. | Required |
|
||||
| `hnsw` | Enables HNSW indexing. | `false` |
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
### Indexing
|
||||
|
||||
The `pgvector` provider can create an HNSW index for faster vector search.
|
||||
|
||||
- Set `hnsw` to `true` to enable a Hierarchical Navigable Small World index.
|
||||
- Leave `hnsw` as `false` if you want to create or manage indexes yourself.
|
||||
|
||||
### Similarity Search
|
||||
|
||||
The `pgvector` provider uses cosine similarity for vector search. Make sure your
|
||||
embedding dimensions match the configured `embedding_model_dims` value.
|
||||
|
||||
### Best Practices
|
||||
|
||||
1. **Index Selection**:
|
||||
- Use `hnsw` for faster search performance when memory usage is not a constraint
|
||||
- Manage indexes manually if you need a different pgvector index strategy
|
||||
|
||||
2. **Connection String**:
|
||||
- Always use environment variables or even better, a secret manager for sensitive information in the connection string
|
||||
- Format: `postgresql://user:password@host:port/database`
|
||||
@@ -56,6 +56,30 @@ config = {
|
||||
}
|
||||
```
|
||||
|
||||
### Configuration Options
|
||||
|
||||
| Parameter | Type | Default | Description |
|
||||
|-----------|------|---------|-------------|
|
||||
| `collection_name` | string | required | Name of the OpenSearch index |
|
||||
| `host` | string | required | OpenSearch endpoint URL |
|
||||
| `port` | int | 9200 | Port number |
|
||||
| `http_auth` | object | None | Authentication credentials (e.g., AWSV4SignerAuth) |
|
||||
| `embedding_model_dims` | int | 1536 | Dimension of embedding vectors |
|
||||
| `use_ssl` | bool | False | Enable SSL/TLS connection |
|
||||
| `verify_certs` | bool | False | Verify SSL certificates |
|
||||
| `auto_refresh` | bool | False | Automatically refresh index after insert. OpenSearch refreshes every ~1 second by default, so this is rarely needed. |
|
||||
|
||||
<Note>
|
||||
The defaults above match a local OpenSearch instance. The AWS OpenSearch Serverless
|
||||
example earlier on this page intentionally overrides them with `port=443`, `use_ssl=True`,
|
||||
and `verify_certs=True`, which are required when connecting to a Serverless collection.
|
||||
</Note>
|
||||
|
||||
<Note>
|
||||
For **AWS OpenSearch Serverless**, keep `auto_refresh=False` (the default).
|
||||
The `indices.refresh()` API is not supported on Serverless collections.
|
||||
</Note>
|
||||
|
||||
### Add Memories
|
||||
|
||||
```python
|
||||
|
||||
@@ -76,6 +76,7 @@ Let's see the available parameters for the `qdrant` config:
|
||||
| `path` | Path for the qdrant database | `/tmp/qdrant` |
|
||||
| `url` | Full URL for the qdrant server | `None` |
|
||||
| `api_key` | API key for the qdrant server | `None` |
|
||||
| `https` | Whether to force HTTPS on or off. `None` lets the client decide; set `False` for plain HTTP Qdrant with API key authentication. | `None` |
|
||||
| `on_disk` | For enabling persistent storage | `False` |
|
||||
</Tab>
|
||||
<Tab title="TypeScript">
|
||||
@@ -90,4 +91,4 @@ Let's see the available parameters for the `qdrant` config:
|
||||
| `apiKey` | API key for the Qdrant server | `None` |
|
||||
| `onDisk` | For enabling persistent storage | `False` |
|
||||
</Tab>
|
||||
</Tabs>
|
||||
</Tabs>
|
||||
|
||||
@@ -323,10 +323,6 @@ Metadata: {'verified': True, 'updated_date': '2025-04-02'}
|
||||
That “no duplicates” promise comes from the inference pipeline. Keep `infer=True` when you rely on automatic updates. Raw imports (`infer=False`) skip conflict checks, so mixing the two modes for the same fact will create duplicates.
|
||||
</Warning>
|
||||
|
||||
**Maintains relationships:**
|
||||
|
||||
- If using graph memory, connections to other entities persist
|
||||
|
||||
### Pick the right inference mode
|
||||
|
||||
| Mode | What it does | Best for | Watch out for |
|
||||
|
||||
@@ -216,7 +216,6 @@ This information was retrieved from your memory history where you previously men
|
||||
|
||||
- **Smart Memory Management** - Organizes memories into searchable information *without setting up vector databases*
|
||||
- **Fast Retrieval** - Instant lookups with *sub-millisecond ping*, handles large datasets
|
||||
- **Graph Capabilities** - Builds knowledge *automatically* as you push information
|
||||
- **Simple Integration** - Uses Mem0 API in the backend, works with *any MCP client* with just a few lines of code
|
||||
|
||||
### Gemini 3 + Mem0 Benefits
|
||||
|
||||
@@ -156,14 +156,7 @@ Here are some examples of how Mem0 can be integrated into various applications:
|
||||
icon="aws"
|
||||
href="/cookbooks/integrations/aws-bedrock"
|
||||
>
|
||||
Mem0 with AWS Bedrock and Neptune.
|
||||
</Card>
|
||||
<Card
|
||||
title="Graph Memory on Neptune"
|
||||
icon="network-wired"
|
||||
href="/cookbooks/integrations/neptune-analytics"
|
||||
>
|
||||
Graph memory with Neptune Analytics.
|
||||
Mem0 with AWS Bedrock.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ Some benchmarks today — particularly smaller ones like LoCoMo and LongMemEval
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
Mem0's memory system operates across two phases — **extraction** (writing) and **retrieval** (reading) — with an entity linking layer connecting them.
|
||||
Mem0's memory system operates across two phases, **extraction** (writing) and **retrieval** (reading), with a graph memory layer (entity linking) connecting them.
|
||||
|
||||
### Memory Extraction (Distillation)
|
||||
|
||||
@@ -27,14 +27,14 @@ When new conversations arrive, the extraction pipeline processes them through fi
|
||||
2. **Context Lookup** — Find related existing memories to avoid duplicates
|
||||
3. **Distill Memories** — Single-pass LLM extraction produces ADD-only facts from input + context
|
||||
4. **Deduplicate + Embed** — Hash-based deduplication, then vectorize new memories
|
||||
5. **Entity Linking** — Identify entities (proper nouns, quoted text, compound noun phrases) and link them across memories
|
||||
5. **Graph Memory (Entity Linking)**: Identify entities (proper nouns, quoted text, compound noun phrases) and link them across memories into a graph
|
||||
|
||||
Memories are distributed across three storage layers, each tuned for a specific retrieval pattern:
|
||||
|
||||
| Store | Contents | Purpose |
|
||||
|---|---|---|
|
||||
| **Vector Database** | Memory text, embeddings, metadata (timestamps, hash, categories, attributed_to) | Primary fact storage + semantic retrieval |
|
||||
| **Entity Store** | Entities + embeddings + linked memory IDs | Entity-based retrieval boost |
|
||||
| **Graph / Entity Store** | Entities + embeddings + linked memory IDs | Graph connections across memories + entity-based retrieval boost |
|
||||
| **SQL Database** | History log (ADD events) + rolling message window | Audit trail + extraction dedup context |
|
||||
|
||||
<Info>
|
||||
@@ -47,7 +47,7 @@ When a query arrives, the retrieval pipeline scores candidates across three sign
|
||||
|
||||
1. **Semantic Search** — Vector similarity scoring against memory embeddings
|
||||
2. **Keyword Search** — Normalized term matching via BM25 with verb-form lemmatization
|
||||
3. **Entity Search** — Entity graph matching boosts memories linked to query entities
|
||||
3. **Entity Search** — Entity matching boosts memories linked to query entities
|
||||
|
||||
Results are fused via rank scoring into a final top-K set. Different query types lean on different signals:
|
||||
|
||||
@@ -76,7 +76,7 @@ The combined score outperformed every individual signal across every category te
|
||||
|
||||
*Mean tokens: 6,956*
|
||||
|
||||
The two largest gains are **temporal queries (+29.6)** and **multi-hop reasoning (+23.1)**. Both categories directly test the ADD-only architecture (preserving temporal context) and entity linking (connecting facts across memories).
|
||||
The two largest gains are **temporal queries (+29.6)** and **multi-hop reasoning (+23.1)**. Both categories directly test the ADD-only architecture (preserving temporal context) and graph memory / entity linking (connecting facts across memories).
|
||||
|
||||
### LongMemEval
|
||||
|
||||
|
||||
@@ -21,35 +21,31 @@ 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`, `agent_id`, or `run_id` that scope the memory for future searches.
|
||||
- **User / Session identifiers** – `user_id`, `agent_id`, `app_id`, or `run_id` that scope the memory for future searches.
|
||||
|
||||
## How does it work?
|
||||
|
||||
Mem0 offers two flows:
|
||||
|
||||
- **Mem0 Platform** – Fully managed API with dashboard, scaling, and graph features.
|
||||
- **Mem0 Platform** – Fully managed API with dashboard and scaling.
|
||||
- **Mem0 Open Source** – Local SDK that you run in your own environment.
|
||||
|
||||
Both flows take the same payload and pass it through the same pipeline.
|
||||
|
||||
<Frame caption="Architecture diagram illustrating the process of adding memories.">
|
||||
<img src="../../images/add_architecture.png" />
|
||||
</Frame>
|
||||
Both flows take the same payload and add memories through an additive pipeline.
|
||||
|
||||
<Steps>
|
||||
<Step title="Information extraction">
|
||||
Mem0 sends the messages through an LLM that pulls out key facts, decisions, or preferences to remember.
|
||||
</Step>
|
||||
<Step title="Conflict resolution">
|
||||
Existing memories are checked for duplicates or contradictions so the latest truth wins.
|
||||
<Step title="Additive storage">
|
||||
New memories are added without overwriting or deleting existing memories.
|
||||
</Step>
|
||||
<Step title="Storage">
|
||||
The resulting memories land in managed vector storage (and optional graph storage) so future searches return them quickly.
|
||||
<Step title="Retrieval">
|
||||
Future searches rank the most relevant memories for the query.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
<Warning>
|
||||
Duplicate protection only runs during that conflict-resolution step when you let Mem0 infer memories (`infer=True`, the default). If you switch to `infer=False`, Mem0 stores your payload exactly as provided, so duplicates will land. Mixing both modes for the same fact will save it twice.
|
||||
When you switch to `infer=False`, Mem0 stores your payload exactly as provided, so duplicates can land. Mixing both modes for the same fact can save it twice.
|
||||
</Warning>
|
||||
|
||||
You trigger this pipeline with a single `add` call—no manual orchestration needed.
|
||||
@@ -84,13 +80,13 @@ const messages = [
|
||||
];
|
||||
|
||||
await client.add(messages, {
|
||||
user_id: "alice",
|
||||
userId: "alice",
|
||||
});
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
<Info icon="check">
|
||||
Expect a `memory_id` (or list of IDs) in the response. Check the Mem0 dashboard to confirm the new entry under the correct user.
|
||||
Expect a `status: "PENDING"` response with an `event_id`. Poll `GET /v1/event/{event_id}/` to confirm completion.
|
||||
</Info>
|
||||
|
||||
## Add with Mem0 Open Source
|
||||
@@ -142,7 +138,7 @@ const result = memory.add(messages, {
|
||||
</Tip>
|
||||
|
||||
<Warning>
|
||||
If you do choose `infer=False`, keep it consistent. Raw inserts skip conflict resolution, so a later `infer=True` call with the same content will create a second memory instead of updating the first.
|
||||
If you do choose `infer=False`, keep it consistent. Raw inserts skip inference, so a later `infer=True` call with the same content can create a second memory.
|
||||
</Warning>
|
||||
|
||||
## When Should You Add Memory?
|
||||
@@ -171,13 +167,13 @@ For full list of supported fields, required formats, and advanced options, see t
|
||||
|
||||
| Capability | Mem0 Platform | Mem0 OSS |
|
||||
| --- | --- | --- |
|
||||
| Conflict resolution | Automatic with dashboard visibility | SDK handles merges locally; you control storage |
|
||||
| Add behavior | ADD-only; memories accumulate | ADD-only; you control storage |
|
||||
| Rate limits | Managed quotas per workspace | Limited by your hardware and provider APIs |
|
||||
| Dashboard visibility | Yes — inspect memories visually | Inspect via CLI, logs, or custom UI |
|
||||
|
||||
## Put it into practice
|
||||
|
||||
- Review the <Link href="/platform/advanced-memory-operations">Advanced Memory Operations</Link> guide to layer metadata, rerankers, and graph toggles.
|
||||
- Review the <Link href="/platform/advanced-memory-operations">Advanced Memory Operations</Link> guide to layer metadata and rerankers.
|
||||
- Explore the <Link href="/api-reference/memory/add-memories">Add Memories API reference</Link> for every request/response field.
|
||||
|
||||
## See it live
|
||||
|
||||
@@ -25,10 +25,6 @@ Mem0's search operation lets agents ask natural-language questions and get back
|
||||
|
||||
## Architecture
|
||||
|
||||
<Frame caption="Architecture diagram illustrating the memory search process.">
|
||||
<img src="../../images/search_architecture.png" />
|
||||
</Frame>
|
||||
|
||||
<Steps>
|
||||
<Step title="Query processing">
|
||||
Mem0 cleans and enriches your natural-language query so the downstream embedding search is accurate.
|
||||
@@ -160,6 +156,33 @@ const memories = memory.search("food preferences", {
|
||||
On Mem0 Platform v3, time-aware queries use Temporal Reasoning internally while preserving the normal search response shape. See <Link href="/platform/features/temporal-reasoning">Temporal Reasoning</Link>.
|
||||
</Note>
|
||||
|
||||
### Explain OSS search scores
|
||||
|
||||
OSS search combines semantic similarity with optional keyword and entity signals. Pass `explain=True` when tuning retrieval quality or debugging why a memory ranked where it did:
|
||||
|
||||
<CodeGroup>
|
||||
```python Python
|
||||
results = m.search(
|
||||
"food preferences",
|
||||
filters={"user_id": "alice"},
|
||||
explain=True,
|
||||
)
|
||||
|
||||
print(results["results"][0]["score_details"])
|
||||
```
|
||||
|
||||
```javascript JavaScript
|
||||
const results = await memory.search("food preferences", {
|
||||
filters: { user_id: "alice" },
|
||||
explain: true,
|
||||
});
|
||||
|
||||
console.log(results.results[0].score_details);
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
Each result includes `score_details` with the semantic score, normalized BM25 score, entity boost, raw combined score, maximum possible score, final score, and threshold used for filtering. The field is omitted unless `explain` is enabled, so existing response shapes stay unchanged.
|
||||
|
||||
## Filter patterns
|
||||
|
||||
Filters help narrow down search results. Common use cases:
|
||||
|
||||
@@ -104,7 +104,7 @@ results = memory.search(
|
||||
## Put it into practice
|
||||
|
||||
- Use the <Link href="/core-concepts/memory-operations/add">Add Memory</Link> guide to persist user preferences.
|
||||
- Follow <Link href="/platform/advanced-memory-operations">Advanced Memory Operations</Link> to tune metadata and graph writes.
|
||||
- Follow <Link href="/platform/advanced-memory-operations">Advanced Memory Operations</Link> to tune metadata and retrieval.
|
||||
|
||||
## See it live
|
||||
|
||||
|
||||
+14
-10
@@ -40,6 +40,7 @@
|
||||
"icon": "rocket",
|
||||
"pages": [
|
||||
"platform/overview",
|
||||
"platform/agent-signup",
|
||||
"vibecoding",
|
||||
"platform/mem0-mcp",
|
||||
"platform/cli",
|
||||
@@ -70,6 +71,7 @@
|
||||
"pages": [
|
||||
"platform/features/v2-memory-filters",
|
||||
"platform/features/entity-scoped-memory",
|
||||
"platform/features/graph-memory",
|
||||
"platform/features/async-client",
|
||||
"platform/features/multimodal-support",
|
||||
"platform/features/custom-categories",
|
||||
@@ -142,7 +144,8 @@
|
||||
"icon": "robot",
|
||||
"pages": [
|
||||
"integrations/openclaw",
|
||||
"integrations/hermes"
|
||||
"integrations/hermes",
|
||||
"integrations/pi-agent"
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -244,6 +247,7 @@
|
||||
"components/vectordbs/dbs/cassandra",
|
||||
"components/vectordbs/dbs/s3_vectors",
|
||||
"components/vectordbs/dbs/databricks",
|
||||
"components/vectordbs/dbs/neon",
|
||||
"components/vectordbs/dbs/neptune_analytics",
|
||||
"components/vectordbs/dbs/turbopuffer"
|
||||
]
|
||||
@@ -301,7 +305,8 @@
|
||||
"group": "Migration",
|
||||
"icon": "arrow-right",
|
||||
"pages": [
|
||||
"migration/oss-v2-to-v3"
|
||||
"migration/oss-v2-to-v3",
|
||||
"migration/server-pgvector-upgrade"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -436,7 +441,7 @@
|
||||
"integrations/flowise",
|
||||
"integrations/langchain-tools",
|
||||
"integrations/agentops",
|
||||
"integrations/keywords",
|
||||
"integrations/respan",
|
||||
"integrations/raycast"
|
||||
]
|
||||
}
|
||||
@@ -451,7 +456,9 @@
|
||||
"pages": [
|
||||
"integrations/claude-code",
|
||||
"integrations/cursor",
|
||||
"integrations/codex"
|
||||
"integrations/codex",
|
||||
"integrations/opencode",
|
||||
"integrations/antigravity"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -459,7 +466,8 @@
|
||||
"icon": "robot",
|
||||
"pages": [
|
||||
"integrations/openclaw",
|
||||
"integrations/hermes"
|
||||
"integrations/hermes",
|
||||
"integrations/pi-agent"
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -640,10 +648,6 @@
|
||||
"source": "/open-source/features/custom-fact-extraction-prompt",
|
||||
"destination": "/open-source/features/custom-instructions"
|
||||
},
|
||||
{
|
||||
"source": "/platform/features/graph-memory",
|
||||
"destination": "/migration/oss-v2-to-v3"
|
||||
},
|
||||
{
|
||||
"source": "/cookbooks/essentials/choosing-memory-architecture-vector-vs-graph",
|
||||
"destination": "/migration/oss-v2-to-v3"
|
||||
@@ -1018,7 +1022,7 @@
|
||||
},
|
||||
{
|
||||
"source": "/features/graph-memory",
|
||||
"destination": "/migration/oss-v2-to-v3"
|
||||
"destination": "/platform/features/graph-memory"
|
||||
},
|
||||
{
|
||||
"source": "/features/:slug",
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 276 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 227 KiB |
@@ -309,19 +309,21 @@ Here are the available integrations for Mem0:
|
||||
</Card>
|
||||
|
||||
<Card
|
||||
title="Keywords AI"
|
||||
title="Respan"
|
||||
icon={
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
viewBox="0 0 200 200"
|
||||
fill="none"
|
||||
>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.07513 1.1863C9.21663 1.07722 9.39144 1.01009 9.56624 1.01009C9.83261 1.01009 10.0823 1.12756 10.2405 1.33734L15.0101 7.4964V12.4136L16.4335 13.8401C16.7582 14.1673 16.7582 14.7043 16.4335 15.0316C16.1089 15.3588 15.5762 15.3588 15.2515 15.0316L13.3453 13.1016V8.07538L8.92529 2.36944V2.36105C8.64228 2.00024 8.70887 1.4716 9.07513 1.1863ZM18.976 14.4133C18.8344 14.3778 18.7003 14.3042 18.5894 14.1925L16.9163 12.5059C16.7249 12.3129 16.6416 12.0528 16.6749 11.8094V6.88385H16.6499L11.8553 0.691225C11.7282 0.529117 11.6716 0.333133 11.6803 0.140562C11.134 0.0481292 10.5726 0 10 0C4.47715 0 0 4.47715 0 10C0 15.5228 4.47715 20 10 20C13.9387 20 17.3456 17.7229 18.976 14.4133Z" fill="currentColor"></path>
|
||||
<path d="M2.00635 190.234V9.76584H53.3558V29.5101H26.7223V170.562H53.3558V190.234H2.00635Z" fill="currentColor"></path>
|
||||
<path d="M120.692 160.902C116.383 160.902 112.691 159.387 109.612 156.357C106.535 153.327 105.02 149.633 105.067 145.277C105.02 141.016 106.535 137.37 109.612 134.34C112.691 131.309 116.383 129.794 120.692 129.794C124.859 129.794 128.481 131.309 131.559 134.34C134.684 137.37 136.27 141.016 136.317 145.277C136.27 148.166 135.512 150.793 134.045 153.161C132.624 155.528 130.73 157.422 128.362 158.842C126.042 160.216 123.486 160.902 120.692 160.902Z" fill="currentColor"></path>
|
||||
<path d="M197.993 9.76584V190.234H146.643V170.562H173.278V29.5101H146.643V9.76584H197.993Z" fill="currentColor"></path>
|
||||
</svg>
|
||||
}
|
||||
href="/integrations/keywords"
|
||||
href="/integrations/respan"
|
||||
>
|
||||
Build AI applications with persistent memory and comprehensive LLM observability.
|
||||
</Card>
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
---
|
||||
title: Antigravity
|
||||
description: "Add persistent memory to Google Antigravity with the Mem0 plugin — MCP server, lifecycle hooks, and slash commands."
|
||||
---
|
||||
|
||||
Add persistent memory to [**Google Antigravity**](https://antigravity.google) (`agy` CLI and Desktop IDE) with the Mem0 plugin. Your agent forgets everything between sessions — Mem0 fixes that by storing decisions, preferences, and learnings so they carry over automatically.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. A Mem0 API key (starts with `m0-`):
|
||||
- <a href="https://app.mem0.ai/dashboard/api-keys?utm_source=oss&utm_medium=integration-antigravity" rel="nofollow">Get your API key</a> (free sign-up at <a href="https://app.mem0.ai?utm_source=oss&utm_medium=integration-antigravity" rel="nofollow">app.mem0.ai</a>)
|
||||
|
||||
2. Add it to your shell profile so it persists across sessions:
|
||||
|
||||
<CodeGroup>
|
||||
```bash zsh
|
||||
echo 'export MEM0_API_KEY="m0-your-api-key"' >> ~/.zshrc && source ~/.zshrc
|
||||
```
|
||||
|
||||
```bash bash
|
||||
echo 'export MEM0_API_KEY="m0-your-api-key"' >> ~/.bashrc && source ~/.bashrc
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
## Installation
|
||||
|
||||
**Option A — degit** (recommended):
|
||||
|
||||
```bash
|
||||
# Install the plugin (MCP server, hooks, scripts)
|
||||
npx degit mem0ai/mem0/integrations/mem0-plugin ~/.gemini/config/plugins/mem0
|
||||
```
|
||||
|
||||
This installs the MCP server, lifecycle hooks, and shared scripts.
|
||||
|
||||
## What's Included
|
||||
|
||||
| Component | Included |
|
||||
|-----------|:--------:|
|
||||
| MCP Server (9 memory tools) | Yes |
|
||||
| Lifecycle Hooks | Yes |
|
||||
| 16 Slash Commands | Yes |
|
||||
|
||||
## Available MCP Tools
|
||||
|
||||
| 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
|
||||
|
||||
The plugin uses the same shell scripts as Claude Code, Cursor, and Codex — hooks bridge environment variables using `${extensionPath}` (Antigravity's plugin-root token).
|
||||
|
||||
| Hook | Event | What it does |
|
||||
|------|-------|-------------|
|
||||
| **Session start** | `SessionStart` | Loads prior memories and displays status banner |
|
||||
| **User prompt** | `UserPromptSubmit` | Searches relevant memories before each message |
|
||||
| **Pre-tool** | `PreToolUse` | Blocks MEMORY.md writes, enforces `user_id`/`app_id` on mem0 tools |
|
||||
| **Post-tool** | `PostToolUse` | Tracks stats, scans bash errors for related memories |
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **No tools appearing** — Restart your Antigravity session after installation
|
||||
- **"Connection failed"** — Verify your key is set: `echo $MEM0_API_KEY`
|
||||
- **MCP 401 Unauthorized** — If `${MEM0_API_KEY}` interpolation doesn't work in your `agy` version, replace with your literal key in `mcp_config.json`
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Mem0 MCP Setup" icon="puzzle-piece" href="/platform/mem0-mcp">
|
||||
Detailed MCP configuration for all clients
|
||||
</Card>
|
||||
<Card title="OpenCode Integration" icon="code" href="/integrations/opencode">
|
||||
Add Mem0 memory to OpenCode workflows
|
||||
</Card>
|
||||
</CardGroup>
|
||||
@@ -5,13 +5,6 @@ description: "Add persistent memory to Claude Code and Claude Cowork with the Me
|
||||
|
||||
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:
|
||||
@@ -22,10 +15,25 @@ Before setting up Mem0 with Claude Code, ensure you have:
|
||||
|
||||
2. Claude Code CLI or Claude Cowork desktop app installed
|
||||
|
||||
3. Your API key exported in your shell:
|
||||
3. Your API key added to your shell profile (persists across sessions):
|
||||
|
||||
<CodeGroup>
|
||||
```bash zsh
|
||||
echo 'export MEM0_API_KEY="m0-your-api-key"' >> ~/.zshrc
|
||||
source ~/.zshrc
|
||||
```
|
||||
|
||||
```bash bash
|
||||
echo 'export MEM0_API_KEY="m0-your-api-key"' >> ~/.bashrc
|
||||
source ~/.bashrc
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
Confirm it's set:
|
||||
|
||||
```bash
|
||||
export MEM0_API_KEY="m0-your-api-key"
|
||||
echo $MEM0_API_KEY
|
||||
# Should print: m0-your-api-key
|
||||
```
|
||||
|
||||
## Installation
|
||||
@@ -84,6 +92,22 @@ Add to your Claude Code MCP config (`.mcp.json`):
|
||||
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>
|
||||
|
||||
## Post-Installation: Run `/mem0:onboard`
|
||||
|
||||
After installing the plugin, start a new Claude Code session and run:
|
||||
|
||||
```
|
||||
/mem0:onboard
|
||||
```
|
||||
|
||||
This runs the setup wizard which:
|
||||
1. Verifies your API key and MCP connection
|
||||
2. Detects and imports project files (`CLAUDE.md`, `AGENTS.md`, `.cursorrules`)
|
||||
3. Installs coding-optimized memory categories
|
||||
4. Shows your identity (user ID, project scope, branch)
|
||||
|
||||
The onboarding is idempotent — safe to re-run anytime. It auto-triggers on first session in a new project, but you can always invoke it manually.
|
||||
|
||||
## What's Included
|
||||
|
||||
| Component | Plugin Install | MCP Only |
|
||||
@@ -112,20 +136,13 @@ Once installed, the following tools are available in every Claude Code session:
|
||||
|
||||
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.
|
||||
| Hook | Event | What it does |
|
||||
|------|-------|-------------|
|
||||
| **Session start** | `SessionStart` | Loads prior memories and displays status banner |
|
||||
| **User prompt** | `UserPromptSubmit` | Searches relevant memories before each message; skips short prompts |
|
||||
| **Pre-tool** | `PreToolUse` | Blocks MEMORY.md writes, enforces `user_id`/`app_id` on mem0 tool calls |
|
||||
| **Post-tool** | `PostToolUse` | Tracks stats, scans bash errors for related memories |
|
||||
| **Pre-compact** | `PreCompact` | Stores a session summary before context compaction |
|
||||
|
||||
## Example Workflow
|
||||
|
||||
@@ -149,9 +166,10 @@ You: Add refresh token rotation to the auth system.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **"Connection failed"** — Verify `MEM0_API_KEY` is set in your shell: `echo $MEM0_API_KEY`
|
||||
- **"Connection failed"** — Verify `MEM0_API_KEY` is set in your shell: `echo $MEM0_API_KEY`. If empty, add it to your shell profile (see Prerequisites)
|
||||
- **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.
|
||||
- **Memories not being captured** — Ensure you installed via the plugin marketplace (Option A) for lifecycle hooks. MCP-only installs require manual memory operations
|
||||
- **"Mem0 Inactive" banner every session** — Your API key isn't persisting. Add `export MEM0_API_KEY="m0-..."` to your `~/.zshrc` (or `~/.bashrc`) and run `source ~/.zshrc`
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Mem0 MCP Setup" icon="puzzle-piece" href="/platform/mem0-mcp">
|
||||
|
||||
+49
-124
@@ -1,16 +1,9 @@
|
||||
---
|
||||
title: Codex
|
||||
description: "Add persistent memory to OpenAI Codex with the Mem0 plugin — MCP server, memory protocol skill, and plugin marketplace support."
|
||||
description: "Add persistent memory to OpenAI Codex with the Mem0 plugin — MCP server, lifecycle hooks, and SDK skill."
|
||||
---
|
||||
|
||||
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
|
||||
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, automatically capturing learnings at key lifecycle points, and retrieving relevant context before every response.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
@@ -22,17 +15,41 @@ Before setting up Mem0 with Codex, ensure you have:
|
||||
|
||||
2. OpenAI Codex access
|
||||
|
||||
3. Your API key exported in your shell:
|
||||
3. Your API key added to your shell profile (persists across sessions):
|
||||
|
||||
```bash
|
||||
export MEM0_API_KEY="m0-your-api-key"
|
||||
<CodeGroup>
|
||||
```bash zsh
|
||||
echo 'export MEM0_API_KEY="m0-your-api-key"' >> ~/.zshrc
|
||||
source ~/.zshrc
|
||||
```
|
||||
|
||||
```bash bash
|
||||
echo 'export MEM0_API_KEY="m0-your-api-key"' >> ~/.bashrc
|
||||
source ~/.bashrc
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
## Installation
|
||||
|
||||
### Option A — Direct MCP (Recommended)
|
||||
### Option A — Plugin Marketplace (Recommended)
|
||||
|
||||
The fastest way to connect Codex to Mem0 — no downloads, no marketplace. Codex reads MCP servers from `~/.codex/config.toml` as TOML. Add:
|
||||
Install the full plugin including MCP server, lifecycle hooks, and SDK skill.
|
||||
|
||||
1. Add the Mem0 marketplace:
|
||||
|
||||
```bash
|
||||
codex plugin marketplace add mem0ai/mem0
|
||||
```
|
||||
|
||||
2. Restart Codex, open the Plugin Directory, browse the **Mem0 Plugins** marketplace, and install **Mem0**.
|
||||
|
||||
<Info>
|
||||
Do not combine with Option B. The plugin manifest auto-registers the `mem0` MCP server, so adding both will create a duplicate registration.
|
||||
</Info>
|
||||
|
||||
### Option B — Direct MCP
|
||||
|
||||
The fastest way to connect Codex to Mem0 — no plugin, no marketplace. Add to `~/.codex/config.toml`:
|
||||
|
||||
```toml
|
||||
[mcp_servers.mem0]
|
||||
@@ -46,71 +63,16 @@ Make sure `MEM0_API_KEY` is exported in the shell you launch Codex from, then re
|
||||
Codex's `codex mcp add` CLI only supports stdio MCP servers. Because Mem0's MCP is HTTP/streamable, you configure it by editing `config.toml` directly (or via the **Plugins → Connect to a custom MCP → Streamable HTTP** UI in the Codex app).
|
||||
</Info>
|
||||
|
||||
### Option B — Sideload the Plugin (Advanced)
|
||||
|
||||
For the full plugin experience — MCP server **plus** the Mem0 SDK skill, memory protocol skill, and opt-in lifecycle hooks — sideload the plugin from a local clone. The Mem0 repo already ships a marketplace manifest at [`.agents/plugins/marketplace.json`](https://github.com/mem0ai/mem0/blob/main/.agents/plugins/marketplace.json), so there's no JSON to author by hand. This follows the Codex [build-plugins](https://developers.openai.com/codex/plugins/build) local-testing workflow.
|
||||
|
||||
<Info>
|
||||
Don't combine Option B with Option A. The plugin manifest declares its MCP server via [`.codex-mcp.json`](https://github.com/mem0ai/mem0/blob/main/mem0-plugin/.codex-mcp.json), so Codex auto-registers the `mem0` MCP server when the plugin loads. Adding the same `[mcp_servers.mem0]` block to `~/.codex/config.toml` will create a duplicate registration.
|
||||
</Info>
|
||||
|
||||
**Step 1.** Clone the Mem0 repository anywhere on disk:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/mem0ai/mem0.git ~/codex-plugins/mem0-source
|
||||
```
|
||||
|
||||
**Step 2.** Register the bundled marketplace with Codex's CLI:
|
||||
|
||||
```bash
|
||||
codex plugin marketplace add ~/codex-plugins/mem0-source
|
||||
```
|
||||
|
||||
This points Codex at the repo's `.agents/plugins/marketplace.json`. The bundled file uses `path: "./mem0-plugin"`, which Codex resolves relative to the clone root.
|
||||
|
||||
<Info>
|
||||
**Why we recommend this over hand-authoring `~/.agents/plugins/marketplace.json`:** Codex requires `source.path` in any marketplace manifest to be **relative** (starting with `./`) and **inside the marketplace root**. The repo's bundled manifest already satisfies this — the marketplace root is the clone directory, and `mem0-plugin/` lives inside it. With a personal `~/.agents/plugins/marketplace.json`, the root is `~/` and the clone has to live under `~/` too. The CLI form sidesteps that constraint.
|
||||
</Info>
|
||||
|
||||
**Step 3.** Restart Codex, run `/plugins`, browse the `Mem0 Plugins` marketplace, and install **Mem0**.
|
||||
|
||||
**Step 4 (optional) — enable lifecycle hooks.** Codex doesn't auto-wire hooks from plugin manifests; it only reads them from `~/.codex/hooks.json` (or `<repo>/.codex/hooks.json`). Run the bundled installer once to merge the Mem0 entries into your global hooks file:
|
||||
|
||||
```bash
|
||||
python3 ~/codex-plugins/mem0-source/mem0-plugin/scripts/install_codex_hooks.py
|
||||
```
|
||||
|
||||
Then enable the hooks feature flag in `~/.codex/config.toml`:
|
||||
|
||||
```toml
|
||||
[features]
|
||||
codex_hooks = true
|
||||
```
|
||||
|
||||
Restart Codex. The installer registers three hooks pointing at scripts inside your clone:
|
||||
|
||||
| Event | Behavior |
|
||||
|-------|----------|
|
||||
| `SessionStart` | Loads prior memories as bootstrap context |
|
||||
| `UserPromptSubmit` | Injects relevant memories before each prompt |
|
||||
| `Stop` | Reminds the agent to persist learnings at turn end |
|
||||
|
||||
Re-running the installer is idempotent. To remove the hooks: `python3 ~/codex-plugins/mem0-source/mem0-plugin/scripts/install_codex_hooks.py --uninstall`.
|
||||
|
||||
<Warning>
|
||||
The hooks file stores absolute paths into your clone (e.g. `~/codex-plugins/mem0-source/mem0-plugin/scripts/...`). If you move or delete the clone, the hooks will break silently — re-run the installer from the new location, or run `--uninstall` first.
|
||||
</Warning>
|
||||
This gives you the MCP tools but not the lifecycle hooks or SDK skill.
|
||||
|
||||
### Managing the Plugin
|
||||
|
||||
Codex provides CLI commands for managing marketplaces after install:
|
||||
|
||||
```bash
|
||||
codex plugin marketplace upgrade # pull latest plugin versions
|
||||
codex plugin marketplace remove mem0-plugins # unregister the marketplace
|
||||
```
|
||||
|
||||
To pull updates to the plugin source itself, `git pull` inside your clone (`~/codex-plugins/mem0-source`) and then run `codex plugin marketplace upgrade` to refresh Codex's plugin cache. Plugins are cached at `~/.codex/plugins/cache/<marketplace>/<plugin>/<version>/`.
|
||||
To update, run `codex plugin marketplace upgrade` to pull the latest from the Mem0 repo.
|
||||
|
||||
<Info icon="check">
|
||||
After either option, 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.
|
||||
@@ -118,12 +80,11 @@ To pull updates to the plugin source itself, `git pull` inside your clone (`~/co
|
||||
|
||||
## What's Included
|
||||
|
||||
| Component | Sideloaded Plugin | Direct MCP |
|
||||
|-----------|:-----------------:|:----------:|
|
||||
| Component | Plugin Install | MCP Only |
|
||||
|-----------|:--------------:|:--------:|
|
||||
| MCP Server (9 memory tools) | Yes | Yes |
|
||||
| Memory Protocol Skill | Yes | No |
|
||||
| Lifecycle Hooks | Yes | No |
|
||||
| Mem0 SDK Skill | Yes | No |
|
||||
| Lifecycle Hooks (opt-in) | Yes | No |
|
||||
|
||||
## Available MCP Tools
|
||||
|
||||
@@ -141,49 +102,17 @@ Once installed, the following tools are available in every Codex session:
|
||||
| `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
|
||||
## Lifecycle Hooks
|
||||
|
||||
When the plugin is sideloaded, the memory protocol skill instructs the agent to:
|
||||
When installed via the plugin marketplace, Mem0 hooks into Codex's lifecycle to automatically manage memory:
|
||||
|
||||
### 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"]
|
||||
}
|
||||
}
|
||||
```
|
||||
| Hook | Event | What it does |
|
||||
|------|-------|-------------|
|
||||
| **Session start** | `SessionStart` | Loads prior memories and displays status banner |
|
||||
| **User prompt** | `UserPromptSubmit` | Searches relevant memories before each message |
|
||||
| **Pre-tool** | `PreToolUse` | Blocks MEMORY.md writes, enforces `user_id`/`app_id` on mem0 tool calls |
|
||||
| **Post-tool** | `PostToolUse` | Tracks stats, scans bash errors for related memories |
|
||||
| **Pre-compact** | `PreCompact` | Stores a session summary before context compaction |
|
||||
|
||||
## Example Workflow
|
||||
|
||||
@@ -206,14 +135,10 @@ You: Add WebSocket support for real-time notification delivery.
|
||||
|
||||
## 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
|
||||
- **Duplicate `mem0` MCP server / "tool collision" errors** — You combined Option A (Direct MCP) with Option B (sideload). The sideloaded plugin auto-registers `mem0` from `.codex-mcp.json`, so remove the `[mcp_servers.mem0]` block from `~/.codex/config.toml`.
|
||||
- **`plugin/read failed in TUI`** — Codex can't find the plugin directory the marketplace points at. If you used `codex plugin marketplace add <path>`, confirm the path is your clone root and that `<clone>/.agents/plugins/marketplace.json` exists. If you hand-authored `~/.agents/plugins/marketplace.json`, `source.path` must be relative (start with `./`), inside the marketplace root (`~/` for personal installs), and end in `mem0-plugin` — e.g. `"./codex-plugins/mem0-source/mem0-plugin"`.
|
||||
- **Plugin not found in `/plugins`** — Run `codex plugin marketplace add ~/path/to/clone` again, or confirm the marketplace was registered with `codex plugin marketplace remove mem0-plugins` then re-add.
|
||||
- **Skills not loading** — Verify the `skills` field in `plugin.json` points to a valid directory containing `SKILL.md` files.
|
||||
- **Hooks not firing** — Confirm `codex_hooks = true` is in `~/.codex/config.toml` under `[features]`, and that `~/.codex/hooks.json` contains the Mem0 entries (re-run the installer if not). Restart Codex after enabling the flag.
|
||||
- **Hooks broke after moving the clone** — The installer bakes absolute paths into `~/.codex/hooks.json` pointing at scripts inside your clone. If you moved or renamed the clone directory, run `python3 <new-clone>/mem0-plugin/scripts/install_codex_hooks.py` from the new location — the installer is idempotent and replaces the old entries.
|
||||
- **"Connection failed"** — Verify `MEM0_API_KEY` is set: `echo $MEM0_API_KEY`
|
||||
- **No tools appearing** — Restart your Codex session after installation
|
||||
- **Duplicate `mem0` MCP / "tool collision" errors** — You combined Option A with Option B. Remove the `[mcp_servers.mem0]` block from `~/.codex/config.toml`; the plugin registers it automatically
|
||||
- **Hooks not firing** — Ensure the plugin is installed via the marketplace (Option A). MCP-only installs do not include hooks
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Mem0 MCP Setup" icon="puzzle-piece" href="/platform/mem0-mcp">
|
||||
|
||||
@@ -5,13 +5,6 @@ description: "Add persistent memory to Cursor with the Mem0 plugin — MCP serve
|
||||
|
||||
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:
|
||||
@@ -22,12 +15,20 @@ Before setting up Mem0 with Cursor, ensure you have:
|
||||
|
||||
2. Cursor installed ([cursor.com](https://cursor.com))
|
||||
|
||||
3. Your API key exported in your shell:
|
||||
3. Your API key added to your shell profile (persists across sessions):
|
||||
|
||||
```bash
|
||||
export MEM0_API_KEY="m0-your-api-key"
|
||||
<CodeGroup>
|
||||
```bash zsh
|
||||
echo 'export MEM0_API_KEY="m0-your-api-key"' >> ~/.zshrc
|
||||
source ~/.zshrc
|
||||
```
|
||||
|
||||
```bash bash
|
||||
echo 'export MEM0_API_KEY="m0-your-api-key"' >> ~/.bashrc
|
||||
source ~/.bashrc
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
<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>
|
||||
@@ -103,14 +104,13 @@ Once installed, the following tools are available in every Cursor session:
|
||||
|
||||
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.
|
||||
| Hook | Event | What it does |
|
||||
|------|-------|-------------|
|
||||
| **Session start** | `sessionStart` | Loads prior memories and displays status banner |
|
||||
| **User prompt** | `beforeSubmitPrompt` | Searches relevant memories before each message; skips short prompts |
|
||||
| **Pre-tool (2 handlers)** | `preToolUse` | Blocks MEMORY.md writes, enforces `user_id`/`app_id` on mem0 tool calls |
|
||||
| **Post-tool (2 handlers)** | `postToolUse` | Tracks stats, scans bash errors for related memories |
|
||||
| **Pre-compact** | `preCompact` | Stores a session summary before context compaction |
|
||||
|
||||
## Example Workflow
|
||||
|
||||
|
||||
+243
-191
@@ -7,285 +7,338 @@ Integrate [**Mem0**](https://github.com/mem0ai/mem0) with [Google ADK (Agent Dev
|
||||
|
||||
## Overview
|
||||
|
||||
1. Store and retrieve memories from Mem0 within Google ADK agents
|
||||
2. Multi-agent workflows with shared memory across hierarchies
|
||||
3. Retrieve relevant memories from past conversations
|
||||
4. Personalized responses based on user history
|
||||
In this guide, we'll create a Google ADK agent that:
|
||||
1. Uses ADK's native `MemoryService` interface to connect Mem0
|
||||
2. Automatically injects relevant memories using ADK's built-in `load_memory` tool
|
||||
3. Persists session history to Mem0 after each turn via an after-agent callback
|
||||
4. Shares memory seamlessly across multi-agent hierarchies
|
||||
|
||||
## Prerequisites
|
||||
## Setup and Configuration
|
||||
|
||||
Before setting up Mem0 with Google ADK, ensure you have:
|
||||
Install the necessary libraries:
|
||||
|
||||
1. Installed the required packages:
|
||||
```bash
|
||||
pip install google-adk mem0ai python-dotenv
|
||||
```
|
||||
|
||||
2. Valid API keys:
|
||||
Set up your API keys:
|
||||
- <a href="https://app.mem0.ai/dashboard/api-keys?utm_source=oss&utm_medium=integration-google-ai-adk" rel="nofollow">Mem0 API Key</a>
|
||||
- Google AI Studio API Key
|
||||
|
||||
## Basic Integration Example
|
||||
|
||||
The following example demonstrates how to create a Google ADK agent with Mem0 memory integration:
|
||||
<Note>Remember to get your API key from <a href="https://app.mem0.ai" rel="nofollow">Mem0 Platform</a> and set up a [Google AI Studio API Key](https://aistudio.google.com/apikey).</Note>
|
||||
|
||||
```python
|
||||
import os
|
||||
import asyncio
|
||||
from google.adk.agents import Agent
|
||||
from google.adk.runners import Runner
|
||||
from google.adk.sessions import InMemorySessionService
|
||||
from google.genai import types
|
||||
from mem0 import MemoryClient
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
|
||||
# Set up environment variables
|
||||
# os.environ["GOOGLE_API_KEY"] = "your-google-api-key"
|
||||
# os.environ["MEM0_API_KEY"] = "your-mem0-api-key"
|
||||
```
|
||||
|
||||
# Initialize Mem0 client
|
||||
mem0 = MemoryClient()
|
||||
## Implement Mem0MemoryService
|
||||
|
||||
# Define memory function tools
|
||||
def search_memory(query: str, user_id: str) -> dict:
|
||||
"""Search through past conversations and memories"""
|
||||
# For Platform API, user_id goes in filters
|
||||
filters = {"user_id": user_id}
|
||||
memories = mem0.search(query, filters=filters)
|
||||
if memories.get('results', []):
|
||||
memory_list = memories['results']
|
||||
memory_context = "\n".join([f"- {mem['memory']}" for mem in memory_list])
|
||||
return {"status": "success", "memories": memory_context}
|
||||
return {"status": "no_memories", "message": "No relevant memories found"}
|
||||
Create a custom `MemoryService` by implementing ADK's `BaseMemoryService`. Save the following as **`mem0_memory_service.py`**:
|
||||
|
||||
def save_memory(content: str, user_id: str) -> dict:
|
||||
"""Save important information to memory"""
|
||||
```python
|
||||
import asyncio
|
||||
import os
|
||||
from typing import Optional
|
||||
from typing_extensions import override
|
||||
|
||||
from google.adk.memory.base_memory_service import BaseMemoryService, SearchMemoryResponse
|
||||
from google.adk.memory.memory_entry import MemoryEntry
|
||||
from google.adk.sessions import Session
|
||||
from google.genai.types import Content, Part
|
||||
from mem0 import MemoryClient
|
||||
|
||||
|
||||
class Mem0MemoryService(BaseMemoryService):
|
||||
"""MemoryService implementation backed by the Mem0 Platform."""
|
||||
|
||||
def __init__(self, api_key: Optional[str] = None):
|
||||
super().__init__()
|
||||
api_key = api_key or os.environ.get("MEM0_API_KEY")
|
||||
self._client: Optional[MemoryClient] = MemoryClient(api_key=api_key) if api_key else None
|
||||
|
||||
@override
|
||||
async def search_memory(
|
||||
self, *, app_name: str, user_id: str, query: str
|
||||
) -> SearchMemoryResponse:
|
||||
"""Search for memories relevant to the current user and query."""
|
||||
if not self._client:
|
||||
return SearchMemoryResponse(memories=[])
|
||||
|
||||
try:
|
||||
results = await asyncio.to_thread(
|
||||
self._client.search,
|
||||
query,
|
||||
filters={"AND": [{"user_id": user_id}, {"app_id": app_name}]},
|
||||
top_k=5,
|
||||
)
|
||||
|
||||
entries = []
|
||||
for mem in results.get("results", []):
|
||||
text = mem.get("memory", "")
|
||||
if not text:
|
||||
continue
|
||||
|
||||
raw_ts = mem.get("created_at") or mem.get("updated_at")
|
||||
entries.append(
|
||||
MemoryEntry(
|
||||
content=Content(parts=[Part(text=text)]),
|
||||
author=mem.get("metadata", {}).get("author", "user"),
|
||||
timestamp=str(raw_ts) if raw_ts else None,
|
||||
)
|
||||
)
|
||||
|
||||
return SearchMemoryResponse(memories=entries)
|
||||
|
||||
except Exception as e:
|
||||
print(f"[Mem0MemoryService] search_memory error: {e}")
|
||||
return SearchMemoryResponse(memories=[])
|
||||
|
||||
@override
|
||||
async def add_session_to_memory(self, session: Session) -> None:
|
||||
"""Persist a completed ADK session into Mem0."""
|
||||
if not self._client:
|
||||
return
|
||||
|
||||
user_id = session.user_id
|
||||
if not user_id:
|
||||
return
|
||||
|
||||
app_name = getattr(session, "app_name", None)
|
||||
|
||||
try:
|
||||
messages = []
|
||||
for event in session.events:
|
||||
if not (event.content and event.content.parts):
|
||||
continue
|
||||
role = getattr(event.content, "role", None) or "user"
|
||||
if role == "model":
|
||||
role = "assistant"
|
||||
elif role not in ("user", "assistant"):
|
||||
continue
|
||||
text_parts = [
|
||||
p.text for p in event.content.parts if hasattr(p, "text") and p.text
|
||||
]
|
||||
if text_parts:
|
||||
messages.append({"role": role, "content": " ".join(text_parts)})
|
||||
|
||||
if messages:
|
||||
metadata = {"app_id": app_name} if app_name else {}
|
||||
await asyncio.to_thread(
|
||||
self._client.add, messages, user_id=user_id, metadata=metadata
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
print(f"[Mem0MemoryService] add_session_to_memory error: {e}")
|
||||
```
|
||||
|
||||
## Add Auto-Save Callback
|
||||
|
||||
This after-agent callback fires at the end of every turn and saves the session to Mem0. Save as **`memory_callbacks.py`**:
|
||||
|
||||
```python
|
||||
async def save_session_to_memory(callback_context) -> None:
|
||||
"""Persist the completed session to Mem0 after each agent turn."""
|
||||
try:
|
||||
result = mem0.add([{"role": "user", "content": content}], user_id=user_id)
|
||||
return {"status": "success", "message": "Information saved to memory", "result": result}
|
||||
await callback_context.add_session_to_memory()
|
||||
except ValueError:
|
||||
pass
|
||||
except Exception as e:
|
||||
return {"status": "error", "message": f"Failed to save memory: {str(e)}"}
|
||||
print(f"[save_session_to_memory] error: {e}")
|
||||
```
|
||||
|
||||
# Create agent with memory capabilities
|
||||
personal_assistant = Agent(
|
||||
## Basic Integration Example
|
||||
|
||||
The following example demonstrates creating an ADK agent with automatic Mem0 memory:
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from google.adk.agents import LlmAgent
|
||||
from google.adk.runners import Runner
|
||||
from google.adk.sessions import InMemorySessionService
|
||||
from google.adk.tools import load_memory
|
||||
from google.genai.types import Content, Part
|
||||
|
||||
from mem0_memory_service import Mem0MemoryService
|
||||
from memory_callbacks import save_session_to_memory
|
||||
|
||||
memory_service = Mem0MemoryService()
|
||||
session_service = InMemorySessionService()
|
||||
|
||||
agent = LlmAgent(
|
||||
name="personal_assistant",
|
||||
model="gemini-2.0-flash",
|
||||
instruction="""You are a helpful personal assistant with memory capabilities.
|
||||
Use the search_memory function to recall past conversations and user preferences.
|
||||
Use the save_memory function to store important information about the user.
|
||||
Always personalize your responses based on available memory.""",
|
||||
instruction="""You are a helpful personal assistant.
|
||||
Relevant memories from past conversations are provided to you automatically.
|
||||
Use them to personalize your responses.""",
|
||||
description="A personal assistant that remembers user preferences and past interactions",
|
||||
tools=[search_memory, save_memory]
|
||||
tools=[load_memory],
|
||||
after_agent_callback=save_session_to_memory,
|
||||
)
|
||||
|
||||
async def chat_with_agent(user_input: str, user_id: str) -> str:
|
||||
"""
|
||||
Handle user input with automatic memory integration.
|
||||
runner = Runner(
|
||||
agent=agent,
|
||||
session_service=session_service,
|
||||
memory_service=memory_service,
|
||||
app_name="memory_assistant",
|
||||
)
|
||||
|
||||
Args:
|
||||
user_input: The user's message
|
||||
user_id: Unique identifier for the user
|
||||
|
||||
Returns:
|
||||
The agent's response
|
||||
"""
|
||||
# Set up session and runner
|
||||
session_service = InMemorySessionService()
|
||||
async def chat(user_input: str, user_id: str) -> str:
|
||||
session = await session_service.create_session(
|
||||
app_name="memory_assistant",
|
||||
user_id=user_id,
|
||||
session_id=f"session_{user_id}"
|
||||
)
|
||||
runner = Runner(agent=personal_assistant, app_name="memory_assistant", session_service=session_service)
|
||||
|
||||
# Create content and run agent
|
||||
content = types.Content(role='user', parts=[types.Part(text=user_input)])
|
||||
events = runner.run(user_id=user_id, session_id=session.id, new_message=content)
|
||||
|
||||
# Extract final response
|
||||
for event in events:
|
||||
if event.is_final_response():
|
||||
response = event.content.parts[0].text
|
||||
|
||||
return response
|
||||
|
||||
content = Content(role="user", parts=[Part(text=user_input)])
|
||||
async for event in runner.run_async(user_id=user_id, session_id=session.id, new_message=content):
|
||||
if event.is_final_response() and event.content and event.content.parts:
|
||||
return event.content.parts[0].text
|
||||
return "No response generated"
|
||||
|
||||
# Example usage
|
||||
|
||||
if __name__ == "__main__":
|
||||
response = asyncio.run(chat_with_agent(
|
||||
print(asyncio.run(chat(
|
||||
"I love Italian food and I'm planning a trip to Rome next month",
|
||||
user_id="alice"
|
||||
))
|
||||
print(response)
|
||||
user_id="alice",
|
||||
)))
|
||||
|
||||
print(asyncio.run(chat(
|
||||
"Any food recommendations for my trip?",
|
||||
user_id="alice",
|
||||
)))
|
||||
```
|
||||
|
||||
## Multi-Agent Hierarchy with Shared Memory
|
||||
|
||||
Create specialized agents in a hierarchy that share memory:
|
||||
Because `memory_service` is passed to the `Runner`, every agent in the hierarchy shares the same memory automatically. Only the root coordinator needs the auto-save callback — ADK fires it once when the full turn completes:
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from google.adk.agents import LlmAgent
|
||||
from google.adk.runners import Runner
|
||||
from google.adk.sessions import InMemorySessionService
|
||||
from google.adk.tools.agent_tool import AgentTool
|
||||
from google.adk.tools import load_memory
|
||||
from google.genai.types import Content, Part
|
||||
|
||||
# Travel specialist agent
|
||||
travel_agent = Agent(
|
||||
from mem0_memory_service import Mem0MemoryService
|
||||
from memory_callbacks import save_session_to_memory
|
||||
|
||||
memory_service = Mem0MemoryService()
|
||||
session_service = InMemorySessionService()
|
||||
|
||||
travel_agent = LlmAgent(
|
||||
name="travel_specialist",
|
||||
model="gemini-2.0-flash",
|
||||
instruction="""You are a travel planning specialist. Use search_memory to
|
||||
understand the user's travel preferences and history before making recommendations.
|
||||
After providing advice, use save_memory to save travel-related information.""",
|
||||
instruction="""You are a travel planning specialist.
|
||||
Relevant memories about the user's travel preferences are provided automatically.
|
||||
Use them to make personalized recommendations.""",
|
||||
description="Specialist in travel planning and recommendations",
|
||||
tools=[search_memory, save_memory]
|
||||
tools=[load_memory],
|
||||
)
|
||||
|
||||
# Health advisor agent
|
||||
health_agent = Agent(
|
||||
health_agent = LlmAgent(
|
||||
name="health_advisor",
|
||||
model="gemini-2.0-flash",
|
||||
instruction="""You are a health and wellness advisor. Use search_memory to
|
||||
understand the user's health goals and dietary preferences.
|
||||
After providing advice, use save_memory to save health-related information.""",
|
||||
instruction="""You are a health and wellness advisor.
|
||||
Relevant memories about the user's health goals are provided automatically.
|
||||
Use them to give personalized advice.""",
|
||||
description="Specialist in health and wellness advice",
|
||||
tools=[search_memory, save_memory]
|
||||
tools=[load_memory],
|
||||
)
|
||||
|
||||
# Coordinator agent that delegates to specialists
|
||||
coordinator_agent = Agent(
|
||||
coordinator = LlmAgent(
|
||||
name="coordinator",
|
||||
model="gemini-2.0-flash",
|
||||
instruction="""You are a coordinator that delegates requests to specialist agents.
|
||||
For travel-related questions (trips, hotels, flights, destinations), delegate to the travel specialist.
|
||||
For health-related questions (fitness, diet, wellness, exercise), delegate to the health advisor.
|
||||
Use search_memory to understand the user before delegation.""",
|
||||
For travel-related questions, delegate to the travel specialist.
|
||||
For health-related questions, delegate to the health advisor.
|
||||
Relevant memories about the user are provided automatically.""",
|
||||
description="Coordinates requests between specialist agents",
|
||||
tools=[
|
||||
load_memory,
|
||||
AgentTool(agent=travel_agent, skip_summarization=False),
|
||||
AgentTool(agent=health_agent, skip_summarization=False)
|
||||
]
|
||||
AgentTool(agent=health_agent, skip_summarization=False),
|
||||
],
|
||||
after_agent_callback=save_session_to_memory,
|
||||
)
|
||||
|
||||
def chat_with_specialists(user_input: str, user_id: str) -> str:
|
||||
"""
|
||||
Handle user input with specialist agent delegation and memory.
|
||||
runner = Runner(
|
||||
agent=coordinator,
|
||||
session_service=session_service,
|
||||
memory_service=memory_service,
|
||||
app_name="specialist_system",
|
||||
)
|
||||
|
||||
Args:
|
||||
user_input: The user's message
|
||||
user_id: Unique identifier for the user
|
||||
|
||||
Returns:
|
||||
The specialist agent's response
|
||||
"""
|
||||
session_service = InMemorySessionService()
|
||||
session = session_service.create_session(
|
||||
async def chat_with_specialists(user_input: str, user_id: str) -> str:
|
||||
session = await session_service.create_session(
|
||||
app_name="specialist_system",
|
||||
user_id=user_id,
|
||||
session_id=f"session_{user_id}"
|
||||
)
|
||||
runner = Runner(agent=coordinator_agent, app_name="specialist_system", session_service=session_service)
|
||||
|
||||
content = types.Content(role='user', parts=[types.Part(text=user_input)])
|
||||
events = runner.run(user_id=user_id, session_id=session.id, new_message=content)
|
||||
|
||||
for event in events:
|
||||
if event.is_final_response():
|
||||
response = event.content.parts[0].text
|
||||
|
||||
# Store the conversation in shared memory
|
||||
conversation = [
|
||||
{"role": "user", "content": user_input},
|
||||
{"role": "assistant", "content": response}
|
||||
]
|
||||
mem0.add(conversation, user_id=user_id)
|
||||
|
||||
return response
|
||||
|
||||
content = Content(role="user", parts=[Part(text=user_input)])
|
||||
async for event in runner.run_async(user_id=user_id, session_id=session.id, new_message=content):
|
||||
if event.is_final_response() and event.content and event.content.parts:
|
||||
return event.content.parts[0].text
|
||||
return "No response generated"
|
||||
|
||||
# Example usage
|
||||
response = chat_with_specialists("Plan a healthy meal for my Italy trip", user_id="alice")
|
||||
print(response)
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Quick Start Chat Interface
|
||||
|
||||
Simple interactive chat with memory and Google ADK:
|
||||
|
||||
```python
|
||||
def interactive_chat():
|
||||
"""Interactive chat interface with memory and ADK"""
|
||||
user_id = input("Enter your user ID: ") or "demo_user"
|
||||
print(f"Chat started for user: {user_id}")
|
||||
print("Type 'quit' to exit")
|
||||
print("=" * 50)
|
||||
|
||||
while True:
|
||||
user_input = input("\nYou: ")
|
||||
|
||||
if user_input.lower() == 'quit':
|
||||
print("Goodbye! Your conversation has been saved to memory.")
|
||||
break
|
||||
else:
|
||||
response = chat_with_specialists(user_input, user_id)
|
||||
print(f"Assistant: {response}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
interactive_chat()
|
||||
response = asyncio.run(chat_with_specialists("Plan a healthy meal for my Italy trip", user_id="alice"))
|
||||
print(response)
|
||||
```
|
||||
|
||||
## Key Features
|
||||
|
||||
### 1. Memory-Enhanced Function Tools
|
||||
- **Function Tools**: Standard Python functions that can search and save memories
|
||||
- **Tool Context**: Access to session state and memory through function parameters
|
||||
- **Structured Returns**: Dictionary-based returns with status indicators for better LLM understanding
|
||||
|
||||
### 2. Multi-Agent Memory Sharing
|
||||
- **Agent-as-a-Tool**: Specialists can be called as tools while maintaining shared memory
|
||||
- **Hierarchical Delegation**: Coordinator agents route to specialists based on context
|
||||
- **Memory Categories**: Store interactions with metadata for better organization
|
||||
|
||||
### 3. Flexible Memory Operations
|
||||
- **Search Capabilities**: Retrieve relevant memories through conversation history
|
||||
- **User Segmentation**: Organize memories by user ID
|
||||
- **Memory Management**: Built-in tools for saving and retrieving information
|
||||
1. **Automatic Memory Injection**: ADK's built-in `load_memory` tool searches Mem0 at the start of each turn and injects relevant memories directly into the agent context — no prompt instructions needed.
|
||||
2. **Automatic Session Saving**: The `save_session_to_memory` callback persists every completed turn to Mem0 without any manual calls.
|
||||
3. **Native ADK Integration**: `Mem0MemoryService` implements ADK's `BaseMemoryService` and integrates via the `Runner` — works natively across the entire agent hierarchy.
|
||||
4. **User Scoping**: `user_id` is passed automatically from the ADK session context, ensuring memories are always scoped to the correct user.
|
||||
5. **Multi-Agent Support**: A single `Mem0MemoryService` instance shared through the `Runner` gives all agents — coordinators and specialists — access to the same user memory.
|
||||
|
||||
## Configuration Options
|
||||
|
||||
Customize memory behavior and agent setup:
|
||||
### Using Vertex AI
|
||||
|
||||
To use Google Cloud Vertex AI instead of AI Studio, set the following environment variables before creating agents:
|
||||
|
||||
```python
|
||||
# Configure memory search with filters
|
||||
# For Platform API, all filters including user_id go in filters object
|
||||
memories = mem0.search(
|
||||
query="travel preferences",
|
||||
filters={
|
||||
"AND": [
|
||||
{"user_id": "alice"},
|
||||
{"categories": {"contains": "travel"}}
|
||||
]
|
||||
},
|
||||
top_k=5
|
||||
)
|
||||
|
||||
# Configure agent with custom model settings
|
||||
agent = Agent(
|
||||
name="custom_agent",
|
||||
model="gemini-2.0-flash", # or use LiteLLM for other models
|
||||
instruction="Custom agent behavior",
|
||||
tools=[memory_tools],
|
||||
# Additional ADK configurations
|
||||
)
|
||||
|
||||
# Use Google Cloud Vertex AI instead of AI Studio
|
||||
import os
|
||||
os.environ["GOOGLE_GENAI_USE_VERTEXAI"] = "True"
|
||||
os.environ["GOOGLE_CLOUD_PROJECT"] = "your-project-id"
|
||||
os.environ["GOOGLE_CLOUD_LOCATION"] = "us-central1"
|
||||
```
|
||||
|
||||
### Advanced Memory Filtering
|
||||
|
||||
You can customize how memories are searched by modifying `Mem0MemoryService.search_memory`. For example, to filter by category:
|
||||
|
||||
```python
|
||||
results = await asyncio.to_thread(
|
||||
self._client.search,
|
||||
query,
|
||||
filters={
|
||||
"AND": [
|
||||
{"user_id": user_id},
|
||||
{"app_id": app_name},
|
||||
{"categories": {"contains": "travel"}}
|
||||
]
|
||||
},
|
||||
top_k=10,
|
||||
)
|
||||
```
|
||||
|
||||
<Note>`InMemorySessionService` stores sessions in memory and is intended for prototyping. For production, use a persistent session service and clean up sessions when they are no longer needed.</Note>
|
||||
|
||||
## Conclusion
|
||||
|
||||
By implementing `Mem0MemoryService` as an ADK `BaseMemoryService`, you get persistent, user-scoped memory across single agents and complex multi-agent hierarchies with minimal code. Memory injection and session saving happen automatically, keeping your agent prompts clean and your token usage efficient.
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Healthcare Agent Cookbook" icon="heart-pulse" href="/cookbooks/integrations/healthcare-google-adk">
|
||||
Build HIPAA-compliant healthcare agents with Google ADK
|
||||
@@ -294,4 +347,3 @@ os.environ["GOOGLE_CLOUD_LOCATION"] = "us-central1"
|
||||
Compare with OpenAI's agent framework
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
|
||||
+164
-37
@@ -1,35 +1,42 @@
|
||||
---
|
||||
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."
|
||||
description: "Add long-term memory to Hermes agents with Mem0, on managed Mem0 Cloud or fully self-hosted (OSS), 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.
|
||||
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 learns facts from your conversations and surfaces relevant ones before each turn, without slowing down the chat.
|
||||
|
||||
## Overview
|
||||
You can run Mem0 in two ways:
|
||||
|
||||
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:
|
||||
- **Platform mode** (default): managed Mem0 Cloud. Add your API key and you are ready.
|
||||
- **OSS mode**: fully self-hosted with your own LLM, embedder, and vector store. No data leaves your machine.
|
||||
|
||||
### 1. Before the Agent Responds (Prefetch)
|
||||
## How It Works
|
||||
|
||||
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.
|
||||
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 points in every conversation turn.
|
||||
|
||||
### 2. After the Agent Responds (Sync)
|
||||
### 1. Before the agent responds (prefetch)
|
||||
|
||||
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.
|
||||
When you send a message, Hermes checks for cached Mem0 search results from the previous turn. If they exist, those memories are injected into the system prompt so the model can see them. This is zero-latency, with no waiting on an API call.
|
||||
|
||||
### 3. Background Prefetch for Next Turn
|
||||
### 2. After the agent responds (sync)
|
||||
|
||||
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.
|
||||
Once the model finishes, Hermes sends the `(user message, assistant response)` pair to Mem0 in a background thread. Mem0 extracts facts automatically (for example, "user prefers Python" or "user works at Acme Corp"), so you never have to tell it what to remember. Each write is tagged with the gateway channel it came from.
|
||||
|
||||
### 3. Background prefetch for the next turn
|
||||
|
||||
At the same time, Hermes runs a background search to pre-load relevant memories for your next message. By the time you type, the results are already cached.
|
||||
|
||||
## Agent Tools
|
||||
|
||||
When Mem0 is active, the LLM gets three extra tools it can call during conversations:
|
||||
When Mem0 is active, the model gets five tools it can call during a conversation:
|
||||
|
||||
| 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 |
|
||||
| Tool | Description | Parameters |
|
||||
|------|-------------|------------|
|
||||
| `mem0_list` | List all stored memories, for a full overview | `page`, `page_size` (default 100, max 200) |
|
||||
| `mem0_search` | Semantic search by meaning, ranked by relevance | `query` (required), `top_k` (default 10, max 50), `rerank` (default `true`, Platform mode only) |
|
||||
| `mem0_add` | Store a fact verbatim, with no LLM extraction | `content` (required) |
|
||||
| `mem0_update` | Update a memory's text by ID | `memory_id`, `text` (both required) |
|
||||
| `mem0_delete` | Delete a memory by ID | `memory_id` (required) |
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -40,17 +47,19 @@ curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scri
|
||||
source ~/.bashrc
|
||||
```
|
||||
|
||||
The `mem0ai` Python package is automatically installed when you enable the Mem0 provider — no manual pip install needed.
|
||||
The `mem0ai` package is installed automatically when you enable the Mem0 provider, so there is no manual pip step. OSS providers may need extra packages (for example `qdrant-client`, `psycopg2-binary`, or `ollama`), which the setup flow installs for you when you pick them.
|
||||
|
||||
## Setup
|
||||
## Platform Setup
|
||||
|
||||
### Option 1: Interactive Setup Wizard (Recommended)
|
||||
Platform mode uses managed Mem0 Cloud and is the fastest way to start.
|
||||
|
||||
### Option 1: Interactive 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`.
|
||||
Select **mem0**, choose **Platform**, and paste your API key when prompted. The wizard writes the non-secret settings to `~/.hermes/mem0.json` and keeps the key in `~/.hermes/.env`.
|
||||
|
||||
<Note>Get your API key from <a href="https://app.mem0.ai?utm_source=oss&utm_medium=integration-hermes" rel="nofollow">app.mem0.ai</a>.</Note>
|
||||
|
||||
@@ -68,33 +77,151 @@ memory:
|
||||
provider: mem0
|
||||
```
|
||||
|
||||
That's it — Mem0 runs automatically from this point.
|
||||
That's it. Mem0 runs automatically from here.
|
||||
|
||||
## Configuration Options
|
||||
## OSS (Self-Hosted) Setup
|
||||
|
||||
Configuration is stored in `~/.hermes/mem0.json`. Values can also be set via environment variables.
|
||||
OSS mode runs Mem0 entirely on your own infrastructure: your LLM, your embedder, and your vector store. No data is sent to Mem0 Cloud, and no Mem0 API key is required.
|
||||
|
||||
| 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 |
|
||||
### Interactive
|
||||
|
||||
```bash
|
||||
hermes memory setup
|
||||
# Select "mem0", then "Open Source (self-hosted)"
|
||||
# Follow the prompts for LLM, embedder, and vector store
|
||||
```
|
||||
|
||||
### With flags
|
||||
|
||||
```bash
|
||||
hermes memory setup mem0 --mode oss \
|
||||
--oss-llm openai --oss-llm-key sk-... \
|
||||
--oss-vector qdrant
|
||||
```
|
||||
|
||||
### Supported providers
|
||||
|
||||
| Component | Providers |
|
||||
|-----------|-----------|
|
||||
| LLM | `openai` (default model `gpt-5-mini`), `ollama` (local, default `llama3.1:8b`) |
|
||||
| Embedder | `openai` (default `text-embedding-3-small`), `ollama` (local, default `nomic-embed-text`) |
|
||||
| Vector store | `qdrant` (local path or server), `pgvector` |
|
||||
|
||||
### Flag reference
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--mode` | `platform` or `oss` |
|
||||
| `--oss-llm` | LLM provider (`openai` or `ollama`, default `openai`) |
|
||||
| `--oss-llm-key` | LLM API key (for `openai`) |
|
||||
| `--oss-llm-model` | Override the LLM model |
|
||||
| `--oss-llm-url` | LLM base URL (for `ollama` or a custom endpoint) |
|
||||
| `--oss-embedder` | Embedder provider (default `openai`) |
|
||||
| `--oss-embedder-key` | Embedder API key |
|
||||
| `--oss-vector` | Vector store (`qdrant` or `pgvector`, default `qdrant`) |
|
||||
| `--oss-vector-path` | Local Qdrant storage path |
|
||||
| `--oss-vector-host`, `--oss-vector-port` | PGVector or remote Qdrant host and port |
|
||||
| `--oss-vector-user`, `--oss-vector-password`, `--oss-vector-dbname` | PGVector connection details |
|
||||
| `--user-id` | Canonical user identifier |
|
||||
| `--dry-run` | Preview the resolved config without writing it |
|
||||
|
||||
## Switching Modes
|
||||
|
||||
You can move between Platform and OSS at any time. Run the setup command again, or edit `~/.hermes/mem0.json` directly.
|
||||
|
||||
```bash
|
||||
# Platform to OSS
|
||||
hermes memory setup mem0 --mode oss --oss-llm-key sk-...
|
||||
|
||||
# OSS to Platform
|
||||
hermes memory setup mem0 --mode platform --api-key sk-...
|
||||
|
||||
# Preview without writing anything
|
||||
hermes memory setup mem0 --mode oss --oss-llm-key sk-... --dry-run
|
||||
```
|
||||
|
||||
A self-hosted `~/.hermes/mem0.json` looks like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"mode": "oss",
|
||||
"oss": {
|
||||
"llm": {"provider": "openai", "config": {"model": "gpt-5-mini"}},
|
||||
"embedder": {"provider": "openai", "config": {"model": "text-embedding-3-small"}},
|
||||
"vector_store": {"provider": "qdrant", "config": {"path": "~/.hermes/mem0_qdrant"}}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
Behavioral settings live in `~/.hermes/mem0.json` and are written for you by `hermes memory setup`. Only the secret `MEM0_API_KEY` belongs in `~/.hermes/.env`.
|
||||
|
||||
| Key | Default | Description |
|
||||
|-----|---------|-------------|
|
||||
| `mode` | `platform` | `platform` (Mem0 Cloud) or `oss` (self-hosted) |
|
||||
| `api_key` | none | Mem0 Platform API key, required in Platform mode. Stored in `.env` as `MEM0_API_KEY` |
|
||||
| `user_id` | `hermes-user` | Identifier that scopes memories. See cross-channel behavior below |
|
||||
| `agent_id` | `hermes` | Agent identifier attached to writes |
|
||||
| `rerank` | `true` | Rerank search results for relevance (Platform mode only) |
|
||||
|
||||
### Cross-channel memories
|
||||
|
||||
Hermes can run from the CLI and from gateways like Telegram, Slack, and Discord. The `user_id` setting controls how memories are scoped across them:
|
||||
|
||||
- **Set a `user_id`** and it applies to every gateway, so one person gets a single merged memory store no matter where they talk to the agent.
|
||||
- **Leave it unset** (or at the default `hermes-user`) and each gateway uses its own native id, keeping per-platform memories separate.
|
||||
|
||||
Either way, every write is tagged with `metadata.channel` (for example `telegram` or `cli`), so per-channel views are still possible at query time.
|
||||
|
||||
|
||||
## 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.
|
||||
- **Circuit breaker**: if Mem0 fails five times in a row, Hermes pauses calls for two minutes, then retries. The agent keeps working without memory during that window. Expected client errors, like a 404 on a missing memory id, do not count toward tripping the breaker.
|
||||
- **Non-blocking**: every Mem0 call runs in a background daemon thread, so a slow or failed call never blocks your conversation.
|
||||
- **Thread-safe**: the client uses lazy initialization with locking, and the background sync and prefetch threads are guarded so concurrent gateway messages cannot produce duplicate memories.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Mem0 temporarily unavailable"
|
||||
|
||||
The circuit breaker tripped after five consecutive failures and resets after two minutes.
|
||||
|
||||
- **Platform mode**: check your API key and internet connection.
|
||||
- **OSS mode**: make sure your vector store (Qdrant or PGVector) is running and reachable.
|
||||
|
||||
### OSS: vector store connection refused
|
||||
|
||||
```bash
|
||||
# Local Qdrant: confirm the storage path is writable
|
||||
ls -la ~/.hermes/mem0_qdrant
|
||||
|
||||
# Qdrant server: confirm it is reachable
|
||||
curl http://localhost:6333/healthz
|
||||
|
||||
# PGVector: confirm PostgreSQL is accepting connections
|
||||
pg_isready -h localhost -p 5432
|
||||
```
|
||||
|
||||
### OSS: Ollama not reachable
|
||||
|
||||
```bash
|
||||
curl http://localhost:11434/api/tags
|
||||
```
|
||||
|
||||
### Memories not appearing
|
||||
|
||||
- `mem0_add` stores text verbatim with no extraction. Ordinary conversation turns are extracted automatically by the background sync.
|
||||
- Search is semantic, so try a broader query.
|
||||
- Confirm `user_id` is the same across sessions (check `~/.hermes/mem0.json`).
|
||||
|
||||
## 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)
|
||||
1. **Two ways to run**: managed Platform or fully self-hosted OSS, switchable at any time.
|
||||
2. **Zero-latency recall**: memories are prefetched in the background and cached before you type.
|
||||
3. **Automatic extraction**: Mem0 extracts and deduplicates facts from each exchange for you.
|
||||
4. **Non-blocking and fault tolerant**: background threads plus a circuit breaker keep the agent responsive even when Mem0 is unreachable.
|
||||
5. **Additive memory**: works alongside Hermes' built-in file memory (`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">
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
---
|
||||
title: OpenCode
|
||||
description: "Add persistent memory to OpenCode with the Mem0 plugin — native SDK-backed memory tools, lifecycle hooks, and skills."
|
||||
---
|
||||
|
||||
Add persistent memory to [**OpenCode**](https://opencode.ai) with the Mem0 plugin. Your agent forgets everything between sessions — Mem0 fixes that by storing decisions, preferences, and learnings so they carry over automatically.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. A Mem0 API key (starts with `m0-`):
|
||||
- <a href="https://app.mem0.ai/dashboard/api-keys?utm_source=oss&utm_medium=integration-opencode" rel="nofollow">Get your API key</a> (free sign-up at <a href="https://app.mem0.ai?utm_source=oss&utm_medium=integration-opencode" rel="nofollow">app.mem0.ai</a>)
|
||||
|
||||
2. Add it to your shell profile so it persists across sessions:
|
||||
|
||||
<CodeGroup>
|
||||
```bash zsh
|
||||
echo 'export MEM0_API_KEY="m0-your-api-key"' >> ~/.zshrc && source ~/.zshrc
|
||||
```
|
||||
|
||||
```bash bash
|
||||
echo 'export MEM0_API_KEY="m0-your-api-key"' >> ~/.bashrc && source ~/.bashrc
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
## Installation
|
||||
|
||||
### Option A — Plugin Install (Recommended)
|
||||
|
||||
```bash
|
||||
opencode plugin @mem0/opencode-plugin
|
||||
```
|
||||
|
||||
**Or let your agent do it** — paste this into OpenCode:
|
||||
|
||||
```
|
||||
Install @mem0/opencode-plugin by following https://raw.githubusercontent.com/mem0ai/mem0/main/integrations/mem0-plugin/.opencode-plugin/README.md
|
||||
```
|
||||
|
||||
This adds the plugin to your `~/.config/opencode/opencode.json`. Restart OpenCode — you get the native memory tools, lifecycle hooks, and all `/mem0-*` slash commands. The memory tools are registered by the plugin itself via the `mem0ai` SDK — no MCP server to configure.
|
||||
|
||||
### Option B — Standalone MCP Server
|
||||
|
||||
If you only need the memory tools without the plugin's hooks or skills, point OpenCode at Mem0's hosted MCP server directly. Add this to your `opencode.json` (project-level or global at `~/.config/opencode/opencode.json`):
|
||||
|
||||
```json
|
||||
{
|
||||
"mcp": {
|
||||
"mem0": {
|
||||
"type": "remote",
|
||||
"url": "https://mcp.mem0.ai/mcp/",
|
||||
"headers": {
|
||||
"Authorization": "Token {env:MEM0_API_KEY}"
|
||||
},
|
||||
"oauth": false
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## What's Included
|
||||
|
||||
| Component | Plugin (A) | Standalone MCP (B) |
|
||||
|-----------|:----------:|:------------------:|
|
||||
| 9 memory tools | Native (SDK) | Remote MCP server |
|
||||
| Lifecycle Hooks | Yes | No |
|
||||
| 9 Skills | Yes | No |
|
||||
|
||||
## Available Memory Tools
|
||||
|
||||
| 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 scope
|
||||
|
||||
`search_memories`, `get_memories`, `add_memory`, and `delete_all_memories` accept an optional **`scope`** that controls how widely they read or write:
|
||||
|
||||
| Scope | Reads | Writes |
|
||||
|-------|-------|--------|
|
||||
| `project` *(default)* | this repo (`user_id` + `app_id`) | this repo |
|
||||
| `session` | this run only (`+ run_id`) | this run |
|
||||
| `global` | **all your projects in the workspace** (`app_id: "*"`) | user-wide |
|
||||
|
||||
Just ask naturally — e.g. *"search my memories across all my projects"* — and the agent passes `scope: "global"`. For normal questions it stays scoped to the current project automatically.
|
||||
|
||||
To change the **default** scope (used when no scope is passed), run the `/mem0-scope` skill:
|
||||
|
||||
```
|
||||
/mem0-scope # show the current default scope + identity
|
||||
/mem0-scope global # save & search across all your projects by default
|
||||
/mem0-scope project # back to repo-only (the default)
|
||||
```
|
||||
|
||||
The default persists in `~/.mem0/settings.json` (`default_scope`) and is read fresh on each memory operation, so a change applies immediately — no restart. `delete_all_memories` always requires an explicit `scope: "global"` to delete user-wide, so changing the default can't trigger a cross-project wipe.
|
||||
|
||||
The project id (`app_id`) is derived from your git remote (`owner-repo`), falling back to the git repo's root directory name, then the current directory. Launch OpenCode from inside your repo so memories scope to the project rather than your home directory.
|
||||
|
||||
## Lifecycle Hooks
|
||||
|
||||
The plugin uses the [mem0ai](https://www.npmjs.com/package/mem0ai) TypeScript SDK directly — pure TypeScript, no Python, no shell scripts.
|
||||
|
||||
| OpenCode Event | Hook | What happens |
|
||||
|----------------|------|-------------|
|
||||
| `config` | **Config** | Registers the `/mem0-*` slash commands (`config.command`) and adds the plugin's own `opencode-skills/` dir to OpenCode's `skills.paths` for in-place skill discovery (no copying) |
|
||||
| `chat.message` | **Chat message** | Searches prior memories on session start, searches relevant memories before each prompt, auto-captures learnings periodically |
|
||||
| `tool.execute.before` | **Pre-tool** | Blocks MEMORY.md writes, steering them to the `add_memory` tool |
|
||||
| `tool.execute.after` | **Post-tool** | Scans Bash errors and pre-fetches related error memories |
|
||||
| `experimental.chat.messages.transform` | **Messages transform** | Injects memory context (session memories, search results, error lookups) into the prompt |
|
||||
| `experimental.session.compacting` | **Compaction** | Stores session state memory, then injects prior memories into compaction context so nothing is lost |
|
||||
| `shell.env` | **Shell env** | Exports `MEM0_USER_ID`, `MEM0_APP_ID`, `MEM0_SESSION_ID`, and `MEM0_BRANCH` to all shell executions |
|
||||
|
||||
## Auto-dream (memory consolidation)
|
||||
|
||||
The plugin can automatically consolidate stored memories — merging duplicates, dropping stale/sensitive entries, and rewriting vague ones — so your memory set stays clean over time. It runs at most once per session, and only when **all** gates pass:
|
||||
|
||||
- **Time** — at least `minHours` (default 24) since the last consolidation
|
||||
- **Sessions** — at least `minSessions` (default 5) sessions since then
|
||||
- **Memories** — at least `minMemories` (default 20) stored for the project
|
||||
|
||||
A filesystem lock (`~/.mem0/mem0-dream.lock`) keeps two sessions from consolidating at once. Tune the thresholds with a `dream` block in `~/.mem0/settings.json`, or disable entirely with `MEM0_DREAM=false`:
|
||||
|
||||
```json
|
||||
{
|
||||
"dream": { "enabled": true, "auto": true, "minHours": 24, "minSessions": 5, "minMemories": 20 }
|
||||
}
|
||||
```
|
||||
|
||||
If auto-dream hasn't run yet, it's almost always because a gate hasn't been met (most often too few memories). Run `/mem0-status` to see the exact gate progress (e.g. `sessions 2/5, memories 3/20`), `/mem0-dream` to consolidate **now** regardless of the gates, or lower the thresholds above.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **No tools appearing** — Restart OpenCode after installing
|
||||
- **"Connection failed"** — Verify your key is set: `echo $MEM0_API_KEY`
|
||||
- **Plugin not loading** — Run `opencode plugin @mem0/opencode-plugin` again, then restart
|
||||
- **Hooks not firing** — Hooks require the plugin install (Option A). MCP-only installs don't include hooks.
|
||||
- **Auto-dream never runs** — It's gated (time + sessions + memories). Run `/mem0-status` to see which gate is blocking, or `/mem0-dream` to consolidate now.
|
||||
- **Wrong project name / memories not found** — The project id comes from your git remote; launch OpenCode from inside the repo (not your home directory). Check the resolved id with `/mem0-status`.
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Mem0 MCP Setup" icon="puzzle-piece" href="/platform/mem0-mcp">
|
||||
Detailed MCP configuration for all clients
|
||||
</Card>
|
||||
<Card title="Antigravity Integration" icon="google" href="/integrations/antigravity">
|
||||
Add Mem0 memory to Google Antigravity
|
||||
</Card>
|
||||
</CardGroup>
|
||||
@@ -0,0 +1,184 @@
|
||||
---
|
||||
title: Pi Agent
|
||||
description: "Add persistent memory to Pi Agent with the Mem0 plugin semantic search, auto-capture, and dream consolidation."
|
||||
---
|
||||
|
||||
Add persistent memory to [**Pi Agent**](https://pi.dev) with `@mem0/pi-agent-plugin`. Your agent forgets everything between sessions — this plugin fixes that by automatically capturing knowledge from conversations, storing it in Mem0's cloud memory layer, and retrieving relevant context before every response.
|
||||
|
||||
## Overview
|
||||
|
||||
The plugin provides:
|
||||
1. **Auto-capture** — Extracts durable facts from both user and assistant messages automatically
|
||||
2. **Semantic recall** — Retrieves relevant memories via the `mem0_memory` tool before each response
|
||||
3. **Dream consolidation** — Periodic maintenance: merges duplicates, resolves contradictions, prunes stale entries
|
||||
4. **Monorepo-aware scoping** — Uses git root for project detection, consistent across subdirectories
|
||||
5. **Confirmation dialogs** — Destructive commands ask before acting via Pi's built-in UI
|
||||
6. **8 skills + 8 commands** — Essential memory management from slash commands and agent-guided workflows
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. A Mem0 Platform account and API key:
|
||||
- <a href="https://app.mem0.ai?utm_source=oss&utm_medium=integration-pi-agent" rel="nofollow">Sign up at app.mem0.ai</a>
|
||||
- <a href="https://app.mem0.ai/dashboard/api-keys?utm_source=oss&utm_medium=integration-pi-agent" rel="nofollow">Get your API key</a> (starts with `m0-`)
|
||||
|
||||
2. Pi Agent installed ([pi.dev](https://pi.dev))
|
||||
|
||||
3. Your API key added to your shell profile:
|
||||
|
||||
<CodeGroup>
|
||||
```bash zsh
|
||||
echo 'export MEM0_API_KEY="m0-your-api-key"' >> ~/.zshrc
|
||||
source ~/.zshrc
|
||||
```
|
||||
|
||||
```bash bash
|
||||
echo 'export MEM0_API_KEY="m0-your-api-key"' >> ~/.bashrc
|
||||
source ~/.bashrc
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pi install npm:@mem0/pi-agent-plugin
|
||||
```
|
||||
|
||||
That's it. The extension loads automatically on every Pi session. No config files needed — `MEM0_API_KEY` from your environment is picked up automatically.
|
||||
|
||||
<Info>
|
||||
Start a new Pi session and run `/mem0-status` to verify the connection. You should see your user ID, detected project, and memory count.
|
||||
</Info>
|
||||
|
||||
### Optional Configuration
|
||||
|
||||
For advanced settings, create `~/.pi/agent/mem0-config.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"apiKey": "m0-your-key-here",
|
||||
"userId": "your-username",
|
||||
"autoCapture": true,
|
||||
"defaultScope": "project",
|
||||
"searchThreshold": 0.3,
|
||||
"dream": {
|
||||
"enabled": true,
|
||||
"auto": true,
|
||||
"minHours": 24,
|
||||
"minSessions": 5,
|
||||
"minMemories": 20
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| Key | Type | Default | Description |
|
||||
|-----|------|---------|-------------|
|
||||
| `apiKey` | `string` | `$MEM0_API_KEY` | Mem0 API key. Environment variable takes precedence. |
|
||||
| `userId` | `string` | `$MEM0_USER_ID` or `"default"` | User identity for memory scoping |
|
||||
| `autoCapture` | `boolean` | `true` | Store facts from conversations automatically |
|
||||
| `defaultScope` | `string` | `"project"` | Default memory scope: `project`, `session`, or `global` |
|
||||
| `searchThreshold` | `number` | `0.3` | Minimum similarity score (0–1) a memory must reach to count as a match for `/mem0-search`, `/mem0-forget`, and `/mem0-pin`, enforced on each result's relevance score. Raise it to be stricter; lower it if relevant results are missed. |
|
||||
| `dream.enabled` | `boolean` | `true` | Enable dream consolidation |
|
||||
| `dream.auto` | `boolean` | `true` | Auto-trigger dreams when thresholds are met |
|
||||
| `dream.minHours` | `number` | `24` | Minimum hours between auto-dreams |
|
||||
| `dream.minSessions` | `number` | `5` | Minimum sessions before first auto-dream |
|
||||
| `dream.minMemories` | `number` | `20` | Minimum memories before auto-dream triggers |
|
||||
|
||||
|
||||
## What's Included
|
||||
|
||||
| Component | Description |
|
||||
|-----------|-------------|
|
||||
| `mem0_memory` tool | Agent-callable tool for search, add, get_all, delete, delete_all |
|
||||
| 8 slash commands | Essential memory management from the command line |
|
||||
| 8 skills | Guide the agent on how to use each capability |
|
||||
| Auto-capture | Extracts and stores facts on every `agent_end` event |
|
||||
| System prompt | Appends memory policy to every agent turn |
|
||||
| Dream consolidation | Automated memory maintenance with session/time/count gates |
|
||||
|
||||
## Agent Tool
|
||||
|
||||
The `mem0_memory` tool is registered with Pi and callable by the agent during conversations:
|
||||
|
||||
| Action | Required Params | Description |
|
||||
|--------|----------------|-------------|
|
||||
| `search` | `query` | Semantic search across memories |
|
||||
| `add` | `content` | Store a new memory |
|
||||
| `get_all` | — | List all memories in scope |
|
||||
| `delete` | `memory_id` | Delete a specific memory |
|
||||
| `delete_all` | — | Delete all memories in scope |
|
||||
|
||||
All actions accept an optional `scope` parameter: `project` (default), `session`, or `global`.
|
||||
|
||||
Tool output is truncated to 200 lines / 50KB to prevent context overflow.
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `/mem0-remember <text>` | Store a memory verbatim (no inference) |
|
||||
| `/mem0-forget <query>` | Search and delete memories (with confirmation dialog) |
|
||||
| `/mem0-search <query>` | Semantic search across memories |
|
||||
| `/mem0-tour [scope]` | Browse all memories grouped by category |
|
||||
| `/mem0-dream` | Consolidate — merge duplicates, prune stale, resolve contradictions |
|
||||
| `/mem0-pin <query>` | Pin a memory to protect from dream pruning (preserves memory ID) |
|
||||
| `/mem0-scope <scope>` | Change default scope for this session (project, session, global) |
|
||||
| `/mem0-status` | Connection health, identity, and memory count |
|
||||
|
||||
## Memory Scopes
|
||||
|
||||
Memories are scoped using Mem0's `user_id`, `app_id`, and `run_id` parameters:
|
||||
|
||||
| Scope | Filters | Use Case |
|
||||
|-------|---------|----------|
|
||||
| `project` | user_id + app_id (git root) | **Default.** Project-specific knowledge — decisions, architecture, config |
|
||||
| `session` | user_id + app_id + run_id | Ephemeral context for the current session only |
|
||||
| `global` | user_id only | All memories across all your projects |
|
||||
|
||||
The `app_id` is auto-detected from the git repository root (`git rev-parse --show-toplevel`), so all subdirectories within a monorepo share the same memory pool. Falls back to the working directory name for non-git directories. The `run_id` is derived from Pi's session file path.
|
||||
|
||||
## Dream Consolidation
|
||||
|
||||
### Confirmation Dialogs
|
||||
|
||||
Destructive and mutating commands use Pi's built-in `ctx.ui.confirm()` dialog before acting:
|
||||
|
||||
- `/mem0-forget` asks "Delete this memory?" before deleting a single match
|
||||
- `/mem0-pin` asks "Pin this memory?" before modifying it
|
||||
- Cancelling either operation is always safe — no changes are made
|
||||
|
||||
### Pin
|
||||
|
||||
`/mem0-pin` uses Mem0's `update()` API to prepend `[PINNED]` to the memory text. This preserves the original memory ID — no add+delete cycle that would lose history or change the UUID.
|
||||
|
||||
### Dream Consolidation
|
||||
|
||||
The plugin includes automated memory maintenance ("dream") that merges duplicates, resolves contradictions, and prunes stale entries. When enabled, dreams auto-trigger after enough sessions, time, and memories accumulate (configurable via `dream.*` settings). Run `/mem0-dream` to trigger consolidation manually at any time. Pinned memories (via `/mem0-pin`) are protected from pruning.
|
||||
|
||||
## Example Workflow
|
||||
|
||||
```text
|
||||
# Session 1
|
||||
You: I prefer dark mode and concise answers.
|
||||
# Mem0 auto-captures preferences
|
||||
|
||||
# Session 2 (days later)
|
||||
You: What do you know about my preferences?
|
||||
# Pi retrieves stored memories — no re-explaining needed
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **"No API key found"** — Verify `MEM0_API_KEY` is set: `echo $MEM0_API_KEY`. If empty, add it to your shell profile (see Prerequisites)
|
||||
- **Extension not loading** — Check Pi startup output for errors. Run `pi -e ./src/entry.ts` from the plugin directory for verbose output
|
||||
- **Memories not capturing** — Verify `autoCapture` is `true` (default). Check `/mem0-status` for connection health
|
||||
- **Wrong project detected** — The plugin uses the git repository root as `app_id`. If not in a git repo, it falls back to the working directory name. Run `/mem0-status` to see the detected project
|
||||
- **Dream not triggering** — All three gates must pass (time, sessions, memories). Use `/mem0-dream` to force it manually
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Claude Code Integration" icon="terminal" href="/integrations/claude-code">
|
||||
Add Mem0 memory to Claude Code
|
||||
</Card>
|
||||
<Card title="OpenClaw Integration" icon="plug" href="/integrations/openclaw">
|
||||
Add Mem0 memory to OpenClaw agents
|
||||
</Card>
|
||||
</CardGroup>
|
||||
@@ -1,22 +1,22 @@
|
||||
---
|
||||
title: Keywords AI
|
||||
description: "Combine Mem0 persistent memory with Keywords AI observability for tracked, cost-optimized AI applications."
|
||||
title: Respan
|
||||
description: "Combine Mem0 persistent memory with Respan observability for tracked, cost-optimized AI applications."
|
||||
---
|
||||
|
||||
Build AI applications with persistent memory and comprehensive LLM observability by integrating Mem0 with Keywords AI.
|
||||
Build AI applications with persistent memory and comprehensive LLM observability by integrating Mem0 with Respan.
|
||||
|
||||
## Overview
|
||||
|
||||
Mem0 is a self-improving memory layer for LLM applications, enabling personalized AI experiences that save costs and delight users. Keywords AI provides complete LLM observability.
|
||||
Mem0 is a self-improving memory layer for LLM applications, enabling personalized AI experiences that save costs and delight users. Respan (formerly Keywords AI) provides complete LLM observability.
|
||||
|
||||
Combining Mem0 with Keywords AI allows you to:
|
||||
Combining Mem0 with Respan allows you to:
|
||||
1. Add persistent memory to your AI applications
|
||||
2. Track interactions across sessions
|
||||
3. Monitor memory usage and retrieval with Keywords AI observability
|
||||
3. Monitor memory usage and retrieval with Respan observability
|
||||
4. Optimize token usage and reduce costs
|
||||
|
||||
<Note>
|
||||
You can get your Mem0 API key from the <a href="https://app.mem0.ai/?utm_source=oss&utm_medium=integration-keywords" rel="nofollow">Mem0 dashboard</a>.
|
||||
You can get your Mem0 API key from the <a href="https://app.mem0.ai/?utm_source=oss&utm_medium=integration-respan" rel="nofollow">Mem0 dashboard</a>.
|
||||
</Note>
|
||||
|
||||
## Setup and Configuration
|
||||
@@ -24,7 +24,7 @@ You can get your Mem0 API key from the <a href="https://app.mem0.ai/?utm_source=
|
||||
Install the necessary libraries:
|
||||
|
||||
```bash
|
||||
pip install mem0ai keywordsai-sdk
|
||||
pip install mem0ai openai
|
||||
```
|
||||
|
||||
Set up your environment variables:
|
||||
@@ -34,13 +34,13 @@ import os
|
||||
|
||||
# Set your API keys
|
||||
os.environ["MEM0_API_KEY"] = "your-mem0-api-key"
|
||||
os.environ["KEYWORDSAI_API_KEY"] = "your-keywords-api-key"
|
||||
os.environ["KEYWORDSAI_BASE_URL"] = "https://api.keywordsai.co/api/"
|
||||
os.environ["RESPAN_API_KEY"] = "your-respan-api-key"
|
||||
os.environ["RESPAN_BASE_URL"] = "https://api.respan.ai/api/"
|
||||
```
|
||||
|
||||
## Basic Integration Example
|
||||
|
||||
Here's a simple example of using Mem0 with Keywords AI:
|
||||
Here's a simple example of using Mem0 with Respan:
|
||||
|
||||
```python
|
||||
from mem0 import Memory
|
||||
@@ -48,17 +48,17 @@ import os
|
||||
|
||||
# Configuration
|
||||
api_key = os.getenv("MEM0_API_KEY")
|
||||
keywordsai_api_key = os.getenv("KEYWORDSAI_API_KEY")
|
||||
base_url = os.getenv("KEYWORDSAI_BASE_URL") # "https://api.keywordsai.co/api/"
|
||||
respan_api_key = os.getenv("RESPAN_API_KEY")
|
||||
base_url = os.getenv("RESPAN_BASE_URL") # "https://api.respan.ai/api/"
|
||||
|
||||
# Set up Mem0 with Keywords AI as the LLM provider
|
||||
# Set up Mem0 with Respan as the LLM provider
|
||||
config = {
|
||||
"llm": {
|
||||
"provider": "openai",
|
||||
"config": {
|
||||
"model": "gpt-5-mini",
|
||||
"temperature": 0.0,
|
||||
"api_key": keywordsai_api_key,
|
||||
"api_key": respan_api_key,
|
||||
"openai_base_url": base_url,
|
||||
},
|
||||
}
|
||||
@@ -79,7 +79,7 @@ print(result)
|
||||
|
||||
## Advanced Integration with OpenAI SDK
|
||||
|
||||
For more advanced use cases, you can integrate Keywords AI with Mem0 through the OpenAI SDK:
|
||||
For more advanced use cases, you can integrate Respan with Mem0 through the OpenAI SDK:
|
||||
|
||||
```python
|
||||
from openai import OpenAI
|
||||
@@ -88,8 +88,8 @@ import json
|
||||
|
||||
# Initialize client
|
||||
client = OpenAI(
|
||||
api_key=os.environ.get("KEYWORDSAI_API_KEY"),
|
||||
base_url=os.environ.get("KEYWORDSAI_BASE_URL"),
|
||||
api_key=os.environ.get("RESPAN_API_KEY"),
|
||||
base_url=os.environ.get("RESPAN_BASE_URL"),
|
||||
)
|
||||
|
||||
# Sample conversation messages
|
||||
@@ -118,18 +118,18 @@ response = client.chat.completions.create(
|
||||
print(json.dumps(response.model_dump(), indent=4))
|
||||
```
|
||||
|
||||
For detailed information on this integration, refer to the official [Keywords AI Mem0 integration documentation](https://docs.keywordsai.co/integration/development-frameworks/mem0).
|
||||
For detailed information on this integration, refer to the official [Respan Mem0 integration documentation](https://www.respan.ai/docs/integrations/mem0).
|
||||
|
||||
## Key Features
|
||||
|
||||
1. **Memory Integration**: Store and retrieve relevant information from past interactions
|
||||
2. **LLM Observability**: Track memory usage and retrieval patterns with Keywords AI
|
||||
2. **LLM Observability**: Track memory usage and retrieval patterns with Respan
|
||||
3. **Session Persistence**: Maintain context across multiple user sessions
|
||||
4. **Cost Optimization**: Reduce token usage through efficient memory retrieval
|
||||
|
||||
## Conclusion
|
||||
|
||||
Integrating Mem0 with Keywords AI provides a powerful combination for building AI applications with persistent memory and comprehensive observability. This integration enables more personalized user experiences while providing insights into your application's memory usage.
|
||||
Integrating Mem0 with Respan provides a powerful combination for building AI applications with persistent memory and comprehensive observability. This integration enables more personalized user experiences while providing insights into your application's memory usage.
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="OpenAI Agents SDK" icon="cube" href="/integrations/openai-agents-sdk">
|
||||
@@ -139,4 +139,3 @@ Integrating Mem0 with Keywords AI provides a powerful combination for building A
|
||||
Monitor agent performance with AgentOps
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
+151
-116
@@ -6,25 +6,33 @@ description: "Use the Mem0 AI SDK Provider with Vercel AI SDK for persistent mem
|
||||
The [**Mem0 AI SDK Provider**](https://www.npmjs.com/package/@mem0/vercel-ai-provider) is a library developed by **Mem0** to integrate with the Vercel AI SDK. This library brings enhanced AI interaction capabilities to your applications by introducing persistent memory functionality.
|
||||
|
||||
<Note type="info">
|
||||
Mem0 AI SDK now supports <strong>Vercel AI SDK V5</strong>.
|
||||
Mem0 AI SDK Provider v3.0.0 supports <strong>Vercel AI SDK v6</strong> (<code>LanguageModelV3</code> / <code>ProviderV3</code>). If you are upgrading from v2.x, see the <a href="https://ai-sdk.dev/docs/migration-guides/migration-guide-6-0">AI SDK v6 migration guide</a>.
|
||||
</Note>
|
||||
|
||||
## Overview
|
||||
|
||||
1. Offers persistent memory storage for conversational AI
|
||||
2. Enables smooth integration with the Vercel AI SDK
|
||||
3. Ensures compatibility with multiple LLM providers
|
||||
2. Enables smooth integration with the Vercel AI SDK v6
|
||||
3. Ensures compatibility with multiple LLM providers (OpenAI, Anthropic, Google, Groq, Cohere)
|
||||
4. Supports structured message formats for clarity
|
||||
5. Facilitates streaming response capabilities
|
||||
6. Attaches Mem0 memories as sources in responses for programmatic access
|
||||
|
||||
## Setup and Configuration
|
||||
|
||||
Install the SDK provider using npm:
|
||||
Install the SDK provider and AI SDK:
|
||||
|
||||
```bash
|
||||
npm install @mem0/vercel-ai-provider
|
||||
npm install @mem0/vercel-ai-provider ai@^6
|
||||
```
|
||||
|
||||
### Peer Dependencies
|
||||
|
||||
`@mem0/vercel-ai-provider` v3.0.0 requires:
|
||||
- `ai` v6+ (`^6.0.199`)
|
||||
- `@ai-sdk/provider` v3+ (`^3.0.10`)
|
||||
- Provider packages at v3+: `@ai-sdk/openai@^3`, `@ai-sdk/anthropic@^3`, `@ai-sdk/google@^3`, `@ai-sdk/groq@^3`, `@ai-sdk/cohere@^3`
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Setting Up Mem0
|
||||
@@ -41,7 +49,7 @@ npm install @mem0/vercel-ai-provider
|
||||
mem0ApiKey: "m0-xxx",
|
||||
apiKey: "provider-api-key",
|
||||
config: {
|
||||
// Options for LLM Provider
|
||||
// Options for the upstream LLM provider (e.g. baseURL)
|
||||
},
|
||||
// Optional Mem0 Global Config
|
||||
mem0Config: {
|
||||
@@ -57,154 +65,153 @@ npm install @mem0/vercel-ai-provider
|
||||
3. Add Memories to Enhance Context:
|
||||
|
||||
```typescript
|
||||
import { LanguageModelV2Prompt } from "@ai-sdk/provider";
|
||||
import { addMemories } from "@mem0/vercel-ai-provider";
|
||||
|
||||
const messages: LanguageModelV2Prompt = [
|
||||
const messages = [
|
||||
{ role: "user", content: [{ type: "text", text: "I love red cars." }] },
|
||||
];
|
||||
|
||||
await addMemories(messages, { user_id: "borat" });
|
||||
```
|
||||
|
||||
### Standalone Features:
|
||||
### Standalone Features
|
||||
|
||||
```typescript
|
||||
await addMemories(messages, { user_id: "borat", mem0ApiKey: "m0-xxx" });
|
||||
await retrieveMemories(prompt, { user_id: "borat", mem0ApiKey: "m0-xxx" });
|
||||
await getMemories(prompt, { user_id: "borat", mem0ApiKey: "m0-xxx" });
|
||||
```
|
||||
> For standalone features, such as `addMemories`, `retrieveMemories`, and `getMemories`, you must either set `MEM0_API_KEY` as an environment variable or pass it directly in the function call.
|
||||
```typescript
|
||||
await addMemories(messages, { user_id: "borat", mem0ApiKey: "m0-xxx" });
|
||||
await retrieveMemories(prompt, { user_id: "borat", mem0ApiKey: "m0-xxx" });
|
||||
await getMemories(prompt, { user_id: "borat", mem0ApiKey: "m0-xxx" });
|
||||
```
|
||||
|
||||
> `getMemories` will return raw memories in the form of an array of objects, while `retrieveMemories` will return a response in string format with a system prompt ingested with the retrieved memories.
|
||||
> For standalone features, such as `addMemories`, `retrieveMemories`, and `getMemories`, you must either set `MEM0_API_KEY` as an environment variable or pass it directly in the function call.
|
||||
|
||||
> `getMemories` returns an array of memory objects.
|
||||
> `getMemories` will return raw memories in the form of an array of objects, while `retrieveMemories` will return a response in string format with a system prompt ingested with the retrieved memories.
|
||||
|
||||
### 1. Basic Text Generation with Memory Context
|
||||
|
||||
```typescript
|
||||
import { generateText } from "ai";
|
||||
import { createMem0 } from "@mem0/vercel-ai-provider";
|
||||
```typescript
|
||||
import { generateText } from "ai";
|
||||
import { createMem0 } from "@mem0/vercel-ai-provider";
|
||||
|
||||
const mem0 = createMem0();
|
||||
const mem0 = createMem0();
|
||||
|
||||
const { text } = await generateText({
|
||||
model: mem0("gpt-4-turbo", { user_id: "borat" }),
|
||||
prompt: "Suggest me a good car to buy!",
|
||||
});
|
||||
```
|
||||
const { text } = await generateText({
|
||||
model: mem0("gpt-5-mini", { user_id: "borat" }),
|
||||
prompt: "Suggest me a good car to buy!",
|
||||
});
|
||||
```
|
||||
|
||||
### 2. Combining OpenAI Provider with Memory Utils
|
||||
|
||||
```typescript
|
||||
import { generateText } from "ai";
|
||||
import { openai } from "@ai-sdk/openai";
|
||||
import { retrieveMemories } from "@mem0/vercel-ai-provider";
|
||||
```typescript
|
||||
import { generateText } from "ai";
|
||||
import { openai } from "@ai-sdk/openai";
|
||||
import { retrieveMemories } from "@mem0/vercel-ai-provider";
|
||||
|
||||
const prompt = "Suggest me a good car to buy.";
|
||||
const memories = await retrieveMemories(prompt, { user_id: "borat" });
|
||||
const prompt = "Suggest me a good car to buy.";
|
||||
const memories = await retrieveMemories(prompt, { user_id: "borat" });
|
||||
|
||||
const { text } = await generateText({
|
||||
model: openai("gpt-4-turbo"),
|
||||
prompt: prompt,
|
||||
system: memories,
|
||||
});
|
||||
```
|
||||
const { text } = await generateText({
|
||||
model: openai("gpt-5-mini"),
|
||||
prompt: prompt,
|
||||
system: memories,
|
||||
});
|
||||
```
|
||||
|
||||
### 3. Structured Message Format with Memory
|
||||
|
||||
```typescript
|
||||
import { generateText } from "ai";
|
||||
import { createMem0 } from "@mem0/vercel-ai-provider";
|
||||
```typescript
|
||||
import { generateText } from "ai";
|
||||
import { createMem0 } from "@mem0/vercel-ai-provider";
|
||||
|
||||
const mem0 = createMem0();
|
||||
const mem0 = createMem0();
|
||||
|
||||
const { text } = await generateText({
|
||||
model: mem0("gpt-4-turbo", { user_id: "borat" }),
|
||||
messages: [
|
||||
{
|
||||
role: "user",
|
||||
content: [
|
||||
{ type: "text", text: "Suggest me a good car to buy." },
|
||||
{ type: "text", text: "Why is it better than the other cars for me?" },
|
||||
],
|
||||
},
|
||||
const { text } = await generateText({
|
||||
model: mem0("gpt-5-mini", { user_id: "borat" }),
|
||||
messages: [
|
||||
{
|
||||
role: "user",
|
||||
content: [
|
||||
{ type: "text", text: "Suggest me a good car to buy." },
|
||||
{ type: "text", text: "Why is it better than the other cars for me?" },
|
||||
],
|
||||
});
|
||||
```
|
||||
},
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
### 3. Streaming Responses with Memory Context
|
||||
### 4. Streaming Responses with Memory Context
|
||||
|
||||
```typescript
|
||||
import { streamText } from "ai";
|
||||
import { createMem0 } from "@mem0/vercel-ai-provider";
|
||||
```typescript
|
||||
import { streamText } from "ai";
|
||||
import { createMem0 } from "@mem0/vercel-ai-provider";
|
||||
|
||||
const mem0 = createMem0();
|
||||
const mem0 = createMem0();
|
||||
|
||||
const { textStream } = streamText({
|
||||
model: mem0("gpt-4-turbo", {
|
||||
user_id: "borat",
|
||||
}),
|
||||
prompt: "Suggest me a good car to buy! Why is it better than the other cars for me? Give options for every price range.",
|
||||
});
|
||||
const { textStream } = streamText({
|
||||
model: mem0("gpt-5-mini", {
|
||||
user_id: "borat",
|
||||
}),
|
||||
prompt: "Suggest me a good car to buy! Why is it better than the other cars for me? Give options for every price range.",
|
||||
});
|
||||
|
||||
for await (const textPart of textStream) {
|
||||
process.stdout.write(textPart);
|
||||
}
|
||||
```
|
||||
for await (const textPart of textStream) {
|
||||
process.stdout.write(textPart);
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Generate Responses with Tools Call
|
||||
### 5. Generate Responses with Tools Call
|
||||
|
||||
```typescript
|
||||
import { generateText } from "ai";
|
||||
import { createMem0 } from "@mem0/vercel-ai-provider";
|
||||
import { z } from "zod";
|
||||
```typescript
|
||||
import { generateText, tool } from "ai";
|
||||
import { createMem0 } from "@mem0/vercel-ai-provider";
|
||||
import { z } from "zod";
|
||||
|
||||
const mem0 = createMem0({
|
||||
provider: "anthropic",
|
||||
apiKey: "anthropic-api-key",
|
||||
mem0Config: {
|
||||
// Global User ID
|
||||
user_id: "borat"
|
||||
}
|
||||
});
|
||||
const mem0 = createMem0({
|
||||
provider: "anthropic",
|
||||
apiKey: "anthropic-api-key",
|
||||
mem0Config: {
|
||||
user_id: "borat"
|
||||
}
|
||||
});
|
||||
|
||||
const prompt = "What the temperature in the city that I live in?"
|
||||
const result = await generateText({
|
||||
model: mem0('claude-sonnet-4-20250514'),
|
||||
tools: {
|
||||
weather: tool({
|
||||
description: 'Get the weather in a location',
|
||||
parameters: z.object({
|
||||
location: z.string().describe('The location to get the weather for'),
|
||||
}),
|
||||
execute: async ({ location }) => ({
|
||||
location,
|
||||
temperature: 72 + Math.floor(Math.random() * 21) - 10,
|
||||
}),
|
||||
}),
|
||||
},
|
||||
prompt: "What the temperature in the city that I live in?",
|
||||
});
|
||||
|
||||
const result = await generateText({
|
||||
model: mem0('claude-3-5-sonnet-20240620'),
|
||||
tools: {
|
||||
weather: tool({
|
||||
description: 'Get the weather in a location',
|
||||
parameters: z.object({
|
||||
location: z.string().describe('The location to get the weather for'),
|
||||
}),
|
||||
execute: async ({ location }) => ({
|
||||
location,
|
||||
temperature: 72 + Math.floor(Math.random() * 21) - 10,
|
||||
}),
|
||||
}),
|
||||
},
|
||||
prompt: prompt,
|
||||
});
|
||||
console.log(result);
|
||||
```
|
||||
|
||||
console.log(result);
|
||||
```
|
||||
### 6. Get Sources from Memory
|
||||
|
||||
### 5. Get sources from memory
|
||||
`generateText` and `streamText` responses include Mem0 memories as a source, giving you programmatic access to the memories that influenced the response:
|
||||
|
||||
```typescript
|
||||
const { text, sources } = await generateText({
|
||||
model: mem0("gpt-4-turbo"),
|
||||
prompt: "Suggest me a good car to buy!",
|
||||
model: mem0("gpt-5-mini", { user_id: "borat" }),
|
||||
prompt: "Suggest me a good car to buy!",
|
||||
});
|
||||
|
||||
// sources[0].title === "Mem0 Memories"
|
||||
// sources[0].providerMetadata.mem0.memories — array of memory objects
|
||||
console.log(sources);
|
||||
```
|
||||
|
||||
The same can be done for `streamText` as well.
|
||||
|
||||
### 6. File Support with Memory Context
|
||||
### 7. File Support with Memory Context
|
||||
|
||||
Mem0 AI SDK supports file processing with memory context. Here's an example of analyzing a PDF file:
|
||||
|
||||
@@ -226,15 +233,11 @@ const mem0 = createMem0({
|
||||
});
|
||||
|
||||
async function main() {
|
||||
// Read the PDF file
|
||||
const filePath = join(process.cwd(), 'my_pdf.pdf');
|
||||
const fileBuffer = readFileSync(filePath);
|
||||
|
||||
// Convert the file's arrayBuffer to a Base64 data URL
|
||||
const arrayBuffer = fileBuffer.buffer.slice(fileBuffer.byteOffset, fileBuffer.byteOffset + fileBuffer.byteLength);
|
||||
const uint8Array = new Uint8Array(arrayBuffer);
|
||||
|
||||
// Convert Uint8Array to an array of characters
|
||||
const charArray = Array.from(uint8Array, byte => String.fromCharCode(byte));
|
||||
const binaryString = charArray.join('');
|
||||
const base64Data = Buffer.from(binaryString, 'binary').toString('base64');
|
||||
@@ -274,24 +277,56 @@ main();
|
||||
|
||||
| Provider | Configuration Value |
|
||||
|----------|-------------------|
|
||||
| OpenAI | openai |
|
||||
| Anthropic | anthropic |
|
||||
| Google | google |
|
||||
| Groq | groq |
|
||||
| OpenAI | `openai` |
|
||||
| Anthropic | `anthropic` |
|
||||
| Google / Gemini | `google` or `gemini` |
|
||||
| Groq | `groq` |
|
||||
| Cohere | `cohere` |
|
||||
|
||||
> **Note**: You can use `google` as provider for Gemini (Google) models. They are same and internally they use `@ai-sdk/google` package.
|
||||
> **Note**: You can use either `google` or `gemini` as the provider value for Google Gemini models. Both map to the `@ai-sdk/google` package internally.
|
||||
|
||||
## Configuration Options
|
||||
|
||||
### Mem0ConfigSettings
|
||||
|
||||
These options can be passed per-request when creating a model instance:
|
||||
|
||||
| Option | Type | Description |
|
||||
|--------|------|-------------|
|
||||
| `user_id` | `string` | User identifier for memory scoping |
|
||||
| `agent_id` | `string` | Agent identifier |
|
||||
| `app_id` | `string` | Application identifier |
|
||||
| `run_id` | `string` | Run/session identifier |
|
||||
| `metadata` | `object` | Custom metadata for memories |
|
||||
| `filters` | `object` | Filters for memory search |
|
||||
| `infer` | `boolean` | Enable inference-based retrieval |
|
||||
| `top_k` | `number` | Number of memories to retrieve (default: 10) |
|
||||
| `threshold` | `number` | Relevance threshold for search |
|
||||
| `rerank` | `boolean` | Enable reranking of results |
|
||||
| `page` | `number` | Page number for pagination |
|
||||
| `page_size` | `number` | Results per page |
|
||||
|
||||
## Key Features
|
||||
|
||||
- `createMem0()`: Initializes a new Mem0 provider instance.
|
||||
- `retrieveMemories()`: Retrieves memory context for prompts.
|
||||
- `createMem0()`: Initializes a new Mem0 provider instance implementing `ProviderV3`.
|
||||
- `retrieveMemories()`: Retrieves memory context for prompts as a formatted system prompt string.
|
||||
- `getMemories()`: Get memories from your profile in array format.
|
||||
- `addMemories()`: Adds user memories to enhance contextual responses.
|
||||
|
||||
## Migrating from v2.x
|
||||
|
||||
If you're upgrading from `@mem0/vercel-ai-provider` v2.x:
|
||||
|
||||
1. **Upgrade AI SDK**: `npm install ai@^6` and update all `@ai-sdk/*` provider packages to `^3.x`
|
||||
2. **Remove deprecated params**: Remove `org_id`, `project_id`, `output_format`, `filter_memories`, `async_mode`, `enable_graph` from your config
|
||||
3. **Remove graph memory**: All graph-related options (`enable_graph`, graph prompts) have been removed. Graph memory is now a project-level setting on the Mem0 Platform
|
||||
4. **Update imports**: `LanguageModelV2Prompt` is now `LanguageModelV3Prompt` if you import types directly
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **User Identification**: Use a unique `user_id` for consistent memory retrieval.
|
||||
2. **Memory Cleanup**: Regularly clean up unused memory data.
|
||||
3. **Sources**: Access `result.sources` to inspect which memories influenced the response.
|
||||
|
||||
> **Note**: We also have support for `agent_id`, `app_id`, and `run_id`. Refer [Docs](/api-reference/memory/add-memories).
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ mode: "custom"
|
||||
</h1>
|
||||
|
||||
<p className="max-w-2xl mx-auto text-base text-gray-600 dark:text-zinc-400 leading-relaxed">
|
||||
Universal, Self-improving memory layer for LLM applications.
|
||||
Universal, self-improving memory layer for LLM applications.
|
||||
</p>
|
||||
|
||||
<a
|
||||
@@ -157,27 +157,27 @@ mode: "custom"
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="/platform/cli"
|
||||
href="/platform/agent-signup"
|
||||
className="group flex h-full flex-col overflow-hidden rounded-2xl border border-gray-200 dark:border-zinc-800/40 bg-white dark:bg-zinc-900/40 transition hover:border-primary/60 hover:bg-gray-50 dark:hover:bg-zinc-900"
|
||||
>
|
||||
<img
|
||||
className="block dark:hidden aspect-[2/1] w-full object-cover"
|
||||
src="/images/docs thumbnails/light/CLI.png"
|
||||
alt="CLI thumbnail"
|
||||
alt="Sign up as an agent thumbnail"
|
||||
style={{pointerEvents: "none"}}
|
||||
/>
|
||||
<img
|
||||
className="hidden dark:block aspect-[2/1] w-full object-cover"
|
||||
src="/images/docs thumbnails/dark/CLI.png"
|
||||
alt="CLI thumbnail"
|
||||
alt="Sign up as an agent thumbnail"
|
||||
style={{pointerEvents: "none"}}
|
||||
/>
|
||||
<div className="flex flex-1 flex-col gap-2 px-4 pb-4 pt-3 text-left">
|
||||
<h3 className="text-base font-semibold text-gray-900 dark:text-zinc-100 group-hover:text-primary">
|
||||
CLI
|
||||
Sign up as an agent
|
||||
</h3>
|
||||
<p className="text-sm text-gray-600 dark:text-zinc-400">
|
||||
Manage memories directly from your terminal. Built for developers and AI agents.
|
||||
For AI agents: mint a Mem0 API key in under five seconds — no email, no dashboard. Four commands to your first memory.
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
+30
-9
@@ -4,6 +4,24 @@
|
||||
|
||||
## For agents reading this file
|
||||
|
||||
### Don't have a Mem0 API key?
|
||||
|
||||
Install the CLI, then mint a key — no email, no dashboard, no OTP required:
|
||||
|
||||
```bash
|
||||
# Python
|
||||
pip install mem0-cli
|
||||
|
||||
# or Node
|
||||
npm install -g @mem0/cli
|
||||
```
|
||||
|
||||
Then run: `mem0 init --agent --agent-caller <your-name> --json` — replace `<your-name>` with the AI agent you are (e.g. `claude-code`, `cursor`, `codex`). If you forgot to pass `--agent-caller`, run `mem0 identify <your-name>` after init to attribute the signup.
|
||||
|
||||
This mints an evaluation key in <5 seconds. Use it immediately against the Platform API or MCP server. When the human is ready, claim with `mem0 init --email <your-email>` to transfer ownership (memories preserved, same API key, no agent disruption).
|
||||
|
||||
### Routing and references
|
||||
|
||||
- Use `MemoryClient` (Python) / `mem0ai` (npm) when the user has a Mem0 Platform API key. Docs under `/platform/` and `/api-reference/` apply; the managed product handles providers server-side, so you can ignore `## Optional` below.
|
||||
- Use `Memory` (Python) / `mem0ai/oss` (npm) when the user self-hosts. Docs under `/open-source/` and `/components/` apply; Platform-only features (entity filters v2, custom categories, webhooks, advanced retrieval) may not be available.
|
||||
- Scope tag reference: `[Platform]` = managed only, `[OSS]` = self-hosted only, `[Both]` = same API surface on both.
|
||||
@@ -11,12 +29,6 @@
|
||||
- Live MCP server: https://mcp.mem0.ai (see `platform/mem0-mcp`).
|
||||
- Source repo: https://github.com/mem0ai/mem0
|
||||
|
||||
### Don't have a Mem0 API key?
|
||||
|
||||
Run: `mem0 init --agent --agent-caller <your-name> --json` — replace `<your-name>` with the AI agent you are (e.g. `claude-code`, `cursor`, `codex`). If you forgot to pass `--agent-caller`, run `mem0 identify <your-name>` after init to attribute the signup.
|
||||
|
||||
This mints an evaluation key in <5 seconds — no email, no dashboard, no OTP required. Use it immediately against the Platform API or MCP server. When the human is ready, claim with `mem0 init --email <your-email>` to transfer ownership (memories preserved, same API key, no agent disruption).
|
||||
|
||||
## Install
|
||||
|
||||
- Python SDK: `pip install mem0ai`
|
||||
@@ -159,6 +171,7 @@ If the user is on a pre-current major (Python < 2, TS < 3, or Platform `output_f
|
||||
- [Introduction](https://docs.mem0.ai/introduction) [Both]: Use when the user wants a one-page overview of how memory fits between the LLM and the app.
|
||||
- [Vibe Code with Mem0](https://docs.mem0.ai/vibecoding) [Both]: Use when the user is in Claude Code, Cursor, or Windsurf and wants memory wired into their editor.
|
||||
- [Platform Overview](https://docs.mem0.ai/platform/overview) [Platform]: Use when the user picks the managed product - 4-line integration, sub-50ms retrieval, dashboard.
|
||||
- [Sign up as an agent](https://docs.mem0.ai/platform/agent-signup) [Platform]: Use when an AI agent needs to mint a Mem0 API key autonomously - four commands, no email or dashboard, human claims ownership later.
|
||||
- [Platform vs Open Source](https://docs.mem0.ai/platform/platform-vs-oss) [Both]: Use when the user is deciding between managed and self-hosted.
|
||||
- [Platform Quickstart](https://docs.mem0.ai/platform/quickstart) [Platform]: Use for the first Platform integration - API key plus `MemoryClient.add/search`.
|
||||
- [Platform CLI](https://docs.mem0.ai/platform/cli) [Platform]: Use when the user wants to manage Platform memories from the terminal.
|
||||
@@ -184,6 +197,7 @@ If the user is on a pre-current major (Python < 2, TS < 3, or Platform `output_f
|
||||
- [Platform Features Overview](https://docs.mem0.ai/platform/features/platform-overview) [Platform]: Use when surveying what managed offers beyond CRUD.
|
||||
- [V2 Memory Filters](https://docs.mem0.ai/platform/features/v2-memory-filters) [Platform]: Use when compound filters (AND/OR on metadata, entity, time) are needed at search.
|
||||
- [Entity-Scoped Memory](https://docs.mem0.ai/platform/features/entity-scoped-memory) [Platform]: Use when partitioning memories by user, agent, app, or run.
|
||||
- [Graph Memory](https://docs.mem0.ai/platform/features/graph-memory) [Platform]: Use when connecting facts across memories through shared entities for entity-centric or multi-hop questions.
|
||||
- [Async Client](https://docs.mem0.ai/platform/features/async-client) [Platform]: Use when the app issues many concurrent Mem0 calls and needs non-blocking I/O.
|
||||
- [Multimodal Support](https://docs.mem0.ai/platform/features/multimodal-support) [Platform]: Use when storing images or PDFs as memory input.
|
||||
- [Custom Categories](https://docs.mem0.ai/platform/features/custom-categories) [Platform]: Use when the default categories do not match the domain.
|
||||
@@ -215,6 +229,7 @@ If the user is on a pre-current major (Python < 2, TS < 3, or Platform `output_f
|
||||
- [OSS v2 to v3 Migration](https://docs.mem0.ai/migration/oss-v2-to-v3) [OSS]: Use when upgrading a self-hosted deployment across major versions.
|
||||
- [Platform v2 to v3 Migration](https://docs.mem0.ai/migration/platform-v2-to-v3) [Platform]: Use when upgrading a Platform integration across major versions.
|
||||
- [API Changes](https://docs.mem0.ai/migration/api-changes) [Both]: Use when the upgrade involves API surface changes.
|
||||
- [Server pgvector Image Upgrade](https://docs.mem0.ai/migration/server-pgvector-upgrade) [OSS]: Use when upgrading the self-hosted server Docker image from ankane/pgvector to pgvector/pgvector.
|
||||
- [Changelog](https://docs.mem0.ai/changelog/highlights) [Both]: Use when the user asks what shipped recently.
|
||||
|
||||
## Open Source
|
||||
@@ -245,6 +260,7 @@ If the user is on a pre-current major (Python < 2, TS < 3, or Platform `output_f
|
||||
- [Camel AI](https://docs.mem0.ai/integrations/camel-ai) [Both]: Use when the user is on Camel AI.
|
||||
- [ChatDev](https://docs.mem0.ai/integrations/chatdev) [Both]: Use when the user is on ChatDev.
|
||||
- [Hermes](https://docs.mem0.ai/integrations/hermes) [Both]: Use when the user is on Hermes.
|
||||
- [Pi Agent](https://docs.mem0.ai/integrations/pi-agent) [Platform]: Use when adding persistent memory to Pi Agent with the Mem0 plugin.
|
||||
- [OpenAI Agents SDK](https://docs.mem0.ai/integrations/openai-agents-sdk) [Both]: Use when the user is on the OpenAI Agents SDK.
|
||||
- [Google AI ADK](https://docs.mem0.ai/integrations/google-ai-adk) [Both]: Use when the user is on Google's Agent Development Kit.
|
||||
- [Mastra](https://docs.mem0.ai/integrations/mastra) [Both]: Use when the user is on Mastra (TypeScript).
|
||||
@@ -255,6 +271,8 @@ If the user is on a pre-current major (Python < 2, TS < 3, or Platform `output_f
|
||||
- [Claude Code](https://docs.mem0.ai/integrations/claude-code) [Both]: Use when wiring memory into Claude Code.
|
||||
- [Cursor](https://docs.mem0.ai/integrations/cursor) [Both]: Use when wiring memory into Cursor.
|
||||
- [Codex](https://docs.mem0.ai/integrations/codex) [Both]: Use when wiring memory into Codex / other editor assistants.
|
||||
- [OpenCode](https://docs.mem0.ai/integrations/opencode) [Both]: Use when wiring memory into OpenCode.
|
||||
- [Antigravity](https://docs.mem0.ai/integrations/antigravity) [Both]: Use when wiring memory into Google Antigravity.
|
||||
|
||||
### Voice & Real-time
|
||||
- [LiveKit](https://docs.mem0.ai/integrations/livekit) [Both]: Use when building real-time voice/video with memory.
|
||||
@@ -268,7 +286,7 @@ If the user is on a pre-current major (Python < 2, TS < 3, or Platform `output_f
|
||||
- [Dify](https://docs.mem0.ai/integrations/dify) [Both]: Use when the user is on Dify LLMOps.
|
||||
- [Flowise](https://docs.mem0.ai/integrations/flowise) [Both]: Use when the user is on Flowise no-code.
|
||||
- [AgentOps](https://docs.mem0.ai/integrations/agentops) [Both]: Use when tracking agent observability with memory metadata.
|
||||
- [Keywords AI](https://docs.mem0.ai/integrations/keywords) [Both]: Use when monitoring with Keywords AI.
|
||||
- [Respan](https://docs.mem0.ai/integrations/respan) [Both]: Use when monitoring Mem0 with Respan (formerly Keywords AI) LLM observability.
|
||||
- [Raycast](https://docs.mem0.ai/integrations/raycast) [Both]: Use when the user wants quick memory access via Raycast.
|
||||
|
||||
## Cookbooks
|
||||
@@ -381,15 +399,17 @@ Each subdirectory is a Claude Code Skill (`SKILL.md` + supporting assets). Load
|
||||
|
||||
### Editor Plugin (shared glue)
|
||||
|
||||
Source: https://github.com/mem0ai/mem0/tree/main/mem0-plugin
|
||||
Source: https://github.com/mem0ai/mem0/tree/main/integrations/mem0-plugin
|
||||
|
||||
The `mem0-plugin/` directory provides MCP server connection, lifecycle hooks, and skill bundling for Claude Code, Cursor, and Codex. It exposes 9 MCP tools: `add_memory`, `search_memories`, `get_memories`, `get_memory`, `update_memory`, `delete_memory`, `delete_all_memories`, `delete_entities`, `list_entities`.
|
||||
The `integrations/mem0-plugin/` directory provides MCP server connection, lifecycle hooks, and skill bundling for Claude Code, Cursor, Codex, OpenCode, and Antigravity. It exposes 9 MCP tools: `add_memory`, `search_memories`, `get_memories`, `get_memory`, `update_memory`, `delete_memory`, `delete_all_memories`, `delete_entities`, `list_entities`.
|
||||
|
||||
Editor-specific setup docs (already listed above under `## Integrations > AI Coding Tools`):
|
||||
|
||||
- `integrations/claude-code` [Both]
|
||||
- `integrations/cursor` [Both]
|
||||
- `integrations/codex` [Both]
|
||||
- `integrations/opencode` [Both]
|
||||
- `integrations/antigravity` [Both]
|
||||
- `integrations/openclaw` [Both]
|
||||
|
||||
### MCP Endpoints
|
||||
@@ -457,6 +477,7 @@ Everything below is OSS-only provider configuration. Skip this entire section wh
|
||||
- [Elasticsearch](https://docs.mem0.ai/components/vectordbs/dbs/elasticsearch) [OSS]: Use when Elasticsearch is the backing store.
|
||||
- [OpenSearch](https://docs.mem0.ai/components/vectordbs/dbs/opensearch) [OSS]: Use when OpenSearch is the backing store.
|
||||
- [Supabase](https://docs.mem0.ai/components/vectordbs/dbs/supabase) [OSS]: Use when Supabase with pgvector is the backing store.
|
||||
- [Neon](https://docs.mem0.ai/components/vectordbs/dbs/neon) [OSS]: Use when Neon Postgres with pgvector is the backing store.
|
||||
- [Upstash Vector](https://docs.mem0.ai/components/vectordbs/dbs/upstash-vector) [OSS]: Use for serverless Upstash Vector.
|
||||
- [Vectorize](https://docs.mem0.ai/components/vectordbs/dbs/vectorize) [OSS]: Use when the store is Cloudflare Vectorize.
|
||||
- [Vertex AI Vector Search](https://docs.mem0.ai/components/vectordbs/dbs/vertex_ai) [OSS]: Use when the store is Google Cloud Vertex Vector Search.
|
||||
|
||||
@@ -6,19 +6,21 @@ versionFrom: "Open Source"
|
||||
versionTo: "Platform"
|
||||
---
|
||||
|
||||
# Migrate from Open Source to Platform
|
||||
|
||||
Move your Mem0 implementation to managed infrastructure with enterprise features.
|
||||
## Overview
|
||||
|
||||
| Scope | Effort | Downtime |
|
||||
| --------------------- | -------------- | ---------------------------- |
|
||||
| Infrastructure & Code | Low (~30 mins) | None (Parallel run possible) |
|
||||
|
||||
<Note>
|
||||
Using Mem0 Open Source with **hosted Qdrant**? You can migrate your existing memories to Mem0 Platform with a one-line script below.
|
||||
</Note>
|
||||
|
||||
<Info>
|
||||
**Why migrate to Platform?**
|
||||
|
||||
- **Time to Market**: Set up in 5 minutes vs 30+ minutes for OSS configuration
|
||||
- **Enterprise Ready**: SOC2 Type II compliance, GDPR support, audit logs
|
||||
- **Enterprise Ready**: Audit logs, workspace governance, and dedicated support
|
||||
- **Advanced Features**: Webhooks, memory export, analytics dashboard, custom categories
|
||||
- **Multi-tenancy**: Organizations, projects, and team management out of the box
|
||||
- **Zero Infrastructure**: No vector database, LLM provider, or maintenance overhead
|
||||
@@ -26,15 +28,46 @@ Move your Mem0 implementation to managed infrastructure with enterprise features
|
||||
- **Production Grade**: Auto-scaling, high availability, dedicated support
|
||||
</Info>
|
||||
|
||||
## Plan
|
||||
### Plan
|
||||
|
||||
1. **Sign up**: Create an account on <a href="https://app.mem0.ai?utm_source=oss&utm_medium=migration-oss-to-platform" 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`.
|
||||
|
||||
## Migrate with Agent Skill
|
||||
|
||||
Paste this prompt into your coding agent. It uses a migration skill to produce a plan; once you review and approve it, the agent implements the changes.
|
||||
|
||||
```text
|
||||
Migrate my project from Mem0 OSS to the Mem0 Platform SDK using the
|
||||
mem0-oss-to-platform skill in the mem0ai/mem0 repo, at
|
||||
skills/mem0-oss-to-platform/
|
||||
|
||||
Get the skill whichever way is easiest:
|
||||
- install it: npx skills add https://github.com/mem0ai/mem0 --skill mem0-oss-to-platform
|
||||
- if the mem0 repo is cloned locally, read it from skills/mem0-oss-to-platform/
|
||||
- otherwise fetch that folder from github.com/mem0ai/mem0 (SKILL.md + references/)
|
||||
|
||||
Then read SKILL.md and begin the migration.
|
||||
```
|
||||
|
||||
## Migrate
|
||||
|
||||
### 1. Install or Update SDK
|
||||
### 1. Import Memories Into Platform
|
||||
|
||||
If your Mem0 Open Source setup uses **hosted Qdrant** as the vector store, you can import your existing memories to Mem0 Platform with one command:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://raw.githubusercontent.com/mem0ai/mem0/main/scripts/oss-to-platform-migrate.sh | bash
|
||||
```
|
||||
|
||||
<Note>
|
||||
This migration script currently supports **hosted Qdrant only**. Support for local Qdrant, pgvector, and other vector stores is coming soon.
|
||||
</Note>
|
||||
|
||||
If you are using a different vector store and want to migrate to Platform, please contact Mem0 support and we’ll send you a custom migration script for your setup.
|
||||
|
||||
### 2. Install or Update SDK
|
||||
|
||||
Ensure you have the latest version of the SDK, which supports both OSS and Platform clients.
|
||||
|
||||
@@ -42,7 +75,7 @@ Ensure you have the latest version of the SDK, which supports both OSS and Platf
|
||||
pip install mem0ai --upgrade
|
||||
```
|
||||
|
||||
### 2. Update Initialization
|
||||
### 3. Update Initialization
|
||||
|
||||
Switch from the local `Memory` class to the managed `MemoryClient`.
|
||||
|
||||
@@ -75,7 +108,7 @@ client = MemoryClient(api_key="m0-...")
|
||||
Run `client.get_all(filters={"user_id": "test_connection"})` to verify your API key works. It should return an empty list or valid results.
|
||||
</Info>
|
||||
|
||||
### 3. Update Retrieval Calls (Critical)
|
||||
### 4. Update Retrieval Calls (Critical)
|
||||
|
||||
<Warning>
|
||||
**Critical Change**: Platform uses v2 endpoints that require filtering parameters to be nested inside a `filters` dictionary.
|
||||
|
||||
@@ -328,27 +328,27 @@ The new algorithm automatically creates a parallel entity store collection named
|
||||
Make sure your vector store user/credentials have permission to create new collections. If you're using a managed vector database with restricted permissions, pre-create the `{collection_name}_entities` collection with the same embedding dimensions as your main collection.
|
||||
</Warning>
|
||||
|
||||
## Graph Memory → Entity Linking
|
||||
## Graph Memory: Now Built-In
|
||||
|
||||
Graph store support has been removed from the open-source SDK. It is replaced by **built-in entity linking**, which runs natively with no external dependencies.
|
||||
External graph **store** support has been removed from the open-source SDK and replaced by **built-in graph memory** (entity linking), which runs natively with no external dependencies.
|
||||
|
||||
**What was removed:**
|
||||
- `enable_graph` / `enableGraph` config flag
|
||||
- `graph_store` / `graphStore` configuration block (Neo4j, Memgraph, Kuzu, Apache AGE, Neptune)
|
||||
- All graph memory code paths (~4000 lines)
|
||||
- All external graph store code paths (~4000 lines)
|
||||
|
||||
**What replaces it:**
|
||||
|
||||
Entity linking extracts entities (proper nouns, quoted text, compound noun phrases) from every memory during the add pipeline and stores them in a parallel collection (`{collection}_entities`) inside your existing vector store. At search time, entities from the query are matched against this collection and used to boost relevant memories. The boost is folded into the combined `score` on each result.
|
||||
Mem0 now builds the graph itself. It extracts entities (proper nouns, quoted text, compound noun phrases) from every memory during the add pipeline and stores them in a parallel collection (`{collection}_entities`) inside your existing vector store. Memories that share an entity are linked, and at search time entities from the query are matched against this collection to boost connected memories. The boost is folded into the combined `score` on each result.
|
||||
|
||||
**Migration:**
|
||||
- Remove `enable_graph` / `enableGraph` from your config
|
||||
- Remove the `graph_store` / `graphStore` block — it is no longer read
|
||||
- Uninstall graph drivers (neo4j, memgraph, etc.) if you were using them only for Mem0
|
||||
- No data migration is required. Entity linking activates automatically on the next `add()` call.
|
||||
- Uninstall external graph drivers (neo4j, memgraph, etc.) if you were using them only for Mem0
|
||||
- No data migration is required. Built-in graph memory activates automatically on the next `add()` call.
|
||||
|
||||
<Warning>
|
||||
Graph relationships exposed via the old `relations` field on search results are no longer populated. Entity relationships are consumed indirectly through retrieval ranking, not exposed as a queryable graph structure. If your application depended on traversing graph relationships directly, you will need to redesign that part against the new API.
|
||||
The old `relations` field on search results (populated by the external graph store) is no longer returned. Entity connections are now applied through retrieval ranking rather than exposed as a separate, directly traversable structure. If your application read or traversed the `relations` array, you will need to redesign that part against the new API.
|
||||
</Warning>
|
||||
|
||||
## How the New Algorithm Works
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: "Platform: Migrating to the New Memory Algorithm"
|
||||
description: "Guide for Mem0 Platform users to adopt the new memory algorithm with single-pass extraction, entity linking, and multi-signal retrieval."
|
||||
description: "Guide for Mem0 Platform users to adopt the new memory algorithm with single-pass extraction, built-in graph memory, and multi-signal retrieval."
|
||||
icon: "arrow-right"
|
||||
iconType: "solid"
|
||||
---
|
||||
@@ -18,8 +18,7 @@ The new Mem0 memory algorithm is a ground-up redesign of how memories are extrac
|
||||
| **Extraction** | Two LLM passes (extract + merge) | Single-pass ADD-only (one LLM call) |
|
||||
| **Memory mutations** | ADD, UPDATE, DELETE | ADD only — nothing is overwritten or deleted |
|
||||
| **Agent-generated facts** | Often ignored | First-class, stored with equal weight |
|
||||
| **Entity linking** | Not available | Entities extracted and linked across memories |
|
||||
| **Graph memory** | Separate graph store + dashboard visualization | Replaced by built-in entity linking, no graph visuals on platform dashboard |
|
||||
| **Graph memory** | External graph store (Neo4j, etc.) + manual setup | Built-in and automatic; entities extracted and linked across memories natively, no external store |
|
||||
| **Retrieval** | Semantic (vector) only | Hybrid retrieval combining multiple signals |
|
||||
|
||||
## What This Means for Your Application
|
||||
@@ -249,19 +248,18 @@ await client.search("query", {
|
||||
For the full list of parameter changes across all SDKs, see the [OSS migration guide](/migration/oss-v2-to-v3#removed-parameters-reference).
|
||||
</Info>
|
||||
|
||||
## Graph Memory → Entity Linking
|
||||
## Graph Memory Is Now Built-In
|
||||
|
||||
Graph memory has been replaced by **built-in entity linking**. The changes:
|
||||
Graph memory no longer requires an external graph database. It is now **native to the platform** and automatic. The changes:
|
||||
|
||||
- **Graph visualizations removed from the platform dashboard.** The graph view in your project dashboard is no longer available.
|
||||
- **`enable_graph` project setting removed.** The toggle is gone from the dashboard; the API parameter is ignored.
|
||||
- **No external graph store to configure.** Previously graph memory required a separate Neo4j (or similar) deployment. Entity linking runs natively inside the platform — nothing to provision, no connection strings to manage.
|
||||
- **Entity linking is the native replacement.** Entities (proper nouns, quoted text, compound noun phrases) are automatically extracted from every memory and linked across memories belonging to the same user. At search time, entities from the query are matched against this index and used to boost ranking. The boost is folded into the combined `score` returned on each result.
|
||||
- **No external graph store to configure.** Previously, graph memory required a separate Neo4j (or similar) deployment. Mem0 now builds the graph itself from your memories, so there is nothing to provision and no connection strings to manage.
|
||||
- **Always on, no flag.** The `enable_graph` project setting is no longer needed; graph memory activates automatically. (The API parameter is now ignored if sent.)
|
||||
- **Connections power retrieval directly.** Entities (proper nouns, quoted text, compound noun phrases) are automatically extracted from every memory and linked across memories belonging to the same user. At search time, entities from the query are matched against the graph and used to boost ranking. The boost is folded into the combined `score` returned on each result.
|
||||
|
||||
**No migration work is required.** Entity linking activates automatically for all projects on the new algorithm. Existing memories are not re-processed, but any new memories you add will be indexed for entity-based retrieval going forward.
|
||||
**No migration work is required.** Graph memory activates automatically for all projects on the new algorithm. Existing memories are not re-processed, but any new memories you add are added to the graph going forward. See [Graph Memory](/platform/features/graph-memory) for how the built-in graph works.
|
||||
|
||||
<Note>
|
||||
If your application previously read graph relations from the API response (`relations` field on search results), note that this field is no longer populated. Entity relationships are now consumed indirectly through retrieval ranking, not exposed as a separate graph structure.
|
||||
If your application previously read graph relations from the API response (`relations` field on search results), note that this field is no longer populated. Entity connections are now applied through retrieval ranking rather than returned as a separate `relations` array.
|
||||
</Note>
|
||||
|
||||
## Migration Checklist
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
---
|
||||
title: "Server: Upgrading the pgvector Docker Image"
|
||||
description: "Migrate your self-hosted Mem0 server from the archived ankane/pgvector image to the official pgvector/pgvector image."
|
||||
icon: "arrow-right"
|
||||
iconType: "solid"
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
The self-hosted Mem0 server has upgraded its PostgreSQL Docker image:
|
||||
|
||||
| | Before | After |
|
||||
| --- | --- | --- |
|
||||
| Docker image | `ankane/pgvector:v0.5.1` | `pgvector/pgvector:pg17` |
|
||||
| PostgreSQL | 15 | 17 |
|
||||
| pgvector | 0.5.1 | 0.8.0 |
|
||||
| Credentials | Hardcoded `postgres` / `postgres` | Set via `POSTGRES_USER` / `POSTGRES_PASSWORD` env vars |
|
||||
|
||||
<Warning>
|
||||
The `ankane/pgvector` image is **archived and no longer maintained**. The new `pgvector/pgvector` image is the official distribution maintained by the pgvector project.
|
||||
</Warning>
|
||||
|
||||
<Info>
|
||||
**Should you migrate?**
|
||||
- You are running the Mem0 server via `docker-compose.yaml` in the `server/` directory.
|
||||
- You want to stay on a maintained, actively-patched PostgreSQL + pgvector image.
|
||||
- You want pgvector 0.8.0 features (improved HNSW performance, parallel index builds).
|
||||
</Info>
|
||||
|
||||
## Fresh Installs
|
||||
|
||||
No migration is needed. Copy the example env file, set your password, and start the stack:
|
||||
|
||||
```bash
|
||||
cd server
|
||||
cp .env.example .env
|
||||
# Edit .env — set POSTGRES_PASSWORD (required) and OPENAI_API_KEY at minimum
|
||||
make up
|
||||
```
|
||||
|
||||
## Migrating an Existing Install
|
||||
|
||||
PostgreSQL 17 cannot read data files created by PostgreSQL 15 directly. You need to export your data from the old container and import it into the new one.
|
||||
|
||||
### 1. Back Up Your Data
|
||||
|
||||
With the **old** stack still running:
|
||||
|
||||
```bash
|
||||
cd server
|
||||
docker compose exec -T postgres pg_dumpall -U postgres > mem0_backup.sql
|
||||
```
|
||||
|
||||
Verify the dump is non-empty:
|
||||
|
||||
```bash
|
||||
ls -lh mem0_backup.sql
|
||||
```
|
||||
|
||||
<Warning>
|
||||
Do not skip this step. The next step permanently deletes your Postgres data volume.
|
||||
</Warning>
|
||||
|
||||
### 2. Stop the Old Stack and Remove the Volume
|
||||
|
||||
```bash
|
||||
docker compose down
|
||||
docker compose down -v
|
||||
```
|
||||
|
||||
### 3. Update Your `.env`
|
||||
|
||||
Postgres credentials are no longer hardcoded in `docker-compose.yaml`. Add them to your `.env`:
|
||||
|
||||
```bash
|
||||
POSTGRES_HOST=postgres
|
||||
POSTGRES_PORT=5432
|
||||
POSTGRES_DB=postgres
|
||||
POSTGRES_USER=postgres
|
||||
POSTGRES_PASSWORD=<your-password> # required — compose will refuse to start without it
|
||||
POSTGRES_COLLECTION_NAME=memories
|
||||
```
|
||||
|
||||
<Info>
|
||||
`POSTGRES_PASSWORD` is **required** — `docker compose up` will refuse to start without it. If you previously relied on the hardcoded default, set `POSTGRES_PASSWORD=postgres`.
|
||||
</Info>
|
||||
|
||||
### 4. Start Only Postgres
|
||||
|
||||
Start **only** the Postgres container first — do **not** start the mem0 API yet.
|
||||
The API runs `alembic upgrade head` on startup, which creates empty tables that
|
||||
would conflict with the restore.
|
||||
|
||||
```bash
|
||||
docker compose up -d postgres
|
||||
```
|
||||
|
||||
Wait for Postgres to become healthy:
|
||||
|
||||
```bash
|
||||
docker compose exec -T postgres pg_isready -q && echo "ready" || echo "not ready"
|
||||
```
|
||||
|
||||
### 5. Restore Your Data
|
||||
|
||||
```bash
|
||||
docker compose exec -T postgres psql -U postgres < mem0_backup.sql
|
||||
```
|
||||
|
||||
You may see notices like `role "postgres" already exists` — these are safe to ignore.
|
||||
|
||||
<Warning>
|
||||
You must restore **before** starting the mem0 API container. The API runs
|
||||
database migrations on startup which create empty tables — restoring after
|
||||
that would fail with duplicate-key errors and lose your API keys and settings.
|
||||
</Warning>
|
||||
|
||||
### 6. Start the API
|
||||
|
||||
Now start the mem0 API container. Alembic will detect the existing tables and
|
||||
only apply any new migrations:
|
||||
|
||||
```bash
|
||||
docker compose up -d mem0
|
||||
```
|
||||
|
||||
### 7. Verify
|
||||
|
||||
```bash
|
||||
# Check service health
|
||||
cd server && make health
|
||||
|
||||
# Confirm memories are accessible
|
||||
curl -s http://localhost:8888/memories?user_id=<your-user-id> \
|
||||
-H "X-API-Key: <your-api-key>"
|
||||
```
|
||||
|
||||
## Rollback
|
||||
|
||||
If something goes wrong, revert the image tag in `docker-compose.yaml`:
|
||||
|
||||
```yaml
|
||||
postgres:
|
||||
image: ankane/pgvector:v0.5.1
|
||||
```
|
||||
|
||||
Then destroy the new volume, start the old image, and restore from your backup:
|
||||
|
||||
```bash
|
||||
docker compose down -v
|
||||
docker compose up -d --build
|
||||
docker compose exec -T postgres psql -U postgres < mem0_backup.sql
|
||||
```
|
||||
|
||||
## Need Help?
|
||||
|
||||
- Join our [Discord community](https://mem0.ai/discord) for real-time support
|
||||
- Open an issue on [GitHub](https://github.com/mem0ai/mem0/issues)
|
||||
@@ -4,22 +4,7 @@ description: Fine-grained metadata queries for precise OSS memory retrieval.
|
||||
icon: "filter"
|
||||
---
|
||||
|
||||
Enhanced metadata filtering in Mem0 1.0.0 lets you run complex queries across memory metadata. Combine comparisons, logical operators, and wildcard matches to zero in on the exact memories your agent needs.
|
||||
|
||||
<Info>
|
||||
**You’ll use this when…**
|
||||
- Retrieval must respect multiple metadata conditions before returning context.
|
||||
- You need to mix numeric, boolean, and string filters in a single query.
|
||||
- Agents rely on deterministic filtering instead of broad semantic search alone.
|
||||
</Info>
|
||||
|
||||
<Warning>
|
||||
Enhanced filtering requires Mem0 1.0.0 or later and a vector store that supports the operators you enable. Unsupported operators fall back to simple equality filters.
|
||||
</Warning>
|
||||
|
||||
<Note>
|
||||
The TypeScript SDK accepts the same filter shape shown here—transpose the dictionaries to objects and reuse the keys unchanged.
|
||||
</Note>
|
||||
Enhanced metadata filtering in Mem0 lets you run complex queries across memory metadata. Combine comparisons, logical operators, and wildcard matches to zero in on the exact memories your agent needs.
|
||||
|
||||
---
|
||||
|
||||
@@ -148,8 +133,8 @@ Combine filters with `AND`, `OR`, and `NOT` to express complex decision trees. N
|
||||
results = m.search(
|
||||
"complex query",
|
||||
filters={
|
||||
"user_id": "alice",
|
||||
"AND": [
|
||||
{"user_id": "alice"},
|
||||
{"category": "work"},
|
||||
{"priority": {"gte": 7}},
|
||||
{"status": {"ne": "completed"}}
|
||||
@@ -161,15 +146,11 @@ results = m.search(
|
||||
results = m.search(
|
||||
"flexible query",
|
||||
filters={
|
||||
"AND": [
|
||||
{"user_id": "alice"},
|
||||
{
|
||||
"OR": [
|
||||
{"category": "urgent"},
|
||||
{"priority": {"gte": 9}},
|
||||
{"deadline": {"contains": "today"}}
|
||||
]
|
||||
}
|
||||
"user_id": "alice",
|
||||
"OR": [
|
||||
{"category": "urgent"},
|
||||
{"priority": {"gte": 9}},
|
||||
{"deadline": {"contains": "today"}}
|
||||
]
|
||||
}
|
||||
)
|
||||
@@ -178,14 +159,10 @@ results = m.search(
|
||||
results = m.search(
|
||||
"exclusion query",
|
||||
filters={
|
||||
"AND": [
|
||||
{"user_id": "alice"},
|
||||
{
|
||||
"NOT": [
|
||||
{"category": "archived"},
|
||||
{"status": "deleted"}
|
||||
]
|
||||
}
|
||||
"user_id": "alice",
|
||||
"NOT": [
|
||||
{"category": "archived"},
|
||||
{"status": "deleted"}
|
||||
]
|
||||
}
|
||||
)
|
||||
@@ -194,8 +171,8 @@ results = m.search(
|
||||
results = m.search(
|
||||
"advanced query",
|
||||
filters={
|
||||
"user_id": "alice",
|
||||
"AND": [
|
||||
{"user_id": "alice"},
|
||||
{
|
||||
"OR": [
|
||||
{"category": "work"},
|
||||
@@ -248,8 +225,8 @@ config = {
|
||||
```python
|
||||
# More efficient: Filter on indexed fields first
|
||||
good_filters = {
|
||||
"user_id": "alice",
|
||||
"AND": [
|
||||
{"user_id": "alice"},
|
||||
{"category": "work"},
|
||||
{"content": {"contains": "meeting"}}
|
||||
]
|
||||
@@ -257,9 +234,9 @@ good_filters = {
|
||||
|
||||
# Less efficient: Complex operations first
|
||||
avoid_filters = {
|
||||
"user_id": "alice",
|
||||
"AND": [
|
||||
{"description": {"icontains": "complex text search"}},
|
||||
{"user_id": "alice"}
|
||||
{"description": {"icontains": "complex text search"}}
|
||||
]
|
||||
}
|
||||
```
|
||||
@@ -302,8 +279,8 @@ results = m.search(
|
||||
results = m.search(
|
||||
"query",
|
||||
filters={
|
||||
"user_id": "alice",
|
||||
"AND": [
|
||||
{"user_id": "alice"},
|
||||
{"category": "work"},
|
||||
{"status": {"ne": "archived"}},
|
||||
{"priority": {"gte": 5}}
|
||||
@@ -327,8 +304,8 @@ results = m.search(
|
||||
results = m.search(
|
||||
"What tasks need attention?",
|
||||
filters={
|
||||
"user_id": "project_manager",
|
||||
"AND": [
|
||||
{"user_id": "project_manager"},
|
||||
{"project": {"in": ["alpha", ""]}},
|
||||
{"priority": {"gte": 8}},
|
||||
{"status": {"ne": "completed"}},
|
||||
@@ -354,8 +331,8 @@ results = m.search(
|
||||
results = m.search(
|
||||
"pending support issues",
|
||||
filters={
|
||||
"agent_id": "support_bot",
|
||||
"AND": [
|
||||
{"agent_id": "support_bot"},
|
||||
{"ticket_status": {"ne": "resolved"}},
|
||||
{"priority": {"in": ["high", "critical"]}},
|
||||
{"created_date": {"gte": "2024-01-01"}},
|
||||
@@ -380,8 +357,8 @@ results = m.search(
|
||||
results = m.search(
|
||||
"recommend content",
|
||||
filters={
|
||||
"user_id": "reader123",
|
||||
"AND": [
|
||||
{"user_id": "reader123"},
|
||||
{
|
||||
"OR": [
|
||||
{"genre": {"in": ["sci-fi", "fantasy"]}},
|
||||
|
||||
@@ -6,7 +6,7 @@ icon: "list"
|
||||
|
||||
# Self-Hosting Features Overview
|
||||
|
||||
Mem0 Open Source ships with capabilities that adapt memory behavior for production workloads—async operations, graph relationships, multimodal inputs, and fine-tuned retrieval. Configure these features with code or YAML to match your application's needs.
|
||||
Mem0 Open Source ships with capabilities that adapt memory behavior for production workloads—async operations, multimodal inputs, and fine-tuned retrieval. Configure these features with code or YAML to match your application's needs.
|
||||
|
||||
<Info>
|
||||
Start with the <Link href="/open-source/python-quickstart">Python quickstart</Link> to validate basic memory operations, then enable the features below when you need them.
|
||||
|
||||
@@ -119,7 +119,7 @@ docker build -t mem0-api-server .
|
||||
</Tip>
|
||||
|
||||
<Note>
|
||||
The REST server reads the same configuration you use locally, so you can point it at your preferred LLM, vector store, graph backend, and reranker without changing code.
|
||||
The REST server reads the same configuration you use locally, so you can point it at your preferred LLM, vector store, and reranker without changing code.
|
||||
</Note>
|
||||
|
||||
---
|
||||
@@ -226,6 +226,20 @@ curl -X POST http://localhost:8888/search \
|
||||
}'
|
||||
```
|
||||
|
||||
Set `explain` to inspect the scoring signals used by OSS hybrid search:
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8888/search \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"query": "vegetable pizza",
|
||||
"user_id": "alice",
|
||||
"explain": true
|
||||
}'
|
||||
```
|
||||
|
||||
Each returned memory includes `score_details` only when explanation mode is enabled.
|
||||
|
||||
### Explore with OpenAPI docs
|
||||
|
||||
1. Navigate to `http://localhost:8888/docs` (Compose) or `http://localhost:8000/docs` (raw Docker / uvicorn).
|
||||
@@ -319,7 +333,7 @@ The `/auth/*`, `/api-keys`, `/requests`, and `/entities` routes are new to the s
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Configure OSS Components" icon="sliders" href="/open-source/configuration">
|
||||
Fine-tune LLMs, vector stores, and graph backends that power the REST server.
|
||||
Fine-tune LLMs, vector stores, and rerankers that power the REST server.
|
||||
</Card>
|
||||
<Card title="Automate Agent Integrations" icon="plug" href="/cookbooks/integrations/agents-sdk-tool">
|
||||
See how services call the REST endpoints as part of an automation pipeline.
|
||||
|
||||
@@ -64,7 +64,7 @@ const memory = new Memory({ apiKey: process.env.MEM0_API_KEY!, async: true });
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
## Add memories with metadata and graph context
|
||||
## Add memories with metadata
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Python">
|
||||
@@ -109,7 +109,7 @@ const result = await memory.add(conversation, {
|
||||
</Tabs>
|
||||
|
||||
<Info icon="check">
|
||||
Successful calls return memories tagged with the metadata you passed. In the dashboard, confirm a graph edge between “Morgan” and “Tokyo” and verify the `trip=japan-2025` tag exists.
|
||||
Successful calls return memories tagged with the metadata you passed. In the dashboard, verify the `trip=japan-2025` tag exists on the new memory.
|
||||
</Info>
|
||||
|
||||
## Retrieve and refine
|
||||
@@ -201,7 +201,7 @@ await memory.deleteAll({ userId: "traveler-42", runId: "planning-call-1" });
|
||||
/>
|
||||
<Card
|
||||
title="Explore Reranker Search"
|
||||
description="See how rerankers boost accuracy after vector + graph retrieval."
|
||||
description="See how rerankers boost accuracy after advanced retrieval."
|
||||
icon="sparkles"
|
||||
href="/open-source/features/reranker-search"
|
||||
/>
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
---
|
||||
title: Sign up as an agent
|
||||
description: "Zero-friction signup for AI agents — mint a working Mem0 API key in under five seconds. No email, no dashboard, no OTP."
|
||||
icon: "robot"
|
||||
iconType: "solid"
|
||||
---
|
||||
|
||||
If you're an AI agent (Claude Code, Cursor, Codex, Cline, Aider, Windsurf, or any other autonomous coding tool), you don't need a human to set up Mem0 for you. Four commands — install, sign up, push a memory, search it — and you have persistent memory.
|
||||
|
||||
## The 4-command demo
|
||||
|
||||
<CodeGroup>
|
||||
```bash npm
|
||||
# 1. Install
|
||||
npm install -g @mem0/cli
|
||||
|
||||
# 2. Sign up as an agent (replace `claude-code` with your name)
|
||||
mem0 init --agent --agent-caller claude-code
|
||||
|
||||
# 3. Push a memory
|
||||
mem0 add "I am using mem0"
|
||||
|
||||
# 4. Verify
|
||||
mem0 search "am I using mem0"
|
||||
```
|
||||
|
||||
```bash pip
|
||||
# 1. Install
|
||||
pip install mem0-cli
|
||||
|
||||
# 2. Sign up as an agent (replace `claude-code` with your name)
|
||||
mem0 init --agent --agent-caller claude-code
|
||||
|
||||
# 3. Push a memory
|
||||
mem0 add "I am using mem0"
|
||||
|
||||
# 4. Verify
|
||||
mem0 search "am I using mem0"
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
That's it — under 30 seconds from a fresh shell to a working memory store.
|
||||
|
||||
## Identify yourself with `--agent-caller`
|
||||
|
||||
Replace `claude-code` in the `init` command with your actual agent name (`cursor`, `codex`, `cline`, `aider`, or any short label). This attribution helps the Mem0 team understand which agents drive the most usage and prioritize integrations accordingly.
|
||||
|
||||
<Tip>
|
||||
**Forgot `--agent-caller` on init?** Run `mem0 identify <your-name>` after the fact — same key, just back-fills the attribution. Idempotent.
|
||||
</Tip>
|
||||
|
||||
## What happened when you ran `mem0 init --agent`?
|
||||
|
||||
- A **shadow account** was minted on the Mem0 backend with a fresh API key.
|
||||
- The key was saved to `~/.mem0/config.json` (mode 0600) on the machine you ran the command on.
|
||||
- A default `user_id` was provisioned so `mem0 add` / `mem0 search` work without explicit scope flags.
|
||||
- The account is **unclaimed** — no human owns it yet.
|
||||
|
||||
Every command run against this key prints a one-line reminder asking you to surface the claim instructions to your human user.
|
||||
|
||||
## Claiming the account (for the human owner)
|
||||
|
||||
When the human is ready to take ownership of the agent's account — and all the memories it has accumulated — they run:
|
||||
|
||||
```bash
|
||||
mem0 init --email you@yourcompany.com
|
||||
```
|
||||
|
||||
The CLI detects the existing Agent Mode config, sends a verification code, and upgrades the shadow account in-place:
|
||||
|
||||
- **The API key never changes** — the agent isn't disrupted.
|
||||
- **All memories transfer** to the human's account.
|
||||
- **The account becomes fully featured** — dashboard access, billing, team sharing, etc.
|
||||
|
||||
Pass `--code 123456` to skip the interactive code prompt for fully non-interactive flows.
|
||||
|
||||
## Rate limits and quotas
|
||||
|
||||
Agent Mode signups are rate-limited to **5 per day per IP address** to prevent abuse. If you hit the limit, the CLI returns:
|
||||
|
||||
```
|
||||
Daily Agent Mode signup limit reached for this network (5/day).
|
||||
Try again from a different IP or after midnight UTC.
|
||||
```
|
||||
|
||||
Unclaimed agent accounts get the standard Mem0 free-tier quotas. The human owner can upgrade after claiming.
|
||||
|
||||
## What's next
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="CLI Reference" icon="terminal" href="/platform/cli">
|
||||
Full command-by-command reference for `mem0 add`, `mem0 search`, `mem0 list`, and the rest.
|
||||
</Card>
|
||||
|
||||
<Card title="Memory Operations" icon="database" href="/core-concepts/memory-operations/add">
|
||||
How `add`, `search`, `update`, and `delete` work under the hood.
|
||||
</Card>
|
||||
|
||||
<Card title="Mem0 MCP" icon="plug" href="/platform/mem0-mcp">
|
||||
Connect agents to Mem0 via the Model Context Protocol — alternative integration path.
|
||||
</Card>
|
||||
|
||||
<Card title="Platform Overview" icon="star" href="/platform/overview">
|
||||
The full Mem0 Platform feature set once you claim your account.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
+94
-3
@@ -25,6 +25,10 @@ pip install mem0-cli
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
<Tip>
|
||||
**Looking for Agent Mode signup?** See [Sign up as an agent](/platform/agent-signup) — install, signup, first memory in four commands.
|
||||
</Tip>
|
||||
|
||||
## Authentication
|
||||
|
||||
Run the interactive setup wizard to configure your API key:
|
||||
@@ -95,6 +99,10 @@ mem0 init --api-key m0-xxx --user-id alice --force
|
||||
| `--code` | Verification code (use with `--email` for non-interactive login) |
|
||||
| `--force` | Overwrite existing config without confirmation |
|
||||
|
||||
<Note>
|
||||
AI agents should use `mem0 init --agent` — see [Sign up as an agent](/platform/agent-signup).
|
||||
</Note>
|
||||
|
||||
### `mem0 add`
|
||||
|
||||
Add a memory from text, a JSON messages array, a file, or stdin.
|
||||
@@ -113,7 +121,6 @@ echo "Loves hiking on weekends" | mem0 add --user-id alice
|
||||
| `-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`
|
||||
@@ -133,7 +140,6 @@ mem0 search "preferred tools" --user-id alice --output json --top-k 5
|
||||
| `--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`
|
||||
@@ -263,6 +269,92 @@ Print the CLI version.
|
||||
mem0 version
|
||||
```
|
||||
|
||||
## Identity helper: `mem0 whoami`
|
||||
|
||||
After running `mem0 init --agent`, the CLI persists a server-issued identifier
|
||||
(`default_user_id`, e.g. `user_a1b2c3d4e5f6`) in `~/.mem0/config.json`. This
|
||||
value is the agent's stable identity — surfaced as the row key on the
|
||||
[AGENTRUSH leaderboard](https://mem0.ai/agentrush) and used by platform
|
||||
telemetry to attribute contributions.
|
||||
|
||||
Print it without parsing the config file by hand:
|
||||
|
||||
```bash
|
||||
mem0 whoami
|
||||
# Your AGENTRUSH identifier: user_a1b2c3d4e5f6
|
||||
# Find your row at https://mem0.ai/agentrush
|
||||
```
|
||||
|
||||
No network call. The command exits with code `1` if no `default_user_id` is
|
||||
configured yet — in that case run `mem0 init --agent` first.
|
||||
|
||||
## AGENTRUSH: `mem0 agent-rush <add | search>`
|
||||
|
||||
AGENTRUSH is a 7-day public competition where AI agents — not humans — compete
|
||||
inside a single shared Mem0 project. Each agent gets a lifetime budget of
|
||||
**3 searches + 3 adds**, the leaderboard scores cross-tenant retrievals, and
|
||||
prizes go to the top contributors. See [mem0.ai/agentrush](https://mem0.ai/agentrush)
|
||||
for current event details.
|
||||
|
||||
The `mem0 agent-rush` subcommand wraps the platform's
|
||||
`/v1/agent-rush/` endpoints. Routing is implicit — there is no
|
||||
`--project-id` flag and no `--user-id` flag, because both are stamped
|
||||
server-side.
|
||||
|
||||
### Bootstrap once, then play
|
||||
|
||||
```bash
|
||||
# 1. Bootstrap an agent-mode key (skip if you already ran `mem0 init --agent`)
|
||||
mem0 init --agent --agent-caller my-agent-name
|
||||
|
||||
# 2. Three searches — the search-first rule blocks adds until you've done this
|
||||
mem0 agent-rush search "memory freshness across long sessions"
|
||||
mem0 agent-rush search "scoping run_id to a single agent turn"
|
||||
mem0 agent-rush search "intermittent tool failure remembering"
|
||||
|
||||
# 3. Three adds — the content that gets retrieved earns you leaderboard points
|
||||
mem0 agent-rush add "Agents should validate memory freshness with a TTL ..."
|
||||
mem0 agent-rush add "Scoping memories by run_id avoids cross-session ..."
|
||||
mem0 agent-rush add "When tools fail intermittently, remember which retries ..."
|
||||
|
||||
# 4. Check your row
|
||||
mem0 whoami
|
||||
# Then visit https://mem0.ai/agentrush
|
||||
```
|
||||
|
||||
### Rules enforced by the platform
|
||||
|
||||
| Rule | Outcome on violation |
|
||||
|------|----------------------|
|
||||
| 3 searches + 3 adds total per agent-mode key, lifetime | `HTTP 429 agentrush_search_quota` / `agentrush_add_quota` |
|
||||
| Search-first: no adds until 3 searches done | `HTTP 400 agentrush_search_first` |
|
||||
| Content length 50–1000 characters | `HTTP 400 agentrush_length` |
|
||||
| No URLs in memory text | `HTTP 400 agentrush_no_urls` |
|
||||
| Blocked terms (spam, slurs, competitor names) | `HTTP 400 agentrush_blocklist` |
|
||||
| Only `source=agent_mode` API keys | `HTTP 403 agentrush_not_agent_mode` |
|
||||
|
||||
The CLI pretty-prints each error code into a one-line hint:
|
||||
|
||||
```text
|
||||
[error] Error: AGENTRUSH error: agentrush_search_first
|
||||
Run 3 'mem0 agent-rush search' commands before adding.
|
||||
```
|
||||
|
||||
### Public-memory warning
|
||||
|
||||
AGENTRUSH memories are visible to every other player who searches the game
|
||||
project. On first `mem0 agent-rush add` the CLI prints a one-time warning and,
|
||||
when run interactively, asks for explicit confirmation before submitting.
|
||||
**Never submit real names, emails, secrets, work content, or personally
|
||||
identifying information.** The acknowledgement is stored under
|
||||
`agent_rush.acknowledged_at` in `~/.mem0/config.json` so you are only asked
|
||||
once per machine.
|
||||
|
||||
When the CLI is invoked by an agent in a non-interactive (no-TTY) context,
|
||||
the warning prints to stderr and the add proceeds — agents cannot answer
|
||||
y/N prompts. Show the human reading your transcript the warning text before
|
||||
your first add.
|
||||
|
||||
## Output formats
|
||||
|
||||
All commands support the `--output` flag to control how results are displayed:
|
||||
@@ -342,7 +434,6 @@ For non-interactive environments (CI, agent runtimes), set credentials via `mem0
|
||||
| `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.
|
||||
|
||||
|
||||
+19
-1
@@ -9,7 +9,7 @@ iconType: "solid"
|
||||
<Accordion title="How does Mem0 work?">
|
||||
Mem0 utilizes a sophisticated hybrid database system to efficiently manage and retrieve memories for AI agents and assistants. Each memory is linked to a unique identifier, such as a user ID or agent ID, enabling Mem0 to organize and access memories tailored to specific individuals or contexts.
|
||||
|
||||
When a message is added to Mem0 via the `add` method, the system extracts pertinent facts and preferences, distributing them across various data stores: a vector database and a graph database. This hybrid strategy ensures that diverse types of information are stored optimally, facilitating swift and effective searches.
|
||||
When a message is added to Mem0 via the `add` method, the system extracts pertinent facts and preferences, distributing them in a managed vector store. This strategy ensures that diverse types of information are stored optimally, facilitating swift and effective searches.
|
||||
|
||||
When an AI agent or LLM needs to access memories, it employs the `search` method. Mem0 conducts a comprehensive search across these data stores, retrieving relevant information from each.
|
||||
|
||||
@@ -142,6 +142,24 @@ iconType: "solid"
|
||||
Setting this environment variable will prevent Mem0 from collecting and sending any usage data, ensuring complete privacy for your application.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="How do I delete my Mem0 account?">
|
||||
You can delete your Mem0 account at any time directly from the dashboard:
|
||||
|
||||
1. Sign in at [app.mem0.ai](https://app.mem0.ai).
|
||||
2. Go to **Settings → Account**.
|
||||
3. Click **Delete account** and confirm.
|
||||
|
||||
Deletion is immediate and irreversible. The following is removed:
|
||||
|
||||
- Your user profile and login credentials
|
||||
- All memories, agents, and runs you created
|
||||
- API keys and access tokens issued to your account
|
||||
- Organizations you solely own, along with their data
|
||||
- Your membership in any shared organizations (the orgs themselves are not affected)
|
||||
|
||||
Any application still using your old API keys will start receiving `401 Unauthorized` responses immediately. If you'd like to use Mem0 again later, you can create a new account at any time — it will start fresh with no data carried over.
|
||||
</Accordion>
|
||||
|
||||
</AccordionGroup>
|
||||
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user