From 760dca6f391277d79c3c7d2096c1bf1d037526c3 Mon Sep 17 00:00:00 2001 From: Kartik Date: Thu, 30 Jul 2026 22:52:42 +0530 Subject: [PATCH] docs(platform): correct 34 audited API discrepancies across platform docs (#6466) --- docs/api-reference/memory/add-memories.mdx | 5 +- .../integrations/openai-tool-calls.mdx | 5 +- docs/integrations/langchain-tools.mdx | 5 +- docs/migration/platform-v2-to-v3.mdx | 5 +- docs/openapi.json | 8 +- docs/platform/advanced-memory-operations.mdx | 6 +- docs/platform/agent-signup.mdx | 7 +- docs/platform/faqs.mdx | 14 +- docs/platform/features/advanced-retrieval.mdx | 24 +--- docs/platform/features/async-client.mdx | 2 +- docs/platform/features/custom-categories.mdx | 18 ++- .../platform/features/custom-instructions.mdx | 2 + docs/platform/features/direct-import.mdx | 30 +++- .../features/entity-scoped-memory.mdx | 24 ++-- docs/platform/features/feedback-mechanism.mdx | 25 ++-- docs/platform/features/graph-memory.mdx | 2 +- docs/platform/features/group-chat.mdx | 134 ++++++++---------- docs/platform/features/memory-decay.mdx | 16 +-- docs/platform/features/memory-export.mdx | 23 ++- docs/platform/features/multimodal-support.mdx | 12 +- docs/platform/features/temporal-reasoning.mdx | 14 +- docs/platform/features/v2-memory-filters.mdx | 56 ++++---- docs/platform/features/webhooks.mdx | 7 +- docs/platform/mem0-mcp.mdx | 2 +- docs/platform/overview.mdx | 2 +- docs/platform/quickstart.mdx | 6 + 26 files changed, 243 insertions(+), 211 deletions(-) diff --git a/docs/api-reference/memory/add-memories.mdx b/docs/api-reference/memory/add-memories.mdx index ab5d73b65..a0529c4da 100644 --- a/docs/api-reference/memory/add-memories.mdx +++ b/docs/api-reference/memory/add-memories.mdx @@ -65,9 +65,8 @@ The request is queued for background processing. The response contains an `event ```json 200 response { - "message": "Memory processing has been queued for background execution", - "status": "PENDING", - "event_id": "evt-uuid" + "event_id": "evt-uuid", + "status": "PENDING" } ``` diff --git a/docs/cookbooks/integrations/openai-tool-calls.mdx b/docs/cookbooks/integrations/openai-tool-calls.mdx index 9ab436aaf..61bb4d3cd 100644 --- a/docs/cookbooks/integrations/openai-tool-calls.mdx +++ b/docs/cookbooks/integrations/openai-tool-calls.mdx @@ -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" } ``` diff --git a/docs/integrations/langchain-tools.mdx b/docs/integrations/langchain-tools.mdx index bf800c050..9c03facf0 100644 --- a/docs/integrations/langchain-tools.mdx +++ b/docs/integrations/langchain-tools.mdx @@ -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" } ``` diff --git a/docs/migration/platform-v2-to-v3.mdx b/docs/migration/platform-v2-to-v3.mdx index 665e882dd..8cc9690da 100644 --- a/docs/migration/platform-v2-to-v3.mdx +++ b/docs/migration/platform-v2-to-v3.mdx @@ -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" } ``` diff --git a/docs/openapi.json b/docs/openapi.json index 09344356e..a53c0c7c7 100644 --- a/docs/openapi.json +++ b/docs/openapi.json @@ -2035,7 +2035,8 @@ "type": "object", "properties": { "message": { - "type": "string" + "type": "string", + "description": "Only present when `infer` is `false`, where processing is synchronous." }, "status": { "type": "string", @@ -2052,9 +2053,8 @@ } }, "example": { - "message": "Memory processing has been queued for background execution", - "status": "PENDING", - "event_id": "2c4d1f44-4f7b-4b2f-9f6e-7b5b4f5a1234" + "event_id": "2c4d1f44-4f7b-4b2f-9f6e-7b5b4f5a1234", + "status": "PENDING" } } } diff --git a/docs/platform/advanced-memory-operations.mdx b/docs/platform/advanced-memory-operations.mdx index dc43a55c3..ae8af5e1a 100644 --- a/docs/platform/advanced-memory-operations.mdx +++ b/docs/platform/advanced-memory-operations.mdx @@ -27,7 +27,7 @@ pip install mem0ai ```bash -export MEM0_API_KEY="sk-platform-..." +export MEM0_API_KEY="m0-..." ``` @@ -49,7 +49,7 @@ npm install mem0ai ```bash -export MEM0_API_KEY="sk-platform-..." +export MEM0_API_KEY="m0-..." ``` @@ -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. + diff --git a/docs/platform/agent-signup.mdx b/docs/platform/agent-signup.mdx index 03353d325..a8b6f16c3 100644 --- a/docs/platform/agent-signup.mdx +++ b/docs/platform/agent-signup.mdx @@ -76,12 +76,7 @@ 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: - -``` -Daily Agent Mode signup limit reached for this network (5/day). -Try again from a different IP or after midnight UTC. -``` +Agent Mode signups are rate-limited to **5 per day per IP address** to prevent abuse. If you hit the limit, the request fails with a generic **403 Forbidden** (no custom error message, no `Retry-After` header). Wait a while or try from a different network. Unclaimed agent accounts get the standard Mem0 free-tier quotas. The human owner can upgrade after claiming. diff --git a/docs/platform/faqs.mdx b/docs/platform/faqs.mdx index 2d5e4b6f0..d84b429c2 100644 --- a/docs/platform/faqs.mdx +++ b/docs/platform/faqs.mdx @@ -17,7 +17,7 @@ iconType: "solid" - - **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 - - 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. + + 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. diff --git a/docs/platform/features/advanced-retrieval.mdx b/docs/platform/features/advanced-retrieval.mdx index 43470da5d..c1b09cf0d 100644 --- a/docs/platform/features/advanced-retrieval.mdx +++ b/docs/platform/features/advanced-retrieval.mdx @@ -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, - }); -} ``` diff --git a/docs/platform/features/async-client.mdx b/docs/platform/features/async-client.mdx index 889483334..c227f6f57 100644 --- a/docs/platform/features/async-client.mdx +++ b/docs/platform/features/async-client.mdx @@ -124,7 +124,7 @@ await client.deleteAll({ userId: "alice" }); - 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. ### History diff --git a/docs/platform/features/custom-categories.mdx b/docs/platform/features/custom-categories.mdx index ce699177a..f66bd26df 100644 --- a/docs/platform/features/custom-categories.mdx +++ b/docs/platform/features/custom-categories.mdx @@ -75,6 +75,8 @@ print(response) ``` +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 @@ -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 } ``` -`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. `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 } ``` -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. diff --git a/docs/platform/features/custom-instructions.mdx b/docs/platform/features/custom-instructions.mdx index f406f6206..a864fe8fa 100644 --- a/docs/platform/features/custom-instructions.mdx +++ b/docs/platform/features/custom-instructions.mdx @@ -68,6 +68,8 @@ console.log(response.customInstructions); ``` +`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: diff --git a/docs/platform/features/direct-import.mdx b/docs/platform/features/direct-import.mdx index b28348cf5..5fd704086 100644 --- a/docs/platform/features/direct-import.mdx +++ b/docs/platform/features/direct-import.mdx @@ -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" + } + ] +} ``` -You can see that the output of the add call is an empty list. - -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. + +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. + -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`. ## How to Retrieve Memories diff --git a/docs/platform/features/entity-scoped-memory.mdx b/docs/platform/features/entity-scoped-memory.mdx index bea1b46fa..305ad6c09 100644 --- a/docs/platform/features/entity-scoped-memory.mdx +++ b/docs/platform/features/entity-scoped-memory.mdx @@ -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. **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,7 +78,9 @@ 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. -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. The HTTP equivalent uses `POST /v1/memories/` with the same identifiers in the JSON body. See the Add Memories API reference for REST details. @@ -130,7 +132,7 @@ print(agent_results) ``` -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. @@ -141,11 +143,11 @@ Want to experiment with AND/OR logic, nested operators, or wildcards? The +### 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: diff --git a/docs/platform/features/graph-memory.mdx b/docs/platform/features/graph-memory.mdx index aeea23dcc..647e6fe4f 100644 --- a/docs/platform/features/graph-memory.mdx +++ b/docs/platform/features/graph-memory.mdx @@ -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. diff --git a/docs/platform/features/group-chat.mdx b/docs/platform/features/group-chat.mdx index 664e978b0..b195965f1 100644 --- a/docs/platform/features/group-chat.mdx +++ b/docs/platform/features/group-chat.mdx @@ -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: @@ -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" } ``` +`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: + + + +```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 +``` + + + +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) -## Async Mode Support - -Group chat supports async processing for improved performance. Memory additions are processed asynchronously by default. - - - -```python Python -# Group chat: async processing is the default -response = client.add( - messages, - run_id="groupchat_async", - infer=True, -) -print(response) -``` - - - ## 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. diff --git a/docs/platform/features/memory-decay.mdx b/docs/platform/features/memory-decay.mdx index 6b2a7233d..c2bfe8ccc 100644 --- a/docs/platform/features/memory-decay.mdx +++ b/docs/platform/features/memory-decay.mdx @@ -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`. ```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" } ``` @@ -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. diff --git a/docs/platform/features/memory-export.mdx b/docs/platform/features/memory-export.mdx index 0a0d67612..c4375b038 100644 --- a/docs/platform/features/memory-export.mdx +++ b/docs/platform/features/memory-export.mdx @@ -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", diff --git a/docs/platform/features/multimodal-support.mdx b/docs/platform/features/multimodal-support.mdx index 24a3b2f4b..1ae115687 100644 --- a/docs/platform/features/multimodal-support.mdx +++ b/docs/platform/features/multimodal-support.mdx @@ -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. + +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`. + + ```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 } } diff --git a/docs/platform/features/temporal-reasoning.mdx b/docs/platform/features/temporal-reasoning.mdx index 9853b708c..0a2fdd510 100644 --- a/docs/platform/features/temporal-reasoning.mdx +++ b/docs/platform/features/temporal-reasoning.mdx @@ -51,24 +51,22 @@ Temporal Reasoning is enabled by default for all v3 searches and writes. There i 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 +- `observation_date` (or `observation_datetime`, which takes priority when both are set) on `add()`: anchors an imported memory to the time it actually happened. Pair with `timezone` when resolving a date-only value. +- `timestamp` on `add()`: a Unix epoch that sets the memory's creation time. When present it takes priority over `observation_datetime` and `observation_date` as the anchor Temporal Reasoning ranks against, so pass only the one you want to win. - `reference_date` on `search()`: resolves relative phrases like `last week` against a fixed point in time ```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()), + observation_date="2025-03-10", ) -# Search with a relative query anchored to a known date results = client.search( "what did I do last week?", filters={"user_id": "jordan"}, @@ -81,16 +79,14 @@ 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), + observationDate: "2025-03-10", } ); -// 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" }, referenceDate: "2025-03-21T00:00:00Z", @@ -131,7 +127,7 @@ const results = await client.search("what did I do last week?", { ## 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. +- Pass `observation_date` (or `observation_datetime`) during historical imports so the ingestion time does not become the only time anchor. Do not also pass `timestamp` on those calls, since it overrides both as the ranking anchor. - Scope searches with `filters` so time-aware ranking operates inside the right user boundary. - Use `reference_date` in automated tests and reproducible demos. diff --git a/docs/platform/features/v2-memory-filters.mdx b/docs/platform/features/v2-memory-filters.mdx index 383feeb31..034fc0f76 100644 --- a/docs/platform/features/v2-memory-filters.mdx +++ b/docs/platform/features/v2-memory-filters.mdx @@ -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. - + ```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. + + + 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`. + @@ -254,10 +253,8 @@ Combine various filters for complex queries across different dimensions. ``` - + ```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. @@ -276,16 +274,16 @@ Level up foundational patterns with compound filters that coordinate entity scop ```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) ``` @@ -330,7 +328,7 @@ Level up foundational patterns with compound filters that coordinate entity scop ## Best practices -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. @@ -338,7 +336,9 @@ Use `"*"` to match any non-null value for a field. -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. ## Troubleshooting @@ -347,7 +347,7 @@ Memories are stored per-entity (user, agent, app, run). Combining `user_id` **an **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 ``` - - **Solution**: Swap to `icontains` to normalize casing. + + **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. @@ -388,7 +392,7 @@ Memories are stored per-entity (user, agent, app, run). Combining `user_id` **an - 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. @@ -408,7 +412,7 @@ Memories are stored per-entity (user, agent, app, run). Combining `user_id` **an - 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)). @@ -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. diff --git a/docs/platform/features/webhooks.mdx b/docs/platform/features/webhooks.mdx index abb7cfcd5..8abd0e89e 100644 --- a/docs/platform/features/webhooks.mdx +++ b/docs/platform/features/webhooks.mdx @@ -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. @@ -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 diff --git a/docs/platform/mem0-mcp.mdx b/docs/platform/mem0-mcp.mdx index 894915447..7440df11a 100644 --- a/docs/platform/mem0-mcp.mdx +++ b/docs/platform/mem0-mcp.mdx @@ -41,7 +41,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 | diff --git a/docs/platform/overview.mdx b/docs/platform/overview.mdx index bc91d6a70..2743dfbac 100644 --- a/docs/platform/overview.mdx +++ b/docs/platform/overview.mdx @@ -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. - How user, agent, run, and session memory differ. + How user, agent, app, and run memory differ. The core memory operations, end to end. diff --git a/docs/platform/quickstart.mdx b/docs/platform/quickstart.mdx index 1e876c122..1b98cecd2 100644 --- a/docs/platform/quickstart.mdx +++ b/docs/platform/quickstart.mdx @@ -132,8 +132,14 @@ 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", + "updated_at": "2025-10-22T04:40:22.864647-07:00", + "expiration_date": null, "score": 0.30 } ]