Compare commits
25
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6c224425d3 | ||
|
|
6e6f5b8d59 | ||
|
|
dd54e387de | ||
|
|
fd32b980b4 | ||
|
|
21aae599be | ||
|
|
ea6fd3b457 | ||
|
|
8ca9a0f2c0 | ||
|
|
5f77d86caf | ||
|
|
9ef409222f | ||
|
|
c90bdbdce0 | ||
|
|
50bdaaea0c | ||
|
|
38e47ac261 | ||
|
|
d06ea1875c | ||
|
|
c2c3a12838 | ||
|
|
07e58c54ae | ||
|
|
cf3355e2ca | ||
|
|
54328ffd97 | ||
|
|
29fa41558c | ||
|
|
8d45fb3c9a | ||
|
|
760dca6f39 | ||
|
|
74f6dc6f0d | ||
|
|
bcca72e3f0 | ||
|
|
9c2d6222ce | ||
|
|
790e190486 | ||
|
|
d4869d24ec |
@@ -38,6 +38,7 @@ jobs:
|
||||
cli_python: ${{ steps.filter.outputs.cli_python }}
|
||||
cli_node: ${{ steps.filter.outputs.cli_node }}
|
||||
openclaw: ${{ steps.filter.outputs.openclaw }}
|
||||
mem0_plugin: ${{ steps.filter.outputs.mem0_plugin }}
|
||||
opencode_plugin: ${{ steps.filter.outputs.opencode_plugin }}
|
||||
pi_agent_plugin: ${{ steps.filter.outputs.pi_agent_plugin }}
|
||||
n8n_nodes_mem0: ${{ steps.filter.outputs.n8n_nodes_mem0 }}
|
||||
@@ -73,6 +74,11 @@ jobs:
|
||||
- 'integrations/openclaw/**'
|
||||
- '.github/workflows/openclaw-checks.yml'
|
||||
- '.github/workflows/ci-gate.yml'
|
||||
mem0_plugin:
|
||||
- 'integrations/mem0-plugin/**'
|
||||
- '!integrations/mem0-plugin/.opencode-plugin/**'
|
||||
- '.github/workflows/mem0-plugin-checks.yml'
|
||||
- '.github/workflows/ci-gate.yml'
|
||||
opencode_plugin:
|
||||
- 'integrations/mem0-plugin/.opencode-plugin/**'
|
||||
- '.github/workflows/opencode-plugin-checks.yml'
|
||||
@@ -131,6 +137,13 @@ jobs:
|
||||
uses: ./.github/workflows/openclaw-checks.yml
|
||||
secrets: inherit
|
||||
|
||||
mem0-plugin:
|
||||
name: Mem0 Plugin
|
||||
needs: changes
|
||||
if: needs.changes.outputs.mem0_plugin == 'true'
|
||||
uses: ./.github/workflows/mem0-plugin-checks.yml
|
||||
secrets: inherit
|
||||
|
||||
opencode-plugin:
|
||||
name: OpenCode Plugin
|
||||
needs: changes
|
||||
@@ -173,6 +186,7 @@ jobs:
|
||||
- cli-python
|
||||
- cli-node
|
||||
- openclaw
|
||||
- mem0-plugin
|
||||
- opencode-plugin
|
||||
- pi-agent-plugin
|
||||
- n8n-nodes-mem0
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
name: Mem0 Plugin Checks
|
||||
|
||||
# On PRs this is invoked by ci-gate.yml (the single required check);
|
||||
# push-to-main and manual runs remain standalone.
|
||||
#
|
||||
# Covers the Python plugin (scripts/ + tests/). The nested .opencode-plugin/
|
||||
# is a separate package with its own workflow (opencode-plugin-checks.yml).
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'integrations/mem0-plugin/**'
|
||||
- '!integrations/mem0-plugin/.opencode-plugin/**'
|
||||
- '.github/workflows/mem0-plugin-checks.yml'
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
python-version: ["3.10", "3.11", "3.12"]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: Install dependencies
|
||||
working-directory: integrations/mem0-plugin
|
||||
run: |
|
||||
pip install -r requirements.txt
|
||||
pip install pytest
|
||||
|
||||
- name: Verify hook entry points are executable
|
||||
working-directory: integrations/mem0-plugin
|
||||
run: |
|
||||
missing=$(find scripts -name '*.sh' ! -name '_*' ! -perm -u+x -print)
|
||||
if [ -n "$missing" ]; then
|
||||
echo "Hook entry points must be executable:"
|
||||
echo "$missing"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Check hook manifests are valid JSON
|
||||
working-directory: integrations/mem0-plugin
|
||||
run: |
|
||||
for f in plugin.json mcp_config.json hooks.json hooks/*.json; do
|
||||
jq empty "$f" || (echo "Invalid JSON: $f" && exit 1)
|
||||
done
|
||||
|
||||
- name: Run tests
|
||||
working-directory: integrations/mem0-plugin
|
||||
run: pytest -q
|
||||
@@ -406,6 +406,7 @@ PR testing is orchestrated by a single entry point: **`ci-gate.yml` (CI Gate)**
|
||||
| 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 |
|
||||
| Mem0 Plugin | `mem0-plugin-checks.yml` | Push to main (on `integrations/mem0-plugin/`, excluding `.opencode-plugin/`), manual | pytest + hook entry-point exec bits + JSON manifest validation on Python 3.10, 3.11, 3.12 |
|
||||
| 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 |
|
||||
| n8n Node | `n8n-nodes-mem0-checks.yml` | Push to main (on `integrations/n8n-nodes-mem0/`), manual | ESLint (n8n-nodes-base) + tsc build (dist artifact check) on Node 20 |
|
||||
|
||||
+1
-2
@@ -60,9 +60,8 @@ mem0 delete <memory-id>
|
||||
| `mem0 entity` | List or delete entities (users, agents, apps, runs) |
|
||||
| `mem0 event` | Inspect background processing events (bulk deletes, large add jobs) |
|
||||
| `mem0 status` | Verify API connection and display current project |
|
||||
| `mem0 version` | Print the CLI version |
|
||||
|
||||
Run `mem0 <command> --help` for detailed usage on any command.
|
||||
Run `mem0 <command> --help` for detailed usage on any command, or `mem0 --version` to print the CLI version.
|
||||
|
||||
## Agent mode
|
||||
|
||||
|
||||
+13
-1
@@ -207,7 +207,11 @@
|
||||
{ "name": "immutable", "flags": ["--immutable"], "type": "boolean", "default": false, "help": "Prevent future updates." },
|
||||
{ "name": "no_infer", "flags": ["--no-infer"], "type": "boolean", "default": false, "help": "Skip inference, store raw." },
|
||||
{ "name": "expires", "flags": ["--expires"], "type": "string", "help": "Expiration date (YYYY-MM-DD)." },
|
||||
{ "name": "categories", "flags": ["--categories"], "type": "string", "help": "Categories (JSON array or comma-separated)." },
|
||||
{ "name": "categories", "flags": ["--categories"], "type": "string", "help": "Not supported on add, use --custom-categories instead." },
|
||||
{ "name": "custom_instructions", "flags": ["--custom-instructions"], "type": "string", "help": "Custom instructions for fact extraction." },
|
||||
{ "name": "custom_categories", "flags": ["--custom-categories"], "type": "string", "help": "Custom categories as a JSON array of {name: description} objects." },
|
||||
{ "name": "structured_data_schema", "flags": ["--structured-data-schema"], "type": "string", "help": "Schema for structured data extraction, as JSON." },
|
||||
{ "name": "timestamp", "flags": ["--timestamp"], "type": "integer", "help": "Unix timestamp for the memory." },
|
||||
{ "name": "graph", "flags": ["--graph"], "type": "boolean", "default": false, "help": "Enable graph memory extraction.", "panel": "Scope" },
|
||||
{ "name": "no_graph", "flags": ["--no-graph"], "type": "boolean", "default": false, "help": "Disable graph memory extraction.", "panel": "Scope" },
|
||||
{ "name": "output", "flags": ["--output", "-o"], "type": "string", "default": "text", "help": "Output format: text, json, quiet.", "panel": "Output" }
|
||||
@@ -244,6 +248,9 @@
|
||||
{ "name": "keyword", "flags": ["--keyword"], "type": "boolean", "default": false, "help": "Use keyword search.", "panel": "Search" },
|
||||
{ "name": "filter_json", "flags": ["--filter"], "type": "string", "help": "Advanced filter expression (JSON).", "panel": "Search" },
|
||||
{ "name": "fields", "flags": ["--fields"], "type": "string", "help": "Specific fields to return (comma-separated).", "panel": "Search" },
|
||||
{ "name": "show_expired", "flags": ["--show-expired"], "type": "boolean", "default": false, "help": "Include expired memories.", "panel": "Search" },
|
||||
{ "name": "reference_date", "flags": ["--reference-date"], "type": "string", "help": "Reference date for relative queries (YYYY-MM-DD or unix timestamp).", "panel": "Search" },
|
||||
{ "name": "latest_only", "flags": ["--latest-only"], "type": "boolean", "default": false, "help": "Only return the latest version of each memory.", "panel": "Search" },
|
||||
{ "name": "graph", "flags": ["--graph"], "type": "boolean", "default": false, "help": "Enable graph in search.", "panel": "Search" },
|
||||
{ "name": "no_graph", "flags": ["--no-graph"], "type": "boolean", "default": false, "help": "Disable graph in search.", "panel": "Search" },
|
||||
{ "name": "output", "flags": ["--output", "-o"], "type": "string", "default": "text", "help": "Output: text, json, table.", "panel": "Output" }
|
||||
@@ -296,6 +303,8 @@
|
||||
{ "name": "category", "flags": ["--category"], "type": "string", "help": "Filter by category.", "panel": "Filters" },
|
||||
{ "name": "after", "flags": ["--after"], "type": "string", "help": "Created after (YYYY-MM-DD).", "panel": "Filters" },
|
||||
{ "name": "before", "flags": ["--before"], "type": "string", "help": "Created before (YYYY-MM-DD).", "panel": "Filters" },
|
||||
{ "name": "show_expired", "flags": ["--show-expired"], "type": "boolean", "default": false, "help": "Include expired memories.", "panel": "Filters" },
|
||||
{ "name": "latest_only", "flags": ["--latest-only"], "type": "boolean", "default": false, "help": "Only return the latest version of each memory.", "panel": "Filters" },
|
||||
{ "name": "graph", "flags": ["--graph"], "type": "boolean", "default": false, "help": "Enable graph in listing.", "panel": "Filters" },
|
||||
{ "name": "no_graph", "flags": ["--no-graph"], "type": "boolean", "default": false, "help": "Disable graph in listing.", "panel": "Filters" },
|
||||
{ "name": "output", "flags": ["--output", "-o"], "type": "string", "default": "table", "help": "Output: text, json, table.", "panel": "Output" }
|
||||
@@ -329,6 +338,8 @@
|
||||
],
|
||||
"options": [
|
||||
{ "name": "metadata", "flags": ["--metadata", "-m"], "type": "string", "help": "Update metadata (JSON)." },
|
||||
{ "name": "expires", "flags": ["--expires"], "type": "string", "help": "Expiration date (YYYY-MM-DD)." },
|
||||
{ "name": "timestamp", "flags": ["--timestamp"], "type": "integer", "help": "Unix timestamp for the memory." },
|
||||
{ "name": "output", "flags": ["--output", "-o"], "type": "string", "default": "text", "help": "Output: text, json, quiet.", "panel": "Output" }
|
||||
],
|
||||
"apiEndpoint": "update"
|
||||
@@ -356,6 +367,7 @@
|
||||
{ "name": "all", "flags": ["--all"], "type": "boolean", "default": false, "help": "Delete all memories matching scope filters." },
|
||||
{ "name": "entity", "flags": ["--entity"], "type": "boolean", "default": false, "help": "Delete the entity itself and all its memories (cascade)." },
|
||||
{ "name": "project", "flags": ["--project"], "type": "boolean", "default": false, "help": "With --all: delete ALL memories project-wide." },
|
||||
{ "name": "delete_linked", "flags": ["--delete-linked"], "type": "boolean", "default": false, "help": "Also delete memories linked to this memory." },
|
||||
{ "name": "dry_run", "flags": ["--dry-run"], "type": "boolean", "default": false, "help": "Show what would be deleted without deleting." },
|
||||
{ "name": "force", "flags": ["--force"], "type": "boolean", "default": false, "help": "Skip confirmation." },
|
||||
{ "name": "user_id", "flags": ["--user-id", "-u"], "type": "string", "help": "Scope to user.", "panel": "Scope" },
|
||||
|
||||
+2
-8
@@ -232,14 +232,6 @@ Verify your API connection and display the current project.
|
||||
mem0 status
|
||||
```
|
||||
|
||||
### `mem0 version`
|
||||
|
||||
Print the CLI version.
|
||||
|
||||
```bash
|
||||
mem0 version
|
||||
```
|
||||
|
||||
## Agent mode
|
||||
|
||||
Pass `--agent` (or its alias `--json`) as a **global flag** on any command to get output designed for AI agent tool loops:
|
||||
@@ -298,6 +290,8 @@ These flags are available on all commands:
|
||||
| `--base-url` | Override the configured API base URL for this request |
|
||||
| `-o, --output` | Set the output format |
|
||||
|
||||
`mem0 --version` prints the CLI version. It is only valid before a subcommand, not after one.
|
||||
|
||||
## Environment variables
|
||||
|
||||
| Variable | Description |
|
||||
|
||||
@@ -51,7 +51,7 @@ pnpm link --global
|
||||
|
||||
# Now use it like a normal CLI
|
||||
mem0 --help
|
||||
mem0 version
|
||||
mem0 --version
|
||||
```
|
||||
|
||||
> **Warning:** If you also have the Python CLI installed, both register the `mem0` command. The last one linked/installed wins. Unlink with `pnpm unlink --global`.
|
||||
|
||||
@@ -51,8 +51,8 @@
|
||||
"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"
|
||||
"esbuild": ">=0.28.1",
|
||||
"postcss@<8.5.18": ">=8.5.18 <9.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+34
-17
@@ -9,8 +9,8 @@ overrides:
|
||||
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'
|
||||
postcss@<8.5.18: '>=8.5.18 <9.0.0'
|
||||
|
||||
importers:
|
||||
|
||||
@@ -40,7 +40,7 @@ importers:
|
||||
version: 20.19.37
|
||||
tsup:
|
||||
specifier: ^8.0.0
|
||||
version: 8.5.1(postcss@8.5.15)(tsx@4.21.0)(typescript@5.9.3)
|
||||
version: 8.5.1(postcss@8.5.23)(tsx@4.21.0)(typescript@5.9.3)
|
||||
tsx:
|
||||
specifier: ^4.7.0
|
||||
version: 4.21.0
|
||||
@@ -78,24 +78,28 @@ packages:
|
||||
engines: {node: '>=14.21.3'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@biomejs/cli-linux-arm64@1.9.4':
|
||||
resolution: {integrity: sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g==}
|
||||
engines: {node: '>=14.21.3'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@biomejs/cli-linux-x64-musl@1.9.4':
|
||||
resolution: {integrity: sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg==}
|
||||
engines: {node: '>=14.21.3'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@biomejs/cli-linux-x64@1.9.4':
|
||||
resolution: {integrity: sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg==}
|
||||
engines: {node: '>=14.21.3'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@biomejs/cli-win32-arm64@1.9.4':
|
||||
resolution: {integrity: sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg==}
|
||||
@@ -316,66 +320,79 @@ packages:
|
||||
resolution: {integrity: sha512-RzeBwv0B3qtVBWtcuABtSuCzToo2IEAIQrcyB/b2zMvBWVbjo8bZDjACUpnaafaxhTw2W+imQbP2BD1usasK4g==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.60.0':
|
||||
resolution: {integrity: sha512-Sf7zusNI2CIU1HLzuu9Tc5YGAHEZs5Lu7N1ssJG4Tkw6e0MEsN7NdjUDDfGNHy2IU+ENyWT+L2obgWiguWibWQ==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-arm64-gnu@4.60.0':
|
||||
resolution: {integrity: sha512-DX2x7CMcrJzsE91q7/O02IJQ5/aLkVtYFryqCjduJhUfGKG6yJV8hxaw8pZa93lLEpPTP/ohdN4wFz7yp/ry9A==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-arm64-musl@4.60.0':
|
||||
resolution: {integrity: sha512-09EL+yFVbJZlhcQfShpswwRZ0Rg+z/CsSELFCnPt3iK+iqwGsI4zht3secj5vLEs957QvFFXnzAT0FFPIxSrkQ==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-loong64-gnu@4.60.0':
|
||||
resolution: {integrity: sha512-i9IcCMPr3EXm8EQg5jnja0Zyc1iFxJjZWlb4wr7U2Wx/GrddOuEafxRdMPRYVaXjgbhvqalp6np07hN1w9kAKw==}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-loong64-musl@4.60.0':
|
||||
resolution: {integrity: sha512-DGzdJK9kyJ+B78MCkWeGnpXJ91tK/iKA6HwHxF4TAlPIY7GXEvMe8hBFRgdrR9Ly4qebR/7gfUs9y2IoaVEyog==}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-ppc64-gnu@4.60.0':
|
||||
resolution: {integrity: sha512-RwpnLsqC8qbS8z1H1AxBA1H6qknR4YpPR9w2XX0vo2Sz10miu57PkNcnHVaZkbqyw/kUWfKMI73jhmfi9BRMUQ==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-ppc64-musl@4.60.0':
|
||||
resolution: {integrity: sha512-Z8pPf54Ly3aqtdWC3G4rFigZgNvd+qJlOE52fmko3KST9SoGfAdSRCwyoyG05q1HrrAblLbk1/PSIV+80/pxLg==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-gnu@4.60.0':
|
||||
resolution: {integrity: sha512-3a3qQustp3COCGvnP4SvrMHnPQ9d1vzCakQVRTliaz8cIp/wULGjiGpbcqrkv0WrHTEp8bQD/B3HBjzujVWLOA==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-musl@4.60.0':
|
||||
resolution: {integrity: sha512-pjZDsVH/1VsghMJ2/kAaxt6dL0psT6ZexQVrijczOf+PeP2BUqTHYejk3l6TlPRydggINOeNRhvpLa0AYpCWSQ==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-s390x-gnu@4.60.0':
|
||||
resolution: {integrity: sha512-3ObQs0BhvPgiUVZrN7gqCSvmFuMWvWvsjG5ayJ3Lraqv+2KhOsp+pUbigqbeWqueGIsnn+09HBw27rJ+gYK4VQ==}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-x64-gnu@4.60.0':
|
||||
resolution: {integrity: sha512-EtylprDtQPdS5rXvAayrNDYoJhIz1/vzN2fEubo3yLE7tfAw+948dO0g4M0vkTVFhKojnF+n6C8bDNe+gDRdTg==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-x64-musl@4.60.0':
|
||||
resolution: {integrity: sha512-k09oiRCi/bHU9UVFqD17r3eJR9bn03TyKraCrlz5ULFJGdJGi7VOmm9jl44vOJvRJ6P7WuBi/s2A97LxxHGIdw==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-openbsd-x64@4.60.0':
|
||||
resolution: {integrity: sha512-1o/0/pIhozoSaDJoDcec+IVLbnRtQmHwPV730+AOD29lHEEo4F5BEUB24H0OBdhbBBDwIOSuf7vgg0Ywxdfiiw==}
|
||||
@@ -653,8 +670,8 @@ packages:
|
||||
mz@2.7.0:
|
||||
resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
|
||||
|
||||
nanoid@3.3.12:
|
||||
resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==}
|
||||
nanoid@3.3.16:
|
||||
resolution: {integrity: sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==}
|
||||
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
||||
hasBin: true
|
||||
|
||||
@@ -695,7 +712,7 @@ packages:
|
||||
engines: {node: '>= 18'}
|
||||
peerDependencies:
|
||||
jiti: '>=1.21.0'
|
||||
postcss: '>=8.5.10'
|
||||
postcss: '>=8.5.18 <9.0.0'
|
||||
tsx: ^4.8.1
|
||||
yaml: ^2.4.2
|
||||
peerDependenciesMeta:
|
||||
@@ -708,8 +725,8 @@ packages:
|
||||
yaml:
|
||||
optional: true
|
||||
|
||||
postcss@8.5.15:
|
||||
resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==}
|
||||
postcss@8.5.23:
|
||||
resolution: {integrity: sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==}
|
||||
engines: {node: ^10 || ^12 || >=14}
|
||||
|
||||
readdirp@4.1.2:
|
||||
@@ -821,7 +838,7 @@ packages:
|
||||
peerDependencies:
|
||||
'@microsoft/api-extractor': ^7.36.0
|
||||
'@swc/core': ^1
|
||||
postcss: '>=8.5.10'
|
||||
postcss: '>=8.5.18 <9.0.0'
|
||||
typescript: '>=4.5.0'
|
||||
peerDependenciesMeta:
|
||||
'@microsoft/api-extractor':
|
||||
@@ -1388,7 +1405,7 @@ snapshots:
|
||||
object-assign: 4.1.1
|
||||
thenify-all: 1.6.0
|
||||
|
||||
nanoid@3.3.12: {}
|
||||
nanoid@3.3.16: {}
|
||||
|
||||
object-assign@4.1.1: {}
|
||||
|
||||
@@ -1424,16 +1441,16 @@ snapshots:
|
||||
mlly: 1.8.2
|
||||
pathe: 2.0.3
|
||||
|
||||
postcss-load-config@6.0.1(postcss@8.5.15)(tsx@4.21.0):
|
||||
postcss-load-config@6.0.1(postcss@8.5.23)(tsx@4.21.0):
|
||||
dependencies:
|
||||
lilconfig: 3.1.3
|
||||
optionalDependencies:
|
||||
postcss: 8.5.15
|
||||
postcss: 8.5.23
|
||||
tsx: 4.21.0
|
||||
|
||||
postcss@8.5.15:
|
||||
postcss@8.5.23:
|
||||
dependencies:
|
||||
nanoid: 3.3.12
|
||||
nanoid: 3.3.16
|
||||
picocolors: 1.1.1
|
||||
source-map-js: 1.2.1
|
||||
|
||||
@@ -1554,7 +1571,7 @@ snapshots:
|
||||
|
||||
ts-interface-checker@0.1.13: {}
|
||||
|
||||
tsup@8.5.1(postcss@8.5.15)(tsx@4.21.0)(typescript@5.9.3):
|
||||
tsup@8.5.1(postcss@8.5.23)(tsx@4.21.0)(typescript@5.9.3):
|
||||
dependencies:
|
||||
bundle-require: 5.1.0(esbuild@0.28.1)
|
||||
cac: 6.7.14
|
||||
@@ -1565,7 +1582,7 @@ snapshots:
|
||||
fix-dts-default-cjs-exports: 1.0.1
|
||||
joycon: 3.1.1
|
||||
picocolors: 1.1.1
|
||||
postcss-load-config: 6.0.1(postcss@8.5.15)(tsx@4.21.0)
|
||||
postcss-load-config: 6.0.1(postcss@8.5.23)(tsx@4.21.0)
|
||||
resolve-from: 5.0.0
|
||||
rollup: 4.60.0
|
||||
source-map: 0.7.6
|
||||
@@ -1574,7 +1591,7 @@ snapshots:
|
||||
tinyglobby: 0.2.15
|
||||
tree-kill: 1.2.2
|
||||
optionalDependencies:
|
||||
postcss: 8.5.15
|
||||
postcss: 8.5.23
|
||||
typescript: 5.9.3
|
||||
transitivePeerDependencies:
|
||||
- jiti
|
||||
@@ -1602,7 +1619,7 @@ snapshots:
|
||||
esbuild: 0.28.1
|
||||
fdir: 6.5.0(picomatch@4.0.4)
|
||||
picomatch: 4.0.4
|
||||
postcss: 8.5.15
|
||||
postcss: 8.5.23
|
||||
rollup: 4.60.0
|
||||
tinyglobby: 0.2.15
|
||||
optionalDependencies:
|
||||
|
||||
@@ -10,5 +10,5 @@ overrides:
|
||||
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"
|
||||
"postcss@<8.5.18": ">=8.5.18 <9.0.0"
|
||||
|
||||
@@ -14,7 +14,10 @@ export interface AddOptions {
|
||||
immutable?: boolean;
|
||||
infer?: boolean;
|
||||
expires?: string;
|
||||
categories?: string[];
|
||||
customInstructions?: string;
|
||||
customCategories?: Record<string, string>[];
|
||||
structuredDataSchema?: Record<string, unknown>;
|
||||
timestamp?: number;
|
||||
}
|
||||
|
||||
export interface SearchOptions {
|
||||
@@ -28,6 +31,9 @@ export interface SearchOptions {
|
||||
keyword?: boolean;
|
||||
filters?: Record<string, unknown>;
|
||||
fields?: string[];
|
||||
showExpired?: boolean;
|
||||
referenceDate?: string | number;
|
||||
latestOnly?: boolean;
|
||||
}
|
||||
|
||||
export interface ListOptions {
|
||||
@@ -40,6 +46,8 @@ export interface ListOptions {
|
||||
category?: string;
|
||||
after?: string;
|
||||
before?: string;
|
||||
showExpired?: boolean;
|
||||
latestOnly?: boolean;
|
||||
}
|
||||
|
||||
export interface DeleteOptions {
|
||||
@@ -48,6 +56,12 @@ export interface DeleteOptions {
|
||||
agentId?: string;
|
||||
appId?: string;
|
||||
runId?: string;
|
||||
deleteLinked?: boolean;
|
||||
}
|
||||
|
||||
export interface UpdateOptions {
|
||||
expirationDate?: string;
|
||||
timestamp?: number;
|
||||
}
|
||||
|
||||
export interface EntityIds {
|
||||
@@ -77,6 +91,7 @@ export interface Backend {
|
||||
memoryId: string,
|
||||
content?: string,
|
||||
metadata?: Record<string, unknown>,
|
||||
opts?: UpdateOptions,
|
||||
): Promise<Record<string, unknown>>;
|
||||
|
||||
delete(
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
type ListOptions,
|
||||
NotFoundError,
|
||||
type SearchOptions,
|
||||
type UpdateOptions,
|
||||
} from "./base.js";
|
||||
|
||||
function encodePathSegment(value: unknown): string {
|
||||
@@ -150,7 +151,13 @@ export class PlatformBackend implements Backend {
|
||||
if (opts.immutable) payload.immutable = true;
|
||||
if (opts.infer === false) payload.infer = false;
|
||||
if (opts.expires) payload.expiration_date = opts.expires;
|
||||
if (opts.categories) payload.categories = opts.categories;
|
||||
if (opts.customInstructions)
|
||||
payload.custom_instructions = opts.customInstructions;
|
||||
if (opts.customCategories)
|
||||
payload.custom_categories = opts.customCategories;
|
||||
if (opts.structuredDataSchema)
|
||||
payload.structured_data_schema = opts.structuredDataSchema;
|
||||
if (opts.timestamp !== undefined) payload.timestamp = opts.timestamp;
|
||||
payload.source = "CLI";
|
||||
|
||||
return (await this._request("POST", "/v3/memories/add/", {
|
||||
@@ -211,6 +218,10 @@ export class PlatformBackend implements Backend {
|
||||
if (opts.rerank) payload.rerank = true;
|
||||
if (opts.keyword) payload.keyword_search = true;
|
||||
if (opts.fields) payload.fields = opts.fields;
|
||||
if (opts.showExpired) payload.show_expired = true;
|
||||
if (opts.referenceDate !== undefined)
|
||||
payload.reference_date = opts.referenceDate;
|
||||
if (opts.latestOnly) payload.latest_only = true;
|
||||
payload.source = "CLI";
|
||||
|
||||
const result = (await this._request("POST", "/v3/memories/search/", {
|
||||
@@ -265,6 +276,8 @@ export class PlatformBackend implements Backend {
|
||||
extraFilters: Object.keys(extra).length > 0 ? extra : undefined,
|
||||
});
|
||||
if (apiFilters) payload.filters = apiFilters;
|
||||
if (opts.showExpired) payload.show_expired = true;
|
||||
if (opts.latestOnly) payload.latest_only = true;
|
||||
payload.source = "CLI";
|
||||
|
||||
const result = (await this._request("POST", "/v3/memories/", {
|
||||
@@ -280,10 +293,13 @@ export class PlatformBackend implements Backend {
|
||||
memoryId: string,
|
||||
content?: string,
|
||||
metadata?: Record<string, unknown>,
|
||||
opts: UpdateOptions = {},
|
||||
): Promise<Record<string, unknown>> {
|
||||
const payload: Record<string, unknown> = {};
|
||||
if (content) payload.text = content;
|
||||
if (metadata) payload.metadata = metadata;
|
||||
if (opts.expirationDate) payload.expiration_date = opts.expirationDate;
|
||||
if (opts.timestamp !== undefined) payload.timestamp = opts.timestamp;
|
||||
payload.source = "CLI";
|
||||
return (await this._request(
|
||||
"PUT",
|
||||
@@ -309,12 +325,12 @@ export class PlatformBackend implements Backend {
|
||||
})) as Record<string, unknown>;
|
||||
}
|
||||
if (memoryId) {
|
||||
const params: Record<string, string> = { source: "CLI" };
|
||||
if (opts.deleteLinked) params.delete_linked = "true";
|
||||
return (await this._request(
|
||||
"DELETE",
|
||||
`/v1/memories/${encodePathSegment(memoryId)}/`,
|
||||
{
|
||||
params: { source: "CLI" },
|
||||
},
|
||||
{ params },
|
||||
)) as Record<string, unknown>;
|
||||
}
|
||||
throw new Error("Either memoryId or --all is required");
|
||||
|
||||
@@ -21,16 +21,19 @@ import {
|
||||
formatSingleMemory,
|
||||
printResultSummary,
|
||||
} from "../output.js";
|
||||
import { isAgentMode, setCurrentCommand } from "../state.js";
|
||||
import { isAgentMode, setCurrentCommand, stdinIsPiped } from "../state.js";
|
||||
|
||||
/** True only when stdin is an actual pipe or file redirect — never in agent mode. */
|
||||
function _stdinIsPiped(): boolean {
|
||||
if (isAgentMode()) return false;
|
||||
try {
|
||||
const stat = fs.fstatSync(0);
|
||||
return stat.isFIFO() || stat.isFile();
|
||||
} catch {
|
||||
return false;
|
||||
/** Exit 1 if value is not a future YYYY-MM-DD date. */
|
||||
function _validateExpires(value: string): void {
|
||||
if (!/^\d{4}-\d{2}-\d{2}$/.test(value)) {
|
||||
printError(
|
||||
"Invalid date format for --expires. Use YYYY-MM-DD (e.g. 2025-12-31).",
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
if (new Date(value) <= new Date()) {
|
||||
printError("--expires date must be in the future.");
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,10 +52,22 @@ export async function cmdAdd(
|
||||
infer?: boolean;
|
||||
expires?: string;
|
||||
categories?: string;
|
||||
customInstructions?: string;
|
||||
customCategories?: string;
|
||||
structuredDataSchema?: string;
|
||||
timestamp?: number;
|
||||
output: string;
|
||||
},
|
||||
): Promise<void> {
|
||||
setCurrentCommand("add");
|
||||
|
||||
if (opts.categories) {
|
||||
printError(
|
||||
"--categories is not supported on add. Use --custom-categories instead.",
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
let msgs: Record<string, unknown>[] | undefined;
|
||||
let content = text;
|
||||
|
||||
@@ -78,7 +93,7 @@ export async function cmdAdd(
|
||||
}
|
||||
}
|
||||
// Read from stdin only if stdin is an actual pipe or file redirect
|
||||
else if (!content && _stdinIsPiped()) {
|
||||
else if (!content && stdinIsPiped()) {
|
||||
content = fs.readFileSync(0, "utf-8").trim();
|
||||
}
|
||||
|
||||
@@ -93,20 +108,6 @@ export async function cmdAdd(
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Validate --expires
|
||||
if (opts.expires) {
|
||||
if (!/^\d{4}-\d{2}-\d{2}$/.test(opts.expires)) {
|
||||
printError(
|
||||
"Invalid date format for --expires. Use YYYY-MM-DD (e.g. 2025-12-31).",
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
if (new Date(opts.expires) <= new Date()) {
|
||||
printError("--expires date must be in the future.");
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
let meta: Record<string, unknown> | undefined;
|
||||
if (opts.metadata) {
|
||||
try {
|
||||
@@ -117,15 +118,28 @@ export async function cmdAdd(
|
||||
}
|
||||
}
|
||||
|
||||
let cats: string[] | undefined;
|
||||
if (opts.categories) {
|
||||
let customCats: Record<string, string>[] | undefined;
|
||||
if (opts.customCategories) {
|
||||
try {
|
||||
cats = JSON.parse(opts.categories);
|
||||
customCats = JSON.parse(opts.customCategories);
|
||||
} catch {
|
||||
cats = opts.categories.split(",").map((c) => c.trim());
|
||||
printError("Invalid JSON in --custom-categories.");
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
let schema: Record<string, unknown> | undefined;
|
||||
if (opts.structuredDataSchema) {
|
||||
try {
|
||||
schema = JSON.parse(opts.structuredDataSchema);
|
||||
} catch {
|
||||
printError("Invalid JSON in --structured-data-schema.");
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.expires) _validateExpires(opts.expires);
|
||||
|
||||
let result: Record<string, unknown>;
|
||||
try {
|
||||
result = await timedStatus("Adding memory...", async () => {
|
||||
@@ -138,7 +152,10 @@ export async function cmdAdd(
|
||||
immutable: opts.immutable,
|
||||
infer: opts.infer !== false,
|
||||
expires: opts.expires,
|
||||
categories: cats,
|
||||
customInstructions: opts.customInstructions,
|
||||
customCategories: customCats,
|
||||
structuredDataSchema: schema,
|
||||
timestamp: opts.timestamp,
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
@@ -223,6 +240,9 @@ export async function cmdSearch(
|
||||
keyword: boolean;
|
||||
filterJson?: string;
|
||||
fields?: string;
|
||||
showExpired?: boolean;
|
||||
referenceDate?: string;
|
||||
latestOnly?: boolean;
|
||||
output: string;
|
||||
},
|
||||
): Promise<void> {
|
||||
@@ -271,6 +291,9 @@ export async function cmdSearch(
|
||||
keyword: opts.keyword,
|
||||
filters,
|
||||
fields: fieldList,
|
||||
showExpired: opts.showExpired,
|
||||
referenceDate: opts.referenceDate,
|
||||
latestOnly: opts.latestOnly,
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
@@ -364,6 +387,8 @@ export async function cmdList(
|
||||
category?: string;
|
||||
after?: string;
|
||||
before?: string;
|
||||
showExpired?: boolean;
|
||||
latestOnly?: boolean;
|
||||
output: string;
|
||||
},
|
||||
): Promise<void> {
|
||||
@@ -391,6 +416,8 @@ export async function cmdList(
|
||||
category: opts.category,
|
||||
after: opts.after,
|
||||
before: opts.before,
|
||||
showExpired: opts.showExpired,
|
||||
latestOnly: opts.latestOnly,
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
@@ -450,7 +477,12 @@ export async function cmdUpdate(
|
||||
backend: Backend,
|
||||
memoryId: string,
|
||||
text: string | undefined,
|
||||
opts: { metadata?: string; output: string },
|
||||
opts: {
|
||||
metadata?: string;
|
||||
expires?: string;
|
||||
timestamp?: number;
|
||||
output: string;
|
||||
},
|
||||
): Promise<void> {
|
||||
setCurrentCommand("update");
|
||||
let meta: Record<string, unknown> | undefined;
|
||||
@@ -463,11 +495,16 @@ export async function cmdUpdate(
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.expires) _validateExpires(opts.expires);
|
||||
|
||||
const start = performance.now();
|
||||
let result: Record<string, unknown>;
|
||||
try {
|
||||
result = await timedStatus("Updating memory...", async () => {
|
||||
return backend.update(memoryId, text, meta);
|
||||
return backend.update(memoryId, text, meta, {
|
||||
expirationDate: opts.expires,
|
||||
timestamp: opts.timestamp,
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
printError(e instanceof Error ? e.message : String(e));
|
||||
@@ -493,7 +530,12 @@ export async function cmdUpdate(
|
||||
export async function cmdDelete(
|
||||
backend: Backend,
|
||||
memoryId: string,
|
||||
opts: { output: string; dryRun?: boolean; force?: boolean },
|
||||
opts: {
|
||||
output: string;
|
||||
dryRun?: boolean;
|
||||
force?: boolean;
|
||||
deleteLinked?: boolean;
|
||||
},
|
||||
): Promise<void> {
|
||||
setCurrentCommand("delete");
|
||||
if (opts.dryRun) {
|
||||
@@ -514,7 +556,7 @@ export async function cmdDelete(
|
||||
let result: Record<string, unknown>;
|
||||
try {
|
||||
result = await timedStatus("Deleting...", async () => {
|
||||
return backend.delete(memoryId);
|
||||
return backend.delete(memoryId, { deleteLinked: opts.deleteLinked });
|
||||
});
|
||||
} catch (e) {
|
||||
printError(e instanceof Error ? e.message : String(e));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Utility commands: status, version, import.
|
||||
* Utility commands: status, import.
|
||||
*/
|
||||
|
||||
import fs from "node:fs";
|
||||
@@ -8,7 +8,6 @@ import type { Backend } from "../backend/base.js";
|
||||
import { colors, printError, printSuccess, timedStatus } from "../branding.js";
|
||||
import { formatAgentEnvelope, formatJsonEnvelope } from "../output.js";
|
||||
import { setCurrentCommand } from "../state.js";
|
||||
import { CLI_VERSION } from "../version.js";
|
||||
|
||||
const { brand, dim, success, error: errorColor } = colors;
|
||||
|
||||
@@ -82,10 +81,6 @@ export async function cmdStatus(
|
||||
console.log();
|
||||
}
|
||||
|
||||
export function cmdVersion(): void {
|
||||
console.log(` ${brand("◆ Mem0")} CLI v${CLI_VERSION}`);
|
||||
}
|
||||
|
||||
export async function cmdImport(
|
||||
backend: Backend,
|
||||
filePath: string,
|
||||
|
||||
+57
-5
@@ -17,6 +17,7 @@ import {
|
||||
isAgentMode,
|
||||
setAgentMode,
|
||||
setCurrentCommand,
|
||||
stdinIsPiped,
|
||||
takeNotice,
|
||||
} from "./state.js";
|
||||
import { captureEvent } from "./telemetry.js";
|
||||
@@ -319,7 +320,25 @@ program
|
||||
.option("--immutable", "Prevent future updates.", false)
|
||||
.option("--no-infer", "Skip inference, store raw.")
|
||||
.option("--expires <date>", "Expiration date (YYYY-MM-DD).")
|
||||
.option("--categories <value>", "Categories (JSON array or comma-separated).")
|
||||
.option(
|
||||
"--categories <value>",
|
||||
"Not supported on add, use --custom-categories instead.",
|
||||
)
|
||||
.option(
|
||||
"--custom-instructions <text>",
|
||||
"Custom instructions for fact extraction.",
|
||||
)
|
||||
.option(
|
||||
"--custom-categories <json>",
|
||||
"Custom categories as a JSON array of {name: description} objects.",
|
||||
)
|
||||
.option(
|
||||
"--structured-data-schema <json>",
|
||||
"Schema for structured data extraction, as JSON.",
|
||||
)
|
||||
.option("--timestamp <unix>", "Unix timestamp for the memory.", (v) =>
|
||||
Number.parseInt(v),
|
||||
)
|
||||
.option("-o, --output <format>", "Output format: text, json, quiet.", "text")
|
||||
.option("--api-key <key>", "Override API key.")
|
||||
.option("--base-url <url>", "Override API base URL.")
|
||||
@@ -366,6 +385,16 @@ program
|
||||
.option("--keyword", "Use keyword search.", false)
|
||||
.option("--filter <json>", "Advanced filter expression (JSON).")
|
||||
.option("--fields <list>", "Specific fields to return (comma-separated).")
|
||||
.option("--show-expired", "Include expired memories.", false)
|
||||
.option(
|
||||
"--reference-date <date>",
|
||||
"Reference date for relative queries (YYYY-MM-DD or unix timestamp).",
|
||||
)
|
||||
.option(
|
||||
"--latest-only",
|
||||
"Only return the latest version of each memory.",
|
||||
false,
|
||||
)
|
||||
.option("-o, --output <format>", "Output: text, json, table.", "text")
|
||||
.option("--api-key <key>", "Override API key.")
|
||||
.option("--base-url <url>", "Override API base URL.")
|
||||
@@ -375,7 +404,7 @@ program
|
||||
)
|
||||
.action(async (query, opts) => {
|
||||
let resolvedQuery = query;
|
||||
if (!resolvedQuery && !process.stdin.isTTY) {
|
||||
if (!resolvedQuery && stdinIsPiped()) {
|
||||
resolvedQuery = fs.readFileSync(0, "utf-8").trim();
|
||||
}
|
||||
if (!resolvedQuery) {
|
||||
@@ -398,6 +427,9 @@ program
|
||||
keyword: opts.keyword,
|
||||
filterJson: opts.filter,
|
||||
fields: opts.fields,
|
||||
showExpired: opts.showExpired,
|
||||
referenceDate: opts.referenceDate,
|
||||
latestOnly: opts.latestOnly,
|
||||
output,
|
||||
});
|
||||
});
|
||||
@@ -441,6 +473,12 @@ program
|
||||
.option("--category <name>", "Filter by category.")
|
||||
.option("--after <date>", "Created after (YYYY-MM-DD).")
|
||||
.option("--before <date>", "Created before (YYYY-MM-DD).")
|
||||
.option("--show-expired", "Include expired memories.", false)
|
||||
.option(
|
||||
"--latest-only",
|
||||
"Only return the latest version of each memory.",
|
||||
false,
|
||||
)
|
||||
.option("-o, --output <format>", "Output: text, json, table.", "table")
|
||||
.option("--api-key <key>", "Override API key.")
|
||||
.option("--base-url <url>", "Override API base URL.")
|
||||
@@ -464,6 +502,8 @@ program
|
||||
category: opts.category,
|
||||
after: opts.after,
|
||||
before: opts.before,
|
||||
showExpired: opts.showExpired,
|
||||
latestOnly: opts.latestOnly,
|
||||
output,
|
||||
});
|
||||
});
|
||||
@@ -474,6 +514,10 @@ program
|
||||
.command("update <memoryId> [text]")
|
||||
.description("Update a memory's text or metadata.")
|
||||
.option("-m, --metadata <json>", "Update metadata (JSON).")
|
||||
.option("--expires <date>", "Expiration date (YYYY-MM-DD).")
|
||||
.option("--timestamp <unix>", "Unix timestamp for the memory.", (v) =>
|
||||
Number.parseInt(v),
|
||||
)
|
||||
.option("-o, --output <format>", "Output: text, json, quiet.", "text")
|
||||
.option("--api-key <key>", "Override API key.")
|
||||
.option("--base-url <url>", "Override API base URL.")
|
||||
@@ -483,7 +527,7 @@ program
|
||||
)
|
||||
.action(async (memoryId, text, opts) => {
|
||||
let resolvedText = text;
|
||||
if (!resolvedText && !opts.metadata && !process.stdin.isTTY) {
|
||||
if (!resolvedText && stdinIsPiped()) {
|
||||
resolvedText = fs.readFileSync(0, "utf-8").trim();
|
||||
}
|
||||
const { cmdUpdate } = await import("./commands/memory.js");
|
||||
@@ -492,6 +536,8 @@ program
|
||||
const output = isAgent ? "agent" : opts.output;
|
||||
await cmdUpdate(backend, memoryId, resolvedText, {
|
||||
metadata: opts.metadata,
|
||||
expires: opts.expires,
|
||||
timestamp: opts.timestamp,
|
||||
output,
|
||||
});
|
||||
});
|
||||
@@ -510,6 +556,11 @@ program
|
||||
.option("--project", "With --all: delete ALL memories project-wide.", false)
|
||||
.option("--dry-run", "Show what would be deleted without deleting.", false)
|
||||
.option("--force", "Skip confirmation.", false)
|
||||
.option(
|
||||
"--delete-linked",
|
||||
"Also delete memories linked to this memory.",
|
||||
false,
|
||||
)
|
||||
.option("-u, --user-id <id>", "Scope to user.")
|
||||
.option("--agent-id <id>", "Scope to agent.")
|
||||
.option("--app-id <id>", "Scope to app.")
|
||||
@@ -563,6 +614,7 @@ program
|
||||
output,
|
||||
dryRun: opts.dryRun,
|
||||
force: opts.force,
|
||||
deleteLinked: opts.deleteLinked,
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -806,8 +858,8 @@ program
|
||||
.addHelpText("after", "\nExamples:\n $ mem0 help\n $ mem0 help --json")
|
||||
.action((opts) => {
|
||||
// opts.json is set when `mem0 help --json` is used (subcommand flag).
|
||||
// program.opts().json is set when the root --json global flag was used first.
|
||||
if (opts.json || program.opts().json) {
|
||||
// program.opts().json/.agent is set when a root global flag was used first.
|
||||
if (opts.json || program.opts().json || program.opts().agent) {
|
||||
// Load spec from parent directory
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const specPath = path.join(__dirname, "..", "..", "cli-spec.json");
|
||||
|
||||
+17
-3
@@ -282,11 +282,24 @@ export function sanitizeAgentData(command: string, data: unknown): unknown {
|
||||
}
|
||||
case "search":
|
||||
return (data as Record<string, unknown>[]).map((r) =>
|
||||
pick(r, ["id", "memory", "score", "created_at", "categories"]),
|
||||
pick(r, [
|
||||
"id",
|
||||
"memory",
|
||||
"score",
|
||||
"created_at",
|
||||
"categories",
|
||||
"expiration_date",
|
||||
]),
|
||||
);
|
||||
case "list":
|
||||
return (data as Record<string, unknown>[]).map((r) =>
|
||||
pick(r, ["id", "memory", "created_at", "categories"]),
|
||||
pick(r, [
|
||||
"id",
|
||||
"memory",
|
||||
"created_at",
|
||||
"categories",
|
||||
"expiration_date",
|
||||
]),
|
||||
);
|
||||
case "get": {
|
||||
const r = data as Record<string, unknown>;
|
||||
@@ -297,11 +310,12 @@ export function sanitizeAgentData(command: string, data: unknown): unknown {
|
||||
"updated_at",
|
||||
"categories",
|
||||
"metadata",
|
||||
"expiration_date",
|
||||
]);
|
||||
}
|
||||
case "update": {
|
||||
const r = data as Record<string, unknown>;
|
||||
return pick(r, ["id", "memory"]);
|
||||
return pick(r, ["id", "memory", "expiration_date"]);
|
||||
}
|
||||
case "delete":
|
||||
case "delete-all":
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
* read by commands and branding functions.
|
||||
*/
|
||||
|
||||
import fs from "node:fs";
|
||||
|
||||
let _agentMode = false;
|
||||
let _currentCommand = "";
|
||||
let _pendingNotice = "";
|
||||
@@ -38,3 +40,14 @@ export function takeNotice(): string {
|
||||
_pendingNotice = "";
|
||||
return msg;
|
||||
}
|
||||
|
||||
/** True only when stdin is an actual pipe or file redirect (never in agent mode). */
|
||||
export function stdinIsPiped(): boolean {
|
||||
if (isAgentMode()) return false;
|
||||
try {
|
||||
const stat = fs.fstatSync(0);
|
||||
return stat.isFIFO() || stat.isFile();
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,15 +44,25 @@ describe("CLI Integration — help and version", () => {
|
||||
expect(result.stdout).toContain("search");
|
||||
});
|
||||
|
||||
it("help --json produces valid JSON", () => {
|
||||
const result = run(["help", "--json"]);
|
||||
expect(result.exitCode).toBe(0);
|
||||
const parsed = JSON.parse(result.stdout);
|
||||
// spec may have cli.name or top-level name
|
||||
const name = parsed.name ?? parsed.cli?.name;
|
||||
expect(name).toBe("mem0");
|
||||
it("prints the version with --version, and has no version subcommand", () => {
|
||||
const flag = run(["--version"]);
|
||||
expect(flag.exitCode).toBe(0);
|
||||
expect(flag.stdout).toContain("Mem0");
|
||||
expect(run(["version"]).exitCode).not.toBe(0);
|
||||
});
|
||||
|
||||
it.each([["help", "--json"], ["--json", "help"], ["--agent", "help"]])(
|
||||
"%s %s produces valid JSON",
|
||||
(...args) => {
|
||||
const result = run(args);
|
||||
expect(result.exitCode).toBe(0);
|
||||
const parsed = JSON.parse(result.stdout);
|
||||
// spec may have cli.name or top-level name
|
||||
const name = parsed.name ?? parsed.cli?.name;
|
||||
expect(name).toBe("mem0");
|
||||
},
|
||||
);
|
||||
|
||||
it("shows add help", () => {
|
||||
const result = run(["add", "--help"]);
|
||||
expect(result.exitCode).toBe(0);
|
||||
|
||||
+580
-373
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,163 @@
|
||||
/**
|
||||
* Drift test: every documented v3 add/search/list param must be reachable from the Node CLI.
|
||||
*/
|
||||
|
||||
import { execSync } from "node:child_process";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
const OPENAPI_PATH = path.join(
|
||||
__dirname,
|
||||
"..",
|
||||
"..",
|
||||
"..",
|
||||
"docs",
|
||||
"openapi.json",
|
||||
);
|
||||
|
||||
const KNOWN_UNSURFACED: Record<string, Record<string, string>> = {
|
||||
"/v3/memories/add/": {
|
||||
includes: "extraction hint, no CLI flag yet",
|
||||
excludes: "extraction hint, no CLI flag yet",
|
||||
enable_graph: "graph memory toggle, no CLI flag yet",
|
||||
output_format: "response envelope is pinned by the CLI",
|
||||
prompt_profile_id: "no CLI flag yet",
|
||||
temporal_reasoning: "no CLI flag yet",
|
||||
timezone: "no CLI flag yet",
|
||||
observation_datetime: "no CLI flag yet, --timestamp backdates instead",
|
||||
observation_date: "no CLI flag yet, --timestamp backdates instead",
|
||||
},
|
||||
"/v3/memories/search/": {
|
||||
categories: "expressible through --filter",
|
||||
metadata: "expressible through --filter",
|
||||
},
|
||||
"/v3/memories/": {
|
||||
start_date: "covered by --after via filters.created_at.gte",
|
||||
end_date: "covered by --before via filters.created_at.lte",
|
||||
categories: "covered by --category via filters.categories",
|
||||
fields: "no CLI flag yet",
|
||||
keywords: "no CLI flag yet",
|
||||
},
|
||||
};
|
||||
|
||||
const ADD_MAPPING: Record<string, string[]> = {
|
||||
messages: ["--messages", "--file", "text"],
|
||||
user_id: ["--user-id"],
|
||||
agent_id: ["--agent-id"],
|
||||
app_id: ["--app-id"],
|
||||
run_id: ["--run-id"],
|
||||
metadata: ["--metadata"],
|
||||
expiration_date: ["--expires"],
|
||||
custom_instructions: ["--custom-instructions"],
|
||||
custom_categories: ["--custom-categories"],
|
||||
infer: ["--no-infer"],
|
||||
immutable: ["--immutable"],
|
||||
structured_data_schema: ["--structured-data-schema"],
|
||||
timestamp: ["--timestamp"],
|
||||
};
|
||||
|
||||
const SEARCH_MAPPING: Record<string, string[]> = {
|
||||
query: ["query"],
|
||||
filters: ["--filter", "--user-id", "--agent-id", "--run-id"],
|
||||
show_expired: ["--show-expired"],
|
||||
top_k: ["--top-k"],
|
||||
threshold: ["--threshold"],
|
||||
rerank: ["--rerank"],
|
||||
reference_date: ["--reference-date"],
|
||||
fields: ["--fields"],
|
||||
};
|
||||
|
||||
const LIST_MAPPING: Record<string, string[]> = {
|
||||
filters: [
|
||||
"--user-id",
|
||||
"--agent-id",
|
||||
"--run-id",
|
||||
"--category",
|
||||
"--after",
|
||||
"--before",
|
||||
],
|
||||
show_expired: ["--show-expired"],
|
||||
page: ["--page"],
|
||||
page_size: ["--page-size"],
|
||||
};
|
||||
|
||||
function documentedFields(endpoint: string): string[] {
|
||||
const spec = JSON.parse(fs.readFileSync(OPENAPI_PATH, "utf-8"));
|
||||
const schema =
|
||||
spec.paths[endpoint].post.requestBody.content["application/json"].schema;
|
||||
return Object.keys(schema.properties);
|
||||
}
|
||||
|
||||
function helpText(command: string): string {
|
||||
return execSync(`npx tsx src/index.ts ${command} --help`, {
|
||||
cwd: path.join(__dirname, ".."),
|
||||
encoding: "utf-8",
|
||||
timeout: 15000,
|
||||
});
|
||||
}
|
||||
|
||||
function assertAllReachable(
|
||||
endpoint: string,
|
||||
mapping: Record<string, string[]>,
|
||||
command: string,
|
||||
) {
|
||||
const documented = documentedFields(endpoint);
|
||||
const help = helpText(command);
|
||||
for (const field of documented) {
|
||||
if (KNOWN_UNSURFACED[endpoint]?.[field]) continue;
|
||||
const candidates = mapping[field];
|
||||
expect(
|
||||
candidates,
|
||||
`${endpoint}: documented field "${field}" has no mapping entry for command "${command}"`,
|
||||
).toBeDefined();
|
||||
const reachable = candidates.some((flag) =>
|
||||
flag.startsWith("--") ? help.includes(flag) : true,
|
||||
);
|
||||
expect(
|
||||
reachable,
|
||||
`${endpoint}: documented field "${field}" not reachable via any of ${JSON.stringify(candidates)} on command "${command}"`,
|
||||
).toBe(true);
|
||||
}
|
||||
}
|
||||
|
||||
describe("Option parity: Node CLI reachability of documented v3 params", () => {
|
||||
it("add covers documented fields", () => {
|
||||
assertAllReachable("/v3/memories/add/", ADD_MAPPING, "add");
|
||||
});
|
||||
|
||||
it("search covers documented fields", () => {
|
||||
assertAllReachable("/v3/memories/search/", SEARCH_MAPPING, "search");
|
||||
});
|
||||
|
||||
it("list covers documented fields", () => {
|
||||
assertAllReachable("/v3/memories/", LIST_MAPPING, "list");
|
||||
});
|
||||
});
|
||||
|
||||
describe("stdin fallback uses the shared piped-stdin guard", () => {
|
||||
const SOURCES = ["src/index.ts", "src/commands/memory.ts"];
|
||||
|
||||
for (const rel of SOURCES) {
|
||||
it(`${rel} never checks process.stdin.isTTY directly`, () => {
|
||||
const src = fs.readFileSync(path.join(__dirname, "..", rel), "utf-8");
|
||||
expect(
|
||||
src.includes("process.stdin.isTTY"),
|
||||
`${rel}: use stdinIsPiped() from state.ts. A bare !isTTY check is also true for /dev/null and sockets, so readFileSync(0) crashes with EAGAIN in scripts, CI, and agent mode.`,
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it(`${rel} guards every readFileSync(0) with stdinIsPiped()`, () => {
|
||||
const src = fs.readFileSync(path.join(__dirname, "..", rel), "utf-8");
|
||||
const lines = src.split("\n");
|
||||
for (const [i, line] of lines.entries()) {
|
||||
if (!line.includes("readFileSync(0")) continue;
|
||||
const guard = lines.slice(Math.max(0, i - 3), i).join("\n");
|
||||
expect(
|
||||
guard.includes("stdinIsPiped()"),
|
||||
`${rel}:${i + 1}: readFileSync(0) must be guarded by stdinIsPiped()`,
|
||||
).toBe(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -7,94 +7,231 @@ import { PlatformBackend } from "../src/backend/platform.js";
|
||||
import { createDefaultConfig } from "../src/config.js";
|
||||
|
||||
function makeBackend(): PlatformBackend {
|
||||
// apiKey/baseUrl only build request headers; every test spies on _request,
|
||||
// so no real network calls are made.
|
||||
return new PlatformBackend(createDefaultConfig().platform);
|
||||
return new PlatformBackend(createDefaultConfig().platform);
|
||||
}
|
||||
|
||||
function mockFetch() {
|
||||
const fetchMock = vi.fn().mockResolvedValue({
|
||||
ok: true,
|
||||
status: 200,
|
||||
headers: { get: vi.fn().mockReturnValue(null) },
|
||||
json: vi.fn().mockResolvedValue({ message: "ok" }),
|
||||
});
|
||||
vi.stubGlobal("fetch", fetchMock);
|
||||
return fetchMock;
|
||||
const fetchMock = vi.fn().mockResolvedValue({
|
||||
ok: true,
|
||||
status: 200,
|
||||
headers: { get: vi.fn().mockReturnValue(null) },
|
||||
json: vi.fn().mockResolvedValue({ message: "ok" }),
|
||||
});
|
||||
vi.stubGlobal("fetch", fetchMock);
|
||||
return fetchMock;
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
vi.unstubAllGlobals();
|
||||
vi.restoreAllMocks();
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
describe("deleteEntities", () => {
|
||||
it("returns all results keyed by entity type for a multi-entity delete", async () => {
|
||||
const backend = makeBackend();
|
||||
const responses: Record<string, unknown> = {
|
||||
"/v2/entities/user/alice/": { message: "user deleted" },
|
||||
"/v2/entities/agent/bob/": { message: "agent deleted" },
|
||||
};
|
||||
const spy = vi
|
||||
// biome-ignore lint/suspicious/noExplicitAny: spying on a private method
|
||||
.spyOn(backend as any, "_request")
|
||||
.mockImplementation(async (_method: string, path: string) => responses[path]);
|
||||
it("returns all results keyed by entity type for a multi-entity delete", async () => {
|
||||
const backend = makeBackend();
|
||||
const responses: Record<string, unknown> = {
|
||||
"/v2/entities/user/alice/": { message: "user deleted" },
|
||||
"/v2/entities/agent/bob/": { message: "agent deleted" },
|
||||
};
|
||||
const spy = vi
|
||||
// biome-ignore lint/suspicious/noExplicitAny: spying on a private method
|
||||
.spyOn(backend as any, "_request")
|
||||
.mockImplementation(
|
||||
async (_method: string, path: string) => responses[path],
|
||||
);
|
||||
|
||||
const result = await backend.deleteEntities({ userId: "alice", agentId: "bob" });
|
||||
const result = await backend.deleteEntities({
|
||||
userId: "alice",
|
||||
agentId: "bob",
|
||||
});
|
||||
|
||||
// Regression: previously only the last entity's response survived.
|
||||
expect(result).toEqual({
|
||||
user: { message: "user deleted" },
|
||||
agent: { message: "agent deleted" },
|
||||
});
|
||||
expect(spy).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
expect(result).toEqual({
|
||||
user: { message: "user deleted" },
|
||||
agent: { message: "agent deleted" },
|
||||
});
|
||||
expect(spy).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it("keys a single-entity delete by its type", async () => {
|
||||
const backend = makeBackend();
|
||||
// biome-ignore lint/suspicious/noExplicitAny: spying on a private method
|
||||
vi.spyOn(backend as any, "_request").mockResolvedValue({ message: "user deleted" });
|
||||
it("keys a single-entity delete by its type", async () => {
|
||||
const backend = makeBackend();
|
||||
// biome-ignore lint/suspicious/noExplicitAny: spying on a private method
|
||||
vi.spyOn(backend as any, "_request").mockResolvedValue({
|
||||
message: "user deleted",
|
||||
});
|
||||
|
||||
const result = await backend.deleteEntities({ userId: "alice" });
|
||||
expect(result).toEqual({ user: { message: "user deleted" } });
|
||||
});
|
||||
const result = await backend.deleteEntities({ userId: "alice" });
|
||||
expect(result).toEqual({ user: { message: "user deleted" } });
|
||||
});
|
||||
|
||||
it("throws when no entity id is provided", async () => {
|
||||
const backend = makeBackend();
|
||||
await expect(backend.deleteEntities({})).rejects.toThrow(
|
||||
"At least one entity ID is required",
|
||||
);
|
||||
});
|
||||
it("throws when no entity id is provided", async () => {
|
||||
const backend = makeBackend();
|
||||
await expect(backend.deleteEntities({})).rejects.toThrow(
|
||||
"At least one entity ID is required",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("PlatformBackend option-parity payloads (MEM-5893)", () => {
|
||||
it("add: custom_instructions, custom_categories, structured_data_schema, timestamp reach the payload alongside existing fields", async () => {
|
||||
const backend = makeBackend();
|
||||
const spy = vi
|
||||
// biome-ignore lint/suspicious/noExplicitAny: spying on a private method
|
||||
.spyOn(backend as any, "_request")
|
||||
.mockResolvedValue({ results: [] });
|
||||
|
||||
await backend.add("hello", undefined, {
|
||||
userId: "alice",
|
||||
metadata: { source: "test" },
|
||||
expires: "2099-01-01",
|
||||
customInstructions: "Extract only preferences.",
|
||||
customCategories: [{ prefs: "user preferences" }],
|
||||
structuredDataSchema: { type: "object" },
|
||||
timestamp: 1700000000,
|
||||
});
|
||||
|
||||
const payload = spy.mock.calls[0][2].json;
|
||||
expect(payload.custom_instructions).toBe("Extract only preferences.");
|
||||
expect(payload.custom_categories).toEqual([{ prefs: "user preferences" }]);
|
||||
expect(payload.structured_data_schema).toEqual({ type: "object" });
|
||||
expect(payload.timestamp).toBe(1700000000);
|
||||
expect(payload.metadata).toEqual({ source: "test" });
|
||||
expect(payload.expiration_date).toBe("2099-01-01");
|
||||
});
|
||||
|
||||
it("add: omitted optional fields are absent from the payload", async () => {
|
||||
const backend = makeBackend();
|
||||
const spy = vi
|
||||
// biome-ignore lint/suspicious/noExplicitAny: spying on a private method
|
||||
.spyOn(backend as any, "_request")
|
||||
.mockResolvedValue({ results: [] });
|
||||
|
||||
await backend.add("hello", undefined, { userId: "alice" });
|
||||
|
||||
const payload = spy.mock.calls[0][2].json;
|
||||
expect(payload).not.toHaveProperty("custom_instructions");
|
||||
expect(payload).not.toHaveProperty("custom_categories");
|
||||
expect(payload).not.toHaveProperty("structured_data_schema");
|
||||
expect(payload).not.toHaveProperty("timestamp");
|
||||
});
|
||||
|
||||
it("search: show_expired, reference_date, latest_only reach the payload", async () => {
|
||||
const backend = makeBackend();
|
||||
// biome-ignore lint/suspicious/noExplicitAny: spying on a private method
|
||||
const spy = vi.spyOn(backend as any, "_request").mockResolvedValue([]);
|
||||
|
||||
await backend.search("query", {
|
||||
showExpired: true,
|
||||
referenceDate: "2024-01-01",
|
||||
latestOnly: true,
|
||||
});
|
||||
|
||||
const payload = spy.mock.calls[0][2].json;
|
||||
expect(payload.show_expired).toBe(true);
|
||||
expect(payload.reference_date).toBe("2024-01-01");
|
||||
expect(payload.latest_only).toBe(true);
|
||||
});
|
||||
|
||||
it("search: keyword_search and fields reach the payload", async () => {
|
||||
const backend = makeBackend();
|
||||
// biome-ignore lint/suspicious/noExplicitAny: spying on a private method
|
||||
const spy = vi.spyOn(backend as any, "_request").mockResolvedValue([]);
|
||||
|
||||
await backend.search("query", {
|
||||
keyword: true,
|
||||
fields: ["memory", "score"],
|
||||
});
|
||||
|
||||
const payload = spy.mock.calls[0][2].json;
|
||||
expect(payload.keyword_search).toBe(true);
|
||||
expect(payload.fields).toEqual(["memory", "score"]);
|
||||
});
|
||||
|
||||
it("search: omitted keyword and fields are absent from the payload", async () => {
|
||||
const backend = makeBackend();
|
||||
// biome-ignore lint/suspicious/noExplicitAny: spying on a private method
|
||||
const spy = vi.spyOn(backend as any, "_request").mockResolvedValue([]);
|
||||
|
||||
await backend.search("query", {});
|
||||
|
||||
const payload = spy.mock.calls[0][2].json;
|
||||
expect(payload).not.toHaveProperty("keyword_search");
|
||||
expect(payload).not.toHaveProperty("fields");
|
||||
});
|
||||
|
||||
it("listMemories: show_expired and latest_only are top-level, not nested inside filters", async () => {
|
||||
const backend = makeBackend();
|
||||
// biome-ignore lint/suspicious/noExplicitAny: spying on a private method
|
||||
const spy = vi.spyOn(backend as any, "_request").mockResolvedValue([]);
|
||||
|
||||
await backend.listMemories({
|
||||
userId: "alice",
|
||||
showExpired: true,
|
||||
latestOnly: true,
|
||||
});
|
||||
|
||||
const payload = spy.mock.calls[0][2].json;
|
||||
expect(payload.show_expired).toBe(true);
|
||||
expect(payload.latest_only).toBe(true);
|
||||
expect(payload.filters ?? {}).not.toHaveProperty("show_expired");
|
||||
expect(payload.filters ?? {}).not.toHaveProperty("latest_only");
|
||||
});
|
||||
|
||||
it("update: expiration_date and timestamp reach the payload", async () => {
|
||||
const backend = makeBackend();
|
||||
// biome-ignore lint/suspicious/noExplicitAny: spying on a private method
|
||||
const spy = vi.spyOn(backend as any, "_request").mockResolvedValue({});
|
||||
|
||||
await backend.update("mem-123", undefined, undefined, {
|
||||
expirationDate: "2099-01-01",
|
||||
timestamp: 1700000000,
|
||||
});
|
||||
|
||||
const payload = spy.mock.calls[0][2].json;
|
||||
expect(payload.expiration_date).toBe("2099-01-01");
|
||||
expect(payload.timestamp).toBe(1700000000);
|
||||
});
|
||||
|
||||
it("delete: delete_linked is a query param, not part of the JSON body", async () => {
|
||||
const backend = makeBackend();
|
||||
// biome-ignore lint/suspicious/noExplicitAny: spying on a private method
|
||||
const spy = vi.spyOn(backend as any, "_request").mockResolvedValue({});
|
||||
|
||||
await backend.delete("mem-123", { deleteLinked: true });
|
||||
|
||||
const opts = spy.mock.calls[0][2];
|
||||
expect(opts.params.delete_linked).toBe("true");
|
||||
expect(opts.json).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe("PlatformBackend path encoding", () => {
|
||||
it("encodes memory IDs before interpolating them into paths", async () => {
|
||||
const fetchMock = mockFetch();
|
||||
const backend = makeBackend();
|
||||
it("encodes memory IDs before interpolating them into paths", async () => {
|
||||
const fetchMock = mockFetch();
|
||||
const backend = makeBackend();
|
||||
|
||||
await backend.get("mem/a?b#c");
|
||||
await backend.update("mem/a?b#c", "updated");
|
||||
await backend.delete("mem/a?b#c");
|
||||
await backend.get("mem/a?b#c");
|
||||
await backend.update("mem/a?b#c", "updated");
|
||||
await backend.delete("mem/a?b#c");
|
||||
|
||||
const urls = fetchMock.mock.calls.map((call) => call[0]);
|
||||
expect(urls).toEqual([
|
||||
"https://api.mem0.ai/v1/memories/mem%2Fa%3Fb%23c/?source=CLI",
|
||||
"https://api.mem0.ai/v1/memories/mem%2Fa%3Fb%23c/",
|
||||
"https://api.mem0.ai/v1/memories/mem%2Fa%3Fb%23c/?source=CLI",
|
||||
]);
|
||||
});
|
||||
const urls = fetchMock.mock.calls.map((call) => call[0]);
|
||||
expect(urls).toEqual([
|
||||
"https://api.mem0.ai/v1/memories/mem%2Fa%3Fb%23c/?source=CLI",
|
||||
"https://api.mem0.ai/v1/memories/mem%2Fa%3Fb%23c/",
|
||||
"https://api.mem0.ai/v1/memories/mem%2Fa%3Fb%23c/?source=CLI",
|
||||
]);
|
||||
});
|
||||
|
||||
it("encodes entity and event IDs before interpolating them into paths", async () => {
|
||||
const fetchMock = mockFetch();
|
||||
const backend = makeBackend();
|
||||
it("encodes entity and event IDs before interpolating them into paths", async () => {
|
||||
const fetchMock = mockFetch();
|
||||
const backend = makeBackend();
|
||||
|
||||
await backend.deleteEntities({ userId: "org/team?active#frag" });
|
||||
await backend.getEvent("evt/a?b#c");
|
||||
await backend.deleteEntities({ userId: "org/team?active#frag" });
|
||||
await backend.getEvent("evt/a?b#c");
|
||||
|
||||
const urls = fetchMock.mock.calls.map((call) => call[0]);
|
||||
expect(urls).toEqual([
|
||||
"https://api.mem0.ai/v2/entities/user/org%2Fteam%3Factive%23frag/?source=CLI",
|
||||
"https://api.mem0.ai/v1/event/evt%2Fa%3Fb%23c/",
|
||||
]);
|
||||
});
|
||||
const urls = fetchMock.mock.calls.map((call) => call[0]);
|
||||
expect(urls).toEqual([
|
||||
"https://api.mem0.ai/v2/entities/user/org%2Fteam%3Factive%23frag/?source=CLI",
|
||||
"https://api.mem0.ai/v1/event/evt%2Fa%3Fb%23c/",
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -241,14 +241,6 @@ Verify your API connection and display the current project.
|
||||
mem0 status
|
||||
```
|
||||
|
||||
### `mem0 version`
|
||||
|
||||
Print the CLI version.
|
||||
|
||||
```bash
|
||||
mem0 version
|
||||
```
|
||||
|
||||
## Agent mode
|
||||
|
||||
Pass `--agent` (or its alias `--json`) as a **global flag** on any command to get output designed for AI agent tool loops:
|
||||
@@ -307,6 +299,8 @@ These flags are available on all commands:
|
||||
| `--base-url` | Override the configured API base URL for this request |
|
||||
| `-o, --output` | Set the output format |
|
||||
|
||||
`mem0 --version` prints the CLI version. It is only valid before a subcommand, not after one.
|
||||
|
||||
## Environment variables
|
||||
|
||||
| Variable | Description |
|
||||
|
||||
@@ -80,7 +80,7 @@ mem0 --help
|
||||
# Using Python directly (with venv activated)
|
||||
source .venv/bin/activate
|
||||
mem0 --help
|
||||
mem0 version
|
||||
mem0 --version
|
||||
|
||||
# Or run without activating
|
||||
.venv/bin/mem0 --help
|
||||
|
||||
@@ -273,7 +273,21 @@ def add(
|
||||
no_infer: bool = typer.Option(False, "--no-infer", help="Skip inference, store raw."),
|
||||
expires: str | None = typer.Option(None, "--expires", help="Expiration date (YYYY-MM-DD)."),
|
||||
categories: str | None = typer.Option(
|
||||
None, "--categories", help="Categories (JSON array or comma-separated)."
|
||||
None, "--categories", help="Not supported on add, use --custom-categories instead."
|
||||
),
|
||||
custom_instructions: str | None = typer.Option(
|
||||
None, "--custom-instructions", help="Custom instructions for fact extraction."
|
||||
),
|
||||
custom_categories: str | None = typer.Option(
|
||||
None,
|
||||
"--custom-categories",
|
||||
help="Custom categories as a JSON array of {name: description} objects.",
|
||||
),
|
||||
structured_data_schema: str | None = typer.Option(
|
||||
None, "--structured-data-schema", help="Schema for structured data extraction, as JSON."
|
||||
),
|
||||
timestamp: int | None = typer.Option(
|
||||
None, "--timestamp", help="Unix timestamp for the memory."
|
||||
),
|
||||
output: str = typer.Option(
|
||||
"text", "--output", "-o", help="Output format: text, json, quiet.", rich_help_panel="Output"
|
||||
@@ -312,6 +326,10 @@ def add(
|
||||
no_infer=no_infer,
|
||||
expires=expires,
|
||||
categories=categories,
|
||||
custom_instructions=custom_instructions,
|
||||
custom_categories=custom_categories,
|
||||
structured_data_schema=structured_data_schema,
|
||||
timestamp=timestamp,
|
||||
output=output,
|
||||
)
|
||||
|
||||
@@ -355,6 +373,21 @@ def search(
|
||||
help="Specific fields to return (comma-separated).",
|
||||
rich_help_panel="Search",
|
||||
),
|
||||
show_expired: bool = typer.Option(
|
||||
False, "--show-expired", help="Include expired memories.", rich_help_panel="Search"
|
||||
),
|
||||
reference_date: str | None = typer.Option(
|
||||
None,
|
||||
"--reference-date",
|
||||
help="Reference date for relative queries (YYYY-MM-DD or unix timestamp).",
|
||||
rich_help_panel="Search",
|
||||
),
|
||||
latest_only: bool = typer.Option(
|
||||
False,
|
||||
"--latest-only",
|
||||
help="Only return the latest version of each memory.",
|
||||
rich_help_panel="Search",
|
||||
),
|
||||
output: str = typer.Option(
|
||||
"text", "--output", "-o", help="Output: text, json, table.", rich_help_panel="Output"
|
||||
),
|
||||
@@ -398,6 +431,9 @@ def search(
|
||||
keyword=keyword,
|
||||
filter_json=filter_json,
|
||||
fields=fields,
|
||||
show_expired=show_expired,
|
||||
reference_date=reference_date,
|
||||
latest_only=latest_only,
|
||||
output=output,
|
||||
)
|
||||
|
||||
@@ -464,6 +500,15 @@ def list_cmd(
|
||||
before: str | None = typer.Option(
|
||||
None, "--before", help="Created before (YYYY-MM-DD).", rich_help_panel="Filters"
|
||||
),
|
||||
show_expired: bool = typer.Option(
|
||||
False, "--show-expired", help="Include expired memories.", rich_help_panel="Filters"
|
||||
),
|
||||
latest_only: bool = typer.Option(
|
||||
False,
|
||||
"--latest-only",
|
||||
help="Only return the latest version of each memory.",
|
||||
rich_help_panel="Filters",
|
||||
),
|
||||
output: str = typer.Option(
|
||||
"table", "--output", "-o", help="Output: text, json, table.", rich_help_panel="Output"
|
||||
),
|
||||
@@ -497,6 +542,8 @@ def list_cmd(
|
||||
category=category,
|
||||
after=after,
|
||||
before=before,
|
||||
show_expired=show_expired,
|
||||
latest_only=latest_only,
|
||||
output=output,
|
||||
)
|
||||
|
||||
@@ -509,6 +556,10 @@ def update(
|
||||
memory_id: str = typer.Argument(..., help="Memory ID to update."),
|
||||
text: str | None = typer.Argument(None, help="New memory text."),
|
||||
metadata: str | None = typer.Option(None, "--metadata", "-m", help="Update metadata (JSON)."),
|
||||
expires: str | None = typer.Option(None, "--expires", help="Expiration date (YYYY-MM-DD)."),
|
||||
timestamp: int | None = typer.Option(
|
||||
None, "--timestamp", help="Unix timestamp for the memory."
|
||||
),
|
||||
output: str = typer.Option(
|
||||
"text", "--output", "-o", help="Output: text, json, quiet.", rich_help_panel="Output"
|
||||
),
|
||||
@@ -537,7 +588,15 @@ def update(
|
||||
text = _read_stdin()
|
||||
|
||||
backend = _get_backend(api_key, base_url)
|
||||
cmd_update(backend, memory_id, text, metadata=metadata, output=output)
|
||||
cmd_update(
|
||||
backend,
|
||||
memory_id,
|
||||
text,
|
||||
metadata=metadata,
|
||||
expires=expires,
|
||||
timestamp=timestamp,
|
||||
output=output,
|
||||
)
|
||||
|
||||
|
||||
# ── Memory: delete ────────────────────────────────────────────────────────
|
||||
@@ -559,6 +618,9 @@ def delete(
|
||||
False, "--dry-run", help="Show what would be deleted without deleting."
|
||||
),
|
||||
force: bool = typer.Option(False, "--force", help="Skip confirmation."),
|
||||
delete_linked: bool = typer.Option(
|
||||
False, "--delete-linked", help="Also delete memories linked to this memory."
|
||||
),
|
||||
user_id: str | None = typer.Option(
|
||||
None, "--user-id", "-u", help="Scope to user.", rich_help_panel="Scope"
|
||||
),
|
||||
@@ -616,7 +678,14 @@ def delete(
|
||||
from mem0_cli.commands.memory import cmd_delete
|
||||
|
||||
backend = _get_backend(api_key, base_url)
|
||||
cmd_delete(backend, memory_id, dry_run=dry_run, force=force, output=output)
|
||||
cmd_delete(
|
||||
backend,
|
||||
memory_id,
|
||||
dry_run=dry_run,
|
||||
force=force,
|
||||
delete_linked=delete_linked,
|
||||
output=output,
|
||||
)
|
||||
|
||||
elif all_:
|
||||
_fire_telemetry("delete", {"delete_mode": "all"})
|
||||
@@ -1068,7 +1137,11 @@ def _build_help_json() -> dict:
|
||||
"--immutable": "Prevent future updates.",
|
||||
"--no-infer": "Skip inference, store raw.",
|
||||
"--expires": "Expiration date (YYYY-MM-DD).",
|
||||
"--categories": "Categories (JSON array or comma-separated).",
|
||||
"--categories": "Not supported on add, use --custom-categories instead.",
|
||||
"--custom-instructions": "Custom instructions for fact extraction.",
|
||||
"--custom-categories": "Custom categories as a JSON array of {name: description} objects.",
|
||||
"--structured-data-schema": "Schema for structured data extraction, as JSON.",
|
||||
"--timestamp": "Unix timestamp for the memory.",
|
||||
"--graph": "Enable graph memory extraction.",
|
||||
"--no-graph": "Disable graph memory extraction.",
|
||||
"--output, -o": "Output format: text, json, quiet.",
|
||||
@@ -1087,6 +1160,9 @@ def _build_help_json() -> dict:
|
||||
"--keyword": "Use keyword search instead of semantic.",
|
||||
"--filter": "Advanced filter expression (JSON).",
|
||||
"--fields": "Specific fields to return (comma-separated).",
|
||||
"--show-expired": "Include expired memories.",
|
||||
"--reference-date": "Reference date for relative queries (YYYY-MM-DD or unix timestamp).",
|
||||
"--latest-only": "Only return the latest version of each memory.",
|
||||
"--graph": "Enable graph in search.",
|
||||
"--no-graph": "Disable graph in search.",
|
||||
"--output, -o": "Output format: text, json, table.",
|
||||
@@ -1110,6 +1186,8 @@ def _build_help_json() -> dict:
|
||||
"--category": "Filter by category.",
|
||||
"--after": "Created after (YYYY-MM-DD).",
|
||||
"--before": "Created before (YYYY-MM-DD).",
|
||||
"--show-expired": "Include expired memories.",
|
||||
"--latest-only": "Only return the latest version of each memory.",
|
||||
"--graph": "Enable graph in listing.",
|
||||
"--no-graph": "Disable graph in listing.",
|
||||
"--output, -o": "Output format: text, json, table.",
|
||||
@@ -1124,6 +1202,8 @@ def _build_help_json() -> dict:
|
||||
},
|
||||
"options": {
|
||||
"--metadata, -m": "Update metadata (JSON).",
|
||||
"--expires": "Expiration date (YYYY-MM-DD).",
|
||||
"--timestamp": "Unix timestamp for the memory.",
|
||||
"--output, -o": "Output format: text, json, quiet.",
|
||||
},
|
||||
},
|
||||
@@ -1140,6 +1220,7 @@ def _build_help_json() -> dict:
|
||||
"--all": "Delete all memories matching scope filters.",
|
||||
"--entity": "Delete the entity itself and all its memories (cascade).",
|
||||
"--project": "With --all: delete ALL memories project-wide.",
|
||||
"--delete-linked": "Also delete memories linked to this memory.",
|
||||
"--dry-run": "Show what would be deleted without deleting.",
|
||||
"--force": "Skip confirmation.",
|
||||
"--user-id, -u": "Scope to user.",
|
||||
@@ -1269,8 +1350,10 @@ def help(
|
||||
mem0 help
|
||||
mem0 help --json
|
||||
"""
|
||||
if json:
|
||||
console.print(_json.dumps(_build_help_json(), indent=2))
|
||||
from mem0_cli.state import is_agent_mode
|
||||
|
||||
if json or is_agent_mode():
|
||||
console.print_json(_json.dumps(_build_help_json()))
|
||||
else:
|
||||
console.print(
|
||||
f"[{BRAND_COLOR}]◆ mem0 CLI[/] v{__version__} — The Memory Layer for AI Agents\n"
|
||||
|
||||
@@ -25,7 +25,10 @@ class Backend(ABC):
|
||||
immutable: bool = False,
|
||||
infer: bool = True,
|
||||
expires: str | None = None,
|
||||
categories: list[str] | None = None,
|
||||
custom_instructions: str | None = None,
|
||||
custom_categories: list[dict] | None = None,
|
||||
structured_data_schema: dict | None = None,
|
||||
timestamp: int | None = None,
|
||||
) -> dict: ...
|
||||
|
||||
@abstractmethod
|
||||
@@ -43,6 +46,9 @@ class Backend(ABC):
|
||||
keyword: bool = False,
|
||||
filters: dict | None = None,
|
||||
fields: list[str] | None = None,
|
||||
show_expired: bool = False,
|
||||
reference_date: str | None = None,
|
||||
latest_only: bool = False,
|
||||
) -> list[dict]: ...
|
||||
|
||||
@abstractmethod
|
||||
@@ -61,11 +67,19 @@ class Backend(ABC):
|
||||
category: str | None = None,
|
||||
after: str | None = None,
|
||||
before: str | None = None,
|
||||
show_expired: bool = False,
|
||||
latest_only: bool = False,
|
||||
) -> list[dict]: ...
|
||||
|
||||
@abstractmethod
|
||||
def update(
|
||||
self, memory_id: str, content: str | None = None, metadata: dict | None = None
|
||||
self,
|
||||
memory_id: str,
|
||||
content: str | None = None,
|
||||
metadata: dict | None = None,
|
||||
*,
|
||||
expiration_date: str | None = None,
|
||||
timestamp: int | None = None,
|
||||
) -> dict: ...
|
||||
|
||||
@abstractmethod
|
||||
@@ -78,6 +92,7 @@ class Backend(ABC):
|
||||
agent_id: str | None = None,
|
||||
app_id: str | None = None,
|
||||
run_id: str | None = None,
|
||||
delete_linked: bool = False,
|
||||
) -> dict: ...
|
||||
|
||||
@abstractmethod
|
||||
|
||||
@@ -87,7 +87,10 @@ class PlatformBackend(Backend):
|
||||
immutable: bool = False,
|
||||
infer: bool = True,
|
||||
expires: str | None = None,
|
||||
categories: list[str] | None = None,
|
||||
custom_instructions: str | None = None,
|
||||
custom_categories: list[dict] | None = None,
|
||||
structured_data_schema: dict | None = None,
|
||||
timestamp: int | None = None,
|
||||
) -> dict:
|
||||
payload: dict[str, Any] = {}
|
||||
|
||||
@@ -112,8 +115,14 @@ class PlatformBackend(Backend):
|
||||
payload["infer"] = False
|
||||
if expires:
|
||||
payload["expiration_date"] = expires
|
||||
if categories:
|
||||
payload["categories"] = categories
|
||||
if custom_instructions:
|
||||
payload["custom_instructions"] = custom_instructions
|
||||
if custom_categories:
|
||||
payload["custom_categories"] = custom_categories
|
||||
if structured_data_schema:
|
||||
payload["structured_data_schema"] = structured_data_schema
|
||||
if timestamp is not None:
|
||||
payload["timestamp"] = timestamp
|
||||
payload["source"] = "CLI"
|
||||
|
||||
return self._request("POST", "/v3/memories/add/", json=payload)
|
||||
@@ -173,6 +182,9 @@ class PlatformBackend(Backend):
|
||||
keyword: bool = False,
|
||||
filters: dict | None = None,
|
||||
fields: list[str] | None = None,
|
||||
show_expired: bool = False,
|
||||
reference_date: str | None = None,
|
||||
latest_only: bool = False,
|
||||
) -> list[dict]:
|
||||
payload: dict[str, Any] = {"query": query, "top_k": top_k, "threshold": threshold}
|
||||
|
||||
@@ -191,6 +203,12 @@ class PlatformBackend(Backend):
|
||||
payload["keyword_search"] = True
|
||||
if fields:
|
||||
payload["fields"] = fields
|
||||
if show_expired:
|
||||
payload["show_expired"] = True
|
||||
if reference_date is not None:
|
||||
payload["reference_date"] = reference_date
|
||||
if latest_only:
|
||||
payload["latest_only"] = True
|
||||
payload["source"] = "CLI"
|
||||
|
||||
result = self._request("POST", "/v3/memories/search/", json=payload)
|
||||
@@ -219,6 +237,8 @@ class PlatformBackend(Backend):
|
||||
category: str | None = None,
|
||||
after: str | None = None,
|
||||
before: str | None = None,
|
||||
show_expired: bool = False,
|
||||
latest_only: bool = False,
|
||||
) -> list[dict]:
|
||||
payload: dict[str, Any] = {}
|
||||
params = {"page": str(page), "page_size": str(page_size)}
|
||||
@@ -241,6 +261,10 @@ class PlatformBackend(Backend):
|
||||
)
|
||||
if api_filters:
|
||||
payload["filters"] = api_filters
|
||||
if show_expired:
|
||||
payload["show_expired"] = True
|
||||
if latest_only:
|
||||
payload["latest_only"] = True
|
||||
payload["source"] = "CLI"
|
||||
|
||||
result = self._request("POST", "/v3/memories/", json=payload, params=params)
|
||||
@@ -251,13 +275,23 @@ class PlatformBackend(Backend):
|
||||
)
|
||||
|
||||
def update(
|
||||
self, memory_id: str, content: str | None = None, metadata: dict | None = None
|
||||
self,
|
||||
memory_id: str,
|
||||
content: str | None = None,
|
||||
metadata: dict | None = None,
|
||||
*,
|
||||
expiration_date: str | None = None,
|
||||
timestamp: int | None = None,
|
||||
) -> dict:
|
||||
payload: dict[str, Any] = {}
|
||||
if content:
|
||||
payload["text"] = content
|
||||
if metadata:
|
||||
payload["metadata"] = metadata
|
||||
if expiration_date:
|
||||
payload["expiration_date"] = expiration_date
|
||||
if timestamp is not None:
|
||||
payload["timestamp"] = timestamp
|
||||
payload["source"] = "CLI"
|
||||
return self._request(
|
||||
"PUT",
|
||||
@@ -274,6 +308,7 @@ class PlatformBackend(Backend):
|
||||
agent_id: str | None = None,
|
||||
app_id: str | None = None,
|
||||
run_id: str | None = None,
|
||||
delete_linked: bool = False,
|
||||
) -> dict:
|
||||
if all:
|
||||
params: dict[str, str] = {"source": "CLI"}
|
||||
@@ -287,10 +322,13 @@ class PlatformBackend(Backend):
|
||||
params["run_id"] = run_id
|
||||
return self._request("DELETE", "/v1/memories/", params=params)
|
||||
elif memory_id:
|
||||
params = {"source": "CLI"}
|
||||
if delete_linked:
|
||||
params["delete_linked"] = "true"
|
||||
return self._request(
|
||||
"DELETE",
|
||||
f"/v1/memories/{_encode_path_segment(memory_id)}/",
|
||||
params={"source": "CLI"},
|
||||
params=params,
|
||||
)
|
||||
else:
|
||||
raise ValueError("Either memory_id or --all is required")
|
||||
|
||||
@@ -4,9 +4,11 @@ from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import stat as _stat_mod
|
||||
import sys
|
||||
import time as _time
|
||||
from datetime import date
|
||||
from pathlib import Path
|
||||
|
||||
import typer
|
||||
@@ -47,6 +49,18 @@ def _stdin_is_piped() -> bool:
|
||||
return False
|
||||
|
||||
|
||||
def _validate_expires(value: str) -> None:
|
||||
"""Exit 1 if value is not a future YYYY-MM-DD date."""
|
||||
if not re.match(r"^\d{4}-\d{2}-\d{2}$", value):
|
||||
print_error(
|
||||
err_console, "Invalid date format for --expires. Use YYYY-MM-DD (e.g. 2025-12-31)."
|
||||
)
|
||||
raise typer.Exit(1)
|
||||
if date.fromisoformat(value) <= date.today():
|
||||
print_error(err_console, "--expires date must be in the future.")
|
||||
raise typer.Exit(1)
|
||||
|
||||
|
||||
def cmd_add(
|
||||
backend: Backend,
|
||||
text: str | None,
|
||||
@@ -62,6 +76,10 @@ def cmd_add(
|
||||
no_infer: bool,
|
||||
expires: str | None,
|
||||
categories: str | None,
|
||||
custom_instructions: str | None = None,
|
||||
custom_categories: str | None = None,
|
||||
structured_data_schema: str | None = None,
|
||||
timestamp: int | None = None,
|
||||
output: str = "text",
|
||||
) -> None:
|
||||
"""Add a memory."""
|
||||
@@ -70,6 +88,13 @@ def cmd_add(
|
||||
set_current_command("add")
|
||||
if is_agent_mode():
|
||||
output = "agent"
|
||||
|
||||
if categories:
|
||||
print_error(
|
||||
err_console, "--categories is not supported on add. Use --custom-categories instead."
|
||||
)
|
||||
raise typer.Exit(1)
|
||||
|
||||
msgs = None
|
||||
content = text
|
||||
|
||||
@@ -108,27 +133,24 @@ def cmd_add(
|
||||
print_error(err_console, "Invalid JSON in --metadata.")
|
||||
raise typer.Exit(1) from None
|
||||
|
||||
cats = None
|
||||
if categories:
|
||||
custom_cats = None
|
||||
if custom_categories:
|
||||
try:
|
||||
cats = json.loads(categories)
|
||||
custom_cats = json.loads(custom_categories)
|
||||
except json.JSONDecodeError:
|
||||
cats = [c.strip() for c in categories.split(",")]
|
||||
print_error(err_console, "Invalid JSON in --custom-categories.")
|
||||
raise typer.Exit(1) from None
|
||||
|
||||
schema = None
|
||||
if structured_data_schema:
|
||||
try:
|
||||
schema = json.loads(structured_data_schema)
|
||||
except json.JSONDecodeError:
|
||||
print_error(err_console, "Invalid JSON in --structured-data-schema.")
|
||||
raise typer.Exit(1) from None
|
||||
|
||||
# Validate --expires
|
||||
if expires:
|
||||
import re
|
||||
|
||||
if not re.match(r"^\d{4}-\d{2}-\d{2}$", expires):
|
||||
print_error(
|
||||
err_console, "Invalid date format for --expires. Use YYYY-MM-DD (e.g. 2025-12-31)."
|
||||
)
|
||||
raise typer.Exit(1)
|
||||
from datetime import date
|
||||
|
||||
if date.fromisoformat(expires) <= date.today():
|
||||
print_error(err_console, "--expires date must be in the future.")
|
||||
raise typer.Exit(1)
|
||||
_validate_expires(expires)
|
||||
|
||||
with timed_status(err_console, "Adding memory...") as ts:
|
||||
try:
|
||||
@@ -143,7 +165,10 @@ def cmd_add(
|
||||
immutable=immutable,
|
||||
infer=not no_infer,
|
||||
expires=expires,
|
||||
categories=cats,
|
||||
custom_instructions=custom_instructions,
|
||||
custom_categories=custom_cats,
|
||||
structured_data_schema=schema,
|
||||
timestamp=timestamp,
|
||||
)
|
||||
except Exception as e:
|
||||
ts.error_msg = str(e)
|
||||
@@ -224,6 +249,9 @@ def cmd_search(
|
||||
keyword: bool,
|
||||
filter_json: str | None,
|
||||
fields: str | None,
|
||||
show_expired: bool = False,
|
||||
reference_date: str | None = None,
|
||||
latest_only: bool = False,
|
||||
output: str = "text",
|
||||
) -> None:
|
||||
"""Search memories."""
|
||||
@@ -266,6 +294,9 @@ def cmd_search(
|
||||
keyword=keyword,
|
||||
filters=filters,
|
||||
fields=field_list,
|
||||
show_expired=show_expired,
|
||||
reference_date=reference_date,
|
||||
latest_only=latest_only,
|
||||
)
|
||||
except Exception as e:
|
||||
print_error(err_console, str(e))
|
||||
@@ -352,6 +383,8 @@ def cmd_list(
|
||||
category: str | None,
|
||||
after: str | None,
|
||||
before: str | None,
|
||||
show_expired: bool = False,
|
||||
latest_only: bool = False,
|
||||
output: str = "table",
|
||||
) -> None:
|
||||
"""List memories."""
|
||||
@@ -380,6 +413,8 @@ def cmd_list(
|
||||
category=category,
|
||||
after=after,
|
||||
before=before,
|
||||
show_expired=show_expired,
|
||||
latest_only=latest_only,
|
||||
)
|
||||
except Exception as e:
|
||||
print_error(err_console, str(e))
|
||||
@@ -446,6 +481,8 @@ def cmd_update(
|
||||
text: str | None,
|
||||
*,
|
||||
metadata: str | None,
|
||||
expires: str | None = None,
|
||||
timestamp: int | None = None,
|
||||
output: str,
|
||||
) -> None:
|
||||
"""Update a memory."""
|
||||
@@ -462,10 +499,19 @@ def cmd_update(
|
||||
print_error(err_console, "Invalid JSON in --metadata.")
|
||||
raise typer.Exit(1) from None
|
||||
|
||||
if expires:
|
||||
_validate_expires(expires)
|
||||
|
||||
_start = _time.perf_counter()
|
||||
with timed_status(err_console, "Updating memory...") as _ts:
|
||||
try:
|
||||
result = backend.update(memory_id, content=text, metadata=meta)
|
||||
result = backend.update(
|
||||
memory_id,
|
||||
content=text,
|
||||
metadata=meta,
|
||||
expiration_date=expires,
|
||||
timestamp=timestamp,
|
||||
)
|
||||
except Exception as e:
|
||||
print_error(err_console, str(e))
|
||||
raise typer.Exit(1) from None
|
||||
@@ -490,6 +536,7 @@ def cmd_delete(
|
||||
*,
|
||||
dry_run: bool = False,
|
||||
force: bool = False,
|
||||
delete_linked: bool = False,
|
||||
output: str,
|
||||
) -> None:
|
||||
"""Delete a single memory by ID."""
|
||||
@@ -512,7 +559,7 @@ def cmd_delete(
|
||||
_start = _time.perf_counter()
|
||||
with timed_status(err_console, "Deleting...") as _ts:
|
||||
try:
|
||||
result = backend.delete(memory_id=memory_id)
|
||||
result = backend.delete(memory_id=memory_id, delete_linked=delete_linked)
|
||||
except Exception as e:
|
||||
print_error(err_console, str(e))
|
||||
raise typer.Exit(1) from None
|
||||
|
||||
@@ -262,16 +262,32 @@ def sanitize_agent_data(command: str, data: Any) -> Any:
|
||||
return result
|
||||
|
||||
if command == "search":
|
||||
return [pick(r, ["id", "memory", "score", "created_at", "categories"]) for r in data]
|
||||
return [
|
||||
pick(r, ["id", "memory", "score", "created_at", "categories", "expiration_date"])
|
||||
for r in data
|
||||
]
|
||||
|
||||
if command == "list":
|
||||
return [pick(r, ["id", "memory", "created_at", "categories"]) for r in data]
|
||||
return [
|
||||
pick(r, ["id", "memory", "created_at", "categories", "expiration_date"]) for r in data
|
||||
]
|
||||
|
||||
if command == "get":
|
||||
return pick(data, ["id", "memory", "created_at", "updated_at", "categories", "metadata"])
|
||||
return pick(
|
||||
data,
|
||||
[
|
||||
"id",
|
||||
"memory",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"categories",
|
||||
"metadata",
|
||||
"expiration_date",
|
||||
],
|
||||
)
|
||||
|
||||
if command == "update":
|
||||
return pick(data, ["id", "memory"])
|
||||
return pick(data, ["id", "memory", "expiration_date"])
|
||||
|
||||
if command in ("delete", "delete-all", "entity delete"):
|
||||
return data
|
||||
|
||||
@@ -7,6 +7,7 @@ boundaries).
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
@@ -84,6 +85,31 @@ class TestCLIIntegration:
|
||||
assert "add" in result.stdout
|
||||
assert "search" in result.stdout
|
||||
|
||||
def test_version_flag_only(self):
|
||||
from mem0_cli import __version__
|
||||
|
||||
flag = _run(["--version"])
|
||||
assert flag.returncode == 0
|
||||
assert __version__ in flag.stdout
|
||||
assert _run(["version"]).returncode != 0
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"args",
|
||||
[["help", "--json"], ["--json", "help"], ["help", "--agent"], ["--agent", "help"]],
|
||||
)
|
||||
def test_help_json_produces_valid_json(self, args):
|
||||
result = _run(args)
|
||||
assert result.returncode == 0
|
||||
spec = json.loads(result.stdout)
|
||||
assert spec["name"] == "mem0"
|
||||
assert "add" in spec["commands"]
|
||||
|
||||
def test_help_without_json_is_text(self):
|
||||
result = _run(["help"])
|
||||
assert result.returncode == 0
|
||||
with pytest.raises(json.JSONDecodeError):
|
||||
json.loads(result.stdout)
|
||||
|
||||
def test_add_help(self):
|
||||
result = _run(["add", "--help"])
|
||||
assert result.returncode == 0
|
||||
|
||||
@@ -252,12 +252,13 @@ class TestAddCommand:
|
||||
)
|
||||
mock_backend.add.assert_called_once()
|
||||
|
||||
def test_add_categories_csv(self, mock_backend):
|
||||
def test_add_categories_rejected(self, mock_backend):
|
||||
console, _buf = _make_console()
|
||||
err_console, _err_buf = _make_err_console()
|
||||
err_console, err_buf = _make_err_console()
|
||||
with (
|
||||
patch("mem0_cli.commands.memory.console", console),
|
||||
patch("mem0_cli.commands.memory.err_console", err_console),
|
||||
pytest.raises((SystemExit, TyperExit)),
|
||||
):
|
||||
cmd_add(
|
||||
mock_backend,
|
||||
@@ -275,7 +276,93 @@ class TestAddCommand:
|
||||
categories="health,prefs",
|
||||
output="text",
|
||||
)
|
||||
mock_backend.add.assert_called_once()
|
||||
assert "--custom-categories" in err_buf.getvalue()
|
||||
mock_backend.add.assert_not_called()
|
||||
|
||||
def test_add_invalid_custom_categories_json(self, mock_backend):
|
||||
console, _buf = _make_console()
|
||||
err_console, err_buf = _make_err_console()
|
||||
with (
|
||||
patch("mem0_cli.commands.memory.console", console),
|
||||
patch("mem0_cli.commands.memory.err_console", err_console),
|
||||
pytest.raises((SystemExit, TyperExit)),
|
||||
):
|
||||
cmd_add(
|
||||
mock_backend,
|
||||
"test",
|
||||
user_id="alice",
|
||||
agent_id=None,
|
||||
app_id=None,
|
||||
run_id=None,
|
||||
messages=None,
|
||||
file=None,
|
||||
metadata=None,
|
||||
immutable=False,
|
||||
no_infer=False,
|
||||
expires=None,
|
||||
categories=None,
|
||||
custom_categories="not-json",
|
||||
output="text",
|
||||
)
|
||||
assert "--custom-categories" in err_buf.getvalue()
|
||||
mock_backend.add.assert_not_called()
|
||||
|
||||
def test_add_invalid_structured_data_schema_json(self, mock_backend):
|
||||
console, _buf = _make_console()
|
||||
err_console, err_buf = _make_err_console()
|
||||
with (
|
||||
patch("mem0_cli.commands.memory.console", console),
|
||||
patch("mem0_cli.commands.memory.err_console", err_console),
|
||||
pytest.raises((SystemExit, TyperExit)),
|
||||
):
|
||||
cmd_add(
|
||||
mock_backend,
|
||||
"test",
|
||||
user_id="alice",
|
||||
agent_id=None,
|
||||
app_id=None,
|
||||
run_id=None,
|
||||
messages=None,
|
||||
file=None,
|
||||
metadata=None,
|
||||
immutable=False,
|
||||
no_infer=False,
|
||||
expires=None,
|
||||
categories=None,
|
||||
structured_data_schema="not-json",
|
||||
output="text",
|
||||
)
|
||||
assert "--structured-data-schema" in err_buf.getvalue()
|
||||
mock_backend.add.assert_not_called()
|
||||
|
||||
def test_add_regression_metadata_expiration_custom_categories_together(self, mock_backend):
|
||||
console, _buf = _make_console()
|
||||
err_console, _err_buf = _make_err_console()
|
||||
with (
|
||||
patch("mem0_cli.commands.memory.console", console),
|
||||
patch("mem0_cli.commands.memory.err_console", err_console),
|
||||
):
|
||||
cmd_add(
|
||||
mock_backend,
|
||||
"test",
|
||||
user_id="alice",
|
||||
agent_id=None,
|
||||
app_id=None,
|
||||
run_id=None,
|
||||
messages=None,
|
||||
file=None,
|
||||
metadata='{"source": "test"}',
|
||||
immutable=False,
|
||||
no_infer=False,
|
||||
expires="2099-01-01",
|
||||
categories=None,
|
||||
custom_categories='[{"prefs": "user preferences"}]',
|
||||
output="text",
|
||||
)
|
||||
call_kwargs = mock_backend.add.call_args.kwargs
|
||||
assert call_kwargs["metadata"] == {"source": "test"}
|
||||
assert call_kwargs["expires"] == "2099-01-01"
|
||||
assert call_kwargs["custom_categories"] == [{"prefs": "user preferences"}]
|
||||
|
||||
|
||||
class TestAddDeduplicatesPending:
|
||||
@@ -464,6 +551,36 @@ class TestSearchCommand:
|
||||
)
|
||||
mock_backend.search.assert_called_once()
|
||||
|
||||
def test_search_new_flags_reach_backend(self, mock_backend):
|
||||
console, _buf = _make_console()
|
||||
err_console, _err_buf = _make_err_console()
|
||||
with (
|
||||
patch("mem0_cli.commands.memory.console", console),
|
||||
patch("mem0_cli.commands.memory.err_console", err_console),
|
||||
):
|
||||
cmd_search(
|
||||
mock_backend,
|
||||
"preferences",
|
||||
user_id="alice",
|
||||
agent_id=None,
|
||||
app_id=None,
|
||||
run_id=None,
|
||||
top_k=10,
|
||||
threshold=0.3,
|
||||
rerank=False,
|
||||
keyword=False,
|
||||
filter_json=None,
|
||||
fields=None,
|
||||
show_expired=True,
|
||||
reference_date="2024-01-01",
|
||||
latest_only=True,
|
||||
output="text",
|
||||
)
|
||||
call_kwargs = mock_backend.search.call_args.kwargs
|
||||
assert call_kwargs["show_expired"] is True
|
||||
assert call_kwargs["reference_date"] == "2024-01-01"
|
||||
assert call_kwargs["latest_only"] is True
|
||||
|
||||
|
||||
class TestGetCommand:
|
||||
def test_get_text(self, mock_backend):
|
||||
@@ -561,6 +678,32 @@ class TestListCommand:
|
||||
output = buf.getvalue()
|
||||
assert "No memories found" in output
|
||||
|
||||
def test_list_new_flags_reach_backend(self, mock_backend):
|
||||
console, _buf = _make_console()
|
||||
err_console, _err_buf = _make_err_console()
|
||||
with (
|
||||
patch("mem0_cli.commands.memory.console", console),
|
||||
patch("mem0_cli.commands.memory.err_console", err_console),
|
||||
):
|
||||
cmd_list(
|
||||
mock_backend,
|
||||
user_id="alice",
|
||||
agent_id=None,
|
||||
app_id=None,
|
||||
run_id=None,
|
||||
page=1,
|
||||
page_size=100,
|
||||
category=None,
|
||||
after=None,
|
||||
before=None,
|
||||
show_expired=True,
|
||||
latest_only=True,
|
||||
output="table",
|
||||
)
|
||||
call_kwargs = mock_backend.list_memories.call_args.kwargs
|
||||
assert call_kwargs["show_expired"] is True
|
||||
assert call_kwargs["latest_only"] is True
|
||||
|
||||
|
||||
class TestUpdateCommand:
|
||||
def test_update(self, mock_backend):
|
||||
@@ -585,6 +728,26 @@ class TestUpdateCommand:
|
||||
output = buf.getvalue()
|
||||
assert '"memory"' in output
|
||||
|
||||
def test_update_new_fields_reach_backend(self, mock_backend):
|
||||
console, _buf = _make_console()
|
||||
err_console, _err_buf = _make_err_console()
|
||||
with (
|
||||
patch("mem0_cli.commands.memory.console", console),
|
||||
patch("mem0_cli.commands.memory.err_console", err_console),
|
||||
):
|
||||
cmd_update(
|
||||
mock_backend,
|
||||
"abc-123",
|
||||
"New text",
|
||||
metadata=None,
|
||||
expires="2099-01-01",
|
||||
timestamp=1700000000,
|
||||
output="text",
|
||||
)
|
||||
call_kwargs = mock_backend.update.call_args.kwargs
|
||||
assert call_kwargs["expiration_date"] == "2099-01-01"
|
||||
assert call_kwargs["timestamp"] == 1700000000
|
||||
|
||||
|
||||
class TestDeleteCommand:
|
||||
def test_delete_single(self, mock_backend):
|
||||
@@ -610,6 +773,17 @@ class TestDeleteCommand:
|
||||
assert "dry run" in output.lower()
|
||||
mock_backend.delete.assert_not_called()
|
||||
|
||||
def test_delete_linked_reaches_backend(self, mock_backend):
|
||||
console, _buf = _make_console()
|
||||
err_console, _err_buf = _make_err_console()
|
||||
with (
|
||||
patch("mem0_cli.commands.memory.console", console),
|
||||
patch("mem0_cli.commands.memory.err_console", err_console),
|
||||
):
|
||||
cmd_delete(mock_backend, "abc-123", delete_linked=True, output="text")
|
||||
call_kwargs = mock_backend.delete.call_args.kwargs
|
||||
assert call_kwargs["delete_linked"] is True
|
||||
|
||||
|
||||
class TestDeleteAllCommand:
|
||||
def test_delete_all_force(self, mock_backend):
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
"""Drift test: every documented v3 add/search/list param must be reachable from the Python CLI."""
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
import typer.main
|
||||
|
||||
from mem0_cli.app import app
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[3]
|
||||
OPENAPI_PATH = REPO_ROOT / "docs" / "openapi.json"
|
||||
|
||||
KNOWN_UNSURFACED: dict[tuple[str, str], str] = {
|
||||
("/v3/memories/add/", "includes"): "extraction hint, no CLI flag yet",
|
||||
("/v3/memories/add/", "excludes"): "extraction hint, no CLI flag yet",
|
||||
("/v3/memories/add/", "enable_graph"): "graph memory toggle, no CLI flag yet",
|
||||
("/v3/memories/add/", "output_format"): "response envelope is pinned by the CLI",
|
||||
("/v3/memories/add/", "prompt_profile_id"): "no CLI flag yet",
|
||||
("/v3/memories/add/", "temporal_reasoning"): "no CLI flag yet",
|
||||
("/v3/memories/add/", "timezone"): "no CLI flag yet",
|
||||
("/v3/memories/add/", "observation_datetime"): "no CLI flag yet, --timestamp backdates instead",
|
||||
("/v3/memories/add/", "observation_date"): "no CLI flag yet, --timestamp backdates instead",
|
||||
("/v3/memories/search/", "categories"): "expressible through --filter",
|
||||
("/v3/memories/search/", "metadata"): "expressible through --filter",
|
||||
("/v3/memories/", "start_date"): "covered by --after via filters.created_at.gte",
|
||||
("/v3/memories/", "end_date"): "covered by --before via filters.created_at.lte",
|
||||
("/v3/memories/", "categories"): "covered by --category via filters.categories",
|
||||
("/v3/memories/", "fields"): "no CLI flag yet",
|
||||
("/v3/memories/", "keywords"): "no CLI flag yet",
|
||||
}
|
||||
|
||||
ADD_MAPPING: dict[str, list[str]] = {
|
||||
"messages": ["messages", "file", "text"],
|
||||
"user_id": ["user_id"],
|
||||
"agent_id": ["agent_id"],
|
||||
"app_id": ["app_id"],
|
||||
"run_id": ["run_id"],
|
||||
"metadata": ["metadata"],
|
||||
"expiration_date": ["expires"],
|
||||
"custom_instructions": ["custom_instructions"],
|
||||
"custom_categories": ["custom_categories"],
|
||||
"infer": ["no_infer"],
|
||||
"immutable": ["immutable"],
|
||||
"structured_data_schema": ["structured_data_schema"],
|
||||
"timestamp": ["timestamp"],
|
||||
}
|
||||
|
||||
SEARCH_MAPPING: dict[str, list[str]] = {
|
||||
"query": ["query"],
|
||||
"filters": ["filter_json", "user_id", "agent_id", "run_id"],
|
||||
"show_expired": ["show_expired"],
|
||||
"top_k": ["top_k"],
|
||||
"threshold": ["threshold"],
|
||||
"rerank": ["rerank"],
|
||||
"reference_date": ["reference_date"],
|
||||
"fields": ["fields"],
|
||||
}
|
||||
|
||||
LIST_MAPPING: dict[str, list[str]] = {
|
||||
"filters": ["user_id", "agent_id", "run_id", "category", "after", "before"],
|
||||
"show_expired": ["show_expired"],
|
||||
"page": ["page"],
|
||||
"page_size": ["page_size"],
|
||||
}
|
||||
|
||||
|
||||
def _documented_fields(endpoint: str) -> set[str]:
|
||||
spec = json.loads(OPENAPI_PATH.read_text())
|
||||
schema = spec["paths"][endpoint]["post"]["requestBody"]["content"]["application/json"]["schema"]
|
||||
return set(schema["properties"])
|
||||
|
||||
|
||||
def _cli_param_names(command_name: str) -> set[str]:
|
||||
click_app = typer.main.get_command(app)
|
||||
command = click_app.commands[command_name]
|
||||
return {param.name for param in command.params}
|
||||
|
||||
|
||||
def _assert_all_reachable(endpoint: str, mapping: dict[str, list[str]], command_name: str) -> None:
|
||||
documented = _documented_fields(endpoint)
|
||||
reachable = _cli_param_names(command_name)
|
||||
for field in documented:
|
||||
if (endpoint, field) in KNOWN_UNSURFACED:
|
||||
continue
|
||||
candidates = mapping.get(field)
|
||||
assert candidates, (
|
||||
f"{endpoint}: documented field {field!r} has no mapping entry for command {command_name!r}"
|
||||
)
|
||||
assert any(candidate in reachable for candidate in candidates), (
|
||||
f"{endpoint}: documented field {field!r} not reachable via any of {candidates} on command {command_name!r}"
|
||||
)
|
||||
|
||||
|
||||
class TestOptionParity:
|
||||
def test_add_covers_documented_fields(self):
|
||||
_assert_all_reachable("/v3/memories/add/", ADD_MAPPING, "add")
|
||||
|
||||
def test_search_covers_documented_fields(self):
|
||||
_assert_all_reachable("/v3/memories/search/", SEARCH_MAPPING, "search")
|
||||
|
||||
def test_list_covers_documented_fields(self):
|
||||
_assert_all_reachable("/v3/memories/", LIST_MAPPING, "list")
|
||||
@@ -0,0 +1,109 @@
|
||||
"""Tests that the MEM-5893 option-parity flags reach the correct request payload/params."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
from mem0_cli.backend.platform import PlatformBackend
|
||||
from mem0_cli.config import PlatformConfig
|
||||
|
||||
|
||||
def _make_backend() -> PlatformBackend:
|
||||
return PlatformBackend(PlatformConfig(api_key="test-key", base_url="https://api.mem0.ai"))
|
||||
|
||||
|
||||
class TestAddOptions:
|
||||
def test_new_fields_and_existing_fields_land_in_payload_together(self):
|
||||
backend = _make_backend()
|
||||
with patch.object(backend, "_request", return_value={"results": []}) as mock_request:
|
||||
backend.add(
|
||||
content="hello",
|
||||
user_id="alice",
|
||||
metadata={"source": "test"},
|
||||
expires="2099-01-01",
|
||||
custom_instructions="Extract only preferences.",
|
||||
custom_categories=[{"prefs": "user preferences"}],
|
||||
structured_data_schema={"type": "object"},
|
||||
timestamp=1700000000,
|
||||
)
|
||||
payload = mock_request.call_args.kwargs["json"]
|
||||
assert payload["custom_instructions"] == "Extract only preferences."
|
||||
assert payload["custom_categories"] == [{"prefs": "user preferences"}]
|
||||
assert payload["structured_data_schema"] == {"type": "object"}
|
||||
assert payload["timestamp"] == 1700000000
|
||||
assert payload["metadata"] == {"source": "test"}
|
||||
assert payload["expiration_date"] == "2099-01-01"
|
||||
|
||||
def test_omitted_fields_are_absent_from_payload(self):
|
||||
backend = _make_backend()
|
||||
with patch.object(backend, "_request", return_value={"results": []}) as mock_request:
|
||||
backend.add(content="hello", user_id="alice")
|
||||
payload = mock_request.call_args.kwargs["json"]
|
||||
assert "custom_instructions" not in payload
|
||||
assert "custom_categories" not in payload
|
||||
assert "structured_data_schema" not in payload
|
||||
assert "timestamp" not in payload
|
||||
|
||||
|
||||
class TestSearchOptions:
|
||||
def test_show_expired_reference_date_latest_only_reach_payload(self):
|
||||
backend = _make_backend()
|
||||
with patch.object(backend, "_request", return_value=[]) as mock_request:
|
||||
backend.search(
|
||||
"query",
|
||||
show_expired=True,
|
||||
reference_date="2024-01-01",
|
||||
latest_only=True,
|
||||
)
|
||||
payload = mock_request.call_args.kwargs["json"]
|
||||
assert payload["show_expired"] is True
|
||||
assert payload["reference_date"] == "2024-01-01"
|
||||
assert payload["latest_only"] is True
|
||||
|
||||
def test_keyword_and_fields_reach_payload(self):
|
||||
backend = _make_backend()
|
||||
with patch.object(backend, "_request", return_value=[]) as mock_request:
|
||||
backend.search("query", keyword=True, fields=["memory", "score"])
|
||||
payload = mock_request.call_args.kwargs["json"]
|
||||
assert payload["keyword_search"] is True
|
||||
assert payload["fields"] == ["memory", "score"]
|
||||
|
||||
def test_keyword_and_fields_omitted_are_absent_from_payload(self):
|
||||
backend = _make_backend()
|
||||
with patch.object(backend, "_request", return_value=[]) as mock_request:
|
||||
backend.search("query")
|
||||
payload = mock_request.call_args.kwargs["json"]
|
||||
assert "keyword_search" not in payload
|
||||
assert "fields" not in payload
|
||||
|
||||
|
||||
class TestListOptions:
|
||||
def test_show_expired_and_latest_only_are_top_level_not_in_filters(self):
|
||||
backend = _make_backend()
|
||||
with patch.object(backend, "_request", return_value=[]) as mock_request:
|
||||
backend.list_memories(user_id="alice", show_expired=True, latest_only=True)
|
||||
payload = mock_request.call_args.kwargs["json"]
|
||||
assert payload["show_expired"] is True
|
||||
assert payload["latest_only"] is True
|
||||
assert "show_expired" not in payload.get("filters", {})
|
||||
assert "latest_only" not in payload.get("filters", {})
|
||||
|
||||
|
||||
class TestUpdateOptions:
|
||||
def test_expires_and_timestamp_reach_payload(self):
|
||||
backend = _make_backend()
|
||||
with patch.object(backend, "_request", return_value={}) as mock_request:
|
||||
backend.update("mem-123", expiration_date="2099-01-01", timestamp=1700000000)
|
||||
payload = mock_request.call_args.kwargs["json"]
|
||||
assert payload["expiration_date"] == "2099-01-01"
|
||||
assert payload["timestamp"] == 1700000000
|
||||
|
||||
|
||||
class TestDeleteOptions:
|
||||
def test_delete_linked_is_a_query_param_not_json_body(self):
|
||||
backend = _make_backend()
|
||||
with patch.object(backend, "_request", return_value={}) as mock_request:
|
||||
backend.delete(memory_id="mem-123", delete_linked=True)
|
||||
call = mock_request.call_args
|
||||
assert call.kwargs["params"]["delete_linked"] == "true"
|
||||
assert "json" not in call.kwargs
|
||||
@@ -65,9 +65,8 @@ The request is queued for background processing. The response contains an `event
|
||||
<CodeGroup>
|
||||
```json 200 response
|
||||
{
|
||||
"message": "Memory processing has been queued for background execution",
|
||||
"status": "PENDING",
|
||||
"event_id": "evt-uuid"
|
||||
"event_id": "evt-uuid",
|
||||
"status": "PENDING"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -4,6 +4,23 @@ description: "Major product launches, headline features, and milestones for Mem0
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
<Update label="2026-07-30" description="n8n and Zapier integrations">
|
||||
|
||||
**Workflow Automation: Mem0 Memory in n8n and Zapier**
|
||||
|
||||
Mem0 now plugs into two no-code automation platforms, so workflows that used to start from zero on every run can store durable facts and recall them later.
|
||||
|
||||
- **n8n community node:** [`@mem0/n8n-nodes-mem0`](https://www.npmjs.com/package/@mem0/n8n-nodes-mem0) adds a **Mem0** node with a Memory resource covering Add, Search, Get, Get Many, Update, and Delete. Install it from **Settings → Community Nodes** on a self-hosted instance, then connect your API key once as a Mem0 API credential. See [n8n](/integrations/n8n).
|
||||
- **n8n AI Agent tool:** Attach the same node to an [AI Agent](https://docs.n8n.io/advanced-ai/) node and it becomes a tool the agent calls on its own, so it can decide when to remember and when to recall.
|
||||
- **Zapier app:** Add Memory, Search Memories, Get Memories, and Delete Memory actions let any of Zapier's thousands of apps write and read Mem0 context with no code and no server. See [Zapier](/integrations/zapier).
|
||||
- **One-time connection:** Both integrations authenticate with a single Mem0 API key and default to `https://api.mem0.ai`, with a configurable base URL for self-hosted deployments.
|
||||
|
||||
<Note>
|
||||
The Zapier app is not yet listed in Zapier's public App Directory. Email [support@mem0.ai](mailto:support@mem0.ai) for an invite link.
|
||||
</Note>
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-07-13" description="TypeScript provider expansion">
|
||||
|
||||
**TypeScript OSS SDK: 26 New Providers, Reranking, and Zero-Dependency Imports**
|
||||
|
||||
+109
-4
@@ -7,6 +7,18 @@ mode: "wide"
|
||||
<Tabs>
|
||||
<Tab title="Python">
|
||||
|
||||
<Update label="2026-08-01" description="v2.0.15">
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Core:** `delete_all()` now paginates through the vector store in batches of 1000 instead of listing once, so accounts with more memories than a single page (most vector stores default to ~100) had the remainder silently left behind ([#6636](https://github.com/mem0ai/mem0/pull/6636))
|
||||
- **Vector Stores:** Cap Supabase `search()`/`list()` `top_k` at the `vecs` query limit of 1000 instead of erroring, and fix a `col_info()` crash by reading collection attributes directly instead of calling the removed `describe()` method ([#6695](https://github.com/mem0ai/mem0/pull/6695))
|
||||
- **Vector Stores:** Set `size` on Elasticsearch KNN search queries, so results respect `top_k` instead of being capped at Elasticsearch's default of 10 hits ([#5910](https://github.com/mem0ai/mem0/pull/5910))
|
||||
|
||||
**Changes:**
|
||||
- **Rerankers:** `LLMReranker`'s default model is now `gpt-5-mini` (was `gpt-4o-mini`) ([#6703](https://github.com/mem0ai/mem0/pull/6703))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-07-25" description="v2.0.14">
|
||||
|
||||
**New Features:**
|
||||
@@ -1157,6 +1169,24 @@ See the [OSS v2 to v3 migration guide](https://docs.mem0.ai/migration/oss-v2-to-
|
||||
|
||||
<Tab title="TypeScript">
|
||||
|
||||
<Update label="2026-08-01" description="v3.1.3">
|
||||
|
||||
**New Features:**
|
||||
- **Vector Stores:** Add Qdrant server-side BM25 `keywordSearch()` (requires Qdrant >= 1.15.2) plus payload filter indexes, so keyword search runs without a client-side BM25 dependency ([#5851](https://github.com/mem0ai/mem0/pull/5851))
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Core:** `deleteAll()` now paginates through the vector store in batches of 1000 instead of listing once, so accounts with more memories than a single page had the remainder silently left behind ([#4872](https://github.com/mem0ai/mem0/pull/4872))
|
||||
- **Vector Stores:** Supabase `list()` now paginates past PostgREST's 1000-row cap instead of stopping at the first page, `search()` warns when results may have been truncated by that same cap, and the initialization probe reads a row instead of writing a test vector, so Row Level Security policies that only grant read access no longer fail table verification ([#6695](https://github.com/mem0ai/mem0/pull/6695))
|
||||
- **Embeddings:** Honor `TOGETHER_API_BASE` in the Together embedder, matching the Together LLM provider, so a custom gateway URL is no longer silently ignored for embeddings ([#6572](https://github.com/mem0ai/mem0/pull/6572))
|
||||
|
||||
**Changes:**
|
||||
- **Rerankers:** `RerankerFactory`'s default LLM reranker model is now `gpt-5-mini` (was `gpt-4o-mini`) ([#6703](https://github.com/mem0ai/mem0/pull/6703))
|
||||
|
||||
**Security:**
|
||||
- **Dependencies:** Patched 32 high and 57 medium severity dependency vulnerabilities across the pnpm workspace via `pnpm.overrides` (`axios`, `brace-expansion`, `js-yaml`, `postcss`, `protobufjs`, `mongoose`, `tar`, `fast-xml-parser`, `thrift`) ([#6639](https://github.com/mem0ai/mem0/pull/6639))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-07-25" description="v3.1.2">
|
||||
|
||||
**Bug Fixes:**
|
||||
@@ -1886,9 +1916,9 @@ A full-featured command-line interface for Mem0, available in both Python and No
|
||||
<Update label="2026-07-14" description="mem0-plugin v0.2.13">
|
||||
|
||||
**Fixes:**
|
||||
- **Assistant messages no longer stored as your own:** The session-summary hook (fires at the end of every assistant turn) and the post-compaction hook were sending the assistant's own message to Mem0 tagged `role: "user"`. Because Mem0 extracts *facts about the user* from each message and uses `role` to decide who spoke, the assistant's first-person prose was being saved as the human's stated preferences — "I recommend we drop Redis" became `User prefers dropping Redis entirely`. Both hooks now send `role: "assistant"`, so the same session is stored as `Assistant recommended...`. Affects Claude Code, Cursor, Codex, and Antigravity, which share these hooks.
|
||||
- **Assistant messages no longer stored as your own:** The session-summary hook (fires at the end of every assistant turn) and the post-compaction hook were sending the assistant's own message to Mem0 tagged `role: "user"`. Because Mem0 extracts *facts about the user* from each message and uses `role` to decide who spoke, the assistant's first-person prose was being saved as the human's stated preferences: "I recommend we drop Redis" became `User prefers dropping Redis entirely`. Both hooks now send `role: "assistant"`, so the same session is stored as `Assistant recommended...`. Affects Claude Code, Cursor, Codex, and Antigravity, which share these hooks.
|
||||
|
||||
Existing memories written by the previous versions are not rewritten. If your memories contain preferences you never expressed, delete them — the plugin will not recreate them.
|
||||
Existing memories written by the previous versions are not rewritten. If your memories contain preferences you never expressed, delete them; the plugin will not recreate them.
|
||||
|
||||
</Update>
|
||||
|
||||
@@ -2225,9 +2255,9 @@ Initial release of the Mem0 plugin for Claude Code and Cursor, followed by Codex
|
||||
<Update label="2026-07-14" description="Antigravity plugin v0.1.5">
|
||||
|
||||
**Fixes:**
|
||||
- **Assistant messages no longer stored as your own:** The session-summary hook (fires at the end of every assistant turn) and the post-compaction hook were sending the assistant's own message to Mem0 tagged `role: "user"`. Because Mem0 extracts *facts about the user* from each message and uses `role` to decide who spoke, the assistant's first-person prose was being saved as the human's stated preferences — "I recommend we drop Redis" became `User prefers dropping Redis entirely`. Both hooks now send `role: "assistant"`, so the same session is stored as `Assistant recommended...`.
|
||||
- **Assistant messages no longer stored as your own:** The session-summary hook (fires at the end of every assistant turn) and the post-compaction hook were sending the assistant's own message to Mem0 tagged `role: "user"`. Because Mem0 extracts *facts about the user* from each message and uses `role` to decide who spoke, the assistant's first-person prose was being saved as the human's stated preferences: "I recommend we drop Redis" became `User prefers dropping Redis entirely`. Both hooks now send `role: "assistant"`, so the same session is stored as `Assistant recommended...`.
|
||||
|
||||
Existing memories written by the previous versions are not rewritten. If your memories contain preferences you never expressed, delete them — the plugin will not recreate them.
|
||||
Existing memories written by the previous versions are not rewritten. If your memories contain preferences you never expressed, delete them; the plugin will not recreate them.
|
||||
|
||||
</Update>
|
||||
|
||||
@@ -2278,6 +2308,16 @@ Existing memories written by the previous versions are not rewritten. If your me
|
||||
|
||||
<Tab title="OpenClaw">
|
||||
|
||||
<Update label="2026-08-01" description="openclaw-mem0 v1.0.15">
|
||||
|
||||
**Improvements:**
|
||||
- **Onboarding suggestions:** The example commands shown by `openclaw mem0 config show` now suggest `gpt-5-mini` instead of `gpt-4o` ([#6704](https://github.com/mem0ai/mem0/pull/6704))
|
||||
|
||||
**Security:**
|
||||
- **Dependencies:** Patched high and medium severity dependency vulnerabilities via `pnpm.overrides` (`protobufjs`, `axios`, `postcss`, `mongoose`) ([#6639](https://github.com/mem0ai/mem0/pull/6639))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-06-30" description="openclaw-mem0 v1.0.14">
|
||||
|
||||
**Improvements:**
|
||||
@@ -2531,6 +2571,13 @@ Existing memories written by the previous versions are not rewritten. If your me
|
||||
|
||||
<Tab title="Pi Agent">
|
||||
|
||||
<Update label="2026-08-01" description="Pi Agent plugin v0.1.4">
|
||||
|
||||
**Security:**
|
||||
- **Dependencies:** Patched high and medium severity dependency vulnerabilities via `pnpm.overrides` (`axios`, `brace-expansion`, `postcss`, `mongoose`, `protobufjs`) ([#6639](https://github.com/mem0ai/mem0/pull/6639))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-06-30" description="Pi Agent plugin v0.1.3">
|
||||
|
||||
**New Features:**
|
||||
@@ -2583,6 +2630,13 @@ Existing memories written by the previous versions are not rewritten. If your me
|
||||
|
||||
<Tab title="Vercel AI SDK">
|
||||
|
||||
<Update label="2026-08-01" description="Vercel AI SDK v3.0.1">
|
||||
|
||||
**Security:**
|
||||
- **Dependencies:** Patched high and medium severity dependency vulnerabilities via `pnpm.overrides` (`brace-expansion`, `js-yaml`) ([#6639](https://github.com/mem0ai/mem0/pull/6639))
|
||||
|
||||
</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.
|
||||
@@ -2664,6 +2718,57 @@ Existing memories written by the previous versions are not rewritten. If your me
|
||||
- Added support for graph memories.
|
||||
</Update>
|
||||
|
||||
</Tab>
|
||||
|
||||
<Tab title="n8n">
|
||||
|
||||
<Update label="2026-07-30" description="n8n-nodes-mem0 v0.1.1">
|
||||
|
||||
**Changes:**
|
||||
- **Published with npm provenance:** Republished through the `n8n-nodes-mem0-cd.yml` GitHub Actions workflow so the package carries a signed provenance attestation. `0.1.0` was published manually and has none, which blocks submission for n8n Creator Portal verification. No functional changes ([#6685](https://github.com/mem0ai/mem0/pull/6685))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-07-29" description="n8n-nodes-mem0 v0.1.0">
|
||||
|
||||
**Initial release** of [`@mem0/n8n-nodes-mem0`](https://www.npmjs.com/package/@mem0/n8n-nodes-mem0), a community node that adds long-term memory to n8n workflows and AI Agents ([#6517](https://github.com/mem0ai/mem0/pull/6517))
|
||||
|
||||
**New Features:**
|
||||
- **Memory operations:** A single **Mem0** node covers Add, Search, Get, Get Many, Update, and Delete on the Memory resource.
|
||||
- **AI Agent tool:** The node sets `usableAsTool`, so it can be attached to an n8n AI Agent node and invoked by the agent itself rather than wired into a fixed workflow path.
|
||||
- **Scoping:** Add, Search, and Get Many accept User ID, Agent ID, App ID, and Run ID, so memories stay partitioned per user, agent, or session.
|
||||
- **Add options:** Metadata JSON, custom categories, custom instructions, includes/excludes, an `infer` toggle, and a **Wait for Completion** switch that polls until the write lands instead of returning immediately.
|
||||
- **Pagination:** Get Many supports Return All, or explicit Page and Page Size.
|
||||
- **Credential:** A **Mem0 API** credential holds the API key plus a configurable base URL, defaulting to `https://api.mem0.ai` for self-hosted deployments.
|
||||
|
||||
<Note>
|
||||
Community nodes install from npm, which is a self-hosted n8n feature. See [n8n](/integrations/n8n) for setup.
|
||||
</Note>
|
||||
|
||||
</Update>
|
||||
|
||||
</Tab>
|
||||
|
||||
<Tab title="Zapier">
|
||||
|
||||
<Update label="2026-07-29" description="Zapier app v0.1.0">
|
||||
|
||||
**Initial release** of the Mem0 Zapier app, built on the Zapier Platform CLI ([#6518](https://github.com/mem0ai/mem0/pull/6518))
|
||||
|
||||
**New Features:**
|
||||
- **Actions:** Add Memory and Delete Memory.
|
||||
- **Searches:** Search Memories and Get Memories, usable as lookup steps in any Zap.
|
||||
- **Authentication:** An API key connection validated against Mem0 the moment it is saved, sent as `Authorization: Token <key>`, with a configurable base URL for self-hosted deployments.
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Add Memory:** Raise the poll budget past the real API latency tail, so a slower write is no longer reported as a failure ([#6680](https://github.com/mem0ai/mem0/pull/6680))
|
||||
|
||||
<Note>
|
||||
The app deploys to Zapier's platform rather than npm and is not yet listed in the public App Directory. See [Zapier](/integrations/zapier) for invite access.
|
||||
</Note>
|
||||
|
||||
</Update>
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ All rerankers share these common configuration parameters:
|
||||
|
||||
| Parameter | Description | Type | Default |
|
||||
| ---------------- | ------------------------------------------ | ------- | ---------------------- |
|
||||
| `model` | LLM model to use for scoring | `str` | `"gpt-4o-mini"` |
|
||||
| `model` | LLM model to use for scoring | `str` | `"gpt-5-mini"` |
|
||||
| `provider` | LLM provider (`openai`, `anthropic`, etc.) | `str` | `"openai"` |
|
||||
| `api_key` | API key for LLM provider | `str` | `None` |
|
||||
| `temperature` | Temperature for LLM generation | `float` | `0.0` |
|
||||
@@ -114,7 +114,7 @@ The self-hosted [TypeScript SDK](/open-source/features/reranker-search#typescrip
|
||||
| `zero_entropy` | `pnpm add zeroentropy` | `zerank-1` | `apiKey`, `model`, `topK` |
|
||||
| `sentence_transformer` | `pnpm add @huggingface/transformers` | `Xenova/ms-marco-MiniLM-L-6-v2` | `model`, `device`, `maxLength`, `normalize`, `topK` |
|
||||
| `huggingface` | `pnpm add @huggingface/transformers` | `Xenova/bge-reranker-base` | `model`, `device`, `maxLength`, `normalize`, `topK` |
|
||||
| `llm_reranker` | None (uses your LLM provider's own SDK) | `openai` / `gpt-4o-mini` | `provider`, `model`, `apiKey`, `llm` (nested override), `topK` |
|
||||
| `llm_reranker` | None (uses your LLM provider's own SDK) | `openai` / `gpt-5-mini` | `provider`, `model`, `apiKey`, `llm` (nested override), `topK` |
|
||||
|
||||
```typescript
|
||||
import { Memory } from "mem0ai/oss";
|
||||
|
||||
@@ -48,7 +48,7 @@ config = {
|
||||
"provider": "llm_reranker",
|
||||
"config": {
|
||||
"provider": "openai",
|
||||
"model": "gpt-4o-mini",
|
||||
"model": "gpt-5-mini",
|
||||
"api_key": "your-openai-key",
|
||||
"scoring_prompt": custom_prompt,
|
||||
"top_k": 5
|
||||
|
||||
@@ -101,7 +101,7 @@ os.environ["COHERE_API_KEY"] = "your-api-key"
|
||||
# Initialize memory with Cohere reranker
|
||||
config = {
|
||||
"vector_store": {"provider": "chroma"},
|
||||
"llm": {"provider": "openai", "config": {"model": "gpt-4o-mini"}},
|
||||
"llm": {"provider": "openai", "config": {"model": "gpt-5-mini"}},
|
||||
"rerank": {
|
||||
"provider": "cohere",
|
||||
"config": {
|
||||
|
||||
@@ -19,7 +19,7 @@ config = {
|
||||
"provider": "llm_reranker",
|
||||
"config": {
|
||||
"provider": "openai",
|
||||
"model": "gpt-4o-mini",
|
||||
"model": "gpt-5-mini",
|
||||
"api_key": "your-openai-api-key"
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,7 @@ m = Memory.from_config(config)
|
||||
| Parameter | Type | Default | Description |
|
||||
|-----------|------|---------|-------------|
|
||||
| `provider` | str | `"openai"` | LLM provider (openai, anthropic, etc.) |
|
||||
| `model` | str | `"gpt-4o-mini"` | LLM model to use for reranking |
|
||||
| `model` | str | `"gpt-5-mini"` | LLM model to use for reranking |
|
||||
| `api_key` | str | None | API key for the LLM provider |
|
||||
| `top_k` | int | None | Number of top documents to return after reranking |
|
||||
| `temperature` | float | 0.0 | LLM temperature for consistency |
|
||||
@@ -69,7 +69,7 @@ config = {
|
||||
|
||||
## TypeScript (self-hosted)
|
||||
|
||||
The [TypeScript OSS SDK](/open-source/features/reranker-search#typescript-sdk) (`mem0ai/oss`) ships the LLM reranker under the provider name `llm_reranker`. It does **not** reuse the Memory's main `llm` instance; it builds its own LLM from the reranker's own config, defaulting to `openai` / `gpt-4o-mini`. Set `provider`/`model`/`apiKey` directly on `config`, or nest a fully separate `config.llm: { provider, config }` (its `provider`/`config` take priority over the top-level fields, which only backfill values missing from the nested config).
|
||||
The [TypeScript OSS SDK](/open-source/features/reranker-search#typescript-sdk) (`mem0ai/oss`) ships the LLM reranker under the provider name `llm_reranker`. It does **not** reuse the Memory's main `llm` instance; it builds its own LLM from the reranker's own config, defaulting to `openai` / `gpt-5-mini`. Set `provider`/`model`/`apiKey` directly on `config`, or nest a fully separate `config.llm: { provider, config }` (its `provider`/`config` take priority over the top-level fields, which only backfill values missing from the nested config).
|
||||
|
||||
```typescript
|
||||
import { Memory } from "mem0ai/oss";
|
||||
@@ -114,7 +114,7 @@ config = {
|
||||
"provider": "llm_reranker",
|
||||
"config": {
|
||||
"provider": "openai",
|
||||
"model": "gpt-4o-mini",
|
||||
"model": "gpt-5-mini",
|
||||
"api_key": "your-openai-api-key",
|
||||
"temperature": 0.0
|
||||
}
|
||||
@@ -170,15 +170,15 @@ config = {
|
||||
"provider": "llm_reranker",
|
||||
"config": {
|
||||
"provider": "azure_openai",
|
||||
"model": "gpt-4o-mini",
|
||||
"model": "gpt-5-mini",
|
||||
"api_key": "your-azure-api-key",
|
||||
"llm": {
|
||||
"provider": "azure_openai",
|
||||
"config": {
|
||||
"model": "gpt-4o-mini",
|
||||
"model": "gpt-5-mini",
|
||||
"api_key": "your-azure-api-key",
|
||||
"azure_endpoint": "https://your-resource.openai.azure.com/",
|
||||
"azure_deployment": "gpt-4o-mini-deployment"
|
||||
"azure_deployment": "gpt-5-mini-deployment"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -232,7 +232,7 @@ config = {
|
||||
"provider": "llm_reranker",
|
||||
"config": {
|
||||
"provider": "openai",
|
||||
"model": "gpt-4o-mini",
|
||||
"model": "gpt-5-mini",
|
||||
"api_key": "your-api-key",
|
||||
"scoring_prompt": custom_prompt
|
||||
}
|
||||
@@ -351,7 +351,7 @@ fast_config = {
|
||||
"provider": "llm_reranker",
|
||||
"config": {
|
||||
"provider": "openai",
|
||||
"model": "gpt-4o-mini",
|
||||
"model": "gpt-5-mini",
|
||||
"api_key": "your-api-key",
|
||||
"top_k": 5,
|
||||
"temperature": 0.0
|
||||
@@ -444,7 +444,7 @@ fallback_config = {
|
||||
"provider": "llm_reranker",
|
||||
"config": {
|
||||
"provider": "openai",
|
||||
"model": "gpt-4o-mini",
|
||||
"model": "gpt-5-mini",
|
||||
"api_key": "your-api-key"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ config = {
|
||||
"llm": {
|
||||
"provider": "openai",
|
||||
"config": {
|
||||
"model": "gpt-4o-mini"
|
||||
"model": "gpt-5-mini"
|
||||
}
|
||||
},
|
||||
"rerank": {
|
||||
@@ -113,7 +113,7 @@ from mem0 import Memory
|
||||
# Initialize memory with local reranker
|
||||
config = {
|
||||
"vector_store": {"provider": "chroma"},
|
||||
"llm": {"provider": "openai", "config": {"model": "gpt-4o-mini"}},
|
||||
"llm": {"provider": "openai", "config": {"model": "gpt-5-mini"}},
|
||||
"rerank": {
|
||||
"provider": "sentence_transformer",
|
||||
"config": {
|
||||
|
||||
@@ -34,7 +34,7 @@ config = {
|
||||
"llm": {
|
||||
"provider": "openai",
|
||||
"config": {
|
||||
"model": "gpt-4o-mini"
|
||||
"model": "gpt-5-mini"
|
||||
}
|
||||
},
|
||||
"rerank": {
|
||||
@@ -98,7 +98,7 @@ os.environ["ZERO_ENTROPY_API_KEY"] = "your-api-key"
|
||||
# Initialize memory with Zero Entropy reranker
|
||||
config = {
|
||||
"vector_store": {"provider": "chroma"},
|
||||
"llm": {"provider": "openai", "config": {"model": "gpt-4o-mini"}},
|
||||
"llm": {"provider": "openai", "config": {"model": "gpt-5-mini"}},
|
||||
"rerank": {"provider": "zero_entropy", "config": {"model": "zerank-1"}}
|
||||
}
|
||||
|
||||
|
||||
@@ -96,8 +96,8 @@ await memory.add(messages, { userId: "alice", metadata: { category: "movies" } }
|
||||
</Tabs>
|
||||
|
||||
Both SDKs store vectors on graph nodes labeled `MEM0_VECTOR_<collection_name>`. Point them at the same
|
||||
graph with the same `collection_name` — the defaults differ, `mem0` in Python and `memories` in
|
||||
TypeScript — and `get()`, `list()`, and `delete()` interoperate across SDKs.
|
||||
graph with the same `collection_name` (the defaults differ, `mem0` in Python and `memories` in
|
||||
TypeScript) and `get()`, `list()`, and `delete()` interoperate across SDKs.
|
||||
|
||||
<Note>
|
||||
`search()` is not currently cross-SDK compatible. The TypeScript provider filters on Neptune's reserved
|
||||
|
||||
@@ -60,6 +60,12 @@ await memory.add(messages, { userId: "alice", metadata: { category: "movies" } }
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### Hybrid keyword search
|
||||
|
||||
Mem0 blends semantic similarity with BM25 keyword scoring. On the TypeScript SDK, Qdrant computes the BM25 vectors server-side, which requires Qdrant 1.15.2 or newer with inference enabled. Qdrant Cloud enables inference by default only for clusters created after 2025-07-07; older clusters must activate it from the Cluster Detail page. The Python SDK encodes BM25 locally instead and needs the `fastembed` package, so scores are not numerically comparable between the two SDKs.
|
||||
|
||||
When BM25 is unavailable, or when the collection was created before hybrid search was added, Mem0 logs a warning and falls back to semantic-only search. Writes are unaffected. To enable keyword scoring on an older collection, use a fresh collection name.
|
||||
|
||||
### Config
|
||||
|
||||
Let's see the available parameters for the `qdrant` config:
|
||||
|
||||
@@ -115,6 +115,27 @@ $$;
|
||||
|
||||
Go to [Supabase](https://supabase.com/dashboard/projects) and run the above SQL migrations in the SQL Editor.
|
||||
|
||||
### Row Level Security
|
||||
|
||||
Tables created through the Supabase dashboard have Row Level Security (RLS) enabled by default with no policies attached. With RLS on and no policies, the TypeScript SDK's queries return zero rows with an HTTP 200 (no error is raised), which looks like an empty memory store rather than a permissions problem. If you use the SQL migrations above (via the SQL Editor), RLS is left in its default off state and this does not apply.
|
||||
|
||||
If your table has RLS enabled, add policies for the key your app uses (the example below grants full access to the `service_role` key; scope it down for anon/authenticated keys as needed):
|
||||
|
||||
```sql
|
||||
alter table memories enable row level security;
|
||||
|
||||
create policy "Allow service role full access to memories"
|
||||
on memories
|
||||
for all
|
||||
to service_role
|
||||
using (true)
|
||||
with check (true);
|
||||
```
|
||||
|
||||
### PostgREST Row Limits
|
||||
|
||||
Supabase's PostgREST layer caps the number of rows returned by a single request at `db-max-rows` (1000 by default), for both `.select()` queries and RPC function calls like `match_vectors`. Requesting a `topK` above this limit for `search()` or `list()` will not raise an error, results are capped at `db-max-rows` instead. The TypeScript `list()` method paginates internally to work around this, but `search()` cannot since `match_vectors` has no offset parameter; it logs a warning when it detects a truncated result. Raise `db-max-rows` in your Supabase project settings if you need more than 1000 results per search.
|
||||
|
||||
### Config
|
||||
|
||||
Here are the parameters available for configuring Supabase:
|
||||
|
||||
@@ -55,9 +55,8 @@ await addUserPreferences();
|
||||
|
||||
```json Output
|
||||
{
|
||||
"message": "Memory processing has been queued for background execution",
|
||||
"status": "PENDING",
|
||||
"event_id": "9f8c2b1a-4e7d-4c3a-9b21-1a2b3c4d5e6f"
|
||||
"event_id": "9f8c2b1a-4e7d-4c3a-9b21-1a2b3c4d5e6f",
|
||||
"status": "PENDING"
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
@@ -67,7 +67,7 @@ The plugin uses the same shell scripts as Claude Code, Cursor, and Codex: hooks
|
||||
| **Post-tool** | `PostToolUse` | Tracks stats, scans bash errors for related memories |
|
||||
| **Stop** | `Stop` | Stores a session summary at the end of every assistant turn (not just at session end) |
|
||||
|
||||
What you type is stored as yours. What the agent produces — session summaries and compaction summaries — is stored as the assistant's, so its suggestions never become your stated preferences.
|
||||
What you type is stored as yours. What the agent produces (session summaries and compaction summaries) is stored as the assistant's, so its suggestions never become your stated preferences.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ When installed via the plugin marketplace, Mem0 hooks into Claude Code's lifecyc
|
||||
| **Stop** | `Stop` | Stores a session summary at the end of every assistant turn (not just at session end) |
|
||||
| **Pre-compact** | `PreCompact` | Stores a summary before the context is compacted |
|
||||
|
||||
What you type is stored as yours. What Claude produces — session summaries and compaction summaries — is stored as the assistant's, so its suggestions never become your stated preferences.
|
||||
What you type is stored as yours. What Claude produces (session summaries and compaction summaries) is stored as the assistant's, so its suggestions never become your stated preferences.
|
||||
|
||||
## Example Workflow
|
||||
|
||||
|
||||
@@ -128,7 +128,7 @@ When installed via the plugin marketplace, Mem0 hooks into Codex's lifecycle to
|
||||
| **Stop** | `Stop` | Stores a session summary at the end of every assistant turn (not just at session end) |
|
||||
| **Pre-compact** | `PreCompact` | Stores a summary before the context is compacted |
|
||||
|
||||
What you type is stored as yours. What Codex produces — session summaries and compaction summaries — is stored as the assistant's, so its suggestions never become your stated preferences.
|
||||
What you type is stored as yours. What Codex produces (session summaries and compaction summaries) is stored as the assistant's, so its suggestions never become your stated preferences.
|
||||
|
||||
## Example Workflow
|
||||
|
||||
|
||||
@@ -98,9 +98,8 @@ add_result = add_tool.invoke(add_input)
|
||||
|
||||
```json Output
|
||||
{
|
||||
"message": "Memory processing has been queued for background execution",
|
||||
"status": "PENDING",
|
||||
"event_id": "3a1b2c3d-4e5f-6789-abcd-ef0123456789"
|
||||
"event_id": "3a1b2c3d-4e5f-6789-abcd-ef0123456789",
|
||||
"status": "PENDING"
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
+13
-13
@@ -10,7 +10,7 @@ mode: "custom"
|
||||
</h1>
|
||||
|
||||
<p className="max-w-3xl mx-auto text-base text-gray-600 dark:text-zinc-400 leading-relaxed">
|
||||
Universal, self-improving memory layer for LLM applications.
|
||||
Mem0 gives your AI agents long-term memory that persists across sessions, tools, and runs.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -34,10 +34,10 @@ mode: "custom"
|
||||
/>
|
||||
<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">
|
||||
Add memory to your app
|
||||
Store your first memory
|
||||
</h3>
|
||||
<p className="text-sm text-gray-600 dark:text-zinc-400">
|
||||
Start with the quickstart and store your first memory in minutes.
|
||||
Five-minute quickstart: get an API key, then save and search a memory in Python or JavaScript.
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
@@ -60,10 +60,10 @@ mode: "custom"
|
||||
/>
|
||||
<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">
|
||||
Add memory to your agent
|
||||
Add memory to your coding agent
|
||||
</h3>
|
||||
<p className="text-sm text-gray-600 dark:text-zinc-400">
|
||||
Give Claude Code, Cursor, and Codex memory that persists across sessions. A drop-in plugin, no code to write.
|
||||
Plugins that let Claude Code, Cursor, Codex, and other harnesses remember your project. Opens the Claude Code guide.
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
@@ -86,10 +86,10 @@ mode: "custom"
|
||||
/>
|
||||
<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">
|
||||
Sign up for Mem0 as an agent
|
||||
Let an AI agent sign itself up
|
||||
</h3>
|
||||
<p className="text-sm text-gray-600 dark:text-zinc-400">
|
||||
Let an AI agent mint a Mem0 API key, claim ownership later, and write its first memory from the terminal.
|
||||
Four terminal commands create an account and API key. No email, no dashboard. Claim it as owner later.
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
@@ -112,10 +112,10 @@ mode: "custom"
|
||||
/>
|
||||
<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">
|
||||
Explore Mem0 integrations
|
||||
Use Mem0 with your framework
|
||||
</h3>
|
||||
<p className="text-sm text-gray-600 dark:text-zinc-400">
|
||||
Connect Mem0 to LangChain, CrewAI, Vercel AI SDK, and 20+ partner frameworks.
|
||||
Setup guides for 22 tools, including LangChain, CrewAI, LlamaIndex, and the Vercel AI SDK.
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
@@ -138,10 +138,10 @@ mode: "custom"
|
||||
/>
|
||||
<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">
|
||||
See memory-app examples
|
||||
Copy a working example
|
||||
</h3>
|
||||
<p className="text-sm text-gray-600 dark:text-zinc-400">
|
||||
Browse cookbooks for companions, support agents, voice agents, research tools, and more.
|
||||
Full walkthroughs for companion chatbots, support agents, voice agents, and research tools.
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
@@ -164,10 +164,10 @@ mode: "custom"
|
||||
/>
|
||||
<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">
|
||||
Self-host Mem0
|
||||
Run Mem0 on your own servers
|
||||
</h3>
|
||||
<p className="text-sm text-gray-600 dark:text-zinc-400">
|
||||
Use Open Source when you want memory without the hosted platform.
|
||||
The open-source version. Run it as a library or a Docker stack, with your data on your infrastructure.
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
+2
-2
@@ -38,7 +38,7 @@ This mints an evaluation key in <5 seconds. Use it immediately against the Platf
|
||||
|
||||
## Identify the User's Setup
|
||||
|
||||
Look at the user's imports first - they determine which product (Platform vs OSS) and which language you should quote docs from. **Mem0 Platform (managed) is the recommended path** - 4-line integration, sub-50ms retrieval, no infra. Route to OSS only when the user has an explicit self-hosting requirement.
|
||||
Look at the user's imports first - they determine which product (Platform vs OSS) and which language you should quote docs from. **Mem0 Platform (managed) is the recommended path** - 4-line integration, no infra to run. Route to OSS only when the user has an explicit self-hosting requirement.
|
||||
|
||||
### Platform - Python [Platform]
|
||||
|
||||
@@ -170,7 +170,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.
|
||||
- [Platform Overview](https://docs.mem0.ai/platform/overview) [Platform]: Use when the user picks the managed product - 4-line integration, hosted API, 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`.
|
||||
|
||||
@@ -146,9 +146,8 @@ curl -X POST 'https://api.mem0.ai/v3/memories/?page=1&page_size=50' \
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "Memory processing has been queued for background execution",
|
||||
"status": "PENDING",
|
||||
"event_id": "evt-uuid"
|
||||
"event_id": "evt-uuid",
|
||||
"status": "PENDING"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ const results = await memory.search("What movies do I like?", {
|
||||
|
||||
### LLM reranker
|
||||
|
||||
To score with an LLM instead of a dedicated reranker, use the `llm_reranker` provider. It builds its own LLM from the reranker's config (defaulting to `openai` / `gpt-4o-mini`) rather than reusing the Memory's main `llm`:
|
||||
To score with an LLM instead of a dedicated reranker, use the `llm_reranker` provider. It builds its own LLM from the reranker's config (defaulting to `openai` / `gpt-5-mini`) rather than reusing the Memory's main `llm`:
|
||||
|
||||
```typescript
|
||||
const memory = new Memory({
|
||||
@@ -137,7 +137,7 @@ const memory = new Memory({
|
||||
| `zero_entropy` | `zerank-1` | `apiKey`, `model`, `topK` |
|
||||
| `sentence_transformer` | `Xenova/ms-marco-MiniLM-L-6-v2` | `model`, `device`, `maxLength`, `normalize`, `topK` |
|
||||
| `huggingface` | `Xenova/bge-reranker-base` | `model`, `device`, `maxLength`, `normalize`, `topK` |
|
||||
| `llm_reranker` | `openai` / `gpt-4o-mini` | `provider`, `model`, `apiKey`, `llm` (nested override), `topK` |
|
||||
| `llm_reranker` | `openai` / `gpt-5-mini` | `provider`, `model`, `apiKey`, `llm` (nested override), `topK` |
|
||||
|
||||
<Note>
|
||||
`rerank` is opt-in per search and a no-op when no `reranker` is configured. If the reranker call fails, Mem0 logs a warning and returns the original vector-ranked results.
|
||||
|
||||
@@ -35,8 +35,7 @@ pip install mem0ai
|
||||
from mem0 import Memory
|
||||
|
||||
m = Memory()
|
||||
|
||||
````
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Add a memory">
|
||||
@@ -46,7 +45,7 @@ messages = [
|
||||
{"role": "assistant", "content": "Hey Alex! I'll remember your interests."}
|
||||
]
|
||||
m.add(messages, user_id="alex")
|
||||
````
|
||||
```
|
||||
|
||||
</Step>
|
||||
|
||||
|
||||
+2260
-452
File diff suppressed because it is too large
Load Diff
@@ -27,7 +27,7 @@ pip install mem0ai
|
||||
</Step>
|
||||
<Step title="Export your API key">
|
||||
```bash
|
||||
export MEM0_API_KEY="sk-platform-..."
|
||||
export MEM0_API_KEY="m0-..."
|
||||
```
|
||||
</Step>
|
||||
<Step title="Create an async client">
|
||||
@@ -49,7 +49,7 @@ npm install mem0ai
|
||||
</Step>
|
||||
<Step title="Load your API key">
|
||||
```bash
|
||||
export MEM0_API_KEY="sk-platform-..."
|
||||
export MEM0_API_KEY="m0-..."
|
||||
```
|
||||
</Step>
|
||||
<Step title="Instantiate the client">
|
||||
@@ -158,6 +158,8 @@ await memory.update(matches.results[0].id, {
|
||||
|
||||
## Clean up
|
||||
|
||||
Scope each delete call to a single entity id where possible; combining more than one entity filter in the same `delete_all` call is not guaranteed to AND them together today.
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Python">
|
||||
<Steps>
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
---
|
||||
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."
|
||||
description: "Let an AI agent create its own Mem0 account and API key in four commands, with no email or dashboard needed."
|
||||
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.
|
||||
Normally a person signs up for Mem0, gets an API key from the dashboard, and hands it to their tools. Agent Mode skips that: a coding agent creates its own account from the terminal and starts storing memories immediately. A human can take ownership of that account later, without disrupting the agent.
|
||||
|
||||
## The 4-command demo
|
||||
This page is written for both readers. The setup below is for the agent; [Claiming the account](#claiming-the-account-for-the-human-owner) is for the person who ends up owning it.
|
||||
|
||||
<Note>
|
||||
**If you're an AI agent** (Claude Code, Cursor, Codex, Cline, Aider, Windsurf, or any other coding tool), run the four commands below. You don't need a human to set Mem0 up for you.
|
||||
</Note>
|
||||
|
||||
## Sign up in four commands
|
||||
|
||||
<CodeGroup>
|
||||
```bash npm
|
||||
@@ -17,11 +23,11 @@ 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"
|
||||
# 3. Store a memory
|
||||
mem0 add "Prefers TypeScript over JavaScript for new projects"
|
||||
|
||||
# 4. Verify
|
||||
mem0 search "am I using mem0"
|
||||
# 4. Search it back
|
||||
mem0 search "what language should I use"
|
||||
```
|
||||
|
||||
```bash pip
|
||||
@@ -31,14 +37,22 @@ 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"
|
||||
# 3. Store a memory
|
||||
mem0 add "Prefers TypeScript over JavaScript for new projects"
|
||||
|
||||
# 4. Verify
|
||||
mem0 search "am I using mem0"
|
||||
# 4. Search it back
|
||||
mem0 search "what language should I use"
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
Step 2 prints your new account's default scope and how to hand the account to a human later:
|
||||
|
||||
```
|
||||
✓ Agent Mode active. Default user_id: swift-otter-4821
|
||||
|
||||
To claim this account later: mem0 init --email <your-email>
|
||||
```
|
||||
|
||||
That's it. Under 30 seconds from a fresh shell to a working memory store.
|
||||
|
||||
## Identify yourself with `--agent-caller`
|
||||
@@ -46,17 +60,17 @@ That's it. Under 30 seconds from a fresh shell to a working memory store.
|
||||
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.
|
||||
**Forgot `--agent-caller` when you ran `init`?** Run `mem0 identify <your-name>` afterwards. It keeps the same API key and just fills in the name, so it is safe to run more than once.
|
||||
</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.
|
||||
- A new Mem0 account was created with its own API key.
|
||||
- The key was saved to `~/.mem0/config.json` on that machine, readable only by you (file mode `0600`).
|
||||
- A default `user_id` was created, so `mem0 add` and `mem0 search` work without you passing scope flags.
|
||||
- **Nobody owns the account yet.** It works, but no human is attached to it until someone claims it.
|
||||
|
||||
Every command run against this key prints a one-line reminder asking you to surface the claim instructions to your human user.
|
||||
Every command run with this key prints a one-line reminder to pass the claim instructions on to your human.
|
||||
|
||||
## Claiming the account (for the human owner)
|
||||
|
||||
@@ -66,7 +80,7 @@ When the human is ready to take ownership of the agent's account (and all the me
|
||||
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 CLI spots the existing Agent Mode setup, emails a verification code, and upgrades the account in place:
|
||||
|
||||
- **The API key never changes**, so the agent isn't disrupted.
|
||||
- **All memories transfer** to the human's account.
|
||||
@@ -76,31 +90,33 @@ Pass `--code 123456` to skip the interactive code prompt for fully non-interacti
|
||||
|
||||
## 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:
|
||||
Agent Mode signups are limited to **5 per day per IP address** to prevent abuse. If you hit the limit, the CLI tells you so:
|
||||
|
||||
```
|
||||
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.
|
||||
Calling the API directly instead of through the CLI returns a plain `403 Forbidden` with no explanation and no `Retry-After` header, so handle that case yourself.
|
||||
|
||||
Until someone claims it, an agent account gets 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 title="CLI reference" icon="terminal" href="/platform/cli">
|
||||
Every command in full: `mem0 add`, `mem0 search`, `mem0 list`, and the rest.
|
||||
</Card>
|
||||
|
||||
<Card title="Memory Operations" icon="database" href="/core-concepts/memory-operations/add">
|
||||
<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, as an alternative integration path.
|
||||
Give your agent memory as a set of tools instead of shell commands.
|
||||
</Card>
|
||||
|
||||
<Card title="Platform Overview" icon="star" href="/platform/overview">
|
||||
The full Mem0 Platform feature set once you claim your account.
|
||||
<Card title="Platform overview" icon="star" href="/platform/overview">
|
||||
Everything the account unlocks once a human claims it.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
+132
-96
@@ -9,9 +9,7 @@ The mem0 CLI lets you add, search, list, update, and delete memories directly fr
|
||||
|
||||
Both implementations provide identical behavior: same commands, same options, same output formats.
|
||||
|
||||
<Tip>
|
||||
**Built for AI agents.** Pass `--agent` (or `--json`) as a global flag on any command to get structured JSON output optimized for programmatic consumption: sanitized fields, no colors or spinners, and errors as JSON too. Drop it into any agent tool loop with zero extra parsing.
|
||||
</Tip>
|
||||
Running it inside an agent? Put `--agent` before any command to get clean JSON instead of human output. See [Use with AI agents](#use-with-ai-agents).
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -97,6 +95,8 @@ mem0 init --api-key m0-xxx --user-id alice --force
|
||||
| `-u, --user-id` | Default user ID (skip prompt) |
|
||||
| `--email` | Login via email verification code |
|
||||
| `--code` | Verification code (use with `--email` for non-interactive login) |
|
||||
| `--agent` | Create an Agent Mode account, with no email needed |
|
||||
| `--agent-caller` | Name the agent running the command, such as `claude-code` |
|
||||
| `--force` | Overwrite existing config without confirmation |
|
||||
|
||||
<Note>
|
||||
@@ -117,12 +117,25 @@ echo "Loves hiking on weekends" | mem0 add --user-id alice
|
||||
|------|-------------|
|
||||
| `-u, --user-id` | Scope to a user |
|
||||
| `--agent-id` | Scope to an agent |
|
||||
| `--app-id` | Scope to an app |
|
||||
| `--run-id` | Scope to a single run or session |
|
||||
| `--messages` | Conversation messages as JSON |
|
||||
| `-f, --file` | Read messages from a JSON file |
|
||||
| `-m, --metadata` | Custom metadata as JSON |
|
||||
| `--categories` | Categories (JSON array or comma-separated) |
|
||||
| `--categories` | Rejected on `add`. Use `--custom-categories` instead |
|
||||
| `--custom-categories` | Custom categories as a JSON array of `{name: description}` objects |
|
||||
| `--custom-instructions` | Custom instructions for fact extraction |
|
||||
| `--structured-data-schema` | Schema for structured data extraction, as JSON |
|
||||
| `--timestamp` | Unix timestamp for the memory |
|
||||
| `--expires` | Expiration date, after which the memory stops being returned |
|
||||
| `--immutable` | Store the memory so it can never be updated or overwritten |
|
||||
| `--no-infer` | Store the text exactly as given, skipping fact extraction |
|
||||
| `-o, --output` | Output format: `text`, `json`, `quiet` |
|
||||
|
||||
<Note>
|
||||
`--categories` is not supported on `add` and exits with an error pointing at `--custom-categories`.
|
||||
</Note>
|
||||
|
||||
### `mem0 search`
|
||||
|
||||
Search memories using natural language.
|
||||
@@ -135,11 +148,18 @@ mem0 search "preferred tools" --user-id alice --output json --top-k 5
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `-u, --user-id` | Filter by user |
|
||||
| `-k, --top-k` | Number of results (default: 10) |
|
||||
| `--agent-id` | Filter by agent |
|
||||
| `--app-id` | Filter by app |
|
||||
| `--run-id` | Filter by run or session |
|
||||
| `-k, --top-k` | Number of results (default: 10). `--limit` does the same thing |
|
||||
| `--threshold` | Minimum similarity score (default: 0.3) |
|
||||
| `--rerank` | Enable reranking |
|
||||
| `--keyword` | Use keyword search instead of semantic |
|
||||
| `--filter` | Advanced filter expression (JSON) |
|
||||
| `--fields` | Return only the named fields |
|
||||
| `--show-expired` | Include expired memories |
|
||||
| `--reference-date` | Reference date for relative queries (`YYYY-MM-DD` or Unix timestamp) |
|
||||
| `--latest-only` | Only return the latest version of each memory |
|
||||
| `-o, --output` | Output format: `text`, `json`, `table` |
|
||||
|
||||
### `mem0 list`
|
||||
@@ -155,11 +175,16 @@ mem0 list --user-id alice --after 2024-01-01 --page-size 50
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `-u, --user-id` | Filter by user |
|
||||
| `--agent-id` | Filter by agent |
|
||||
| `--app-id` | Filter by app |
|
||||
| `--run-id` | Filter by run or session |
|
||||
| `--page` | Page number (default: 1) |
|
||||
| `--page-size` | Results per page (default: 100) |
|
||||
| `--category` | Filter by category |
|
||||
| `--after` | Created after date (YYYY-MM-DD) |
|
||||
| `--before` | Created before date (YYYY-MM-DD) |
|
||||
| `--show-expired` | Include expired memories |
|
||||
| `--latest-only` | Only return the latest version of each memory |
|
||||
| `-o, --output` | Output format: `text`, `json`, `table` |
|
||||
|
||||
### `mem0 get`
|
||||
@@ -171,6 +196,10 @@ mem0 get 7b3c1a2e-4d5f-6789-abcd-ef0123456789
|
||||
mem0 get 7b3c1a2e-4d5f-6789-abcd-ef0123456789 --output json
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `-o, --output` | Output format: `text`, `json` |
|
||||
|
||||
### `mem0 update`
|
||||
|
||||
Update the text or metadata of an existing memory.
|
||||
@@ -181,6 +210,13 @@ mem0 update <memory-id> --metadata '{"priority": "high"}'
|
||||
echo "new text" | mem0 update <memory-id>
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `-m, --metadata` | Replace the memory's metadata with this JSON |
|
||||
| `--expires` | Expiration date (YYYY-MM-DD) |
|
||||
| `--timestamp` | Unix timestamp for the memory |
|
||||
| `-o, --output` | Output format: `text`, `json`, `quiet` |
|
||||
|
||||
### `mem0 delete`
|
||||
|
||||
Delete a single memory, all memories for a scope, or an entire entity.
|
||||
@@ -201,9 +237,14 @@ mem0 delete --all --user-id alice --dry-run
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `-u, --user-id` | Scope the deletion to a user |
|
||||
| `--agent-id` | Scope the deletion to an agent |
|
||||
| `--app-id` | Scope the deletion to an app |
|
||||
| `--run-id` | Scope the deletion to a run or session |
|
||||
| `--all` | Delete all memories matching scope filters |
|
||||
| `--entity` | Delete the entity and all its memories |
|
||||
| `--project` | With `--all`: delete all memories project-wide |
|
||||
| `--delete-linked` | Also delete memories linked to this memory |
|
||||
| `--dry-run` | Preview without deleting |
|
||||
| `--force` | Skip confirmation prompt |
|
||||
|
||||
@@ -217,6 +258,12 @@ mem0 import data.json --user-id alice
|
||||
|
||||
The file should be a JSON array where each item has a `memory` (or `text` or `content`) field and optional `user_id`, `agent_id`, and `metadata` fields.
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `-u, --user-id` | Default user for items that do not set their own |
|
||||
| `--agent-id` | Default agent for items that do not set their own |
|
||||
| `-o, --output` | Output format: `text`, `json` |
|
||||
|
||||
### `mem0 config`
|
||||
|
||||
View or modify the local CLI configuration.
|
||||
@@ -237,6 +284,18 @@ mem0 entity list agents --output json
|
||||
mem0 entity delete --user-id alice --force
|
||||
```
|
||||
|
||||
Deleting an entity removes it and every memory belonging to it. Preview first with `--dry-run`.
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `-u, --user-id` | The user to delete |
|
||||
| `--agent-id` | The agent to delete |
|
||||
| `--app-id` | The app to delete |
|
||||
| `--run-id` | The run or session to delete |
|
||||
| `--dry-run` | Show what would be deleted, without deleting it |
|
||||
| `--force` | Skip confirmation prompt |
|
||||
| `-o, --output` | Output format: `text`, `json` |
|
||||
|
||||
### `mem0 event`
|
||||
|
||||
Inspect background processing events created by async operations (e.g. bulk deletes, large add jobs).
|
||||
@@ -261,23 +320,15 @@ Verify your API connection and display the current project.
|
||||
mem0 status
|
||||
```
|
||||
|
||||
### `mem0 version`
|
||||
### `mem0 whoami`
|
||||
|
||||
Print the CLI version.
|
||||
Print the identity the CLI is currently using. After `mem0 init --agent`, the
|
||||
server issues an identifier (`default_user_id`, for example
|
||||
`user_a1b2c3d4e5f6`) and the CLI stores it in `~/.mem0/config.json`. That value
|
||||
is the agent's stable identity across runs, and it is the row key on the
|
||||
[AGENTRUSH leaderboard](https://mem0.ai/agentrush).
|
||||
|
||||
```bash
|
||||
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:
|
||||
Use this instead of parsing the config file by hand:
|
||||
|
||||
```bash
|
||||
mem0 whoami
|
||||
@@ -288,89 +339,47 @@ mem0 whoami
|
||||
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>`
|
||||
### `mem0 identify`
|
||||
|
||||
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.
|
||||
Attach an agent name to an account created with `mem0 init --agent`, if you did
|
||||
not pass `--agent-caller` at the time. It keeps the same API key and only fills
|
||||
in the name, so it is safe to run more than once. See
|
||||
[Sign up as an agent](/platform/agent-signup).
|
||||
|
||||
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.
|
||||
### `mem0 help`
|
||||
|
||||
### 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.
|
||||
Print the command tree. Adding `--json` returns the whole tree as structured
|
||||
data, so an agent can discover the available commands and options for itself.
|
||||
|
||||
## Output formats
|
||||
|
||||
All commands support the `--output` flag to control how results are displayed:
|
||||
Most commands take `-o, --output` to control how results are displayed. Not every command accepts every format:
|
||||
|
||||
| Format | Description |
|
||||
|--------|-------------|
|
||||
| `text` | Human-readable output with colors and formatting (default for most commands) |
|
||||
| `json` | Structured JSON, suitable for piping to `jq` or consumption by AI agents |
|
||||
| `table` | Tabular format (default for `list`) |
|
||||
| `quiet` | Minimal output: just IDs or status codes |
|
||||
| `agent` | Structured JSON envelope with sanitized fields, set automatically by `--json`/`--agent` |
|
||||
| Format | Description | Accepted by |
|
||||
|--------|-------------|-------------|
|
||||
| `text` | Human-readable output with colors and formatting. The default everywhere except `list` | every command |
|
||||
| `json` | Structured JSON, suitable for piping to `jq` | every command |
|
||||
| `table` | Tabular format, and the default for `list` | `search`, `list` |
|
||||
| `quiet` | Minimal output: just IDs or status codes | `add`, `update`, `delete` |
|
||||
|
||||
Example with JSON output:
|
||||
Passing a format a command does not accept is an error, so check the command's own flag table above.
|
||||
|
||||
There is no `agent` value for `--output`. Agent mode is turned on by the global `--json`/`--agent` flag placed before the command name, and it overrides `--output`. See [Use with AI agents](#use-with-ai-agents).
|
||||
|
||||
The exact JSON shape depends on the command. `search` returns a bare array of memories, while `list` returns an envelope object with the memories under `data`:
|
||||
|
||||
```bash
|
||||
mem0 search "user preferences" --user-id alice --output json | jq '.data.results[].memory'
|
||||
# search: results are the top-level array
|
||||
mem0 search "user preferences" --user-id alice --output json | jq '.[].memory'
|
||||
|
||||
# list: results are nested under .data
|
||||
mem0 list --user-id alice --output json | jq '.data[].memory'
|
||||
```
|
||||
|
||||
Agent mode always returns the envelope, whichever command you run, so `.data[]` works everywhere:
|
||||
|
||||
```bash
|
||||
mem0 --agent search "user preferences" --user-id alice | jq '.data[].memory'
|
||||
```
|
||||
|
||||
## Use with AI agents
|
||||
@@ -424,6 +433,22 @@ Two other agent-friendly features:
|
||||
|
||||
For non-interactive environments (CI, agent runtimes), set credentials via `mem0 init --api-key m0-xxx --user-id alice --force` or the `MEM0_API_KEY` environment variable.
|
||||
|
||||
## Errors and exit codes
|
||||
|
||||
Every command exits `0` when it succeeds and `1` when it fails, so `if mem0 ...; then` works as you would expect in a script. In agent mode (`--json` or `--agent`), failures still print a JSON envelope to stdout alongside the non-zero exit, so you can parse successes and failures the same way.
|
||||
|
||||
Errors you are most likely to hit:
|
||||
|
||||
| Message | Cause | Fix |
|
||||
|---------|-------|-----|
|
||||
| `Authentication failed` | The API key is missing, wrong, or revoked | Run `mem0 init` again, or get a new key from the dashboard |
|
||||
| `No content provided. Pass text, --messages, --file, or pipe via stdin.` | `mem0 add` was called with nothing to store | Give it text, a file, or piped input |
|
||||
| `Invalid JSON in --messages` / `--metadata` / `--filter` | The JSON value would not parse | Check the quoting, especially inside shell single quotes |
|
||||
| `Invalid date format for --expires. Use YYYY-MM-DD` | `--expires` got something other than a date | Use `YYYY-MM-DD`, and make sure the date is in the future |
|
||||
| `--threshold must be between 0.0 and 1.0.` | Score threshold out of range | Pass a value between `0.0` and `1.0` |
|
||||
|
||||
Run [`mem0 status`](#mem0-status) to check whether the CLI can reach the API and which project the key belongs to. It reports the connection state, the API URL, and any error.
|
||||
|
||||
## Environment variables
|
||||
|
||||
| Variable | Description |
|
||||
@@ -434,17 +459,28 @@ 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_TELEMETRY` | Set to `false` to turn off usage telemetry. On by default |
|
||||
|
||||
Environment variables take precedence over values in the config file, which take precedence over defaults.
|
||||
|
||||
## Global flags
|
||||
|
||||
These flags are available on all commands:
|
||||
These two flags belong to `mem0` itself, so they go **before** the command name:
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--json` | Enable agent mode: structured JSON envelope output, no colors or spinners |
|
||||
| `--agent` | Alias for `--json` |
|
||||
| `--version` | Print the CLI version and exit |
|
||||
|
||||
<Warning>
|
||||
On `init` only, `--agent` means something different. `mem0 init --agent` creates an Agent Mode account (see [Sign up as an agent](/platform/agent-signup)); it does not switch the output to JSON. To get JSON from `init`, put the flag first: `mem0 --json init`.
|
||||
</Warning>
|
||||
|
||||
The following flags are accepted by most commands, but they belong to the command, so they go **after** the command name:
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--api-key` | Override the configured API key for this request |
|
||||
| `--base-url` | Override the configured API base URL for this request |
|
||||
| `-o, --output` | Set the output format |
|
||||
@@ -456,11 +492,11 @@ These flags are available on all commands:
|
||||
Store your first memory in under five minutes using the SDK or CLI
|
||||
</Card>
|
||||
|
||||
<Card title="Memory Operations" icon="database" href="/core-concepts/memory-operations/add">
|
||||
<Card title="Memory operations" icon="database" href="/core-concepts/memory-operations/add">
|
||||
Learn about add, search, update, and delete operations in depth
|
||||
</Card>
|
||||
|
||||
<Card title="API Reference" icon="code" href="/api-reference/memory/add-memories">
|
||||
<Card title="API reference" icon="code" href="/api-reference/memory/add-memories">
|
||||
See the complete REST API documentation
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -17,7 +17,7 @@ iconType: "solid"
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="What are the key features of Mem0?">
|
||||
- **User, Session, and AI Agent Memory**: Retains information across sessions and interactions for users and AI agents, ensuring continuity and context.
|
||||
- **User, Agent, App, and Run Memory**: Scopes memories to the individual, AI agent, application, and conversation/session they belong to, ensuring continuity and context.
|
||||
- **Adaptive Personalization**: Continuously updates memories based on user interactions and feedback.
|
||||
- **Developer-Friendly API**: Offers a straightforward API for seamless integration into various applications.
|
||||
- **Platform Consistency**: Ensures consistent behavior and data across different platforms and devices.
|
||||
@@ -84,10 +84,12 @@ iconType: "solid"
|
||||
- Include specific examples or cases rather than general definitions
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="How do I configure Mem0 for AWS Lambda?">
|
||||
When deploying Mem0 on AWS Lambda, you'll need to modify the storage directory configuration due to Lambda's file system restrictions. By default, Lambda only allows writing to the `/tmp` directory.
|
||||
<Accordion title="How do I configure Mem0 for AWS Lambda? (self-hosted / OSS only)">
|
||||
This applies only if you are running the self-hosted OSS `Memory` class yourself (for example with a local vector store) inside a Lambda function. If you're using the hosted Mem0 Platform (`MemoryClient`), there is nothing to configure here: the Platform stores all memory data on Mem0's servers, not on your Lambda instance's filesystem, so Lambda's `/tmp`-only write restriction does not apply to you.
|
||||
|
||||
To configure Mem0 for AWS Lambda, set the `MEM0_DIR` environment variable to point to a writable directory in `/tmp`:
|
||||
When deploying self-hosted Mem0 on AWS Lambda, you'll need to modify the storage directory configuration due to Lambda's file system restrictions. By default, Lambda only allows writing to the `/tmp` directory.
|
||||
|
||||
To configure self-hosted Mem0 for AWS Lambda, set the `MEM0_DIR` environment variable to point to a writable directory in `/tmp`:
|
||||
|
||||
```bash
|
||||
MEM0_DIR=/tmp/.mem0
|
||||
@@ -149,7 +151,7 @@ iconType: "solid"
|
||||
2. Go to **Settings → Account**.
|
||||
3. Click **Delete account** and confirm.
|
||||
|
||||
Deletion is immediate and irreversible. The following is removed:
|
||||
Deletion is asynchronous: the request is accepted immediately and processed in the background, typically within a few minutes. Once it completes, the following is removed:
|
||||
|
||||
- Your user profile and login credentials
|
||||
- All memories, agents, and runs you created
|
||||
@@ -157,7 +159,7 @@ iconType: "solid"
|
||||
- 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.
|
||||
Your old API keys stop working once deletion completes, not the instant you click confirm. 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>
|
||||
|
||||
@@ -51,7 +51,7 @@ results = client.search(
|
||||
# Smart home assistant finding device preferences
|
||||
results = client.search(
|
||||
query="How do I like my bedroom temperature?",
|
||||
rerank=True, # Get most recent preferences first
|
||||
rerank=True, # Closest-matching preferences first
|
||||
filters={"user_id": "user123"},
|
||||
)
|
||||
|
||||
@@ -86,7 +86,7 @@ results = client.search(
|
||||
# Find learning progress for specific topics
|
||||
results = client.search(
|
||||
query="Python programming progress and difficulties",
|
||||
rerank=True, # Recent progress first
|
||||
rerank=True, # Closest-matching progress notes first
|
||||
filters={"user_id": "student123"},
|
||||
)
|
||||
|
||||
@@ -108,21 +108,13 @@ def quick_search(query, user_id):
|
||||
filters={"user_id": user_id},
|
||||
)
|
||||
|
||||
# Reranked search - good for most applications
|
||||
# Reranked search - good when result order matters
|
||||
def standard_search(query, user_id):
|
||||
return client.search(
|
||||
query=query,
|
||||
rerank=True,
|
||||
filters={"user_id": user_id},
|
||||
)
|
||||
|
||||
# Reranked search - good for critical applications
|
||||
def precise_search(query, user_id):
|
||||
return client.search(
|
||||
query=query,
|
||||
rerank=True,
|
||||
filters={"user_id": user_id},
|
||||
)
|
||||
```
|
||||
|
||||
```javascript JavaScript
|
||||
@@ -133,21 +125,13 @@ function quickSearch(query, userId) {
|
||||
});
|
||||
}
|
||||
|
||||
// Reranked search - good for most applications
|
||||
// Reranked search - good when result order matters
|
||||
function standardSearch(query, userId) {
|
||||
return client.search(query, {
|
||||
filters: { user_id: userId },
|
||||
rerank: true,
|
||||
});
|
||||
}
|
||||
|
||||
// Reranked search - good for critical applications
|
||||
function preciseSearch(query, userId) {
|
||||
return client.search(query, {
|
||||
filters: { user_id: userId },
|
||||
rerank: true,
|
||||
});
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ await client.search("What is Alice's favorite sport?", filters={"user_id": "alic
|
||||
```
|
||||
|
||||
```javascript JavaScript
|
||||
await client.search("What is Alice's favorite sport?", { filters: { userId: "alice" } });
|
||||
await client.search("What is Alice's favorite sport?", { filters: { user_id: "alice" } });
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
@@ -124,7 +124,7 @@ await client.deleteAll({ userId: "alice" });
|
||||
</CodeGroup>
|
||||
|
||||
<Note>
|
||||
At least one filter (`user_id`, `agent_id`, `app_id`, or `run_id`) is required: calling `delete_all` with no filters raises an error to prevent accidental data loss. You can pass `"*"` as a value to delete all memories for a given entity type (e.g., `user_id="*"` removes memories for every user). A full project wipe requires all four filters set to `"*"`.
|
||||
At least one filter (`user_id`, `agent_id`, `app_id`, or `run_id`) is required: calling `delete_all` with no filters raises an error to prevent accidental data loss. You can pass `"*"` as a value to delete all memories for a given entity type (e.g., `user_id="*"` removes memories for every user). A full project wipe requires all four filters set to `"*"`. When multiple entity filters are combined on a single `delete_all` call, only one is currently guaranteed to be honored; scope each call to a single entity id to be safe.
|
||||
</Note>
|
||||
|
||||
### History
|
||||
|
||||
@@ -75,6 +75,8 @@ print(response)
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
This "Updated custom categories" message is specific to a PATCH-style partial update, which is what `client.project.update()` sends. Calling the raw API with a full PUT instead returns a generic `{"message": "Project updated successfully."}`, regardless of which fields changed.
|
||||
|
||||
### 2. Confirm the active catalog
|
||||
|
||||
<CodeGroup>
|
||||
@@ -86,16 +88,19 @@ print(categories)
|
||||
|
||||
```json Output
|
||||
{
|
||||
"name": "default-project",
|
||||
"description": null,
|
||||
"custom_categories": [
|
||||
{"lifestyle_management_concerns": "Tracks daily routines, habits, hobbies and interests including cooking, time management and work-life balance"},
|
||||
{"seeking_structure": "Documents goals around creating routines, schedules, and organized systems in various life areas"},
|
||||
{"personal_information": "Basic information about the user including name, preferences, and personality traits"}
|
||||
]
|
||||
],
|
||||
"custom_instructions": null
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
`get` echoes back the shape you set. `update` also accepts a plain list of names, such as `["billing", "support"]`, in which case `get` returns that same list of names. Descriptions are optional here, and the classifier uses them to disambiguate when it has them.
|
||||
`project.get()` always returns the full project object, not just the fields you asked for. The `fields` parameter is accepted but has no filtering effect server-side, so read `custom_categories` off the full response. `update` also accepts a plain list of names, such as `["billing", "support"]`, in which case `custom_categories` comes back as that same list of names. Descriptions are optional here, and the classifier uses them to disambiguate when it has them.
|
||||
|
||||
<Warning>
|
||||
`add` is stricter than `update`. Every entry in a per-call `custom_categories` list must be an object mapping a name to a description. Passing bare names to `add` fails with `400 Expected a dictionary of items but got type "str"`.
|
||||
@@ -306,16 +311,19 @@ client.project.get(["custom_categories"])
|
||||
|
||||
```json Output
|
||||
{
|
||||
"custom_categories": null
|
||||
"name": "default-project",
|
||||
"description": null,
|
||||
"custom_categories": null,
|
||||
"custom_instructions": null
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
A project that has never set a list returns `null`. One you have reset with `project.update(custom_categories=[])` returns `[]`. Both mean the default catalog is active.
|
||||
The response is always the full project object; `["custom_categories"]` does not filter it down. A project that has never set a list returns `custom_categories: null`. One you have reset with `project.update(custom_categories=[])` returns `[]`. Both mean the default catalog is active.
|
||||
|
||||
## Verify the feature is working
|
||||
|
||||
- `client.project.get(["custom_categories"])` returns the category list you set.
|
||||
- `client.project.get(["custom_categories"])` returns the full project object; read the `custom_categories` key off it to see the list you set.
|
||||
- `client.get_all(filters={"user_id": ...})` shows populated `categories` lists on new memories.
|
||||
- The Mem0 dashboard (Project → Memories) displays the custom labels in the Category column.
|
||||
|
||||
|
||||
@@ -68,6 +68,8 @@ console.log(response.customInstructions);
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
`project.get()` always returns the full project object. The `fields` parameter is accepted but has no filtering effect server-side, so `response["custom_instructions"]` above is a key on the full response, not a pre-filtered payload.
|
||||
|
||||
### Best Practice Template
|
||||
|
||||
Structure your instructions using this proven template:
|
||||
|
||||
@@ -22,17 +22,35 @@ messages = [
|
||||
client.add(messages, user_id="alice", infer=False)
|
||||
```
|
||||
|
||||
```markdown Output
|
||||
[]
|
||||
```json Output
|
||||
{
|
||||
"message": "Memories stored successfully",
|
||||
"status": "SUCCEEDED",
|
||||
"event_id": "8c1f5e2b-3d47-4a9e-b6c1-5f2a7d3e9b04",
|
||||
"results": [
|
||||
{
|
||||
"id": "19d6d7aa-2454-4e58-96fc-e74d9e9f8dd1",
|
||||
"data": { "memory": "Alice loves playing badminton" },
|
||||
"event": "ADD"
|
||||
},
|
||||
{
|
||||
"id": "8557f05d-7b3c-47e5-b409-9886f9e314fc",
|
||||
"data": { "memory": "Alice mostly cooks at home because of her gym plan" },
|
||||
"event": "ADD"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
You can see that the output of the add call is an empty list.
|
||||
|
||||
<Note>Only messages with the role "user" will be used for storage. Messages with roles such as "assistant" or "system" will be ignored during the storage process.</Note>
|
||||
<Note>
|
||||
Direct import stores `"user"` and `"assistant"` messages alike, regardless of which entity ids you pass. Only `"system"` messages are dropped. Each surviving message becomes one memory, with its content stored verbatim.
|
||||
</Note>
|
||||
|
||||
<Warning>
|
||||
Direct import skips the inference pipeline, so it also skips duplicate detection. If you later send the same fact with `infer=True`, Mem0 will store a second copy. Pick one mode per memory source unless you truly want both versions.
|
||||
Direct import skips semantic duplicate detection: two different phrasings of the same fact will be stored as two separate memories. Exact repeats in the same scope are deduplicated by an exact hash of the text, so resending identical text is safe. Mixing `infer=False` and `infer=True` for the same fact can still produce two memories, since neither path checks the other for duplicates.
|
||||
|
||||
Direct import also does not support multimodal content (`image_url`, `pdf_url`, `txt_url`, `mdx_url`). Those messages are skipped without raising an error, so they are missing from `results` rather than reported as a failure. Pass plain string content only when `infer=False`.
|
||||
</Warning>
|
||||
|
||||
## How to Retrieve Memories
|
||||
|
||||
@@ -36,11 +36,11 @@ Call `client.project.get()` to verify your connection. It should return your pro
|
||||
| User | `user_id` | Persistent persona or account | `"customer_6412"` |
|
||||
| Agent | `agent_id` | Distinct agent persona or tool | `"meal_planner"` |
|
||||
| Application | `app_id` | White-label app or product surface | `"ios_retail_demo"` |
|
||||
| Session | `run_id` | Short-lived flow, ticket, or conversation thread | `"ticket-9241"` |
|
||||
| Run | `run_id` | Short-lived flow, ticket, or session thread | `"ticket-9241"` |
|
||||
|
||||
- **Writes** (`client.add`) accept any combination of these fields. Absent fields default to `null`.
|
||||
- **Reads** (`client.search`, `client.get_all`, exports, deletes) accept the same identifiers inside the `filters` JSON object.
|
||||
- **Implicit null scoping**: Passing only `{"user_id": "alice"}` automatically restricts results to records where `agent_id`, `app_id`, and `run_id` are `null`. Add wildcards (`"*"`), explicit lists, or additional filters when you need broader joins.
|
||||
- **Writes** (`client.add`) accept any combination of these fields. `app_id` and `run_id` are stored on every memory the call produces. `user_id` and `agent_id` behave differently on the default extraction path: each extracted fact is attributed to whoever stated it, so a record carries `user_id` or `agent_id`, not both. Absent fields default to `null`.
|
||||
- **Reads** (`client.search`, `client.get_all`, exports) accept the same identifiers inside the `filters` JSON object. Deletes (`client.delete_all`) scope via query parameters instead; the SDK builds these for you when you pass `user_id=...`, `run_id=...`, and so on.
|
||||
- **Unmentioned entities are not constrained**: Passing only `{"user_id": "alice"}` matches on `user_id` alone. It does not require `agent_id`, `app_id`, or `run_id` to be `null`, so records that also have those fields set are still returned.
|
||||
|
||||
<Warning>
|
||||
**Common Pitfall**: If you create a memory with `user_id="alice"` but the other fields default to `null`, then search with `{"AND": [{"user_id": "alice"}, {"agent_id": "bot"}]}` will return nothing because you're looking for a memory where `agent_id="bot"`, not `null`.
|
||||
@@ -78,10 +78,12 @@ client.add(
|
||||
The response will include one or more memory IDs. Check the dashboard → Memories to confirm the entry appears under the correct user, agent, app, and run.
|
||||
|
||||
<Warning>
|
||||
Platform writes that include both `user_id` and `agent_id` (or other combinations) are persisted as separate records per entity so we can enforce privacy boundaries. Each record carries exactly one primary entity, which is why `{"AND": [{"user_id": ...}, {"agent_id": ...}]}` never returns results. Plan searches per entity scope or combine scopes with `OR`.
|
||||
Passing both `user_id` and `agent_id` to `client.add` does **not** produce records with both fields set. On the default extraction path, each extracted fact is attributed to the speaker who stated it: facts from `user` messages are stored with `user_id` set and `agent_id` null, facts from `assistant` messages with `agent_id` set and `user_id` null. `app_id` and `run_id` are carried on every record either way.
|
||||
|
||||
As a result, `{"AND": [{"user_id": ...}, {"agent_id": ...}]}` returns nothing for memories created this way. Use `OR` to match either scope. Records with both fields populated only come from [Direct Import](/platform/features/direct-import) (`infer=False`), which writes your text verbatim without attribution splitting.
|
||||
</Warning>
|
||||
|
||||
The HTTP equivalent uses `POST /v1/memories/` with the same identifiers in the JSON body. See the Add Memories API reference for REST details.
|
||||
The HTTP equivalent uses `POST /v3/memories/add/` with the same identifiers in the JSON body. See the [Add Memories](/api-reference/memory/add-memories) API reference for REST details.
|
||||
|
||||
## See it in action
|
||||
|
||||
@@ -130,7 +132,7 @@ print(agent_results)
|
||||
```
|
||||
|
||||
<Tip icon="compass">
|
||||
Writes can include multiple identifiers, but searches resolve one entity space at a time. Query user scope *or* agent scope in a given call: combining both returns an empty list today.
|
||||
A search that `AND`s `user_id` **and** `agent_id` only matches records that have both fields set, which the default extraction path never produces. Use `OR` when you want either scope to match on its own.
|
||||
</Tip>
|
||||
|
||||
<Tip icon="sparkles">
|
||||
@@ -141,11 +143,11 @@ Want to experiment with AND/OR logic, nested operators, or wildcards? The <Link
|
||||
```python
|
||||
app_scope = {
|
||||
"AND": [
|
||||
{"app_id": "concierge_portal"}
|
||||
],
|
||||
"OR": [
|
||||
{"user_id": "*"},
|
||||
{"agent_id": "*"}
|
||||
{"app_id": "concierge_portal"},
|
||||
{"OR": [
|
||||
{"user_id": "*"},
|
||||
{"agent_id": "*"}
|
||||
]}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -150,7 +150,7 @@ Handle potential errors when submitting feedback:
|
||||
|
||||
```python Python
|
||||
from mem0 import MemoryClient
|
||||
from mem0.exceptions import MemoryNotFoundError, NetworkError
|
||||
from mem0.exceptions import MemoryError, ValidationError
|
||||
|
||||
client = MemoryClient(api_key="your_api_key")
|
||||
|
||||
@@ -161,12 +161,10 @@ try:
|
||||
feedback_reason="Helpful context for user query"
|
||||
)
|
||||
print("Feedback submitted successfully")
|
||||
except MemoryNotFoundError:
|
||||
print("Memory not found")
|
||||
except NetworkError as e:
|
||||
print(f"Network error: {e}")
|
||||
except Exception as e:
|
||||
print(f"Unexpected error: {e}")
|
||||
except ValidationError:
|
||||
print("memory_id is not a valid UUID")
|
||||
except MemoryError as e:
|
||||
print(f"memory_id was not found or not accessible ({e.error_code})")
|
||||
```
|
||||
|
||||
```javascript JavaScript
|
||||
@@ -182,16 +180,23 @@ try {
|
||||
});
|
||||
console.log("Feedback submitted successfully");
|
||||
} catch (error) {
|
||||
if (error.status === 404) {
|
||||
console.log("Memory not found");
|
||||
if (error.errorCode === "HTTP_400") {
|
||||
console.log("memory_id is not a valid UUID");
|
||||
} else if (error.errorCode === "HTTP_500") {
|
||||
console.log("Server error - the memory_id may not exist or be inaccessible, or it may be transient; retry if it persists");
|
||||
} else {
|
||||
console.log(`Error: ${error.message}`);
|
||||
console.log(`Unexpected error: ${error.message}`);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
### Handling an unknown or malformed `memory_id`
|
||||
|
||||
- A malformed `memory_id` (not a valid UUID) returns a clean `400` with `{"error": "Invalid memory_id"}`.
|
||||
- A well-formed but non-existent `memory_id` (or one that doesn't belong to your org or project) currently returns a `500 Internal Server Error` instead of a `404`. This is a server-side bug being tracked in [MEM-5745](https://linear.app/mem0/issue/MEM-5745). A `5xx` can also be a transient server error, so don't treat it as a definitive "not found"; to avoid the case entirely, only call `feedback` with a `memory_id` you just read from a `get_all` or `search` response.
|
||||
|
||||
## Feedback Analytics
|
||||
|
||||
Track the impact of your feedback by monitoring memory performance over time. Consider implementing:
|
||||
|
||||
@@ -90,7 +90,7 @@ results = client.search(
|
||||
Earlier versions of Mem0 offered graph memory by connecting an **external graph database** (Neo4j, Memgraph, Kuzu, Apache AGE, or Neptune) through an `enable_graph` flag and a `graph_store` configuration block. That integration has been replaced by **native, built-in Graph Memory**:
|
||||
|
||||
- **No external graph store.** The graph is built inside Mem0 from your memories. There is nothing to provision or connect.
|
||||
- **Always on, all plans.** The `enable_graph` flag is no longer needed; Graph Memory is automatic. (If you still send the parameter, it is ignored.)
|
||||
- **Always on, all plans.** The `enable_graph` flag is no longer needed: Graph Memory is automatic, and `relations` is always an empty list regardless of whether you send it. On non-paginated `get_all` (v1.1 format), sending `enable_graph=True` still adds an empty `"relations": []` key to the response for backward compatibility; it does not restore the old graph behavior.
|
||||
- **Connections power retrieval directly.** Entity connections are folded into the combined `score` on each result. The standalone `relations` field that the external graph store returned is no longer populated. If your application read that field, see the migration guide below.
|
||||
|
||||
<Card title="Platform Migration Guide" icon="arrow-right" href="/migration/platform-v2-to-v3">
|
||||
|
||||
@@ -1,45 +1,33 @@
|
||||
---
|
||||
title: Group Chat
|
||||
description: 'Enable multi-participant conversations with automatic memory attribution to individual speakers'
|
||||
description: 'Enable multi-participant conversations and scope each speaker with user_id or agent_id'
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
The Group Chat feature enables Mem0 to process conversations involving multiple participants and automatically attribute memories to individual speakers. This allows for precise tracking of each participant's preferences, characteristics, and contributions in collaborative discussions, team meetings, or multi-agent conversations.
|
||||
The Group Chat feature helps you use Mem0 with conversations involving multiple participants, such as team meetings or multi-agent conversations. You control which speaker a memory belongs to by scoping each `add()` call with `user_id`, `agent_id`, and `run_id`; Mem0 does not infer that scope automatically from the conversation.
|
||||
|
||||
When you provide messages with participant names, Mem0 automatically:
|
||||
- Extracts memories from each participant's messages separately
|
||||
- Attributes each memory to the correct speaker using their name as the `user_id` or `agent_id`
|
||||
- Maintains individual memory profiles for each participant
|
||||
When you scope conversations correctly, Mem0:
|
||||
- Extracts memories from each participant's messages
|
||||
- Keeps each participant's memories in a separate profile, addressed by the `user_id` or `agent_id` you assigned them
|
||||
- Lets you retrieve any participant's memories independently using filters
|
||||
|
||||
## How Group Chat Works
|
||||
|
||||
Mem0 automatically detects group chat scenarios when messages contain a `name` field:
|
||||
Mem0 does not automatically split a multi-participant conversation into separate memories per speaker. A `name` field on a message is stored as context for extraction, but it does not change which `user_id` or `agent_id` the resulting memories are scoped to: that scope is always whatever `user_id`, `agent_id`, or `run_id` you pass to `add()`.
|
||||
|
||||
```json
|
||||
{
|
||||
"role": "user",
|
||||
"name": "Alice",
|
||||
"content": "Hey team, I think we should use React for the frontend"
|
||||
}
|
||||
```
|
||||
|
||||
When names are present, Mem0:
|
||||
- Formats messages as `"Alice (user): content"` for processing
|
||||
- Extracts memories with proper attribution to each speaker
|
||||
- Stores memories with the speaker's name as the `user_id` (for users) or `agent_id` (for assistants/agents)
|
||||
To keep separate memory profiles per participant, scope each participant's messages explicitly: call `add()` once per participant with their own `user_id`, or use `run_id` to group the conversation and filter by participant in your own message metadata.
|
||||
|
||||
### Memory Attribution Rules
|
||||
|
||||
- **User Messages**: The `name` field becomes the `user_id` in stored memories
|
||||
- **Assistant/Agent Messages**: The `name` field becomes the `agent_id` in stored memories
|
||||
- **Messages without names**: Fall back to standard processing using role as identifier
|
||||
- Memories are always scoped to the `user_id`, `agent_id`, and `run_id` you pass to `add()`, not to the `name` field on individual messages.
|
||||
- If you need per-participant memories, call `add()` separately for each participant's messages with that participant's `user_id`.
|
||||
|
||||
## Using Group Chat
|
||||
|
||||
### Basic Group Chat
|
||||
|
||||
Add memories from a multi-participant conversation:
|
||||
Scope each participant's messages with their own `user_id` and a shared `run_id` for the session. Call `add()` once per participant:
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
@@ -48,46 +36,60 @@ from mem0 import MemoryClient
|
||||
|
||||
client = MemoryClient(api_key="your-api-key")
|
||||
|
||||
# Group chat with multiple users
|
||||
messages = [
|
||||
{"role": "user", "name": "Alice", "content": "Hey team, I think we should use React for the frontend"},
|
||||
{"role": "user", "name": "Bob", "content": "I disagree, Vue.js would be better for our use case"},
|
||||
{"role": "user", "name": "Charlie", "content": "What about considering Angular? It has great enterprise support"},
|
||||
{"role": "assistant", "content": "All three frameworks have their merits. Let me summarize the pros and cons of each."}
|
||||
]
|
||||
|
||||
# Each participant gets their own user_id; run_id ties them to one session
|
||||
client.add(
|
||||
[{"role": "user", "content": "Hey team, I think we should use React for the frontend"}],
|
||||
user_id="alice", run_id="group_chat_1",
|
||||
)
|
||||
client.add(
|
||||
[{"role": "user", "content": "I'd prefer Vue.js for our use case"}],
|
||||
user_id="bob", run_id="group_chat_1",
|
||||
)
|
||||
response = client.add(
|
||||
messages,
|
||||
run_id="group_chat_1",
|
||||
infer=True
|
||||
[{"role": "user", "content": "Consider Angular, it has great enterprise support"}],
|
||||
user_id="charlie", run_id="group_chat_1",
|
||||
)
|
||||
print(response)
|
||||
```
|
||||
|
||||
```json Output
|
||||
{
|
||||
"results": [
|
||||
{
|
||||
"id": "4d82478a-8d50-47e6-9324-1f65efff5829",
|
||||
"event": "ADD",
|
||||
"memory": "prefers using React for the frontend"
|
||||
},
|
||||
{
|
||||
"id": "1d8b8f39-7b17-4d18-8632-ab1c64fa35b9",
|
||||
"event": "ADD",
|
||||
"memory": "prefers Vue.js for our use case"
|
||||
},
|
||||
{
|
||||
"id": "147559a8-c5f7-44d0-9418-91f53f7a89a4",
|
||||
"event": "ADD",
|
||||
"memory": "suggests considering Angular because it has great enterprise support"
|
||||
}
|
||||
]
|
||||
"event_id": "4d82478a-8d50-47e6-9324-1f65efff5829",
|
||||
"status": "PENDING"
|
||||
}
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
`add()` is asynchronous: it queues extraction and returns immediately. Poll `get_all` (see below) once processing completes to see the extracted memories. Each participant's memory is scoped to the `user_id` you passed, so filtering by `run_id` returns all three, and filtering by a single `user_id` returns just that participant.
|
||||
|
||||
### The `name` field does not change scope
|
||||
|
||||
The `name` field is stored as extraction context only. Attribution follows the `user_id`/`agent_id`/`run_id` you pass to `add()`, never the `name`. Passing two different names in one `add()` call does **not** split the memories across two profiles:
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```python Python
|
||||
# BOTH messages are scoped to user_id="team_session", NOT to "alice"/"bob"
|
||||
client.add(
|
||||
[
|
||||
{"role": "user", "name": "Alice", "content": "I strongly prefer React"},
|
||||
{"role": "user", "name": "Bob", "content": "I strongly prefer Vue"},
|
||||
],
|
||||
user_id="team_session", run_id="group_chat_2",
|
||||
)
|
||||
|
||||
# Every extracted memory lands under user_id="team_session"
|
||||
client.get_all(filters={"AND": [{"user_id": "team_session"}]})
|
||||
|
||||
# Nothing is stored under user_id="alice" or user_id="bob"
|
||||
client.get_all(filters={"AND": [{"user_id": "alice"}]}) # -> no results from this call
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
To keep Alice's and Bob's memories in separate profiles, call `add()` once per participant with their own `user_id`, as shown in [Basic Group Chat](#basic-group-chat) above.
|
||||
|
||||
## Retrieving Group Chat Memories
|
||||
|
||||
### Get All Memories for a Session
|
||||
@@ -224,33 +226,15 @@ print(search_response)
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Async Mode Support
|
||||
|
||||
Group chat supports async processing for improved performance. Memory additions are processed asynchronously by default.
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```python Python
|
||||
# Group chat: async processing is the default
|
||||
response = client.add(
|
||||
messages,
|
||||
run_id="groupchat_async",
|
||||
infer=True,
|
||||
)
|
||||
print(response)
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Message Format Requirements
|
||||
|
||||
### Required Fields
|
||||
|
||||
Each message in a group chat must include:
|
||||
Each message must include:
|
||||
|
||||
- `role`: The participant's role (`"user"`, `"assistant"`, `"agent"`)
|
||||
- `content`: The message content
|
||||
- `name`: The participant's name (required for group chat detection)
|
||||
- `name` (optional): The participant's name, stored as context for extraction. It does not change which `user_id` or `agent_id` a memory is scoped to.
|
||||
|
||||
### Example Message Structure
|
||||
|
||||
@@ -261,14 +245,14 @@ Each message in a group chat must include:
|
||||
"content": "I think we should use React for the frontend"
|
||||
}
|
||||
```
|
||||
### Supported Roles
|
||||
### Roles
|
||||
|
||||
- **`user`**: Human participants (memories stored with `user_id`)
|
||||
- **`assistant`**: AI assistants (memories stored with `agent_id`)
|
||||
- **`user`**: Human participants
|
||||
- **`assistant`**: AI assistants
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Consistent Naming**: Use consistent names for participants across sessions to maintain proper memory attribution.
|
||||
1. **Consistent Scoping**: Use a consistent `user_id` (or `agent_id`) per participant across sessions so their memories stay in one profile.
|
||||
|
||||
2. **Clear Role Assignment**: Ensure each participant has the correct role (`user`, `assistant`, or `agent`) for proper memory categorization.
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ At search time the pipeline:
|
||||
5. Truncates to the `top_k` you requested.
|
||||
6. Records a fire-and-forget reinforcement against each returned memory: its access history grows by one, capped at the most recent 20 touches.
|
||||
|
||||
Memories created before decay was enabled don't yet have an access history. They use a sensible fallback: their `updated_at` is treated as a single past touch, so the same scale above applies based on how stale that update is: a recently-updated legacy memory enters near the neutral band, a long-stale one sits closer to the floor. Once surfaced in a search after decay is on, they accumulate access history naturally and behave like any other memory.
|
||||
Memories created before decay was enabled don't yet have an access history. They use a sensible fallback: a memory's `event_date` (if it has one) is treated as its single past touch; only when `event_date` is absent does `updated_at` stand in instead. A future `event_date` gets a fresh/full activation, a past one decays from when the event happened. Once surfaced in a search after decay is on, they accumulate access history naturally and behave like any other memory.
|
||||
|
||||
## Configure access
|
||||
|
||||
@@ -81,26 +81,26 @@ curl -X PATCH https://api.mem0.ai/api/v1/orgs/organizations/$ORG_ID/projects/$PR
|
||||
|
||||
### 2. Confirm the state
|
||||
|
||||
`decay` is returned on every project read. To fetch only this field, use `?fields=decay`.
|
||||
`decay` is returned on every project read; there is currently no way to narrow the response to just this field, so read the full project object and pick out `decay`.
|
||||
|
||||
<CodeGroup>
|
||||
```python Python
|
||||
response = client.project.get(fields=["decay"])
|
||||
response = client.project.get()
|
||||
print(response["decay"])
|
||||
```
|
||||
|
||||
```javascript JavaScript
|
||||
const response = await client.project.get({ fields: ["decay"] });
|
||||
const response = await client.project.get();
|
||||
console.log(response.decay);
|
||||
```
|
||||
|
||||
```bash cURL
|
||||
curl "https://api.mem0.ai/api/v1/orgs/organizations/$ORG_ID/projects/$PROJECT_ID/?fields=decay" \
|
||||
curl "https://api.mem0.ai/api/v1/orgs/organizations/$ORG_ID/projects/$PROJECT_ID/" \
|
||||
-H "Authorization: Token $MEM0_API_KEY"
|
||||
```
|
||||
|
||||
```json Response
|
||||
{ "decay": true }
|
||||
{ "decay": true, "...": "full project object" }
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
@@ -154,7 +154,7 @@ curl -X PATCH https://api.mem0.ai/api/v1/orgs/organizations/$ORG_ID/projects/$PR
|
||||
| Reinforced on a recent search | 1.2 – 1.5× | Sustains its boost for the next several searches. |
|
||||
| Idle for a few days | 0.6 – 1.0× | Falls back into the neutral band. |
|
||||
| Idle for weeks | 0.4 – 0.6× | Mild dampening: can still surface for strong matches. |
|
||||
| Pre-decay legacy memory (no access history) | 0.3 – 1.0× | Falls back to `updated_at`: recently-updated entries land near 1.0×, long-stale entries approach the 0.3× floor. |
|
||||
| Pre-decay legacy memory (no access history) | 0.3 – 1.0× | Falls back to `event_date` if set (future dates land near 1.0×, past dates decay from the event); falls back further to `updated_at` only when `event_date` is absent. |
|
||||
|
||||
The reinforcement is bounded: each memory tracks at most the last 20 access timestamps, so the boost stays well-behaved no matter how many times a memory is retrieved.
|
||||
|
||||
@@ -170,7 +170,7 @@ The threshold is applied to the candidate pool pre-decay; the scaling factor the
|
||||
No. The `client.add(...)` path is unchanged. Decay is a search-time ranking adjustment.
|
||||
|
||||
**What if I had memories before turning decay on?**
|
||||
They use a fallback: the memory's `updated_at` is treated as a single historical touch, so the same scaling applies based on how stale that update is: a recently-updated legacy memory enters near the neutral band (~1.0×), a long-stale one closer to the floor (~0.3×). Once retrieved they accumulate access history and behave like any other memory.
|
||||
They use a fallback: a memory's `event_date`, if it has one, is treated as its single historical touch; `updated_at` only stands in when `event_date` is absent. A memory with a future `event_date` enters near the neutral band (~1.0×); one with a past `event_date` decays from when the event happened, closer to the floor (~0.3×) the further back it is. Once retrieved they accumulate access history and behave like any other memory.
|
||||
|
||||
**Can I tune how aggressively decay scales scores?**
|
||||
Not in this version. The current scaling is calibrated to be conservative: wide enough to meaningfully reorder candidates, narrow enough to never dominate the underlying relevance score. Per-project tuning is on the roadmap.
|
||||
|
||||
@@ -141,7 +141,7 @@ console.log(responseWithInstructions);
|
||||
```
|
||||
|
||||
```bash cURL
|
||||
curl -X POST "https://api.mem0.ai/v1/memories/export/" \
|
||||
curl -X POST "https://api.mem0.ai/v1/exports/" \
|
||||
-H "Authorization: Token your-api-key" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
@@ -185,6 +185,13 @@ const response = await client.getMemoryExport({
|
||||
console.log(response);
|
||||
```
|
||||
|
||||
```bash cURL
|
||||
curl -X POST "https://api.mem0.ai/v1/exports/get/" \
|
||||
-H "Authorization: Token your-api-key" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"memory_export_id": "550e8400-e29b-41d4-a716-446655440000"}'
|
||||
```
|
||||
|
||||
```json Output
|
||||
{
|
||||
"full_name": "John Doe",
|
||||
@@ -231,6 +238,20 @@ const response = await client.getMemoryExport({
|
||||
console.log(response);
|
||||
```
|
||||
|
||||
```bash cURL
|
||||
curl -X POST "https://api.mem0.ai/v1/exports/get/" \
|
||||
-H "Authorization: Token your-api-key" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"filters": {
|
||||
"AND": [
|
||||
{"created_at": {"gte": "2024-07-10", "lte": "2024-07-20"}},
|
||||
{"user_id": "alex"}
|
||||
]
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
```json Output
|
||||
{
|
||||
"full_name": "John Doe",
|
||||
|
||||
@@ -9,6 +9,10 @@ Mem0 extends its capabilities beyond text by supporting multimodal data, includi
|
||||
|
||||
When a user submits an image or document, Mem0 processes it to extract textual information and other pertinent details. These details are then added to the user's memory, enhancing the system's ability to understand and recall multimodal inputs.
|
||||
|
||||
<Warning>
|
||||
Multimodal content (`image_url`, `pdf_url`, `txt_url`, `mdx_url`) requires the default `infer=True`. Do not combine structured multimodal `content` with `infer=False` (Direct Import): the Direct Import path expects plain-text `content` and rejects structured multimodal messages with a `400`.
|
||||
</Warning>
|
||||
|
||||
<CodeGroup>
|
||||
```python Python
|
||||
import os
|
||||
@@ -172,20 +176,18 @@ await client.add([imageMessage], { userId: "alice" })
|
||||
|
||||
### 2. Text Documents (MDX/TXT)
|
||||
|
||||
Mem0 supports both online and local text documents in MDX or TXT format.
|
||||
Mem0 supports both online and local text documents in MDX or TXT format. Use `"type": "mdx_url"` for Markdown/MDX content and `"type": "txt_url"` for plain text; both accept the same shape (`{"url": ...}`, either an HTTP(S) URL or a base64-encoded string).
|
||||
|
||||
#### Using a Document URL
|
||||
|
||||
```python
|
||||
# Define the document URL
|
||||
document_url = "https://www.w3.org/TR/2003/REC-PNG-20031110/iso_8859-1.txt"
|
||||
|
||||
# Create the message dictionary with the document URL
|
||||
document_message = {
|
||||
"role": "user",
|
||||
"content": {
|
||||
"type": "mdx_url",
|
||||
"mdx_url": {
|
||||
"type": "txt_url",
|
||||
"txt_url": {
|
||||
"url": document_url
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,143 +1,80 @@
|
||||
---
|
||||
title: Temporal Reasoning
|
||||
description: "Time-aware memory retrieval for Mem0 Platform v3 so queries like 'last week', 'upcoming', and 'right now' return the right memories."
|
||||
description: "Boost memories whose dates match the time in a search."
|
||||
badge: "v3"
|
||||
---
|
||||
|
||||
Some memories matter because of **when** they happened, not just because they sound similar. Temporal Reasoning lets Mem0 Platform v3 understand time-aware queries and return the most contextually appropriate results.
|
||||
Temporal Reasoning gives a ranking boost to memories whose event dates match the time in a search. Event dates are when something described in a memory happened or will happen. It runs automatically on Mem0 Platform v3.
|
||||
|
||||
<Info>
|
||||
**Use Temporal Reasoning when…**
|
||||
- Users ask questions like "what happened last week?" or "what do I have coming up?"
|
||||
- Your app stores both past events and future plans for the same person
|
||||
- You want time-aware retrieval without building your own date-parsing layer
|
||||
</Info>
|
||||
It is not available in the OSS SDK.
|
||||
|
||||
<Warning>
|
||||
Temporal Reasoning is a **Mem0 Platform v3** feature. It is not available on OSS memory stores or older Platform endpoints.
|
||||
</Warning>
|
||||
Dates from new memories usually affect search within a few seconds.
|
||||
|
||||
## Configure access
|
||||
## Time-aware searches
|
||||
|
||||
Confirm your `MEM0_API_KEY` is set and that you are using the v3 Platform client:
|
||||
Queries can include expressions such as `yesterday`, `last week`, `tomorrow`, `currently`, and `as of March 2025`. Mem0 compares them with dates and date ranges found in stored memories.
|
||||
|
||||
```python
|
||||
from mem0 import MemoryClient
|
||||
## Example
|
||||
|
||||
client = MemoryClient(api_key="your-api-key")
|
||||
```
|
||||
Suppose a user has these memories:
|
||||
|
||||
## How it works
|
||||
- "Yesterday I met Maya at the Orion conference in Paris."
|
||||
- "Last week I met Maya at the Orion conference in Tokyo."
|
||||
- "Last year I met Maya at the Orion conference in Lisbon."
|
||||
|
||||
When a memory describes an event, a future plan, or an ongoing state, Temporal Reasoning recognizes the time context so the right results surface at search time.
|
||||
|
||||
A query like `what did I do last week?` should return a completed past event: not an upcoming appointment and not a stable fact that hasn't changed. Temporal Reasoning handles that distinction automatically.
|
||||
|
||||
### Memory types Temporal Reasoning handles
|
||||
|
||||
| Type | What it represents | Example |
|
||||
| --- | --- | --- |
|
||||
| Dated occurrence | Something that happened at a known time | "I finished the Q1 review on March 10, 2025." |
|
||||
| Future plan | A future commitment or scheduled item | "I have a dentist appointment on March 18, 2025." |
|
||||
| Ongoing state | A fact that remains true over time | "I am the product lead at Acme Corp." |
|
||||
| Relationship | A durable connection between people or entities | "Priya manages Jordan." |
|
||||
| Preference | A stable preference or habit | "I prefer morning meetings." |
|
||||
|
||||
Results come back in the normal search response shape: Temporal Reasoning affects ranking, not the response format.
|
||||
|
||||
## Configure it
|
||||
|
||||
Temporal Reasoning is enabled by default for all v3 searches and writes. There is no per-request toggle.
|
||||
|
||||
Two parameters give you precise control when you need it:
|
||||
|
||||
- `timestamp` on `add()`: anchors an imported memory to the time it actually happened, rather than the time it was added to Mem0
|
||||
- `reference_date` on `search()`: resolves relative phrases like `last week` against a fixed point in time
|
||||
Searching for `Which city did I meet Maya in at the Orion conference last week?` gives the Tokyo memory a temporal boost and ranks it first.
|
||||
|
||||
<CodeGroup>
|
||||
```python Python
|
||||
from datetime import datetime, timezone
|
||||
from mem0 import MemoryClient
|
||||
|
||||
client = MemoryClient(api_key="your-api-key")
|
||||
|
||||
# Import a historical memory anchored to when it happened
|
||||
client.add(
|
||||
[{"role": "user", "content": "I finished the Q1 review on March 10, 2025."}],
|
||||
user_id="jordan",
|
||||
timestamp=int(datetime(2025, 3, 10, tzinfo=timezone.utc).timestamp()),
|
||||
)
|
||||
|
||||
# Search with a relative query anchored to a known date
|
||||
results = client.search(
|
||||
"what did I do last week?",
|
||||
filters={"user_id": "jordan"},
|
||||
"Which city did I meet Maya in at the Orion conference last week?",
|
||||
filters={"user_id": "maya-demo"},
|
||||
)
|
||||
```
|
||||
|
||||
```javascript JavaScript
|
||||
const results = await client.search(
|
||||
"Which city did I meet Maya in at the Orion conference last week?",
|
||||
{ filters: { user_id: "maya-demo" } }
|
||||
);
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
Search returns the usual memory results, reordered using the temporal boost.
|
||||
|
||||
## Search from a specific time
|
||||
|
||||
Use `reference_date` to simulate searching at a specific date and time. Mem0 treats it as the current time for that search.
|
||||
|
||||
<CodeGroup>
|
||||
```python Python
|
||||
results = client.search(
|
||||
"What happened last week?",
|
||||
filters={"user_id": "user-123"},
|
||||
reference_date="2025-03-21T00:00:00Z",
|
||||
)
|
||||
```
|
||||
|
||||
```javascript JavaScript
|
||||
import { MemoryClient } from "mem0ai";
|
||||
|
||||
const client = new MemoryClient({ apiKey: "your-api-key" });
|
||||
|
||||
// Import a historical memory anchored to when it happened
|
||||
await client.add(
|
||||
[{ role: "user", content: "I finished the Q1 review on March 10, 2025." }],
|
||||
{
|
||||
userId: "jordan",
|
||||
timestamp: Math.floor(new Date("2025-03-10T00:00:00Z").getTime() / 1000),
|
||||
}
|
||||
);
|
||||
|
||||
// Search with a relative query anchored to a known date
|
||||
const results = await client.search("what did I do last week?", {
|
||||
filters: { user_id: "jordan" },
|
||||
const results = await client.search("What happened last week?", {
|
||||
filters: { user_id: "user-123" },
|
||||
referenceDate: "2025-03-21T00:00:00Z",
|
||||
});
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
<Tip>
|
||||
`reference_date` is especially useful in automated tests and demos because it makes relative phrases like `last week` resolve consistently every time.
|
||||
</Tip>
|
||||
## Parameters
|
||||
|
||||
## Supported query patterns
|
||||
| Action | Python | TypeScript | Purpose |
|
||||
| --- | --- | --- | --- |
|
||||
| Add memories | `timestamp` | `timestamp` | Preserve the original time of an imported conversation. |
|
||||
| Search memories | `reference_date` | `referenceDate` | Simulate searching at a specific date and time. |
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Historical questions">
|
||||
Examples: `last week`, `last month`, `in March 2025`, `on 2025-03-10`
|
||||
</Accordion>
|
||||
<Accordion title="Upcoming questions">
|
||||
Examples: `upcoming`, `next week`, `tomorrow`, `what do I have coming up?`
|
||||
</Accordion>
|
||||
<Accordion title="Current-state questions">
|
||||
Examples: `right now`, `currently`, `where do I work now?`
|
||||
</Accordion>
|
||||
<Accordion title="As-of questions">
|
||||
Examples: `as of March 2025`, `where was I living as of 2024?`
|
||||
</Accordion>
|
||||
<Accordion title="Duration questions">
|
||||
Examples: `how long have I lived here?`, `since when have I worked there?`
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## Verify the feature is working
|
||||
|
||||
- Run a temporal search with a time-aware query (e.g., "what did I do last week?") and confirm the memory that fits the time window ranks first.
|
||||
- Use `reference_date` in test queries so relative phrases resolve consistently across runs.
|
||||
- For backfilled data, pass `timestamp` on `add()` to confirm the memory reflects the right point in time.
|
||||
|
||||
## Best practices
|
||||
|
||||
- Use explicit dates in source conversations when events or plans matter temporally.
|
||||
- Pass `timestamp` during historical imports so the ingestion time does not become the only time anchor.
|
||||
- Scope searches with `filters` so time-aware ranking operates inside the right user boundary.
|
||||
- Use `reference_date` in automated tests and reproducible demos.
|
||||
For all search inputs and returned fields, see the [Search Memories API reference](/api-reference/memory/search-memories).
|
||||
|
||||
<CardGroup cols={1}>
|
||||
<Card title="Memory Timestamps" icon="calendar" href="/platform/features/timestamp">
|
||||
Anchor imported memories to when they actually happened.
|
||||
Preserve the original time of imported memories.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
|
||||
@@ -49,9 +49,9 @@ Filters use a nested JSON structure with logical operators at the root:
|
||||
### Content fields
|
||||
| Field | Operators | Example |
|
||||
|-------|-----------|---------|
|
||||
| `categories` | `eq`, `ne`, `in`, `contains` | `{"categories": {"in": ["finance"]}}` |
|
||||
| `categories` | `eq`, `ne`, `in` (matches any category in the list), `contains` (case-insensitive) | `{"categories": {"in": ["finance"]}}` |
|
||||
| `metadata` | `eq`, `ne`, `contains` | `{"metadata": {"key": "value"}}` |
|
||||
| `keywords` | `contains`, `icontains` | `{"keywords": {"icontains": "invoice"}}` |
|
||||
| `keywords` | `contains` (case-sensitive), `icontains` (case-insensitive) | `{"keywords": {"icontains": "invoice"}}` |
|
||||
|
||||
### Special fields
|
||||
| Field | Operators | Example |
|
||||
@@ -120,24 +120,23 @@ filters = {
|
||||
Find memories containing specific text, categories, or metadata values.
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Text search">
|
||||
<Accordion title="Text search (keywords)">
|
||||
```python
|
||||
# Case-insensitive match
|
||||
# Substring match on memory text via get_all
|
||||
filters = {
|
||||
"AND": [
|
||||
{"user_id": "user_123"},
|
||||
{"keywords": {"icontains": "pizza"}}
|
||||
]
|
||||
}
|
||||
|
||||
# Case-sensitive match
|
||||
filters = {
|
||||
"AND": [
|
||||
{"user_id": "user_123"},
|
||||
{"keywords": {"contains": "Invoice_2024"}}
|
||||
{"keywords": {"icontains": "invoice"}}
|
||||
]
|
||||
}
|
||||
memories = client.get_all(filters=filters)
|
||||
```
|
||||
|
||||
Use `contains` for case-sensitive matching and `icontains` for case-insensitive.
|
||||
|
||||
<Callout type="warning" icon="exclamation-triangle" color="#E74C3C">
|
||||
A `keywords` filter works on `get_all`, but passing it to `search()` currently returns a `500` ([MEM-5746](https://linear.app/mem0/issue/MEM-5746)). For text relevance during a search, pass the text to the `query` argument instead of filtering on `keywords`.
|
||||
</Callout>
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Categories">
|
||||
@@ -254,10 +253,8 @@ Combine various filters for complex queries across different dimensions.
|
||||
```
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="All entities populated (single entity scope)">
|
||||
<Accordion title="All entities populated">
|
||||
```python
|
||||
# Require user_id plus non-null run/app IDs
|
||||
# (Memories are stored separately per entity, so scope one dimension at a time.)
|
||||
filters = {
|
||||
"AND": [
|
||||
{"user_id": "user_123"},
|
||||
@@ -266,6 +263,7 @@ Combine various filters for complex queries across different dimensions.
|
||||
]
|
||||
}
|
||||
```
|
||||
Matches records where `user_id` equals `user_123` and `run_id`/`app_id` are both non-null. It does not require other entity fields to be null.
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
@@ -276,16 +274,16 @@ Level up foundational patterns with compound filters that coordinate entity scop
|
||||
<AccordionGroup>
|
||||
<Accordion title="Multi-dimensional filtering">
|
||||
```python
|
||||
# Invoice memories in Q1 2024
|
||||
filters = {
|
||||
"AND": [
|
||||
{"user_id": "user_123"},
|
||||
{"keywords": {"icontains": "invoice"}},
|
||||
{"categories": {"in": ["finance"]}},
|
||||
{"keywords": {"icontains": "invoice"}},
|
||||
{"created_at": {"gte": "2024-01-01T00:00:00Z"}},
|
||||
{"created_at": {"lt": "2024-04-01T00:00:00Z"}}
|
||||
]
|
||||
}
|
||||
memories = client.get_all(filters=filters)
|
||||
```
|
||||
</Accordion>
|
||||
|
||||
@@ -330,7 +328,7 @@ Level up foundational patterns with compound filters that coordinate entity scop
|
||||
## Best practices
|
||||
|
||||
<Callout type="tip" icon="lightbulb" color="#26A17B">
|
||||
The root must be `AND`, `OR`, or `NOT` with an array of conditions.
|
||||
The root does not have to be `AND`, `OR`, or `NOT`. A bare filter like `{"user_id": "alice"}` works on its own; wrap conditions in a logical operator only when you need to combine more than one.
|
||||
</Callout>
|
||||
|
||||
<Callout type="tip" icon="lightbulb" color="#26A17B">
|
||||
@@ -338,7 +336,9 @@ Use `"*"` to match any non-null value for a field.
|
||||
</Callout>
|
||||
|
||||
<Callout type="warning" icon="exclamation-triangle" color="#E74C3C">
|
||||
Memories are stored per-entity (user, agent, app, run). Combining `user_id` **and** `agent_id` in the same `AND` clause returns no results because no record contains both values at once. Query one entity scope at a time or use `OR` logic for parallel lookups.
|
||||
Combining `user_id` **and** `agent_id` in the same `AND` clause only returns records that have both values set. Memories created by a normal `client.add` never do: each extracted fact is attributed to its speaker, so it carries `user_id` or `agent_id`, not both. Use `OR` to match either scope. Only [Direct Import](/platform/features/direct-import) (`infer=False`) writes both fields on one record.
|
||||
|
||||
A filter object with both an `AND` key and a sibling `OR` key at the same level silently drops the `OR` branch today. Nest the `OR` inside the `AND` array instead of placing them as siblings.
|
||||
</Callout>
|
||||
|
||||
## Troubleshooting
|
||||
@@ -347,7 +347,7 @@ Memories are stored per-entity (user, agent, app, run). Combining `user_id` **an
|
||||
<Accordion title="Missing results with agent_id">
|
||||
**Problem**: Filtered by `user_id` but don't see agent memories.
|
||||
|
||||
**Solution**: User and agent memories are stored as separate records. Use OR to query both scopes:
|
||||
**Solution**: A `user_id` filter only matches records that have that `user_id` set; it won't surface memories written with only `agent_id`. Use OR to query both scopes:
|
||||
```python
|
||||
{"OR": [{"user_id": "user_123"}, {"agent_id": "agent_name"}]}
|
||||
```
|
||||
@@ -362,8 +362,12 @@ Memories are stored per-entity (user, agent, app, run). Combining `user_id` **an
|
||||
```
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Case-insensitive search">
|
||||
**Solution**: Swap to `icontains` to normalize casing.
|
||||
<Accordion title="Case-insensitive text match">
|
||||
**Solution**: Use `keywords` with `icontains` on `get_all`:
|
||||
```python
|
||||
{"AND": [{"user_id": "user_123"}, {"keywords": {"icontains": "invoice"}}]}
|
||||
```
|
||||
This works on `get_all`. It is not supported on `search()` yet (returns a `500`, [MEM-5746](https://linear.app/mem0/issue/MEM-5746)) - for search, pass the text to the `query` argument instead.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Date range between two dates">
|
||||
@@ -388,7 +392,7 @@ Memories are stored per-entity (user, agent, app, run). Combining `user_id` **an
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Do I need AND/OR/NOT?">
|
||||
Yes. The root must be a logical operator with an array.
|
||||
No. A bare filter like `{"user_id": "u1"}` works on its own. Add `AND`, `OR`, or `NOT` only when you need to combine more than one condition.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="What does * match?">
|
||||
@@ -408,7 +412,7 @@ Memories are stored per-entity (user, agent, app, run). Combining `user_id` **an
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="How to search text?">
|
||||
Use `keywords` with `contains` (case-sensitive) or `icontains` (case-insensitive).
|
||||
For a substring match, use the `keywords` filter with `contains`/`icontains` on `get_all`. For relevance-ranked search, pass the text to the `query` argument on `search()`. Note: `keywords` is not supported inside `search()` filters yet (returns a `500`, [MEM-5746](https://linear.app/mem0/issue/MEM-5746)).
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Can I nest AND/OR?">
|
||||
@@ -428,6 +432,6 @@ Memories are stored per-entity (user, agent, app, run). Combining `user_id` **an
|
||||
|
||||
## Known limitations
|
||||
|
||||
- Entity filters operate on a single scope per record. Use separate queries or `OR` logic to compare users vs agents.
|
||||
- Filters only constrain the fields you mention; unmentioned entity fields are not required to be null. A record carries `user_id` or `agent_id` (never both) unless it came from Direct Import, plus whatever `app_id` and `run_id` were passed.
|
||||
- Metadata supports only bare/`eq`, `contains`, and `ne` comparisons.
|
||||
- Wildcards (`"*"` ) match only records where the field is already non-null.
|
||||
|
||||
@@ -51,6 +51,7 @@ console.log(webhook);
|
||||
"webhook_id": "wh_123",
|
||||
"name": "Memory Logger",
|
||||
"url": "https://your-app.com/webhook",
|
||||
"owner": "john",
|
||||
"event_types": ["memory_add"],
|
||||
"project": "default-project",
|
||||
"is_active": true,
|
||||
@@ -63,7 +64,7 @@ console.log(webhook);
|
||||
|
||||
### Get Webhooks
|
||||
|
||||
Retrieve all webhooks for your project:
|
||||
Retrieve all webhooks for your project. Each webhook includes an `owner` field: the username of the account that created it. This is set automatically and cannot be changed via the API.
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
@@ -168,6 +169,10 @@ Mem0 supports the following event types for webhooks:
|
||||
- `memory_update`: Triggered when an existing memory is updated.
|
||||
- `memory_delete`: Triggered when a memory is deleted.
|
||||
- `memory_categorize`: Triggered when a memory is categorized.
|
||||
- `ingest_job_completed`: Triggered when an ingest job finishes successfully.
|
||||
- `ingest_job_partially_completed`: Triggered when an ingest job finishes with some items failed.
|
||||
- `ingest_job_failed`: Triggered when an ingest job fails entirely.
|
||||
- `ingest_job_cancelled`: Triggered when an ingest job is cancelled.
|
||||
|
||||
## Webhook Payload
|
||||
|
||||
|
||||
+59
-34
@@ -8,18 +8,20 @@ estimatedTime: "~2 minutes"
|
||||
<Info>
|
||||
**Prerequisites**
|
||||
- Mem0 Platform account (<a href="https://app.mem0.ai?utm_source=oss&utm_medium=platform-mem0-mcp" rel="nofollow">Sign up here</a>)
|
||||
- API key (<a href="https://app.mem0.ai/settings/api-keys?utm_source=oss&utm_medium=platform-mem0-mcp" rel="nofollow">Get one from dashboard</a>)
|
||||
- Node.js 14+ (for npx)
|
||||
- API key (<a href="https://app.mem0.ai/dashboard/api-keys?utm_source=oss&utm_medium=platform-mem0-mcp" rel="nofollow">Get one from dashboard</a>)
|
||||
- Node.js 18+ (for npx)
|
||||
- An MCP-compatible client (Claude, Claude Code, Codex, Cursor, Windsurf, VS Code, OpenCode)
|
||||
</Info>
|
||||
|
||||
## What is Mem0 MCP?
|
||||
|
||||
Mem0 MCP Server exposes Mem0's memory capabilities as MCP tools, letting AI agents decide when to save, search, or update information. The cloud-hosted MCP server requires no local installation: just connect and start using memory.
|
||||
MCP (Model Context Protocol) is a standard way for AI clients to call external tools. The Mem0 MCP server hands your agent a set of memory tools, so it can decide for itself when to save something, look something up, or update what it already knows. Nothing runs on your machine: the server is hosted by Mem0, and your client connects to it over HTTPS.
|
||||
|
||||
## Quick Setup
|
||||
Memories you store this way live in your Mem0 account, not on your computer.
|
||||
|
||||
Add Mem0 MCP to your preferred clients with a single command:
|
||||
## Quick setup
|
||||
|
||||
Point your clients at the hosted server with a single command:
|
||||
|
||||
```bash
|
||||
npx mcp-add \
|
||||
@@ -29,9 +31,31 @@ npx mcp-add \
|
||||
--clients "claude,claude code,cursor,windsurf,vscode,opencode"
|
||||
```
|
||||
|
||||
This automatically configures Mem0 MCP for all supported clients at once.
|
||||
`mcp-add` is a helper that writes the Mem0 server into each client's own MCP config file, so you do not have to edit them by hand. Name only the clients you actually use. If you would rather see the change yourself, every client's manual config is under [Client-specific setup](#client-specific-setup).
|
||||
|
||||
## Available Tools
|
||||
Restart each client afterwards so it picks up the new server.
|
||||
|
||||
## Signing in
|
||||
|
||||
The server is authenticated, so connecting is not enough on its own. There are two ways in:
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Sign in through the client">
|
||||
Most clients handle this for you. The first time your agent uses a Mem0 tool, the client opens a browser window asking you to authorize access to your Mem0 account. Approve it once and the client stores the token, refreshing it as needed.
|
||||
|
||||
This is the easier path, and it is what happens by default if you followed the quick setup above.
|
||||
</Tab>
|
||||
|
||||
<Tab title="Use your API key">
|
||||
For clients without browser sign-in, or for headless environments like CI, send your API key as a bearer token instead. Where you put it depends on the client; see [Client-specific setup](#client-specific-setup) for the exact syntax.
|
||||
|
||||
Get a key from the <a href="https://app.mem0.ai/dashboard/api-keys?utm_source=oss&utm_medium=platform-mem0-mcp" rel="nofollow">Mem0 dashboard</a>, and keep it out of any file you commit.
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
If neither is set up, the server replies `401 Authentication required` and your client reports the connection as failed.
|
||||
|
||||
## Available tools
|
||||
|
||||
The MCP server exposes these memory tools to your AI client:
|
||||
|
||||
@@ -41,7 +65,7 @@ The MCP server exposes these memory tools to your AI client:
|
||||
| `search_memories` | Semantic search across existing memories with filters |
|
||||
| `get_memories` | List memories with structured filters and pagination |
|
||||
| `get_memory` | Retrieve one memory by its `memory_id` |
|
||||
| `update_memory` | Overwrite a memory's text after confirming the ID |
|
||||
| `update_memory` | Overwrite a memory's text and/or metadata after confirming the ID |
|
||||
| `delete_memory` | Delete a single memory by `memory_id` |
|
||||
| `delete_all_memories` | Bulk delete all memories in scope |
|
||||
| `delete_entities` | Delete a user/agent/app/run entity and its memories |
|
||||
@@ -51,7 +75,7 @@ The MCP server exposes these memory tools to your AI client:
|
||||
|
||||
---
|
||||
|
||||
## Client-Specific Setup
|
||||
## Client-specific setup
|
||||
|
||||
You can also configure individual clients:
|
||||
|
||||
@@ -170,43 +194,44 @@ You can also configure individual clients:
|
||||
|
||||
---
|
||||
|
||||
## Verify Your Setup
|
||||
## Check that it worked
|
||||
|
||||
Once configured, your AI client can:
|
||||
- Automatically save information with `add_memory`
|
||||
- Search memories with `search_memories`
|
||||
- Update memories with `update_memory`
|
||||
- Delete memories with `delete_memory`
|
||||
|
||||
**Sample Interactions:**
|
||||
Restart your client, then ask it to store something and read it back in a later message:
|
||||
|
||||
```
|
||||
User: Remember that I love tiramisu
|
||||
Agent: Got it! I've saved that you love tiramisu.
|
||||
You: Remember that I prefer TypeScript over JavaScript for new projects.
|
||||
Agent: Saved.
|
||||
|
||||
User: What do you know about my food preferences?
|
||||
Agent: Based on your memories, you love tiramisu.
|
||||
|
||||
User: Update my project: the mobile app is now 80% complete
|
||||
Agent: Updated your project status successfully.
|
||||
You: What language do I prefer for new projects?
|
||||
Agent: You prefer TypeScript over JavaScript.
|
||||
```
|
||||
|
||||
<Info icon="check">
|
||||
If you get "Connection failed", ensure you have a valid API key from <a href="https://app.mem0.ai/settings/api-keys?utm_source=oss&utm_medium=platform-mem0-mcp" rel="nofollow">Mem0 Dashboard</a>.
|
||||
</Info>
|
||||
The second answer only works if the memory was really stored, so this is a genuine round-trip test rather than the model repeating itself.
|
||||
|
||||
Two things to look for while you do it:
|
||||
|
||||
- Your client should show the Mem0 tools among its available tools. Most clients list them in a tools or MCP panel.
|
||||
- The first tool call should trigger the browser sign-in described above, unless you configured an API key.
|
||||
|
||||
To confirm from outside the client, open the <a href="https://app.mem0.ai/dashboard?utm_source=oss&utm_medium=platform-mem0-mcp" rel="nofollow">Mem0 dashboard</a>: anything the agent saved appears there.
|
||||
|
||||
---
|
||||
|
||||
## Quick Recovery
|
||||
## Troubleshooting
|
||||
|
||||
- **"Connection refused"** → Check your internet connection and ensure the MCP client is correctly configured
|
||||
- **"Invalid API key"** → Get a new key from <a href="https://app.mem0.ai/settings/api-keys?utm_source=oss&utm_medium=platform-mem0-mcp" rel="nofollow">Mem0 Dashboard</a>
|
||||
- **"npx command not found"** → Install Node.js from [nodejs.org](https://nodejs.org)
|
||||
| What you see | What it means | What to do |
|
||||
|---|---|---|
|
||||
| `401` or "Authentication required" | The client connected but is not signed in | Complete the browser sign-in, or set your API key as a bearer token |
|
||||
| "Connection refused" or "failed to connect" | The client cannot reach the server | Check your internet connection, then confirm the URL is exactly `https://mcp.mem0.ai/mcp` |
|
||||
| The agent has no Mem0 tools | The config was written but the client has not reloaded it | Restart the client. If the tools are still missing, check that `mcp-add` wrote to the config file your client actually reads |
|
||||
| `npx: command not found` | Node.js is not installed | Install it from [nodejs.org](https://nodejs.org) |
|
||||
| "Invalid API key" | The key is wrong, revoked, or from a different account | Get a new one from the <a href="https://app.mem0.ai/dashboard/api-keys?utm_source=oss&utm_medium=platform-mem0-mcp" rel="nofollow">Mem0 dashboard</a> |
|
||||
|
||||
---
|
||||
|
||||
## Next steps
|
||||
|
||||
- [Platform Quickstart](/platform/quickstart) - direct SDK/API integration guide
|
||||
- [MCP Specification](https://modelcontextprotocol.io) - the Model Context Protocol standard
|
||||
- [Gemini with Mem0 MCP](/cookbooks/frameworks/gemini-3-with-mem0-mcp) - example integration cookbook
|
||||
- [Platform quickstart](/platform/quickstart): call Mem0 from your own code instead of through an agent
|
||||
- [Mem0 CLI](/platform/cli): the same operations from your terminal
|
||||
- [MCP specification](https://modelcontextprotocol.io): the Model Context Protocol standard
|
||||
- [Gemini with Mem0 MCP](/cookbooks/frameworks/gemini-3-with-mem0-mcp): a worked example
|
||||
|
||||
@@ -50,7 +50,7 @@ For the full pipeline, see [How Mem0 works](/core-concepts/how-it-works).
|
||||
Get an API key and save your first memory.
|
||||
</Card>
|
||||
<Card title="Understand memory types" icon="brain" href="/core-concepts/memory-types">
|
||||
How user, agent, run, and session memory differ.
|
||||
How user, agent, app, and run memory differ.
|
||||
</Card>
|
||||
<Card title="Add, search, and update" icon="layer-group" href="/core-concepts/memory-operations/add">
|
||||
The core memory operations, end to end.
|
||||
|
||||
@@ -5,31 +5,42 @@ icon: "bolt"
|
||||
iconType: "solid"
|
||||
---
|
||||
|
||||
Get started with Mem0 Platform's hosted API in under 5 minutes. This guide shows you how to authenticate and store your first memory.
|
||||
In about five minutes you will get an API key, store your first memory, and search it back. Follow along in Python, JavaScript, cURL, or the terminal.
|
||||
|
||||
<Note>
|
||||
**Are you an AI agent?** See [Sign up as an agent](/platform/agent-signup): mint a working API key in four commands, no email or dashboard required.
|
||||
**Are you an AI agent?** See [Sign up as an agent](/platform/agent-signup): create a working API key in four commands, with no email or dashboard.
|
||||
</Note>
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Mem0 Platform account (<a href="https://app.mem0.ai?utm_source=oss&utm_medium=platform-quickstart" rel="nofollow">Sign up here</a>)
|
||||
- API key (<a href="https://app.mem0.ai/dashboard/settings?tab=api-keys&subtab=configuration" rel="nofollow">Get one from dashboard</a>)
|
||||
- Python 3.10+, Node.js 18+, or cURL
|
||||
- Python 3.10+, Node.js 18+, or cURL. The CLI needs either Node.js 18+ or Python 3.10+.
|
||||
|
||||
## Installation
|
||||
## Store your first memory
|
||||
|
||||
<Steps>
|
||||
<Step title="Install SDK">
|
||||
<Step title="Install">
|
||||
Pick a tab and use the same one for every step below.
|
||||
|
||||
<CodeGroup>
|
||||
```bash pip
|
||||
```bash Python
|
||||
pip install mem0ai
|
||||
```
|
||||
|
||||
```bash npm
|
||||
```bash JavaScript
|
||||
npm install mem0ai
|
||||
```
|
||||
|
||||
```bash cURL
|
||||
# Nothing to install. cURL ships with macOS and most Linux distributions.
|
||||
```
|
||||
|
||||
```bash CLI
|
||||
npm install -g @mem0/cli
|
||||
# or, if you prefer Python: pip install mem0-cli
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Step>
|
||||
|
||||
@@ -39,12 +50,12 @@ npm install mem0ai
|
||||
from mem0 import MemoryClient
|
||||
|
||||
client = MemoryClient(api_key="your-api-key")
|
||||
````
|
||||
```
|
||||
|
||||
```javascript JavaScript
|
||||
import MemoryClient from 'mem0ai';
|
||||
const client = new MemoryClient({ apiKey: 'your-api-key' });
|
||||
````
|
||||
```
|
||||
|
||||
```bash cURL
|
||||
export MEM0_API_KEY="your-api-key"
|
||||
@@ -65,7 +76,7 @@ messages = [
|
||||
{"role": "assistant", "content": "Got it! I'll remember your dietary preferences."}
|
||||
]
|
||||
client.add(messages, user_id="user123")
|
||||
````
|
||||
```
|
||||
|
||||
```javascript JavaScript
|
||||
const messages = [
|
||||
@@ -73,7 +84,7 @@ const messages = [
|
||||
{"role": "assistant", "content": "Got it! I'll remember your dietary preferences."}
|
||||
];
|
||||
await client.add(messages, { userId: "user123" });
|
||||
````
|
||||
```
|
||||
|
||||
```bash cURL
|
||||
curl -X POST https://api.mem0.ai/v3/memories/add/ \
|
||||
@@ -93,6 +104,17 @@ mem0 add "I'm a vegetarian and allergic to nuts." --user-id user123
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
Mem0 pulls the individual facts out of the conversation and stores each one separately:
|
||||
|
||||
```json
|
||||
{
|
||||
"results": [
|
||||
{"id": "0f2c1b6e-9a3d-4b18-8f77-1c2d3e4f5a6b", "memory": "Is a vegetarian", "event": "ADD"},
|
||||
{"id": "14e1b28a-2014-40ad-ac42-69c9ef42193d", "memory": "Allergic to nuts", "event": "ADD"}
|
||||
]
|
||||
}
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Search memories">
|
||||
@@ -100,12 +122,12 @@ mem0 add "I'm a vegetarian and allergic to nuts." --user-id user123
|
||||
```python Python
|
||||
results = client.search("What are my dietary restrictions?", filters={"user_id": "user123"})
|
||||
print(results)
|
||||
````
|
||||
```
|
||||
|
||||
```javascript JavaScript
|
||||
const results = await client.search("What are my dietary restrictions?", { filters: { user_id: "user123" } });
|
||||
console.log(results);
|
||||
````
|
||||
```
|
||||
|
||||
```bash cURL
|
||||
curl -X POST https://api.mem0.ai/v3/memories/search/ \
|
||||
@@ -123,7 +145,7 @@ mem0 search "What are my dietary restrictions?" --user-id user123
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
**Output:**
|
||||
Both facts come back, ranked by how well they match the question:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -132,37 +154,65 @@ mem0 search "What are my dietary restrictions?" --user-id user123
|
||||
"id": "14e1b28a-2014-40ad-ac42-69c9ef42193d",
|
||||
"memory": "Allergic to nuts",
|
||||
"user_id": "user123",
|
||||
"agent_id": null,
|
||||
"app_id": null,
|
||||
"run_id": null,
|
||||
"categories": ["health"],
|
||||
"metadata": {},
|
||||
"created_at": "2025-10-22T04:40:22.864647-07:00",
|
||||
"score": 0.30
|
||||
"updated_at": "2025-10-22T04:40:22.864647-07:00",
|
||||
"expiration_date": null,
|
||||
"score": 0.87
|
||||
},
|
||||
{
|
||||
"id": "0f2c1b6e-9a3d-4b18-8f77-1c2d3e4f5a6b",
|
||||
"memory": "Is a vegetarian",
|
||||
"user_id": "user123",
|
||||
"agent_id": null,
|
||||
"app_id": null,
|
||||
"run_id": null,
|
||||
"categories": ["food_preferences"],
|
||||
"metadata": {},
|
||||
"created_at": "2025-10-22T04:40:22.864647-07:00",
|
||||
"updated_at": "2025-10-22T04:40:22.864647-07:00",
|
||||
"expiration_date": null,
|
||||
"score": 0.81
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Pass these memories to your model as context, and it answers with what it already knows about the user instead of asking again.
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
<Callout type="tip" icon="plug">
|
||||
**Pro Tip**: Want AI agents to manage their own memory automatically? Use <Link href="/platform/mem0-mcp">Mem0 MCP</Link> to let LLMs decide when to save, search, and update memories.
|
||||
</Callout>
|
||||
<Tip>
|
||||
Rather than calling `add` and `search` yourself, you can hand Mem0 to your agent as a set of tools and let it decide when to save and look things up. See [Mem0 MCP](/platform/mem0-mcp).
|
||||
</Tip>
|
||||
|
||||
## What's next?
|
||||
|
||||
You stored and searched your first memory. Keep going:
|
||||
You stored and searched your first memory. Start with scoping, since every call you make from here needs it:
|
||||
|
||||
<CardGroup cols={3}>
|
||||
<Card title="How it works" icon="diagram-project" href="/core-concepts/how-it-works">
|
||||
See how Mem0 extracts, stores, and retrieves memories under the hood.
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Scope memories to users and agents" icon="users" href="/platform/features/entity-scoped-memory">
|
||||
What `user_id` actually does, plus the `agent_id`, `app_id`, and `run_id` fields that came back empty above.
|
||||
</Card>
|
||||
|
||||
<Card title="Memory operations" icon="database" href="/core-concepts/memory-operations/add">
|
||||
Go beyond add and search: update, delete, and the full memory lifecycle.
|
||||
<Card title="How Mem0 works" icon="diagram-project" href="/core-concepts/how-it-works">
|
||||
Why one sentence became two memories, and how Mem0 decides what to keep.
|
||||
</Card>
|
||||
|
||||
<Card title="Build an AI companion" icon="users" href="/cookbooks/essentials/building-ai-companion">
|
||||
Put it to work in a real app, end to end, in about 10 minutes.
|
||||
<Card title="Update and delete memories" icon="database" href="/core-concepts/memory-operations/add">
|
||||
The operations beyond add and search, for when stored facts change or go stale.
|
||||
</Card>
|
||||
|
||||
<Card title="Use Mem0 with your agent framework" icon="plug" href="/integrations">
|
||||
Wire memory into LangChain, CrewAI, LangGraph, or the OpenAI Agents SDK.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
Stuck on setup? See the [FAQs and troubleshooting](/platform/faqs).
|
||||
<Note>
|
||||
Something not working? The [FAQs and troubleshooting](/platform/faqs) page covers the common setup errors.
|
||||
</Note>
|
||||
|
||||
+18
-16
@@ -5,13 +5,15 @@ description: "Agent skills, starter prompts, and setup for building with Mem0 us
|
||||
icon: "wand-magic-sparkles"
|
||||
---
|
||||
|
||||
These docs are designed to be easily consumable by LLMs. Each page has a button that lets you copy the page as Markdown or paste directly into ChatGPT, Claude, or any AI coding tool.
|
||||
Vibecoding means building software by describing what you want to an AI coding assistant and letting it write the code. The catch is that assistants guess at unfamiliar libraries, and a wrong guess about Mem0 costs you a debugging session.
|
||||
|
||||
We follow the llms.txt standard:
|
||||
This page fixes that three ways: skills that teach your assistant the Mem0 SDKs, an MCP connection so it can read and write memories itself, and a starter prompt you can paste into any tool.
|
||||
|
||||
- [llms.txt](https://docs.mem0.ai/llms.txt)
|
||||
<Note>
|
||||
Every page in these docs has a button to copy it as Markdown or send it straight to ChatGPT or Claude, so you can hand your assistant any page it needs. We follow the [llms.txt](https://docs.mem0.ai/llms.txt) standard.
|
||||
</Note>
|
||||
|
||||
## Agent Skills
|
||||
## Agent skills
|
||||
|
||||
Mem0 ships two kinds of skills for AI coding assistants. Both work with Claude Code, Codex, Cursor, Windsurf, OpenCode, OpenClaw, and any assistant that supports the skills standard.
|
||||
|
||||
@@ -45,7 +47,7 @@ npx skills add https://github.com/mem0ai/mem0 --skill mem0-oss-to-platform
|
||||
|
||||
See the [skills index](https://github.com/mem0ai/mem0/tree/main/skills) for the full catalog.
|
||||
|
||||
## MCP Server Setup
|
||||
## MCP server setup
|
||||
|
||||
Connect Claude, Claude Code, Cursor, Windsurf, VS Code, OpenCode, or any MCP-compatible client to Mem0.
|
||||
|
||||
@@ -61,13 +63,13 @@ npx mcp-add \
|
||||
|
||||
For per-client setup and advanced options, see [Mem0 MCP Setup](/platform/mem0-mcp).
|
||||
|
||||
## Universal Starter Prompt
|
||||
## Universal starter prompt
|
||||
|
||||
Copy this into any AI tool to start building with Mem0:
|
||||
|
||||
```text
|
||||
I want to start building with Mem0, a self-improving memory layer for LLM
|
||||
applications that gives agents persistent context across sessions.
|
||||
I want to start building with Mem0, which gives AI agents long-term memory
|
||||
that persists across sessions, tools, and runs.
|
||||
|
||||
## Mem0 Resources
|
||||
|
||||
@@ -86,10 +88,10 @@ applications that gives agents persistent context across sessions.
|
||||
- Cookbooks: https://docs.mem0.ai/cookbooks/overview
|
||||
|
||||
**What Mem0 Does:**
|
||||
Mem0 is a memory layer for AI apps, managed (Mem0 Platform) or self-hosted
|
||||
(Open Source). It stores, retrieves, and manages user memories so agents
|
||||
remember preferences, learn from interactions, and personalize over time.
|
||||
Sub-50ms retrieval. Storage: vector embeddings.
|
||||
Mem0 gives AI agents long-term memory, either managed (Mem0 Platform) or
|
||||
self-hosted (Open Source). It stores, retrieves, and manages memories so
|
||||
agents remember preferences, learn from past runs, and personalize over
|
||||
time. Storage: vector embeddings.
|
||||
|
||||
**Architecture Overview:**
|
||||
- Memory is scoped by user_id, agent_id, or run_id
|
||||
@@ -109,7 +111,7 @@ Sub-50ms retrieval. Storage: vector embeddings.
|
||||
import MemoryClient from 'mem0ai';
|
||||
const client = new MemoryClient({ apiKey: 'm0-xxx' });
|
||||
await client.add([{ role: "user", content: "I prefer dark mode." }], { userId: "user1" });
|
||||
const results = await client.search("What editor?", { filters: { userId: "user1" } });
|
||||
const results = await client.search("What editor?", { filters: { user_id: "user1" } });
|
||||
|
||||
**Quick Usage (Python Open Source):**
|
||||
from mem0 import Memory
|
||||
@@ -121,10 +123,10 @@ Help me integrate Mem0 into my project. Start by asking what I'm building,
|
||||
what language/framework I'm using, and whether I want managed or self-hosted.
|
||||
```
|
||||
|
||||
## Go Deeper
|
||||
## Go deeper
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Platform Quickstart" icon="cloud" href="/platform/quickstart">
|
||||
<Card title="Platform quickstart" icon="cloud" href="/platform/quickstart">
|
||||
Get started with the managed API
|
||||
</Card>
|
||||
<Card title="Open Source" icon="code-branch" href="/open-source/overview">
|
||||
@@ -133,7 +135,7 @@ what language/framework I'm using, and whether I want managed or self-hosted.
|
||||
<Card title="Cookbooks" icon="book" href="/cookbooks/overview">
|
||||
Production-ready tutorials and examples
|
||||
</Card>
|
||||
<Card title="API Reference" icon="code" href="/api-reference">
|
||||
<Card title="API reference" icon="code" href="/api-reference">
|
||||
Explore every REST endpoint
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
"clsx": "^2.1.1",
|
||||
"js-cookie": "^3.0.6",
|
||||
"lucide-react": "^0.477.0",
|
||||
"next": "15.5.18",
|
||||
"next": "15.5.21",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-markdown": "^10.0.1",
|
||||
|
||||
@@ -27,24 +27,45 @@ def load_settings() -> dict:
|
||||
try:
|
||||
with open(SETTINGS_PATH) as f:
|
||||
user = json.load(f)
|
||||
settings.update({k: v for k, v in user.items() if k in DEFAULTS})
|
||||
except (json.JSONDecodeError, OSError):
|
||||
pass
|
||||
return settings
|
||||
if isinstance(user, dict):
|
||||
settings.update({k: v for k, v in user.items() if k in DEFAULTS})
|
||||
return settings
|
||||
|
||||
|
||||
def create_default_settings() -> None:
|
||||
def create_default_settings() -> bool:
|
||||
"""Write the default settings file if absent. Returns True if it was created."""
|
||||
SETTINGS_PATH.parent.mkdir(parents=True, exist_ok=True)
|
||||
if SETTINGS_PATH.exists():
|
||||
return False
|
||||
with open(SETTINGS_PATH, "w") as f:
|
||||
json.dump(DEFAULTS, f, indent=2)
|
||||
f.write("\n")
|
||||
return True
|
||||
|
||||
|
||||
def unknown_keys() -> list[str]:
|
||||
"""Keys present in the user's settings file that no code reads."""
|
||||
if not SETTINGS_PATH.exists():
|
||||
with open(SETTINGS_PATH, "w") as f:
|
||||
json.dump(DEFAULTS, f, indent=2)
|
||||
f.write("\n")
|
||||
return []
|
||||
try:
|
||||
with open(SETTINGS_PATH) as f:
|
||||
user = json.load(f)
|
||||
except (json.JSONDecodeError, OSError):
|
||||
return []
|
||||
if not isinstance(user, dict):
|
||||
return []
|
||||
return sorted(k for k in user if k not in DEFAULTS)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
if len(sys.argv) > 1 and sys.argv[1] == "init":
|
||||
create_default_settings()
|
||||
print(f"Created {SETTINGS_PATH}")
|
||||
if create_default_settings():
|
||||
print(f"Created {SETTINGS_PATH}")
|
||||
ignored = unknown_keys()
|
||||
if ignored:
|
||||
print(f"Ignoring unrecognized settings in {SETTINGS_PATH}: {', '.join(ignored)}")
|
||||
else:
|
||||
print(json.dumps(load_settings()))
|
||||
|
||||
@@ -23,15 +23,14 @@ def _scripts_on_path():
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _clean_project_map(monkeypatch):
|
||||
"""Remove project_map.json and clear MEM0_PROJECT_ID before each test."""
|
||||
def _isolated_home(tmp_path, monkeypatch):
|
||||
"""Point HOME at a tmp dir so ~/.mem0 writes never touch the real home."""
|
||||
home = tmp_path / "home"
|
||||
home.mkdir()
|
||||
monkeypatch.setenv("HOME", str(home))
|
||||
monkeypatch.setenv("USERPROFILE", str(home))
|
||||
monkeypatch.delenv("MEM0_PROJECT_ID", raising=False)
|
||||
map_path = os.path.expanduser("~/.mem0/project_map.json")
|
||||
if os.path.isfile(map_path):
|
||||
os.remove(map_path)
|
||||
yield
|
||||
if os.path.isfile(map_path):
|
||||
os.remove(map_path)
|
||||
yield home
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
"""Tests for scripts/load_settings.py."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def settings(tmp_path, monkeypatch):
|
||||
import load_settings
|
||||
|
||||
path = tmp_path / ".mem0" / "settings.json"
|
||||
monkeypatch.setattr(load_settings, "SETTINGS_PATH", path)
|
||||
return load_settings
|
||||
|
||||
|
||||
def test_creates_file_when_absent(settings):
|
||||
assert settings.create_default_settings() is True
|
||||
assert settings.SETTINGS_PATH.exists()
|
||||
assert json.loads(settings.SETTINGS_PATH.read_text()) == settings.DEFAULTS
|
||||
|
||||
|
||||
def test_does_not_recreate_or_overwrite_existing(settings):
|
||||
settings.SETTINGS_PATH.parent.mkdir(parents=True)
|
||||
settings.SETTINGS_PATH.write_text('{"search_limit": 42}')
|
||||
|
||||
assert settings.create_default_settings() is False
|
||||
assert json.loads(settings.SETTINGS_PATH.read_text()) == {"search_limit": 42}
|
||||
|
||||
|
||||
def test_user_values_override_defaults(settings):
|
||||
settings.SETTINGS_PATH.parent.mkdir(parents=True)
|
||||
settings.SETTINGS_PATH.write_text('{"search_limit": 3, "auto_save": false}')
|
||||
|
||||
loaded = settings.load_settings()
|
||||
assert loaded["search_limit"] == 3
|
||||
assert loaded["auto_save"] is False
|
||||
assert loaded["global_search"] == settings.DEFAULTS["global_search"]
|
||||
|
||||
|
||||
def test_unknown_keys_are_dropped_but_reported(settings):
|
||||
settings.SETTINGS_PATH.parent.mkdir(parents=True)
|
||||
settings.SETTINGS_PATH.write_text('{"skip_tools": ["Read"], "output_style": "compact"}')
|
||||
|
||||
assert "skip_tools" not in settings.load_settings()
|
||||
assert settings.unknown_keys() == ["output_style", "skip_tools"]
|
||||
|
||||
|
||||
def test_unknown_keys_empty_for_clean_file(settings):
|
||||
settings.create_default_settings()
|
||||
assert settings.unknown_keys() == []
|
||||
|
||||
|
||||
@pytest.mark.parametrize("body", ["{not json", '["a", "list"]'])
|
||||
def test_malformed_file_falls_back_to_defaults(settings, body):
|
||||
settings.SETTINGS_PATH.parent.mkdir(parents=True)
|
||||
settings.SETTINGS_PATH.write_text(body)
|
||||
|
||||
assert settings.load_settings() == settings.DEFAULTS
|
||||
assert settings.unknown_keys() == []
|
||||
|
||||
|
||||
def test_init_announces_creation_only_once(_isolated_home):
|
||||
import load_settings
|
||||
|
||||
home = _isolated_home
|
||||
|
||||
def run_init():
|
||||
return subprocess.run(
|
||||
[sys.executable, load_settings.__file__, "init"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True,
|
||||
env={**os.environ, "HOME": str(home)},
|
||||
).stdout
|
||||
|
||||
first = run_init()
|
||||
second = run_init()
|
||||
|
||||
assert "Created" in first
|
||||
assert "Created" not in second
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mem0/n8n-nodes-mem0",
|
||||
"version": "0.1.0",
|
||||
"version": "0.1.1",
|
||||
"description": "n8n community node for Mem0 — the memory layer for AI agents. Add, search, get, update, and delete long-term memories.",
|
||||
"keywords": [
|
||||
"n8n-community-node-package",
|
||||
|
||||
@@ -1449,7 +1449,7 @@ export function registerCliCommands(
|
||||
console.log(" openclaw mem0 config set auto_recall false");
|
||||
} else {
|
||||
console.log(" openclaw mem0 config set vector_provider qdrant");
|
||||
console.log(" openclaw mem0 config set llm_model gpt-4o");
|
||||
console.log(" openclaw mem0 config set llm_model gpt-5-mini");
|
||||
console.log(" openclaw mem0 config set embedder_provider openai");
|
||||
}
|
||||
console.log("");
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"id": "openclaw-mem0",
|
||||
"name": "Memory (Mem0)",
|
||||
"description": "Mem0 memory backend for OpenClaw — platform (mem0.ai cloud) or self-hosted open-source. Auto-recall and auto-capture are opt-in (disabled by default). Supports OpenAI, Anthropic, Ollama (fully local), Qdrant, and PGVector providers.",
|
||||
"version": "1.0.14",
|
||||
"version": "1.0.15",
|
||||
"kind": "memory",
|
||||
"skills": ["skills"],
|
||||
"commandAliases": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mem0/openclaw-mem0",
|
||||
"version": "1.0.14",
|
||||
"version": "1.0.15",
|
||||
"type": "module",
|
||||
"description": "Mem0 memory backend for OpenClaw — platform or self-hosted open-source",
|
||||
"license": "Apache-2.0",
|
||||
@@ -65,14 +65,17 @@
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"form-data@<4.0.6": ">=4.0.6",
|
||||
"protobufjs@<7.5.5": "^7.5.5",
|
||||
"protobufjs@<7.6.5": ">=7.6.5 <8.0.0",
|
||||
"vite": "^8.0.5",
|
||||
"langsmith@<0.6.0": "^0.6.0",
|
||||
"picomatch@<2.3.2": "^2.3.2",
|
||||
"@qdrant/js-client-rest": "^1.18.0",
|
||||
"uuid@<11.1.1": ">=11.1.1",
|
||||
"esbuild": ">=0.28.1",
|
||||
"undici@<6.27.0": ">=6.27.0 <8.0.0"
|
||||
"undici@<6.27.0": ">=6.27.0 <8.0.0",
|
||||
"axios@<1.18.0": ">=1.18.0 <2.0.0",
|
||||
"postcss@<8.5.18": ">=8.5.18 <9.0.0",
|
||||
"mongoose@>=9.0.0 <9.7.2": ">=9.7.2 <10.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+100
-43
@@ -6,7 +6,7 @@ settings:
|
||||
|
||||
overrides:
|
||||
form-data@<4.0.6: '>=4.0.6'
|
||||
protobufjs@<7.5.5: ^7.5.5
|
||||
protobufjs@<7.6.5: '>=7.6.5 <8.0.0'
|
||||
vite: ^8.0.5
|
||||
langsmith@<0.6.0: ^0.6.0
|
||||
picomatch@<2.3.2: ^2.3.2
|
||||
@@ -14,6 +14,9 @@ overrides:
|
||||
uuid@<11.1.1: '>=11.1.1'
|
||||
esbuild: '>=0.28.1'
|
||||
undici@<6.27.0: '>=6.27.0 <8.0.0'
|
||||
axios@<1.18.0: '>=1.18.0 <2.0.0'
|
||||
postcss@<8.5.18: '>=8.5.18 <9.0.0'
|
||||
mongoose@>=9.0.0 <9.7.2: '>=9.7.2 <10.0.0'
|
||||
|
||||
importers:
|
||||
|
||||
@@ -24,7 +27,7 @@ importers:
|
||||
version: 0.34.47
|
||||
mem0ai:
|
||||
specifier: 3.0.7
|
||||
version: 3.0.7(@anthropic-ai/sdk@0.40.1)(@azure/identity@4.13.1)(@azure/search-documents@12.2.0)(@cloudflare/workers-types@4.20260610.1)(@google/genai@1.52.0)(@langchain/core@1.1.48(openai@4.104.0(ws@8.21.0)(zod@3.25.76))(ws@8.21.0))(@mistralai/mistralai@1.15.1)(@qdrant/js-client-rest@1.18.0(typescript@5.9.3))(@supabase/supabase-js@2.108.1)(@types/jest@29.5.14)(@types/pg@8.11.0)(better-sqlite3@12.10.0)(cloudflare@4.5.0)(compromise@14.15.1)(groq-sdk@0.3.0)(natural@8.1.1)(ollama@0.5.18)(pg@8.21.0)(redis@5.12.1)(ws@8.21.0)
|
||||
version: 3.0.7(@anthropic-ai/sdk@0.40.1)(@azure/identity@4.13.1)(@azure/search-documents@12.2.0)(@cloudflare/workers-types@4.20260610.1)(@google/genai@1.52.0)(@langchain/core@1.1.48(openai@4.104.0(ws@8.21.0)(zod@3.25.76))(ws@8.21.0))(@mistralai/mistralai@1.15.1)(@qdrant/js-client-rest@1.18.0(typescript@5.9.3))(@supabase/supabase-js@2.108.1)(@types/jest@29.5.14)(@types/pg@8.11.0)(better-sqlite3@12.10.0)(cloudflare@4.5.0)(compromise@14.15.1)(groq-sdk@0.3.0)(natural@8.1.1)(ollama@0.5.18)(pg@8.11.3)(redis@5.12.1)(ws@8.21.0)
|
||||
devDependencies:
|
||||
'@qdrant/js-client-rest':
|
||||
specifier: ^1.18.0
|
||||
@@ -37,7 +40,7 @@ importers:
|
||||
version: 4.1.8(vitest@4.1.8)
|
||||
tsup:
|
||||
specifier: ^8.5.0
|
||||
version: 8.5.1(postcss@8.5.15)(typescript@5.9.3)
|
||||
version: 8.5.1(postcss@8.5.23)(typescript@5.9.3)
|
||||
typescript:
|
||||
specifier: ^5.8.3
|
||||
version: 5.9.3
|
||||
@@ -379,9 +382,6 @@ packages:
|
||||
'@protobufjs/float@1.0.2':
|
||||
resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==}
|
||||
|
||||
'@protobufjs/inquire@1.1.2':
|
||||
resolution: {integrity: sha512-pa0vFRuws4wkvaXKK1uXZMAwAX4/t8ANaJo45iw/oQHNQ9q5xUzwgFmVJGXiga2BeN+zpX7Vf9vmsiIa2J+MUw==}
|
||||
|
||||
'@protobufjs/path@1.1.2':
|
||||
resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==}
|
||||
|
||||
@@ -472,36 +472,42 @@ packages:
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-arm64-musl@1.0.3':
|
||||
resolution: {integrity: sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rolldown/binding-linux-ppc64-gnu@1.0.3':
|
||||
resolution: {integrity: sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-s390x-gnu@1.0.3':
|
||||
resolution: {integrity: sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-x64-gnu@1.0.3':
|
||||
resolution: {integrity: sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-x64-musl@1.0.3':
|
||||
resolution: {integrity: sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rolldown/binding-openharmony-arm64@1.0.3':
|
||||
resolution: {integrity: sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==}
|
||||
@@ -563,66 +569,79 @@ packages:
|
||||
resolution: {integrity: sha512-Q8CBCCQtDFrYtXoeUXSrnFXKOnyUhx6bz+SkL6A0E7V8kAiCJ5pamq1WtbfpVGhR5TSpXY6ak3avmDc5fHTyJA==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.61.1':
|
||||
resolution: {integrity: sha512-nwnhk1581l0FBVellGcVCAT0Oi06onEA3WB53sf01VO3I0UPBkMH9sXONYME2K0ovXcNayJfNtHfm6mpJElatQ==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-arm64-gnu@4.61.1':
|
||||
resolution: {integrity: sha512-x5Xr49hwt3hdW75UOZm3395YwwzPyauktslv29KpWL/T+vVAzoT3azLcTWv0eMciBNrx+DYjH4paehHoLpPvpg==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-arm64-musl@4.61.1':
|
||||
resolution: {integrity: sha512-unMS3H73DpaoPyyEVPjGKleM/s0mkmsauTENpw4INQY8y4+IuLNjkueQ5QCtC0D3N38Y38yhAU8OoZ20S2Tm6w==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-loong64-gnu@4.61.1':
|
||||
resolution: {integrity: sha512-zNZzGRnAhwjFEYmvphJRV5XaQGjs62cCmeYYHUT//NbvEnHauw+I85nGG+SiVg5ld4GX8D1IbKIX+ozITQnhMQ==}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-loong64-musl@4.61.1':
|
||||
resolution: {integrity: sha512-LdpWGL8X209B2SIvWjqlc8VZgM6PKfontSerGepuldQmHYrAOtnMCXeJkxXGbC+PPZVOuu5czJo7fNV6aeW8rQ==}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-ppc64-gnu@4.61.1':
|
||||
resolution: {integrity: sha512-EC5kTtNaNGOmbMGqar8dvJy6y/hg99GAwjfBz++pxZhQATXGcRjd6c5en5wcbru0vkRmiMGsQKdMJOOf6sza4g==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-ppc64-musl@4.61.1':
|
||||
resolution: {integrity: sha512-8hiwp6D4acEcNK78I4rP0/XtS1sknWIAMJBPdR4l6zUtyTm5KiTDr5bXmWt4foY7nAN7AThDHgkLIEZOWKbzWw==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-gnu@4.61.1':
|
||||
resolution: {integrity: sha512-10dh/h/BqA7DuMPWSxkR8uks18FRwnwOEqr5zOTEl+NOwP/OMzKX8OFR/Of9xxDA7D5qef1Nzar5WDD2kCCr1g==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-musl@4.61.1':
|
||||
resolution: {integrity: sha512-YKJ5lg35DP17gcAOggnihe+APw9HLyj1Xn7gsmGumBJAUDa6NGXNixJzmkWLhcK9TOuuyQjdamzvJefkO7qHZQ==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-s390x-gnu@4.61.1':
|
||||
resolution: {integrity: sha512-Mlil5G2Jj6a7B3LWGctg+XPL9vdXYuzCtNXfxOQ0nPjc2m6ueUktocPGH9bnAM0bNRKb/bAWTujUU7IJQdQA+g==}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-x64-gnu@4.61.1':
|
||||
resolution: {integrity: sha512-bVWIOIk6pV01p4CdUbPP7CJ/434z+OooYjDuFcR+44N35YvKUC66G8MGnvcWx5mWKW3g61J+t74l3Kj15Kwn2Q==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-x64-musl@4.61.1':
|
||||
resolution: {integrity: sha512-qy5pBvZbqNFheBz61R1rzsezjm0J7O2oNGoWtGoY89SZYLUfxAJTBAqDChqAIdB4rCiIbi9nF7yZ83GnNiLwSw==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-openbsd-x64@4.61.1':
|
||||
resolution: {integrity: sha512-E83TXjI4zm0+5f2qO+UOudaCYIhYwpJ5jq6YCZNIZ+6CbfhKrkAGezeiASBL9ElxAxFsRS9ZhESv8mfnj6TKeg==}
|
||||
@@ -838,8 +857,8 @@ packages:
|
||||
asynckit@0.4.0:
|
||||
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
|
||||
|
||||
axios@1.17.0:
|
||||
resolution: {integrity: sha512-J8SwNxprqqpbfenehxWYXE7CW+wM1BB4w3+N+g+/Wx40xM4rsLrfPmHHxSWIxJLYDgSY/HqlFPIYb2/S3rxafw==}
|
||||
axios@1.18.1:
|
||||
resolution: {integrity: sha512-3nTvFlvpn9Zu/RkHUqtc7/+al4UpRW5az71ap5zccp6e8RAYEzhMTecX8Dz1wWDYrPpUoB1HAQEGEAEvUr7S9g==}
|
||||
|
||||
base-64@0.1.0:
|
||||
resolution: {integrity: sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA==}
|
||||
@@ -871,6 +890,10 @@ packages:
|
||||
buffer-equal-constant-time@1.0.1:
|
||||
resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==}
|
||||
|
||||
buffer-writer@2.0.0:
|
||||
resolution: {integrity: sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
buffer@5.7.1:
|
||||
resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
|
||||
|
||||
@@ -1360,24 +1383,28 @@ packages:
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
lightningcss-linux-arm64-musl@1.32.0:
|
||||
resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
lightningcss-linux-x64-gnu@1.32.0:
|
||||
resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
lightningcss-linux-x64-musl@1.32.0:
|
||||
resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
lightningcss-win32-arm64-msvc@1.32.0:
|
||||
resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==}
|
||||
@@ -1507,15 +1534,15 @@ packages:
|
||||
resolution: {integrity: sha512-h0AZ9A7IDVwwHyMxmdMXKy+9oNlF0zFoahHiX3vQ8e3KFcSP3VmsmfvtRSuLPxmyv2vjIDxqty8smTgie/SNRQ==}
|
||||
engines: {node: '>=20.19.0'}
|
||||
|
||||
mongodb@7.2.0:
|
||||
resolution: {integrity: sha512-F/2+BMZtLVhY30ioZp0dAmZ+IRZMBqI+nrv6t5+9/1AIwCa8sMRC3jBf81lpxMhnZgqq8CoUD503Z1oZWq1/sw==}
|
||||
mongodb@7.5.0:
|
||||
resolution: {integrity: sha512-5FnrEDLnvp6ycUOGLNLLU33BfCx2qmp2mJjGPDwKLruYsVzXVSK5fsGpoDXvsXJwBfBsD7ebMRdawbDxC2814g==}
|
||||
engines: {node: '>=20.19.0'}
|
||||
peerDependencies:
|
||||
'@aws-sdk/credential-providers': ^3.806.0
|
||||
'@mongodb-js/zstd': ^7.0.0
|
||||
gcp-metadata: ^7.0.1
|
||||
kerberos: ^7.0.0
|
||||
mongodb-client-encryption: '>=7.0.0 <7.1.0'
|
||||
mongodb-client-encryption: ^7.2.0
|
||||
snappy: ^7.3.2
|
||||
socks: ^2.8.6
|
||||
peerDependenciesMeta:
|
||||
@@ -1534,8 +1561,8 @@ packages:
|
||||
socks:
|
||||
optional: true
|
||||
|
||||
mongoose@9.7.0:
|
||||
resolution: {integrity: sha512-pkrLZ6U41pD4Ai0ju/FYL7o5I5k+rV3RZINQTG937hbhnLGKRuqqYm1Dlt/kTQ+M4FHijzV6JawzsdHKRGt7QA==}
|
||||
mongoose@9.8.0:
|
||||
resolution: {integrity: sha512-PDGx3XACxrBQyWf4YT+5s1Xsx19x84UWGlRVIza4i9RG6qKjGcoG7odotT6uquR6YoaDMTZ6ZZc/jMXLrNPyyA==}
|
||||
engines: {node: '>=20.19.0'}
|
||||
|
||||
mpath@0.9.0:
|
||||
@@ -1556,8 +1583,8 @@ packages:
|
||||
mz@2.7.0:
|
||||
resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
|
||||
|
||||
nanoid@3.3.12:
|
||||
resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==}
|
||||
nanoid@3.3.16:
|
||||
resolution: {integrity: sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==}
|
||||
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
||||
hasBin: true
|
||||
|
||||
@@ -1639,6 +1666,9 @@ packages:
|
||||
resolution: {integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
packet-reader@1.0.0:
|
||||
resolution: {integrity: sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==}
|
||||
|
||||
pathe@2.0.3:
|
||||
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
|
||||
|
||||
@@ -1672,6 +1702,15 @@ packages:
|
||||
resolution: {integrity: sha512-o2XFanIMy/3+mThw69O8d4n1E5zsLhdO+OPqswezu7Z5ekP4hYDqlDjlmOpYMbzY2Br0ufCwJLdDIXeNVwcWFg==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
pg@8.11.3:
|
||||
resolution: {integrity: sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==}
|
||||
engines: {node: '>= 8.0.0'}
|
||||
peerDependencies:
|
||||
pg-native: '>=3.0.1'
|
||||
peerDependenciesMeta:
|
||||
pg-native:
|
||||
optional: true
|
||||
|
||||
pg@8.21.0:
|
||||
resolution: {integrity: sha512-AUP1EYJuHraQGsVoCQVIcM7TEJVGtDzxWtGFZd8rds9d+CCXlU5Js1rYgfLNvxy9iJrpHjGrRjoi/3BT9fRyiA==}
|
||||
engines: {node: '>= 16.0.0'}
|
||||
@@ -1707,7 +1746,7 @@ packages:
|
||||
engines: {node: '>= 18'}
|
||||
peerDependencies:
|
||||
jiti: '>=1.21.0'
|
||||
postcss: '>=8.0.9'
|
||||
postcss: '>=8.5.18 <9.0.0'
|
||||
tsx: ^4.8.1
|
||||
yaml: ^2.4.2
|
||||
peerDependenciesMeta:
|
||||
@@ -1720,8 +1759,8 @@ packages:
|
||||
yaml:
|
||||
optional: true
|
||||
|
||||
postcss@8.5.15:
|
||||
resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==}
|
||||
postcss@8.5.23:
|
||||
resolution: {integrity: sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==}
|
||||
engines: {node: ^10 || ^12 || >=14}
|
||||
|
||||
postgres-array@2.0.0:
|
||||
@@ -1769,8 +1808,8 @@ packages:
|
||||
resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==}
|
||||
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
||||
|
||||
protobufjs@7.6.3:
|
||||
resolution: {integrity: sha512-+k0vdJKNdW+Vu+dYe8tZA/VvQb6XKNWexC6URwBFXxNnjLJz9nQJCemGyNgRAWD+B7+nGNc9qMPGwcD7s4nzUw==}
|
||||
protobufjs@7.6.5:
|
||||
resolution: {integrity: sha512-/FPD0nUc9jH6rfFjji9IBqOz4pcSE3CsT1m7Ep6Mdb0LxSUMj8hgl6GomOvZzpNpAqqGaXA0P3VSrZLFzIhQrw==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
|
||||
proxy-from-env@2.1.0:
|
||||
@@ -1965,7 +2004,7 @@ packages:
|
||||
peerDependencies:
|
||||
'@microsoft/api-extractor': ^7.36.0
|
||||
'@swc/core': ^1
|
||||
postcss: ^8.4.12
|
||||
postcss: '>=8.5.18 <9.0.0'
|
||||
typescript: '>=4.5.0'
|
||||
peerDependenciesMeta:
|
||||
'@microsoft/api-extractor':
|
||||
@@ -2408,7 +2447,7 @@ snapshots:
|
||||
dependencies:
|
||||
google-auth-library: 10.7.0
|
||||
p-retry: 4.6.2
|
||||
protobufjs: 7.6.3
|
||||
protobufjs: 7.6.5
|
||||
ws: 8.21.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
@@ -2498,8 +2537,6 @@ snapshots:
|
||||
|
||||
'@protobufjs/float@1.0.2': {}
|
||||
|
||||
'@protobufjs/inquire@1.1.2': {}
|
||||
|
||||
'@protobufjs/path@1.1.2': {}
|
||||
|
||||
'@protobufjs/pool@1.1.0': {}
|
||||
@@ -2869,7 +2906,7 @@ snapshots:
|
||||
|
||||
asynckit@0.4.0: {}
|
||||
|
||||
axios@1.17.0:
|
||||
axios@1.18.1:
|
||||
dependencies:
|
||||
follow-redirects: 1.16.0
|
||||
form-data: 4.0.6
|
||||
@@ -2908,6 +2945,8 @@ snapshots:
|
||||
|
||||
buffer-equal-constant-time@1.0.1: {}
|
||||
|
||||
buffer-writer@2.0.0: {}
|
||||
|
||||
buffer@5.7.1:
|
||||
dependencies:
|
||||
base64-js: 1.5.1
|
||||
@@ -3477,7 +3516,7 @@ snapshots:
|
||||
crypt: 0.0.2
|
||||
is-buffer: 1.1.6
|
||||
|
||||
mem0ai@3.0.7(@anthropic-ai/sdk@0.40.1)(@azure/identity@4.13.1)(@azure/search-documents@12.2.0)(@cloudflare/workers-types@4.20260610.1)(@google/genai@1.52.0)(@langchain/core@1.1.48(openai@4.104.0(ws@8.21.0)(zod@3.25.76))(ws@8.21.0))(@mistralai/mistralai@1.15.1)(@qdrant/js-client-rest@1.18.0(typescript@5.9.3))(@supabase/supabase-js@2.108.1)(@types/jest@29.5.14)(@types/pg@8.11.0)(better-sqlite3@12.10.0)(cloudflare@4.5.0)(compromise@14.15.1)(groq-sdk@0.3.0)(natural@8.1.1)(ollama@0.5.18)(pg@8.21.0)(redis@5.12.1)(ws@8.21.0):
|
||||
mem0ai@3.0.7(@anthropic-ai/sdk@0.40.1)(@azure/identity@4.13.1)(@azure/search-documents@12.2.0)(@cloudflare/workers-types@4.20260610.1)(@google/genai@1.52.0)(@langchain/core@1.1.48(openai@4.104.0(ws@8.21.0)(zod@3.25.76))(ws@8.21.0))(@mistralai/mistralai@1.15.1)(@qdrant/js-client-rest@1.18.0(typescript@5.9.3))(@supabase/supabase-js@2.108.1)(@types/jest@29.5.14)(@types/pg@8.11.0)(better-sqlite3@12.10.0)(cloudflare@4.5.0)(compromise@14.15.1)(groq-sdk@0.3.0)(natural@8.1.1)(ollama@0.5.18)(pg@8.11.3)(redis@5.12.1)(ws@8.21.0):
|
||||
dependencies:
|
||||
'@anthropic-ai/sdk': 0.40.1
|
||||
'@azure/identity': 4.13.1
|
||||
@@ -3490,7 +3529,7 @@ snapshots:
|
||||
'@supabase/supabase-js': 2.108.1
|
||||
'@types/jest': 29.5.14
|
||||
'@types/pg': 8.11.0
|
||||
axios: 1.17.0
|
||||
axios: 1.18.1
|
||||
better-sqlite3: 12.10.0
|
||||
cloudflare: 4.5.0
|
||||
compromise: 14.15.1
|
||||
@@ -3498,7 +3537,7 @@ snapshots:
|
||||
natural: 8.1.1
|
||||
ollama: 0.5.18
|
||||
openai: 4.104.0(ws@8.21.0)(zod@3.25.76)
|
||||
pg: 8.21.0
|
||||
pg: 8.11.3
|
||||
redis: 5.12.1
|
||||
uuid: 14.0.0
|
||||
zod: 3.25.76
|
||||
@@ -3541,16 +3580,17 @@ snapshots:
|
||||
'@types/whatwg-url': 13.0.0
|
||||
whatwg-url: 14.2.0
|
||||
|
||||
mongodb@7.2.0:
|
||||
mongodb@7.5.0:
|
||||
dependencies:
|
||||
'@mongodb-js/saslprep': 1.4.11
|
||||
bson: 7.2.0
|
||||
mongodb-connection-string-url: 7.0.1
|
||||
|
||||
mongoose@9.7.0:
|
||||
mongoose@9.8.0:
|
||||
dependencies:
|
||||
'@standard-schema/spec': 1.1.0
|
||||
kareem: 3.3.0
|
||||
mongodb: 7.2.0
|
||||
mongodb: 7.5.0
|
||||
mpath: 0.9.0
|
||||
mquery: 6.0.0
|
||||
ms: 2.1.3
|
||||
@@ -3578,7 +3618,7 @@ snapshots:
|
||||
object-assign: 4.1.1
|
||||
thenify-all: 1.6.0
|
||||
|
||||
nanoid@3.3.12: {}
|
||||
nanoid@3.3.16: {}
|
||||
|
||||
napi-build-utils@2.0.0: {}
|
||||
|
||||
@@ -3589,7 +3629,7 @@ snapshots:
|
||||
apparatus: 0.0.10
|
||||
dotenv: 17.4.2
|
||||
memjs: 1.3.2
|
||||
mongoose: 9.7.0
|
||||
mongoose: 9.8.0
|
||||
pg: 8.21.0
|
||||
redis: 5.12.1
|
||||
safe-stable-stringify: 2.5.0
|
||||
@@ -3678,6 +3718,8 @@ snapshots:
|
||||
dependencies:
|
||||
p-finally: 1.0.0
|
||||
|
||||
packet-reader@1.0.0: {}
|
||||
|
||||
pathe@2.0.3: {}
|
||||
|
||||
pg-cloudflare@1.4.0:
|
||||
@@ -3689,6 +3731,10 @@ snapshots:
|
||||
|
||||
pg-numeric@1.0.2: {}
|
||||
|
||||
pg-pool@3.14.0(pg@8.11.3):
|
||||
dependencies:
|
||||
pg: 8.11.3
|
||||
|
||||
pg-pool@3.14.0(pg@8.21.0):
|
||||
dependencies:
|
||||
pg: 8.21.0
|
||||
@@ -3713,6 +3759,18 @@ snapshots:
|
||||
postgres-interval: 3.0.0
|
||||
postgres-range: 1.1.4
|
||||
|
||||
pg@8.11.3:
|
||||
dependencies:
|
||||
buffer-writer: 2.0.0
|
||||
packet-reader: 1.0.0
|
||||
pg-connection-string: 2.13.0
|
||||
pg-pool: 3.14.0(pg@8.11.3)
|
||||
pg-protocol: 1.14.0
|
||||
pg-types: 2.2.0
|
||||
pgpass: 1.0.5
|
||||
optionalDependencies:
|
||||
pg-cloudflare: 1.4.0
|
||||
|
||||
pg@8.21.0:
|
||||
dependencies:
|
||||
pg-connection-string: 2.13.0
|
||||
@@ -3741,15 +3799,15 @@ snapshots:
|
||||
mlly: 1.8.2
|
||||
pathe: 2.0.3
|
||||
|
||||
postcss-load-config@6.0.1(postcss@8.5.15):
|
||||
postcss-load-config@6.0.1(postcss@8.5.23):
|
||||
dependencies:
|
||||
lilconfig: 3.1.3
|
||||
optionalDependencies:
|
||||
postcss: 8.5.15
|
||||
postcss: 8.5.23
|
||||
|
||||
postcss@8.5.15:
|
||||
postcss@8.5.23:
|
||||
dependencies:
|
||||
nanoid: 3.3.12
|
||||
nanoid: 3.3.16
|
||||
picocolors: 1.1.1
|
||||
source-map-js: 1.2.1
|
||||
|
||||
@@ -3796,7 +3854,7 @@ snapshots:
|
||||
ansi-styles: 5.2.0
|
||||
react-is: 18.3.1
|
||||
|
||||
protobufjs@7.6.3:
|
||||
protobufjs@7.6.5:
|
||||
dependencies:
|
||||
'@protobufjs/aspromise': 1.1.2
|
||||
'@protobufjs/base64': 1.1.2
|
||||
@@ -3804,7 +3862,6 @@ snapshots:
|
||||
'@protobufjs/eventemitter': 1.1.1
|
||||
'@protobufjs/fetch': 1.1.1
|
||||
'@protobufjs/float': 1.0.2
|
||||
'@protobufjs/inquire': 1.1.2
|
||||
'@protobufjs/path': 1.1.2
|
||||
'@protobufjs/pool': 1.1.0
|
||||
'@protobufjs/utf8': 1.1.1
|
||||
@@ -4022,7 +4079,7 @@ snapshots:
|
||||
|
||||
tslib@2.8.1: {}
|
||||
|
||||
tsup@8.5.1(postcss@8.5.15)(typescript@5.9.3):
|
||||
tsup@8.5.1(postcss@8.5.23)(typescript@5.9.3):
|
||||
dependencies:
|
||||
bundle-require: 5.1.0(esbuild@0.28.1)
|
||||
cac: 6.7.14
|
||||
@@ -4033,7 +4090,7 @@ snapshots:
|
||||
fix-dts-default-cjs-exports: 1.0.1
|
||||
joycon: 3.1.1
|
||||
picocolors: 1.1.1
|
||||
postcss-load-config: 6.0.1(postcss@8.5.15)
|
||||
postcss-load-config: 6.0.1(postcss@8.5.23)
|
||||
resolve-from: 5.0.0
|
||||
rollup: 4.61.1
|
||||
source-map: 0.7.6
|
||||
@@ -4042,7 +4099,7 @@ snapshots:
|
||||
tinyglobby: 0.2.17
|
||||
tree-kill: 1.2.2
|
||||
optionalDependencies:
|
||||
postcss: 8.5.15
|
||||
postcss: 8.5.23
|
||||
typescript: 5.9.3
|
||||
transitivePeerDependencies:
|
||||
- jiti
|
||||
@@ -4076,7 +4133,7 @@ snapshots:
|
||||
dependencies:
|
||||
lightningcss: 1.32.0
|
||||
picomatch: 4.0.4
|
||||
postcss: 8.5.15
|
||||
postcss: 8.5.23
|
||||
rolldown: 1.0.3
|
||||
tinyglobby: 0.2.17
|
||||
optionalDependencies:
|
||||
|
||||
@@ -14,7 +14,7 @@ onlyBuiltDependencies:
|
||||
|
||||
overrides:
|
||||
"form-data@<4.0.6": ">=4.0.6"
|
||||
"protobufjs@<7.5.5": "^7.5.5"
|
||||
"protobufjs@<7.6.5": ">=7.6.5 <8.0.0"
|
||||
"vite": "^8.0.5"
|
||||
"langsmith@<0.6.0": "^0.6.0"
|
||||
"picomatch@<2.3.2": "^2.3.2"
|
||||
@@ -22,3 +22,6 @@ overrides:
|
||||
"uuid@<11.1.1": ">=11.1.1"
|
||||
"esbuild": ">=0.28.1"
|
||||
"undici@<6.27.0": ">=6.27.0 <8.0.0"
|
||||
"axios@<1.18.0": ">=1.18.0 <2.0.0"
|
||||
"postcss@<8.5.18": ">=8.5.18 <9.0.0"
|
||||
"mongoose@>=9.0.0 <9.7.2": ">=9.7.2 <10.0.0"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mem0/pi-agent-plugin",
|
||||
"version": "0.1.3",
|
||||
"version": "0.1.4",
|
||||
"type": "module",
|
||||
"description": "Mem0 memory extension for Pi Agent persistent, scoped, semantic memory across sessions and projects",
|
||||
"license": "Apache-2.0",
|
||||
@@ -74,7 +74,12 @@
|
||||
"uuid@<11.1.1": ">=11.1.1",
|
||||
"esbuild": ">=0.28.1",
|
||||
"undici@<6.27.0": ">=6.27.0 <8.0.0",
|
||||
"undici@>=8.0.0 <8.5.0": ">=8.5.0"
|
||||
"undici@>=8.0.0 <8.5.0": ">=8.5.0",
|
||||
"axios@<1.18.0": ">=1.18.0 <2.0.0",
|
||||
"brace-expansion@>=3.0.0 <5.0.8": ">=5.0.8 <6.0.0",
|
||||
"postcss@<8.5.18": ">=8.5.18 <9.0.0",
|
||||
"mongoose@>=9.0.0 <9.7.2": ">=9.7.2 <10.0.0",
|
||||
"protobufjs@<7.6.5": ">=7.6.5 <8.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+44
-44
@@ -10,6 +10,11 @@ overrides:
|
||||
esbuild: '>=0.28.1'
|
||||
undici@<6.27.0: '>=6.27.0 <8.0.0'
|
||||
undici@>=8.0.0 <8.5.0: '>=8.5.0'
|
||||
axios@<1.18.0: '>=1.18.0 <2.0.0'
|
||||
brace-expansion@>=3.0.0 <5.0.8: '>=5.0.8 <6.0.0'
|
||||
postcss@<8.5.18: '>=8.5.18 <9.0.0'
|
||||
mongoose@>=9.0.0 <9.7.2: '>=9.7.2 <10.0.0'
|
||||
protobufjs@<7.6.5: '>=7.6.5 <8.0.0'
|
||||
|
||||
importers:
|
||||
|
||||
@@ -30,7 +35,7 @@ importers:
|
||||
version: 25.9.2
|
||||
tsup:
|
||||
specifier: ^8.5.0
|
||||
version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(typescript@6.0.3)(yaml@2.9.0)
|
||||
version: 8.5.1(jiti@2.7.0)(postcss@8.5.23)(typescript@6.0.3)(yaml@2.9.0)
|
||||
typebox:
|
||||
specifier: ^1.2.3
|
||||
version: 1.2.8
|
||||
@@ -555,9 +560,6 @@ packages:
|
||||
'@protobufjs/float@1.0.2':
|
||||
resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==}
|
||||
|
||||
'@protobufjs/inquire@1.1.2':
|
||||
resolution: {integrity: sha512-pa0vFRuws4wkvaXKK1uXZMAwAX4/t8ANaJo45iw/oQHNQ9q5xUzwgFmVJGXiga2BeN+zpX7Vf9vmsiIa2J+MUw==}
|
||||
|
||||
'@protobufjs/path@1.1.2':
|
||||
resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==}
|
||||
|
||||
@@ -1064,8 +1066,8 @@ packages:
|
||||
asynckit@0.4.0:
|
||||
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
|
||||
|
||||
axios@1.17.0:
|
||||
resolution: {integrity: sha512-J8SwNxprqqpbfenehxWYXE7CW+wM1BB4w3+N+g+/Wx40xM4rsLrfPmHHxSWIxJLYDgSY/HqlFPIYb2/S3rxafw==}
|
||||
axios@1.18.1:
|
||||
resolution: {integrity: sha512-3nTvFlvpn9Zu/RkHUqtc7/+al4UpRW5az71ap5zccp6e8RAYEzhMTecX8Dz1wWDYrPpUoB1HAQEGEAEvUr7S9g==}
|
||||
|
||||
balanced-match@4.0.4:
|
||||
resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==}
|
||||
@@ -1093,9 +1095,9 @@ packages:
|
||||
bowser@2.14.1:
|
||||
resolution: {integrity: sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==}
|
||||
|
||||
brace-expansion@5.0.6:
|
||||
resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==}
|
||||
engines: {node: 18 || 20 || >=22}
|
||||
brace-expansion@5.0.8:
|
||||
resolution: {integrity: sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==}
|
||||
engines: {node: 20 || >=22}
|
||||
|
||||
braces@3.0.3:
|
||||
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
|
||||
@@ -1793,15 +1795,15 @@ packages:
|
||||
resolution: {integrity: sha512-h0AZ9A7IDVwwHyMxmdMXKy+9oNlF0zFoahHiX3vQ8e3KFcSP3VmsmfvtRSuLPxmyv2vjIDxqty8smTgie/SNRQ==}
|
||||
engines: {node: '>=20.19.0'}
|
||||
|
||||
mongodb@7.2.0:
|
||||
resolution: {integrity: sha512-F/2+BMZtLVhY30ioZp0dAmZ+IRZMBqI+nrv6t5+9/1AIwCa8sMRC3jBf81lpxMhnZgqq8CoUD503Z1oZWq1/sw==}
|
||||
mongodb@7.5.0:
|
||||
resolution: {integrity: sha512-5FnrEDLnvp6ycUOGLNLLU33BfCx2qmp2mJjGPDwKLruYsVzXVSK5fsGpoDXvsXJwBfBsD7ebMRdawbDxC2814g==}
|
||||
engines: {node: '>=20.19.0'}
|
||||
peerDependencies:
|
||||
'@aws-sdk/credential-providers': ^3.806.0
|
||||
'@mongodb-js/zstd': ^7.0.0
|
||||
gcp-metadata: ^7.0.1
|
||||
kerberos: ^7.0.0
|
||||
mongodb-client-encryption: '>=7.0.0 <7.1.0'
|
||||
mongodb-client-encryption: ^7.2.0
|
||||
snappy: ^7.3.2
|
||||
socks: ^2.8.6
|
||||
peerDependenciesMeta:
|
||||
@@ -1820,8 +1822,8 @@ packages:
|
||||
socks:
|
||||
optional: true
|
||||
|
||||
mongoose@9.7.0:
|
||||
resolution: {integrity: sha512-pkrLZ6U41pD4Ai0ju/FYL7o5I5k+rV3RZINQTG937hbhnLGKRuqqYm1Dlt/kTQ+M4FHijzV6JawzsdHKRGt7QA==}
|
||||
mongoose@9.8.0:
|
||||
resolution: {integrity: sha512-PDGx3XACxrBQyWf4YT+5s1Xsx19x84UWGlRVIza4i9RG6qKjGcoG7odotT6uquR6YoaDMTZ6ZZc/jMXLrNPyyA==}
|
||||
engines: {node: '>=20.19.0'}
|
||||
|
||||
mpath@0.9.0:
|
||||
@@ -1842,8 +1844,8 @@ packages:
|
||||
mz@2.7.0:
|
||||
resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
|
||||
|
||||
nanoid@3.3.12:
|
||||
resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==}
|
||||
nanoid@3.3.16:
|
||||
resolution: {integrity: sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==}
|
||||
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
||||
hasBin: true
|
||||
|
||||
@@ -2032,7 +2034,7 @@ packages:
|
||||
engines: {node: '>= 18'}
|
||||
peerDependencies:
|
||||
jiti: '>=1.21.0'
|
||||
postcss: '>=8.0.9'
|
||||
postcss: '>=8.5.18 <9.0.0'
|
||||
tsx: ^4.8.1
|
||||
yaml: ^2.4.2
|
||||
peerDependenciesMeta:
|
||||
@@ -2045,8 +2047,8 @@ packages:
|
||||
yaml:
|
||||
optional: true
|
||||
|
||||
postcss@8.5.15:
|
||||
resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==}
|
||||
postcss@8.5.23:
|
||||
resolution: {integrity: sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==}
|
||||
engines: {node: ^10 || ^12 || >=14}
|
||||
|
||||
postgres-array@2.0.0:
|
||||
@@ -2097,8 +2099,8 @@ packages:
|
||||
proper-lockfile@4.1.2:
|
||||
resolution: {integrity: sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==}
|
||||
|
||||
protobufjs@7.6.3:
|
||||
resolution: {integrity: sha512-+k0vdJKNdW+Vu+dYe8tZA/VvQb6XKNWexC6URwBFXxNnjLJz9nQJCemGyNgRAWD+B7+nGNc9qMPGwcD7s4nzUw==}
|
||||
protobufjs@7.6.5:
|
||||
resolution: {integrity: sha512-/FPD0nUc9jH6rfFjji9IBqOz4pcSE3CsT1m7Ep6Mdb0LxSUMj8hgl6GomOvZzpNpAqqGaXA0P3VSrZLFzIhQrw==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
|
||||
proxy-from-env@2.1.0:
|
||||
@@ -2314,7 +2316,7 @@ packages:
|
||||
peerDependencies:
|
||||
'@microsoft/api-extractor': ^7.36.0
|
||||
'@swc/core': ^1
|
||||
postcss: ^8.4.12
|
||||
postcss: '>=8.5.18 <9.0.0'
|
||||
typescript: '>=4.5.0'
|
||||
peerDependenciesMeta:
|
||||
'@microsoft/api-extractor':
|
||||
@@ -3055,7 +3057,7 @@ snapshots:
|
||||
dependencies:
|
||||
google-auth-library: 10.7.0
|
||||
p-retry: 4.6.2
|
||||
protobufjs: 7.6.3
|
||||
protobufjs: 7.6.5
|
||||
ws: 8.21.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
@@ -3191,8 +3193,6 @@ snapshots:
|
||||
|
||||
'@protobufjs/float@1.0.2': {}
|
||||
|
||||
'@protobufjs/inquire@1.1.2': {}
|
||||
|
||||
'@protobufjs/path@1.1.2': {}
|
||||
|
||||
'@protobufjs/pool@1.1.0': {}
|
||||
@@ -3598,7 +3598,7 @@ snapshots:
|
||||
|
||||
asynckit@0.4.0: {}
|
||||
|
||||
axios@1.17.0:
|
||||
axios@1.18.1:
|
||||
dependencies:
|
||||
follow-redirects: 1.16.0
|
||||
form-data: 4.0.6
|
||||
@@ -3633,7 +3633,7 @@ snapshots:
|
||||
|
||||
bowser@2.14.1: {}
|
||||
|
||||
brace-expansion@5.0.6:
|
||||
brace-expansion@5.0.8:
|
||||
dependencies:
|
||||
balanced-match: 4.0.4
|
||||
|
||||
@@ -4253,7 +4253,7 @@ snapshots:
|
||||
'@supabase/supabase-js': 2.108.1
|
||||
'@types/jest': 29.5.14
|
||||
'@types/pg': 8.11.0
|
||||
axios: 1.17.0
|
||||
axios: 1.18.1
|
||||
better-sqlite3: 12.10.0
|
||||
cloudflare: 4.5.0
|
||||
compromise: 14.15.1
|
||||
@@ -4290,7 +4290,7 @@ snapshots:
|
||||
|
||||
minimatch@10.2.5:
|
||||
dependencies:
|
||||
brace-expansion: 5.0.6
|
||||
brace-expansion: 5.0.8
|
||||
|
||||
minimist@1.2.8: {}
|
||||
|
||||
@@ -4310,16 +4310,17 @@ snapshots:
|
||||
'@types/whatwg-url': 13.0.0
|
||||
whatwg-url: 14.2.0
|
||||
|
||||
mongodb@7.2.0:
|
||||
mongodb@7.5.0:
|
||||
dependencies:
|
||||
'@mongodb-js/saslprep': 1.4.11
|
||||
bson: 7.2.0
|
||||
mongodb-connection-string-url: 7.0.1
|
||||
|
||||
mongoose@9.7.0:
|
||||
mongoose@9.8.0:
|
||||
dependencies:
|
||||
'@standard-schema/spec': 1.1.0
|
||||
kareem: 3.3.0
|
||||
mongodb: 7.2.0
|
||||
mongodb: 7.5.0
|
||||
mpath: 0.9.0
|
||||
mquery: 6.0.0
|
||||
ms: 2.1.3
|
||||
@@ -4347,7 +4348,7 @@ snapshots:
|
||||
object-assign: 4.1.1
|
||||
thenify-all: 1.6.0
|
||||
|
||||
nanoid@3.3.12: {}
|
||||
nanoid@3.3.16: {}
|
||||
|
||||
napi-build-utils@2.0.0: {}
|
||||
|
||||
@@ -4358,7 +4359,7 @@ snapshots:
|
||||
apparatus: 0.0.10
|
||||
dotenv: 17.4.2
|
||||
memjs: 1.3.2
|
||||
mongoose: 9.7.0
|
||||
mongoose: 9.8.0
|
||||
pg: 8.21.0
|
||||
redis: 5.12.1
|
||||
safe-stable-stringify: 2.5.0
|
||||
@@ -4544,17 +4545,17 @@ snapshots:
|
||||
mlly: 1.8.2
|
||||
pathe: 2.0.3
|
||||
|
||||
postcss-load-config@6.0.1(jiti@2.7.0)(postcss@8.5.15)(yaml@2.9.0):
|
||||
postcss-load-config@6.0.1(jiti@2.7.0)(postcss@8.5.23)(yaml@2.9.0):
|
||||
dependencies:
|
||||
lilconfig: 3.1.3
|
||||
optionalDependencies:
|
||||
jiti: 2.7.0
|
||||
postcss: 8.5.15
|
||||
postcss: 8.5.23
|
||||
yaml: 2.9.0
|
||||
|
||||
postcss@8.5.15:
|
||||
postcss@8.5.23:
|
||||
dependencies:
|
||||
nanoid: 3.3.12
|
||||
nanoid: 3.3.16
|
||||
picocolors: 1.1.1
|
||||
source-map-js: 1.2.1
|
||||
|
||||
@@ -4607,7 +4608,7 @@ snapshots:
|
||||
retry: 0.12.0
|
||||
signal-exit: 3.0.7
|
||||
|
||||
protobufjs@7.6.3:
|
||||
protobufjs@7.6.5:
|
||||
dependencies:
|
||||
'@protobufjs/aspromise': 1.1.2
|
||||
'@protobufjs/base64': 1.1.2
|
||||
@@ -4615,7 +4616,6 @@ snapshots:
|
||||
'@protobufjs/eventemitter': 1.1.1
|
||||
'@protobufjs/fetch': 1.1.1
|
||||
'@protobufjs/float': 1.0.2
|
||||
'@protobufjs/inquire': 1.1.2
|
||||
'@protobufjs/path': 1.1.2
|
||||
'@protobufjs/pool': 1.1.0
|
||||
'@protobufjs/utf8': 1.1.1
|
||||
@@ -4849,7 +4849,7 @@ snapshots:
|
||||
|
||||
tslib@2.8.1: {}
|
||||
|
||||
tsup@8.5.1(jiti@2.7.0)(postcss@8.5.15)(typescript@6.0.3)(yaml@2.9.0):
|
||||
tsup@8.5.1(jiti@2.7.0)(postcss@8.5.23)(typescript@6.0.3)(yaml@2.9.0):
|
||||
dependencies:
|
||||
bundle-require: 5.1.0(esbuild@0.28.1)
|
||||
cac: 6.7.14
|
||||
@@ -4860,7 +4860,7 @@ snapshots:
|
||||
fix-dts-default-cjs-exports: 1.0.1
|
||||
joycon: 3.1.1
|
||||
picocolors: 1.1.1
|
||||
postcss-load-config: 6.0.1(jiti@2.7.0)(postcss@8.5.15)(yaml@2.9.0)
|
||||
postcss-load-config: 6.0.1(jiti@2.7.0)(postcss@8.5.23)(yaml@2.9.0)
|
||||
resolve-from: 5.0.0
|
||||
rollup: 4.61.1
|
||||
source-map: 0.7.6
|
||||
@@ -4869,7 +4869,7 @@ snapshots:
|
||||
tinyglobby: 0.2.17
|
||||
tree-kill: 1.2.2
|
||||
optionalDependencies:
|
||||
postcss: 8.5.15
|
||||
postcss: 8.5.23
|
||||
typescript: 6.0.3
|
||||
transitivePeerDependencies:
|
||||
- jiti
|
||||
@@ -4909,7 +4909,7 @@ snapshots:
|
||||
dependencies:
|
||||
lightningcss: 1.32.0
|
||||
picomatch: 4.0.4
|
||||
postcss: 8.5.15
|
||||
postcss: 8.5.23
|
||||
rolldown: 1.0.3
|
||||
tinyglobby: 0.2.17
|
||||
optionalDependencies:
|
||||
|
||||
@@ -7,3 +7,8 @@ overrides:
|
||||
"esbuild": ">=0.28.1"
|
||||
"undici@<6.27.0": ">=6.27.0 <8.0.0"
|
||||
"undici@>=8.0.0 <8.5.0": ">=8.5.0"
|
||||
"axios@<1.18.0": ">=1.18.0 <2.0.0"
|
||||
"brace-expansion@>=3.0.0 <5.0.8": ">=5.0.8 <6.0.0"
|
||||
"postcss@<8.5.18": ">=8.5.18 <9.0.0"
|
||||
"mongoose@>=9.0.0 <9.7.2": ">=9.7.2 <10.0.0"
|
||||
"protobufjs@<7.6.5": ">=7.6.5 <8.0.0"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mem0/vercel-ai-provider",
|
||||
"version": "3.0.0",
|
||||
"version": "3.0.1",
|
||||
"description": "Vercel AI Provider for providing memory to LLMs",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.mjs",
|
||||
@@ -80,13 +80,16 @@
|
||||
],
|
||||
"overrides": {
|
||||
"glob@>=10.2.0 <10.5.0": "^10.5.0",
|
||||
"js-yaml@<=4.1.1": ">=4.2.0",
|
||||
"minimatch@<3.1.3": "^3.1.3",
|
||||
"minimatch@>=5.0.0 <5.1.8": "^5.1.8",
|
||||
"minimatch@>=9.0.0 <9.0.7": "^9.0.7",
|
||||
"picomatch@<2.3.2": "^2.3.2",
|
||||
"rollup@>=4.0.0 <4.59.0": "^4.59.0",
|
||||
"esbuild": ">=0.28.1"
|
||||
"esbuild": ">=0.28.1",
|
||||
"brace-expansion@<1.1.16": ">=1.1.16 <2.0.0",
|
||||
"brace-expansion@>=3.0.0 <5.0.8": ">=5.0.8 <6.0.0",
|
||||
"js-yaml@<3.15.0": ">=3.15.0 <4.0.0",
|
||||
"js-yaml@>=4.0.0 <4.3.0": ">=4.3.0 <5.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+36
-18
@@ -6,13 +6,16 @@ settings:
|
||||
|
||||
overrides:
|
||||
glob@>=10.2.0 <10.5.0: ^10.5.0
|
||||
js-yaml@<=4.1.1: '>=4.2.0'
|
||||
minimatch@<3.1.3: ^3.1.3
|
||||
minimatch@>=5.0.0 <5.1.8: ^5.1.8
|
||||
minimatch@>=9.0.0 <9.0.7: ^9.0.7
|
||||
picomatch@<2.3.2: ^2.3.2
|
||||
rollup@>=4.0.0 <4.59.0: ^4.59.0
|
||||
esbuild: '>=0.28.1'
|
||||
brace-expansion@<1.1.16: '>=1.1.16 <2.0.0'
|
||||
brace-expansion@>=3.0.0 <5.0.8: '>=5.0.8 <6.0.0'
|
||||
js-yaml@<3.15.0: '>=3.15.0 <4.0.0'
|
||||
js-yaml@>=4.0.0 <4.3.0: '>=4.3.0 <5.0.0'
|
||||
|
||||
importers:
|
||||
|
||||
@@ -794,8 +797,8 @@ packages:
|
||||
arg@4.1.3:
|
||||
resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==}
|
||||
|
||||
argparse@2.0.1:
|
||||
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
|
||||
argparse@1.0.10:
|
||||
resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
|
||||
|
||||
babel-jest@29.7.0:
|
||||
resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==}
|
||||
@@ -838,12 +841,12 @@ packages:
|
||||
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
brace-expansion@1.1.15:
|
||||
resolution: {integrity: sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==}
|
||||
brace-expansion@1.1.16:
|
||||
resolution: {integrity: sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==}
|
||||
|
||||
brace-expansion@5.0.6:
|
||||
resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==}
|
||||
engines: {node: 18 || 20 || >=22}
|
||||
brace-expansion@5.0.8:
|
||||
resolution: {integrity: sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==}
|
||||
engines: {node: 20 || >=22}
|
||||
|
||||
braces@3.0.3:
|
||||
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
|
||||
@@ -1026,6 +1029,11 @@ packages:
|
||||
resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
esprima@4.0.1:
|
||||
resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
|
||||
engines: {node: '>=4'}
|
||||
hasBin: true
|
||||
|
||||
eventsource-parser@3.1.0:
|
||||
resolution: {integrity: sha512-kJezFj9YFAMLeORyi7aCLxLbD5/qWMQnoMVlVPyHIll7lgRJCc3JVln9Vgl9nwQi0YkMnhdGTMNn7CkRRAptMg==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
@@ -1347,8 +1355,8 @@ packages:
|
||||
js-tokens@4.0.0:
|
||||
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
|
||||
|
||||
js-yaml@4.2.0:
|
||||
resolution: {integrity: sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==}
|
||||
js-yaml@3.15.0:
|
||||
resolution: {integrity: sha512-ttBQIIQPDeLjpPOohtUdXuXUVoA2uIB6fEH9HyJ7234s5mBJ5wTx20njxplLZQgLaOfpmPQA7X2t5AX6tIPbog==}
|
||||
hasBin: true
|
||||
|
||||
jsesc@3.1.0:
|
||||
@@ -1650,6 +1658,9 @@ packages:
|
||||
resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==}
|
||||
engines: {node: '>= 12'}
|
||||
|
||||
sprintf-js@1.0.3:
|
||||
resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
|
||||
|
||||
stack-utils@2.0.6:
|
||||
resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==}
|
||||
engines: {node: '>=10'}
|
||||
@@ -2219,7 +2230,7 @@ snapshots:
|
||||
camelcase: 5.3.1
|
||||
find-up: 4.1.0
|
||||
get-package-type: 0.1.0
|
||||
js-yaml: 4.2.0
|
||||
js-yaml: 3.15.0
|
||||
resolve-from: 5.0.0
|
||||
|
||||
'@istanbuljs/schema@0.1.6': {}
|
||||
@@ -2598,7 +2609,9 @@ snapshots:
|
||||
|
||||
arg@4.1.3: {}
|
||||
|
||||
argparse@2.0.1: {}
|
||||
argparse@1.0.10:
|
||||
dependencies:
|
||||
sprintf-js: 1.0.3
|
||||
|
||||
babel-jest@29.7.0(@babel/core@7.29.7):
|
||||
dependencies:
|
||||
@@ -2663,12 +2676,12 @@ snapshots:
|
||||
|
||||
binary-extensions@2.3.0: {}
|
||||
|
||||
brace-expansion@1.1.15:
|
||||
brace-expansion@1.1.16:
|
||||
dependencies:
|
||||
balanced-match: 1.0.2
|
||||
concat-map: 0.0.1
|
||||
|
||||
brace-expansion@5.0.6:
|
||||
brace-expansion@5.0.8:
|
||||
dependencies:
|
||||
balanced-match: 4.0.4
|
||||
|
||||
@@ -2848,6 +2861,8 @@ snapshots:
|
||||
|
||||
escape-string-regexp@2.0.0: {}
|
||||
|
||||
esprima@4.0.1: {}
|
||||
|
||||
eventsource-parser@3.1.0: {}
|
||||
|
||||
execa@5.1.1:
|
||||
@@ -3344,9 +3359,10 @@ snapshots:
|
||||
|
||||
js-tokens@4.0.0: {}
|
||||
|
||||
js-yaml@4.2.0:
|
||||
js-yaml@3.15.0:
|
||||
dependencies:
|
||||
argparse: 2.0.1
|
||||
argparse: 1.0.10
|
||||
esprima: 4.0.1
|
||||
|
||||
jsesc@3.1.0: {}
|
||||
|
||||
@@ -3401,11 +3417,11 @@ snapshots:
|
||||
|
||||
minimatch@10.2.5:
|
||||
dependencies:
|
||||
brace-expansion: 5.0.6
|
||||
brace-expansion: 5.0.8
|
||||
|
||||
minimatch@3.1.5:
|
||||
dependencies:
|
||||
brace-expansion: 1.1.15
|
||||
brace-expansion: 1.1.16
|
||||
|
||||
minimist@1.2.8: {}
|
||||
|
||||
@@ -3616,6 +3632,8 @@ snapshots:
|
||||
|
||||
source-map@0.7.6: {}
|
||||
|
||||
sprintf-js@1.0.3: {}
|
||||
|
||||
stack-utils@2.0.6:
|
||||
dependencies:
|
||||
escape-string-regexp: 2.0.0
|
||||
|
||||
@@ -7,10 +7,13 @@ onlyBuiltDependencies:
|
||||
|
||||
overrides:
|
||||
"glob@>=10.2.0 <10.5.0": "^10.5.0"
|
||||
"js-yaml@<=4.1.1": ">=4.2.0"
|
||||
"minimatch@<3.1.3": "^3.1.3"
|
||||
"minimatch@>=5.0.0 <5.1.8": "^5.1.8"
|
||||
"minimatch@>=9.0.0 <9.0.7": "^9.0.7"
|
||||
"picomatch@<2.3.2": "^2.3.2"
|
||||
"rollup@>=4.0.0 <4.59.0": "^4.59.0"
|
||||
"esbuild": ">=0.28.1"
|
||||
"brace-expansion@<1.1.16": ">=1.1.16 <2.0.0"
|
||||
"brace-expansion@>=3.0.0 <5.0.8": ">=5.0.8 <6.0.0"
|
||||
"js-yaml@<3.15.0": ">=3.15.0 <4.0.0"
|
||||
"js-yaml@>=4.0.0 <4.3.0": ">=4.3.0 <5.0.0"
|
||||
|
||||
@@ -115,7 +115,7 @@ export default {
|
||||
choices: { user: 'User', assistant: 'Assistant', system: 'System' },
|
||||
default: 'user',
|
||||
},
|
||||
{ key: 'user_id', label: 'User ID', type: 'string' },
|
||||
{ key: 'user_id', label: 'User ID', type: 'string', required: true, helpText: 'Scope this memory to a user. Mem0 requires at least one entity ID.' },
|
||||
{ key: 'agent_id', label: 'Agent ID', type: 'string' },
|
||||
{ key: 'run_id', label: 'Run ID', type: 'string' },
|
||||
{ key: 'metadata', label: 'Metadata (JSON)', type: 'string' },
|
||||
|
||||
+15
-7
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mem0ai",
|
||||
"version": "3.1.2",
|
||||
"version": "3.1.3",
|
||||
"description": "The Memory Layer For Your AI Apps",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.mjs",
|
||||
@@ -102,7 +102,7 @@
|
||||
"@mochow/mochow-sdk-node": "^2.1.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.16.0",
|
||||
"axios": "^1.18.0",
|
||||
"openai": "^4.93.0",
|
||||
"uuid": "^11.1.1",
|
||||
"zod": "^3.24.1"
|
||||
@@ -271,26 +271,34 @@
|
||||
"picomatch@<2.3.2": "^2.3.2",
|
||||
"picomatch@>=4.0.0 <4.0.4": "^4.0.4",
|
||||
"jws@4.0.0": "4.0.1",
|
||||
"js-yaml@<3.14.2": ">=3.14.2",
|
||||
"js-yaml@<3.15.0": ">=3.15.0 <4.0.0",
|
||||
"js-yaml@>=4.0.0 <4.3.0": ">=4.3.0 <5.0.0",
|
||||
"langsmith@<0.6.0": "^0.6.0",
|
||||
"minimatch@<3.1.3": "^3.1.3",
|
||||
"minimatch@>=5.0.0 <5.1.8": "^5.1.8",
|
||||
"minimatch@>=9.0.0 <9.0.7": "^9.0.7",
|
||||
"path-to-regexp@>=8.0.0 <8.4.0": "^8.4.0",
|
||||
"postcss@<8.5.10": ">=8.5.10",
|
||||
"postcss@<8.5.18": ">=8.5.18 <9.0.0",
|
||||
"uuid@<11.1.1": ">=11.1.1",
|
||||
"weaviate-client>uuid": "^11.1.1",
|
||||
"ws@>=8.0.0 <8.20.1": ">=8.20.1",
|
||||
"rollup@>=4.0.0 <4.59.0": "^4.59.0",
|
||||
"tar-fs@>=2.0.0 <2.1.4": "^2.1.4",
|
||||
"glob@>=10.2.0 <10.5.0": "^10.5.0",
|
||||
"fast-xml-parser@>=5.0.0 <5.7.0": "^5.9.3",
|
||||
"tar@<=7.5.15": "^7.5.19",
|
||||
"@modelcontextprotocol/sdk": "^1.25.4",
|
||||
"esbuild": ">=0.28.1",
|
||||
"undici@<6.27.0": ">=6.27.0 <8.0.0",
|
||||
"@aws-sdk/client-bedrock-runtime": "3.967.0",
|
||||
"@aws-sdk/client-neptune-graph": "3.966.0"
|
||||
"@aws-sdk/client-neptune-graph": "3.966.0",
|
||||
"axios@<1.18.0": ">=1.18.0 <2.0.0",
|
||||
"brace-expansion@<1.1.16": ">=1.1.16 <2.0.0",
|
||||
"brace-expansion@>=2.0.0 <2.1.2": ">=2.1.2 <3.0.0",
|
||||
"brace-expansion@>=3.0.0 <5.0.8": ">=5.0.8 <6.0.0",
|
||||
"fast-xml-parser@>=5.0.0 <5.10.1": ">=5.10.1 <6.0.0",
|
||||
"tar@>=7.0.0 <7.5.21": ">=7.5.21 <8.0.0",
|
||||
"thrift@<0.23.0": "^0.23.0",
|
||||
"mongoose@>=9.0.0 <9.7.2": ">=9.7.2 <10.0.0",
|
||||
"protobufjs@<7.6.5": ">=7.6.5 <8.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+181
-86
@@ -9,26 +9,34 @@ overrides:
|
||||
picomatch@<2.3.2: ^2.3.2
|
||||
picomatch@>=4.0.0 <4.0.4: ^4.0.4
|
||||
jws@4.0.0: 4.0.1
|
||||
js-yaml@<3.14.2: '>=3.14.2'
|
||||
js-yaml@<3.15.0: '>=3.15.0 <4.0.0'
|
||||
js-yaml@>=4.0.0 <4.3.0: '>=4.3.0 <5.0.0'
|
||||
langsmith@<0.6.0: ^0.6.0
|
||||
minimatch@<3.1.3: ^3.1.3
|
||||
minimatch@>=5.0.0 <5.1.8: ^5.1.8
|
||||
minimatch@>=9.0.0 <9.0.7: ^9.0.7
|
||||
path-to-regexp@>=8.0.0 <8.4.0: ^8.4.0
|
||||
postcss@<8.5.10: '>=8.5.10'
|
||||
postcss@<8.5.18: '>=8.5.18 <9.0.0'
|
||||
uuid@<11.1.1: '>=11.1.1'
|
||||
weaviate-client>uuid: ^11.1.1
|
||||
ws@>=8.0.0 <8.20.1: '>=8.20.1'
|
||||
rollup@>=4.0.0 <4.59.0: ^4.59.0
|
||||
tar-fs@>=2.0.0 <2.1.4: ^2.1.4
|
||||
glob@>=10.2.0 <10.5.0: ^10.5.0
|
||||
fast-xml-parser@>=5.0.0 <5.7.0: ^5.9.3
|
||||
tar@<=7.5.15: ^7.5.19
|
||||
'@modelcontextprotocol/sdk': ^1.25.4
|
||||
esbuild: '>=0.28.1'
|
||||
undici@<6.27.0: '>=6.27.0 <8.0.0'
|
||||
'@aws-sdk/client-bedrock-runtime': 3.967.0
|
||||
'@aws-sdk/client-neptune-graph': 3.966.0
|
||||
axios@<1.18.0: '>=1.18.0 <2.0.0'
|
||||
brace-expansion@<1.1.16: '>=1.1.16 <2.0.0'
|
||||
brace-expansion@>=2.0.0 <2.1.2: '>=2.1.2 <3.0.0'
|
||||
brace-expansion@>=3.0.0 <5.0.8: '>=5.0.8 <6.0.0'
|
||||
fast-xml-parser@>=5.0.0 <5.10.1: '>=5.10.1 <6.0.0'
|
||||
tar@>=7.0.0 <7.5.21: '>=7.5.21 <8.0.0'
|
||||
thrift@<0.23.0: ^0.23.0
|
||||
mongoose@>=9.0.0 <9.7.2: '>=9.7.2 <10.0.0'
|
||||
protobufjs@<7.6.5: '>=7.6.5 <8.0.0'
|
||||
|
||||
importers:
|
||||
|
||||
@@ -104,8 +112,8 @@ importers:
|
||||
specifier: ^2.4.0 || ^3.0.0
|
||||
version: 3.0.3
|
||||
axios:
|
||||
specifier: ^1.16.0
|
||||
version: 1.17.0
|
||||
specifier: ^1.18.0
|
||||
version: 1.18.1
|
||||
better-sqlite3:
|
||||
specifier: ^12.6.2
|
||||
version: 12.10.0
|
||||
@@ -1304,8 +1312,8 @@ packages:
|
||||
'@mongodb-js/saslprep@1.4.11':
|
||||
resolution: {integrity: sha512-o9rAHc0IpIjuPSxRutWpE1F62x7n+4mVS4rCNHkzhIUMQcc18bb6xEq5wd2NdN0WjepIyXIppRshYI2kQDOZVA==}
|
||||
|
||||
'@nodable/entities@2.2.0':
|
||||
resolution: {integrity: sha512-9uGyhaQavEUMC8AIddIjau4NsnsXhou+j5sBAGojCM1oxmQpVKTWR/9JxABD6UAv12vpIms55fPZKFQEhG6uBg==}
|
||||
'@nodable/entities@3.0.0':
|
||||
resolution: {integrity: sha512-8L9xFeTYKhm49xfIypoe2W5wV1m/3Z58kT+7kR9A8OyFxcPduI4VmxaUMQyKYrRjUoLLSXv6EKKID5Tvj9cUVw==}
|
||||
|
||||
'@nodelib/fs.scandir@2.1.5':
|
||||
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
|
||||
@@ -1366,9 +1374,6 @@ packages:
|
||||
'@protobufjs/float@1.0.2':
|
||||
resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==}
|
||||
|
||||
'@protobufjs/inquire@1.1.2':
|
||||
resolution: {integrity: sha512-pa0vFRuws4wkvaXKK1uXZMAwAX4/t8ANaJo45iw/oQHNQ9q5xUzwgFmVJGXiga2BeN+zpX7Vf9vmsiIa2J+MUw==}
|
||||
|
||||
'@protobufjs/path@1.1.2':
|
||||
resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==}
|
||||
|
||||
@@ -2043,8 +2048,8 @@ packages:
|
||||
arg@4.1.3:
|
||||
resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==}
|
||||
|
||||
argparse@2.0.1:
|
||||
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
|
||||
argparse@1.0.10:
|
||||
resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
|
||||
|
||||
array-back@3.1.0:
|
||||
resolution: {integrity: sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==}
|
||||
@@ -2074,8 +2079,8 @@ packages:
|
||||
aws4@1.13.2:
|
||||
resolution: {integrity: sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==}
|
||||
|
||||
axios@1.17.0:
|
||||
resolution: {integrity: sha512-J8SwNxprqqpbfenehxWYXE7CW+wM1BB4w3+N+g+/Wx40xM4rsLrfPmHHxSWIxJLYDgSY/HqlFPIYb2/S3rxafw==}
|
||||
axios@1.18.1:
|
||||
resolution: {integrity: sha512-3nTvFlvpn9Zu/RkHUqtc7/+al4UpRW5az71ap5zccp6e8RAYEzhMTecX8Dz1wWDYrPpUoB1HAQEGEAEvUr7S9g==}
|
||||
|
||||
babel-jest@29.7.0:
|
||||
resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==}
|
||||
@@ -2148,15 +2153,15 @@ packages:
|
||||
bowser@2.14.1:
|
||||
resolution: {integrity: sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==}
|
||||
|
||||
brace-expansion@1.1.15:
|
||||
resolution: {integrity: sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==}
|
||||
brace-expansion@1.1.16:
|
||||
resolution: {integrity: sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==}
|
||||
|
||||
brace-expansion@2.1.1:
|
||||
resolution: {integrity: sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==}
|
||||
brace-expansion@2.1.2:
|
||||
resolution: {integrity: sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==}
|
||||
|
||||
brace-expansion@5.0.6:
|
||||
resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==}
|
||||
engines: {node: 18 || 20 || >=22}
|
||||
brace-expansion@5.0.8:
|
||||
resolution: {integrity: sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==}
|
||||
engines: {node: 20 || >=22}
|
||||
|
||||
braces@3.0.3:
|
||||
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
|
||||
@@ -2268,6 +2273,10 @@ packages:
|
||||
chownr@1.1.4:
|
||||
resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
|
||||
|
||||
chownr@2.0.0:
|
||||
resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
chownr@3.0.0:
|
||||
resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==}
|
||||
engines: {node: '>=18'}
|
||||
@@ -2681,8 +2690,8 @@ packages:
|
||||
fast-xml-builder@1.2.1:
|
||||
resolution: {integrity: sha512-tPb5TTWfgfVx5BNSi2xV0eLr89POeXXn0dXIsCJ9m1narrWxeIyx6je9d7Rce/3NyXLbvuQmLkxq+RuxMWejvw==}
|
||||
|
||||
fast-xml-parser@5.9.3:
|
||||
resolution: {integrity: sha512-brCNCeScma/kqa54J4PIDriSSSLssRkuYaUCpvHJulGc3HGI/xxKUCTDcYkAdqJsyb//ydpbxecjC3hB9+tb/g==}
|
||||
fast-xml-parser@5.10.1:
|
||||
resolution: {integrity: sha512-IEMIf7298kXuZSRFoGfMYrl7is8LpavODgbNz1cwIudv7KwVFnuU+UsMporfq6PD6aXSlawZlARiA3UywCTfMw==}
|
||||
hasBin: true
|
||||
|
||||
fastembed@2.1.0:
|
||||
@@ -2780,6 +2789,10 @@ packages:
|
||||
fs-constants@1.0.0:
|
||||
resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
|
||||
|
||||
fs-minipass@2.1.0:
|
||||
resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==}
|
||||
engines: {node: '>= 8'}
|
||||
|
||||
fs.realpath@1.0.0:
|
||||
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
|
||||
|
||||
@@ -3065,8 +3078,8 @@ packages:
|
||||
resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
is-unsafe@1.0.1:
|
||||
resolution: {integrity: sha512-CLK2+VdgERgD96EYm5lUQssZYlRg2tkZnbsxZoacmSiRxiFJ4Nk4SzjCl+Ur+v3kXIY9dTIdb3IH22y1mZ56LA==}
|
||||
is-unsafe@2.0.0:
|
||||
resolution: {integrity: sha512-2LdV822R+wmI86unXA93WCFpL6g+av8ynWk0nrHyJqGop5VoocYsSLFgN8jrfalT6iGeLNM4KXuVSsULP53kEA==}
|
||||
|
||||
is-wsl@2.2.0:
|
||||
resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==}
|
||||
@@ -3253,8 +3266,8 @@ packages:
|
||||
js-tokens@4.0.0:
|
||||
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
|
||||
|
||||
js-yaml@4.2.0:
|
||||
resolution: {integrity: sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==}
|
||||
js-yaml@3.15.0:
|
||||
resolution: {integrity: sha512-ttBQIIQPDeLjpPOohtUdXuXUVoA2uIB6fEH9HyJ7234s5mBJ5wTx20njxplLZQgLaOfpmPQA7X2t5AX6tIPbog==}
|
||||
hasBin: true
|
||||
|
||||
jsesc@3.1.0:
|
||||
@@ -3508,10 +3521,22 @@ packages:
|
||||
minimist@1.2.8:
|
||||
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
|
||||
|
||||
minipass@3.3.6:
|
||||
resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
minipass@5.0.0:
|
||||
resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
minipass@7.1.3:
|
||||
resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==}
|
||||
engines: {node: '>=16 || 14 >=14.17'}
|
||||
|
||||
minizlib@2.1.2:
|
||||
resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==}
|
||||
engines: {node: '>= 8'}
|
||||
|
||||
minizlib@3.1.0:
|
||||
resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==}
|
||||
engines: {node: '>= 18'}
|
||||
@@ -3519,6 +3544,11 @@ packages:
|
||||
mkdirp-classic@0.5.3:
|
||||
resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
|
||||
|
||||
mkdirp@1.0.4:
|
||||
resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==}
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
|
||||
mlly@1.8.2:
|
||||
resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==}
|
||||
|
||||
@@ -3553,8 +3583,35 @@ packages:
|
||||
socks:
|
||||
optional: true
|
||||
|
||||
mongoose@9.7.0:
|
||||
resolution: {integrity: sha512-pkrLZ6U41pD4Ai0ju/FYL7o5I5k+rV3RZINQTG937hbhnLGKRuqqYm1Dlt/kTQ+M4FHijzV6JawzsdHKRGt7QA==}
|
||||
mongodb@7.5.0:
|
||||
resolution: {integrity: sha512-5FnrEDLnvp6ycUOGLNLLU33BfCx2qmp2mJjGPDwKLruYsVzXVSK5fsGpoDXvsXJwBfBsD7ebMRdawbDxC2814g==}
|
||||
engines: {node: '>=20.19.0'}
|
||||
peerDependencies:
|
||||
'@aws-sdk/credential-providers': ^3.806.0
|
||||
'@mongodb-js/zstd': ^7.0.0
|
||||
gcp-metadata: ^7.0.1
|
||||
kerberos: ^7.0.0
|
||||
mongodb-client-encryption: ^7.2.0
|
||||
snappy: ^7.3.2
|
||||
socks: ^2.8.6
|
||||
peerDependenciesMeta:
|
||||
'@aws-sdk/credential-providers':
|
||||
optional: true
|
||||
'@mongodb-js/zstd':
|
||||
optional: true
|
||||
gcp-metadata:
|
||||
optional: true
|
||||
kerberos:
|
||||
optional: true
|
||||
mongodb-client-encryption:
|
||||
optional: true
|
||||
snappy:
|
||||
optional: true
|
||||
socks:
|
||||
optional: true
|
||||
|
||||
mongoose@9.8.0:
|
||||
resolution: {integrity: sha512-PDGx3XACxrBQyWf4YT+5s1Xsx19x84UWGlRVIza4i9RG6qKjGcoG7odotT6uquR6YoaDMTZ6ZZc/jMXLrNPyyA==}
|
||||
engines: {node: '>=20.19.0'}
|
||||
|
||||
mpath@0.9.0:
|
||||
@@ -3907,7 +3964,7 @@ packages:
|
||||
engines: {node: '>= 18'}
|
||||
peerDependencies:
|
||||
jiti: '>=1.21.0'
|
||||
postcss: '>=8.5.10'
|
||||
postcss: '>=8.5.18 <9.0.0'
|
||||
tsx: ^4.8.1
|
||||
yaml: ^2.4.2
|
||||
peerDependenciesMeta:
|
||||
@@ -3986,8 +4043,8 @@ packages:
|
||||
resolution: {integrity: sha512-E1sbAYg3aEbXrq0n1ojJkRHQJGE1kaE/O6GLA94y8rnJBfgvOPTOd1b9hOceQK1FFZI9qMh1vBERCyO2ifubcw==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
protobufjs@7.6.3:
|
||||
resolution: {integrity: sha512-+k0vdJKNdW+Vu+dYe8tZA/VvQb6XKNWexC6URwBFXxNnjLJz9nQJCemGyNgRAWD+B7+nGNc9qMPGwcD7s4nzUw==}
|
||||
protobufjs@7.6.5:
|
||||
resolution: {integrity: sha512-/FPD0nUc9jH6rfFjji9IBqOz4pcSE3CsT1m7Ep6Mdb0LxSUMj8hgl6GomOvZzpNpAqqGaXA0P3VSrZLFzIhQrw==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
|
||||
proxy-agent@6.5.0:
|
||||
@@ -4240,6 +4297,9 @@ packages:
|
||||
resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==}
|
||||
engines: {node: '>= 10.x'}
|
||||
|
||||
sprintf-js@1.0.3:
|
||||
resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
|
||||
|
||||
sprintf-js@1.1.3:
|
||||
resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==}
|
||||
|
||||
@@ -4356,8 +4416,13 @@ packages:
|
||||
resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
tar@7.5.19:
|
||||
resolution: {integrity: sha512-4LeEWl96twnS2Q7Bz4MGqgazLqO+hJN63GZxXoIqh1T3VweYD997gbU1ItNsQafqqXTXd5WFyFdReLtwvRBNiw==}
|
||||
tar@6.2.1:
|
||||
resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==}
|
||||
engines: {node: '>=10'}
|
||||
deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
|
||||
|
||||
tar@7.5.22:
|
||||
resolution: {integrity: sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
teeny-request@10.1.3:
|
||||
@@ -4378,10 +4443,6 @@ packages:
|
||||
thenify@3.3.1:
|
||||
resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
|
||||
|
||||
thrift@0.16.0:
|
||||
resolution: {integrity: sha512-W8DpGyTPlIaK3f+e1XOCLxefaUWXtrOXAaVIDbfYhmVyriYeAKgsBVFNJUV1F9SQ2SPt2sG44AZQxSGwGj/3VA==}
|
||||
engines: {node: '>= 10.18.0'}
|
||||
|
||||
thrift@0.23.0:
|
||||
resolution: {integrity: sha512-j7F1ls8JogClU88Ta/pwD/OzYuiFeD6Z5GoWw7ip+jcDhcNYFKgfXYEsyLXYpiNfJO94fbLnITGxyfZ19YzA6Q==}
|
||||
engines: {node: '>= 10.18.0'}
|
||||
@@ -4476,7 +4537,7 @@ packages:
|
||||
peerDependencies:
|
||||
'@microsoft/api-extractor': ^7.36.0
|
||||
'@swc/core': ^1
|
||||
postcss: '>=8.5.10'
|
||||
postcss: '>=8.5.18 <9.0.0'
|
||||
typescript: '>=4.5.0'
|
||||
peerDependenciesMeta:
|
||||
'@microsoft/api-extractor':
|
||||
@@ -4693,6 +4754,10 @@ packages:
|
||||
resolution: {integrity: sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw==}
|
||||
engines: {node: '>=16.0.0'}
|
||||
|
||||
xml-naming@0.3.0:
|
||||
resolution: {integrity: sha512-ghig2TBE/H11aOVgmahA3MhimvkBr6JIYknH/Dhdk10nXwdbIqBJsbfMxpvFPG8bAw77gN29aQWvKpmVoPlvPQ==}
|
||||
engines: {node: '>=16.0.0'}
|
||||
|
||||
xtend@4.0.2:
|
||||
resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
|
||||
engines: {node: '>=0.4'}
|
||||
@@ -5681,7 +5746,7 @@ snapshots:
|
||||
'@aws-sdk/xml-builder@3.965.0':
|
||||
dependencies:
|
||||
'@smithy/types': 4.15.0
|
||||
fast-xml-parser: 5.9.3
|
||||
fast-xml-parser: 5.10.1
|
||||
tslib: 2.8.1
|
||||
|
||||
'@aws-sdk/xml-builder@3.972.34':
|
||||
@@ -6039,7 +6104,7 @@ snapshots:
|
||||
open: 8.4.2
|
||||
openid-client: 5.7.1
|
||||
proxy-agent: 6.5.0
|
||||
thrift: 0.16.0
|
||||
thrift: 0.23.0
|
||||
uuid: 11.1.1
|
||||
winston: 3.19.0
|
||||
optionalDependencies:
|
||||
@@ -6174,7 +6239,7 @@ snapshots:
|
||||
dependencies:
|
||||
google-auth-library: 10.7.0
|
||||
p-retry: 4.6.2
|
||||
protobufjs: 7.6.3
|
||||
protobufjs: 7.6.5
|
||||
ws: 8.21.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
@@ -6194,7 +6259,7 @@ snapshots:
|
||||
dependencies:
|
||||
lodash.camelcase: 4.3.0
|
||||
long: 5.3.2
|
||||
protobufjs: 7.6.3
|
||||
protobufjs: 7.6.5
|
||||
yargs: 17.7.2
|
||||
|
||||
'@huggingface/blake3-jit@0.0.2': {}
|
||||
@@ -6341,7 +6406,7 @@ snapshots:
|
||||
camelcase: 5.3.1
|
||||
find-up: 4.1.0
|
||||
get-package-type: 0.1.0
|
||||
js-yaml: 4.2.0
|
||||
js-yaml: 3.15.0
|
||||
resolve-from: 5.0.0
|
||||
|
||||
'@istanbuljs/schema@0.1.6': {}
|
||||
@@ -6568,7 +6633,7 @@ snapshots:
|
||||
dependencies:
|
||||
sparse-bitfield: 3.0.3
|
||||
|
||||
'@nodable/entities@2.2.0': {}
|
||||
'@nodable/entities@3.0.0': {}
|
||||
|
||||
'@nodelib/fs.scandir@2.1.5':
|
||||
dependencies:
|
||||
@@ -6623,8 +6688,6 @@ snapshots:
|
||||
|
||||
'@protobufjs/float@1.0.2': {}
|
||||
|
||||
'@protobufjs/inquire@1.1.2': {}
|
||||
|
||||
'@protobufjs/path@1.1.2': {}
|
||||
|
||||
'@protobufjs/pool@1.1.0': {}
|
||||
@@ -7253,7 +7316,7 @@ snapshots:
|
||||
dayjs: 1.11.21
|
||||
generic-pool: 3.9.0
|
||||
lru-cache: 9.1.2
|
||||
protobufjs: 7.6.3
|
||||
protobufjs: 7.6.5
|
||||
winston: 3.19.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
@@ -7335,7 +7398,9 @@ snapshots:
|
||||
|
||||
arg@4.1.3: {}
|
||||
|
||||
argparse@2.0.1: {}
|
||||
argparse@1.0.10:
|
||||
dependencies:
|
||||
sprintf-js: 1.0.3
|
||||
|
||||
array-back@3.1.0: {}
|
||||
|
||||
@@ -7355,7 +7420,7 @@ snapshots:
|
||||
|
||||
aws4@1.13.2: {}
|
||||
|
||||
axios@1.17.0:
|
||||
axios@1.18.1:
|
||||
dependencies:
|
||||
follow-redirects: 1.16.0
|
||||
form-data: 4.0.6
|
||||
@@ -7455,16 +7520,16 @@ snapshots:
|
||||
|
||||
bowser@2.14.1: {}
|
||||
|
||||
brace-expansion@1.1.15:
|
||||
brace-expansion@1.1.16:
|
||||
dependencies:
|
||||
balanced-match: 1.0.2
|
||||
concat-map: 0.0.1
|
||||
|
||||
brace-expansion@2.1.1:
|
||||
brace-expansion@2.1.2:
|
||||
dependencies:
|
||||
balanced-match: 1.0.2
|
||||
|
||||
brace-expansion@5.0.6:
|
||||
brace-expansion@5.0.8:
|
||||
dependencies:
|
||||
balanced-match: 4.0.4
|
||||
|
||||
@@ -7573,6 +7638,8 @@ snapshots:
|
||||
|
||||
chownr@1.1.4: {}
|
||||
|
||||
chownr@2.0.0: {}
|
||||
|
||||
chownr@3.0.0: {}
|
||||
|
||||
chromadb-js-bindings-darwin-arm64@1.3.4:
|
||||
@@ -7971,14 +8038,14 @@ snapshots:
|
||||
path-expression-matcher: 1.6.2
|
||||
xml-naming: 0.1.0
|
||||
|
||||
fast-xml-parser@5.9.3:
|
||||
fast-xml-parser@5.10.1:
|
||||
dependencies:
|
||||
'@nodable/entities': 2.2.0
|
||||
'@nodable/entities': 3.0.0
|
||||
fast-xml-builder: 1.2.1
|
||||
is-unsafe: 1.0.1
|
||||
is-unsafe: 2.0.0
|
||||
path-expression-matcher: 1.6.2
|
||||
strnum: 2.4.1
|
||||
xml-naming: 0.1.0
|
||||
xml-naming: 0.3.0
|
||||
|
||||
fastembed@2.1.0:
|
||||
dependencies:
|
||||
@@ -7986,7 +8053,7 @@ snapshots:
|
||||
'@huggingface/hub': 2.13.2
|
||||
onnxruntime-node: 1.21.0
|
||||
progress: 2.0.3
|
||||
tar: 7.5.19
|
||||
tar: 6.2.1
|
||||
|
||||
fastq@1.20.1:
|
||||
dependencies:
|
||||
@@ -8073,6 +8140,10 @@ snapshots:
|
||||
|
||||
fs-constants@1.0.0: {}
|
||||
|
||||
fs-minipass@2.1.0:
|
||||
dependencies:
|
||||
minipass: 3.3.6
|
||||
|
||||
fs.realpath@1.0.0: {}
|
||||
|
||||
fsevents@2.3.3:
|
||||
@@ -8209,7 +8280,7 @@ snapshots:
|
||||
node-fetch: 3.3.2
|
||||
object-hash: 3.0.0
|
||||
proto3-json-serializer: 3.0.4
|
||||
protobufjs: 7.6.3
|
||||
protobufjs: 7.6.5
|
||||
retry-request: 8.0.3
|
||||
rimraf: 5.0.10
|
||||
transitivePeerDependencies:
|
||||
@@ -8398,7 +8469,7 @@ snapshots:
|
||||
|
||||
is-stream@2.0.1: {}
|
||||
|
||||
is-unsafe@1.0.1: {}
|
||||
is-unsafe@2.0.0: {}
|
||||
|
||||
is-wsl@2.2.0:
|
||||
dependencies:
|
||||
@@ -8780,9 +8851,10 @@ snapshots:
|
||||
|
||||
js-tokens@4.0.0: {}
|
||||
|
||||
js-yaml@4.2.0:
|
||||
js-yaml@3.15.0:
|
||||
dependencies:
|
||||
argparse: 2.0.1
|
||||
argparse: 1.0.10
|
||||
esprima: 4.0.1
|
||||
|
||||
jsesc@3.1.0: {}
|
||||
|
||||
@@ -8979,26 +9051,39 @@ snapshots:
|
||||
|
||||
minimatch@10.2.5:
|
||||
dependencies:
|
||||
brace-expansion: 5.0.6
|
||||
brace-expansion: 5.0.8
|
||||
|
||||
minimatch@3.1.5:
|
||||
dependencies:
|
||||
brace-expansion: 1.1.15
|
||||
brace-expansion: 1.1.16
|
||||
|
||||
minimatch@9.0.9:
|
||||
dependencies:
|
||||
brace-expansion: 2.1.1
|
||||
brace-expansion: 2.1.2
|
||||
|
||||
minimist@1.2.8: {}
|
||||
|
||||
minipass@3.3.6:
|
||||
dependencies:
|
||||
yallist: 4.0.0
|
||||
|
||||
minipass@5.0.0: {}
|
||||
|
||||
minipass@7.1.3: {}
|
||||
|
||||
minizlib@2.1.2:
|
||||
dependencies:
|
||||
minipass: 3.3.6
|
||||
yallist: 4.0.0
|
||||
|
||||
minizlib@3.1.0:
|
||||
dependencies:
|
||||
minipass: 7.1.3
|
||||
|
||||
mkdirp-classic@0.5.3: {}
|
||||
|
||||
mkdirp@1.0.4: {}
|
||||
|
||||
mlly@1.8.2:
|
||||
dependencies:
|
||||
acorn: 8.16.0
|
||||
@@ -9019,10 +9104,19 @@ snapshots:
|
||||
optionalDependencies:
|
||||
socks: 2.8.9
|
||||
|
||||
mongoose@9.7.0(socks@2.8.9):
|
||||
mongodb@7.5.0(socks@2.8.9):
|
||||
dependencies:
|
||||
'@mongodb-js/saslprep': 1.4.11
|
||||
bson: 7.2.0
|
||||
mongodb-connection-string-url: 7.0.1
|
||||
optionalDependencies:
|
||||
socks: 2.8.9
|
||||
|
||||
mongoose@9.8.0(socks@2.8.9):
|
||||
dependencies:
|
||||
'@standard-schema/spec': 1.1.0
|
||||
kareem: 3.3.0
|
||||
mongodb: 7.2.0(socks@2.8.9)
|
||||
mongodb: 7.5.0(socks@2.8.9)
|
||||
mpath: 0.9.0
|
||||
mquery: 6.0.0
|
||||
ms: 2.1.3
|
||||
@@ -9080,7 +9174,7 @@ snapshots:
|
||||
apparatus: 0.0.10
|
||||
dotenv: 17.4.2
|
||||
memjs: 1.3.2
|
||||
mongoose: 9.7.0(socks@2.8.9)
|
||||
mongoose: 9.8.0(socks@2.8.9)
|
||||
pg: 8.21.0
|
||||
redis: 5.12.1(@opentelemetry/api@1.9.1)
|
||||
safe-stable-stringify: 2.5.0
|
||||
@@ -9203,7 +9297,7 @@ snapshots:
|
||||
dependencies:
|
||||
global-agent: 3.0.0
|
||||
onnxruntime-common: 1.21.0
|
||||
tar: 7.5.19
|
||||
tar: 7.5.22
|
||||
|
||||
onnxruntime-node@1.24.3:
|
||||
dependencies:
|
||||
@@ -9218,7 +9312,7 @@ snapshots:
|
||||
long: 5.3.2
|
||||
onnxruntime-common: 1.24.0-dev.20251116-b39e144322
|
||||
platform: 1.3.6
|
||||
protobufjs: 7.6.3
|
||||
protobufjs: 7.6.5
|
||||
|
||||
open@10.2.0:
|
||||
dependencies:
|
||||
@@ -9490,9 +9584,9 @@ snapshots:
|
||||
|
||||
proto3-json-serializer@3.0.4:
|
||||
dependencies:
|
||||
protobufjs: 7.6.3
|
||||
protobufjs: 7.6.5
|
||||
|
||||
protobufjs@7.6.3:
|
||||
protobufjs@7.6.5:
|
||||
dependencies:
|
||||
'@protobufjs/aspromise': 1.1.2
|
||||
'@protobufjs/base64': 1.1.2
|
||||
@@ -9500,7 +9594,6 @@ snapshots:
|
||||
'@protobufjs/eventemitter': 1.1.1
|
||||
'@protobufjs/fetch': 1.1.1
|
||||
'@protobufjs/float': 1.0.2
|
||||
'@protobufjs/inquire': 1.1.2
|
||||
'@protobufjs/path': 1.1.2
|
||||
'@protobufjs/pool': 1.1.0
|
||||
'@protobufjs/utf8': 1.1.1
|
||||
@@ -9806,6 +9899,8 @@ snapshots:
|
||||
|
||||
split2@4.2.0: {}
|
||||
|
||||
sprintf-js@1.0.3: {}
|
||||
|
||||
sprintf-js@1.1.3: {}
|
||||
|
||||
sql-escaper@1.3.3: {}
|
||||
@@ -9926,7 +10021,16 @@ snapshots:
|
||||
inherits: 2.0.4
|
||||
readable-stream: 3.6.2
|
||||
|
||||
tar@7.5.19:
|
||||
tar@6.2.1:
|
||||
dependencies:
|
||||
chownr: 2.0.0
|
||||
fs-minipass: 2.1.0
|
||||
minipass: 5.0.0
|
||||
minizlib: 2.1.2
|
||||
mkdirp: 1.0.4
|
||||
yallist: 4.0.0
|
||||
|
||||
tar@7.5.22:
|
||||
dependencies:
|
||||
'@isaacs/fs-minipass': 4.0.1
|
||||
chownr: 3.0.0
|
||||
@@ -9959,17 +10063,6 @@ snapshots:
|
||||
dependencies:
|
||||
any-promise: 1.3.0
|
||||
|
||||
thrift@0.16.0:
|
||||
dependencies:
|
||||
browser-or-node: 1.3.0
|
||||
isomorphic-ws: 4.0.1(ws@5.2.5)
|
||||
node-int64: 0.4.0
|
||||
q: 1.5.1
|
||||
ws: 5.2.5
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- utf-8-validate
|
||||
|
||||
thrift@0.23.0:
|
||||
dependencies:
|
||||
browser-or-node: 1.3.0
|
||||
@@ -10254,6 +10347,8 @@ snapshots:
|
||||
|
||||
xml-naming@0.1.0: {}
|
||||
|
||||
xml-naming@0.3.0: {}
|
||||
|
||||
xtend@4.0.2: {}
|
||||
|
||||
xxhash-wasm@1.1.0: {}
|
||||
|
||||
@@ -10,13 +10,14 @@ overrides:
|
||||
"picomatch@<2.3.2": "^2.3.2"
|
||||
"picomatch@>=4.0.0 <4.0.4": "^4.0.4"
|
||||
"jws@4.0.0": "4.0.1"
|
||||
"js-yaml@<3.14.2": ">=3.14.2"
|
||||
"js-yaml@<3.15.0": ">=3.15.0 <4.0.0"
|
||||
"js-yaml@>=4.0.0 <4.3.0": ">=4.3.0 <5.0.0"
|
||||
"langsmith@<0.6.0": "^0.6.0"
|
||||
"minimatch@<3.1.3": "^3.1.3"
|
||||
"minimatch@>=5.0.0 <5.1.8": "^5.1.8"
|
||||
"minimatch@>=9.0.0 <9.0.7": "^9.0.7"
|
||||
"path-to-regexp@>=8.0.0 <8.4.0": "^8.4.0"
|
||||
"postcss@<8.5.10": ">=8.5.10"
|
||||
"postcss@<8.5.18": ">=8.5.18 <9.0.0"
|
||||
"uuid@<11.1.1": ">=11.1.1"
|
||||
"ws@>=8.0.0 <8.20.1": ">=8.20.1"
|
||||
"rollup@>=4.0.0 <4.59.0": "^4.59.0"
|
||||
@@ -25,3 +26,12 @@ overrides:
|
||||
"@modelcontextprotocol/sdk": "^1.25.4"
|
||||
"esbuild": ">=0.28.1"
|
||||
"undici@<6.27.0": ">=6.27.0 <8.0.0"
|
||||
"axios@<1.18.0": ">=1.18.0 <2.0.0"
|
||||
"brace-expansion@<1.1.16": ">=1.1.16 <2.0.0"
|
||||
"brace-expansion@>=2.0.0 <2.1.2": ">=2.1.2 <3.0.0"
|
||||
"brace-expansion@>=3.0.0 <5.0.8": ">=5.0.8 <6.0.0"
|
||||
"fast-xml-parser@>=5.0.0 <5.10.1": ">=5.10.1 <6.0.0"
|
||||
"tar@>=7.0.0 <7.5.21": ">=7.5.21 <8.0.0"
|
||||
"thrift@<0.23.0": "^0.23.0"
|
||||
"mongoose@>=9.0.0 <9.7.2": ">=9.7.2 <10.0.0"
|
||||
"protobufjs@<7.6.5": ">=7.6.5 <8.0.0"
|
||||
|
||||
@@ -27,6 +27,8 @@ export interface SearchMemoryOptions {
|
||||
fields?: string[];
|
||||
categories?: string[];
|
||||
showExpired?: boolean;
|
||||
referenceDate?: string | number;
|
||||
keywordSearch?: boolean;
|
||||
}
|
||||
|
||||
export interface GetAllMemoryOptions {
|
||||
|
||||
@@ -99,6 +99,42 @@ describe("MemoryClient - search()", () => {
|
||||
expect(getFetchBody(call!).show_expired).toBe(true);
|
||||
});
|
||||
|
||||
test("serializes referenceDate as reference_date (MEM-5893)", async () => {
|
||||
const extra = new Map<string, { status: number; body: unknown }>();
|
||||
extra.set("/v3/memories/search/", {
|
||||
status: 200,
|
||||
body: { results: [] },
|
||||
});
|
||||
const mock = setupMockFetch(extra);
|
||||
|
||||
const client = new MemoryClient({ apiKey: TEST_API_KEY });
|
||||
await client.search("test", {
|
||||
filters: { user_id: "u1" },
|
||||
referenceDate: "2024-01-01",
|
||||
});
|
||||
|
||||
const call = findFetchCall(mock, "/v3/memories/search/", "POST");
|
||||
expect(getFetchBody(call!).reference_date).toBe("2024-01-01");
|
||||
});
|
||||
|
||||
test("serializes keywordSearch as keyword_search (MEM-5893)", async () => {
|
||||
const extra = new Map<string, { status: number; body: unknown }>();
|
||||
extra.set("/v3/memories/search/", {
|
||||
status: 200,
|
||||
body: { results: [] },
|
||||
});
|
||||
const mock = setupMockFetch(extra);
|
||||
|
||||
const client = new MemoryClient({ apiKey: TEST_API_KEY });
|
||||
await client.search("test", {
|
||||
filters: { user_id: "u1" },
|
||||
keywordSearch: true,
|
||||
});
|
||||
|
||||
const call = findFetchCall(mock, "/v3/memories/search/", "POST");
|
||||
expect(getFetchBody(call!).keyword_search).toBe(true);
|
||||
});
|
||||
|
||||
test("passes complex OR filters through to the API body", async () => {
|
||||
const extra = new Map<string, { status: number; body: unknown }>();
|
||||
extra.set("/v3/memories/search/", {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user