From 2bca30ebe6216e7e23af8d68c46b148276b7c616 Mon Sep 17 00:00:00 2001 From: Parth Sharma <109902593+parthshr370@users.noreply.github.com> Date: Fri, 14 Nov 2025 01:28:36 +0530 Subject: [PATCH] [docs] Minor Docs fixes ( enhancements , restructure ) (#3748) --- docs/api-reference/memory/add-memories.mdx | 96 +- .../essentials/building-ai-companion.mdx | 6 +- .../integrations/agents-sdk-tool.mdx | 2 +- docs/platform/features/async-client.mdx | 8 +- .../features/async-mode-default-change.mdx | 6 +- .../platform/features/custom-instructions.mdx | 2 +- docs/platform/features/direct-import.mdx | 6 +- docs/platform/features/graph-memory.mdx | 8 +- docs/platform/features/v2-memory-filters.mdx | 877 ++++++++---------- docs/templates/feature_guide_template.mdx | 2 +- 10 files changed, 507 insertions(+), 506 deletions(-) diff --git a/docs/api-reference/memory/add-memories.mdx b/docs/api-reference/memory/add-memories.mdx index ae95f1c20..70bae11fe 100644 --- a/docs/api-reference/memory/add-memories.mdx +++ b/docs/api-reference/memory/add-memories.mdx @@ -3,10 +3,96 @@ title: 'Add Memories' openapi: post /v1/memories/ --- -## Graph Memory +Add new facts, messages, or metadata to a user’s memory store. The Add Memories endpoint accepts either raw text or conversational turns and commits them asynchronously so the memory is ready for later search, retrieval, and graph queries. -To enable graph-based memory relationships, pass the `enable_graph=True` parameter. This creates relationships between entities in your memories for more contextual retrieval. +## Endpoint - -Learn more in the [Graph Memory documentation](/platform/features/graph-memory). - \ No newline at end of file +- **Method**: `POST` +- **URL**: `/v1/memories/` +- **Content-Type**: `application/json` + +Memories are processed asynchronously by default. The response contains queued events you can track while the platform finalizes enrichment. + +## Required headers + +| Header | Required | Description | +| --- | --- | --- | +| `Authorization: Bearer ` | Yes | API key scoped to your workspace. | +| `Accept: application/json` | Yes | Ensures a JSON response. | + +## Request body + +Provide at least one message or direct memory string. Most callers supply `messages` so Mem0 can infer structured memories as part of ingestion. + + +```json Basic request +{ + "user_id": "alice", + "messages": [ + { "role": "user", "content": "I moved to Austin last month." } + ], + "metadata": { + "source": "onboarding_form" + } +} +``` + + +### Common fields + +| Field | Type | Required | Description | +| --- | --- | --- | --- | +| `user_id` | string | No* | Associates the memory with a user. Provide when you want the memory scoped to a specific identity. | +| `messages` | array | No* | Conversation turns for Mem0 to infer memories from. Each object should include `role` and `content`. | +| `memory` | string | No* | Direct memory text when you do not need inference. | +| `metadata` | object | Optional | Custom key/value metadata (e.g., `{"topic": "preferences"}`). | +| `infer` | boolean (default `true`) | Optional | Set to `false` to skip inference and store the provided text as-is. | +| `async_mode` | boolean (default `true`) | Optional | Controls asynchronous processing. Most clients leave this enabled. | +| `output_format` | string (default `v1.1`) | Optional | Response format. `v1.1` wraps results in a `results` array. | + +> \* Provide either `messages` or `memory` to describe what you are storing. For scoped memories, include `user_id`. You can also attach `agent_id`, `app_id`, `run_id`, `project_id`, or `org_id` to refine ownership. + +## Response + +Successful requests return an array of events queued for processing. Each event includes the generated memory text and an identifier you can persist for auditing. + + +```json 200 response +[ + { + "id": "mem_01JF8ZS4Y0R0SPM13R5R6H32CJ", + "event": "ADD", + "data": { + "memory": "The user moved to Austin in 2025." + } + } +] +``` + +```json 400 response +{ + "error": "400 Bad Request", + "details": { + "message": "Invalid input data. Please refer to the memory creation documentation at https://docs.mem0.ai/platform/quickstart#4-1-create-memories for correct formatting and required fields." + } +} +``` + + +## Graph relationships + +Add Memories can enrich the knowledge graph on write. Set `enable_graph: true` to create entity nodes and relationships for the stored memory. Use this when you want downstream `get_all` or search calls to traverse connected entities. + + +```json Graph-aware request +{ + "user_id": "alice", + "messages": [ + { "role": "user", "content": "I met with Dr. Lee at General Hospital." } + ], + "enable_graph": true +} +``` + + +The response follows the same format, and related entities become available in [Graph Memory](/platform/features/graph-memory) queries. diff --git a/docs/cookbooks/essentials/building-ai-companion.mdx b/docs/cookbooks/essentials/building-ai-companion.mdx index 6cbaf0e12..bcaaada17 100644 --- a/docs/cookbooks/essentials/building-ai-companion.mdx +++ b/docs/cookbooks/essentials/building-ai-companion.mdx @@ -164,7 +164,7 @@ Ray can plan workouts that avoid aggravating Max's knee, without pulling in race Run the basic loop for a week and check what's stored: ```python -memories = mem0_client.get_all(user_id="max") +memories = mem0_client.get_all(filters={"AND": [{"user_id": "max"}]}) print([m["memory"] for m in memories["results"]]) # Output: ["Max wants to run marathon under 4 hours", "hey", "lol ok", "cool thanks", "gtg bye"] @@ -202,7 +202,7 @@ Now chat again: chat("hey how's it going", user_id="max") chat("I prefer trail running over roads", user_id="max") -memories = mem0_client.get_all(user_id="max") +memories = mem0_client.get_all(filters={"AND": [{"user_id": "max"}]}) print([m["memory"] for m in memories["results"]]) # Output: ["Max wants to run marathon under 4 hours", "Max prefers trail running over roads"] @@ -411,7 +411,7 @@ Max changes his goal from sub-4 to sub-3:45: ```python # Find the old memory -memories = mem0_client.get_all(user_id="max") +memories = mem0_client.get_all(filters={"AND": [{"user_id": "max"}]}) goal_memory = [m for m in memories["results"] if "sub-4" in m["memory"]][0] # Update it diff --git a/docs/cookbooks/integrations/agents-sdk-tool.mdx b/docs/cookbooks/integrations/agents-sdk-tool.mdx index 91c8f210b..29b8c5db8 100644 --- a/docs/cookbooks/integrations/agents-sdk-tool.mdx +++ b/docs/cookbooks/integrations/agents-sdk-tool.mdx @@ -126,7 +126,7 @@ async def get_all_memory( ) -> str: """Retrieve all memories from Mem0""" user_id = context.context.user_id or "default_user" - memories = await client.get_all(user_id=user_id) + memories = await client.get_all(filters={"AND": [{"user_id": user_id}]}) results = '\n'.join([result["memory"] for result in memories["results"]]) return str(results) ``` diff --git a/docs/platform/features/async-client.mdx b/docs/platform/features/async-client.mdx index cd5fbdc6a..14f34dfeb 100644 --- a/docs/platform/features/async-client.mdx +++ b/docs/platform/features/async-client.mdx @@ -75,14 +75,18 @@ await client.search("What is Alice's favorite sport?", { user_id: "alice" }); Retrieve all memories for a user asynchronously. + +`get_all()` now requires filters to be specified. + + ```python Python -await client.get_all(user_id="alice") +await client.get_all(filters={"AND": [{"user_id": "alice"}]}) ``` ```javascript JavaScript -await client.getAll({ user_id: "alice" }); +await client.getAll({ filters: {"AND": [{"user_id": "alice"}]} }); ``` diff --git a/docs/platform/features/async-mode-default-change.mdx b/docs/platform/features/async-mode-default-change.mdx index 28a7dc490..d7a7da93e 100644 --- a/docs/platform/features/async-mode-default-change.mdx +++ b/docs/platform/features/async-mode-default-change.mdx @@ -161,12 +161,14 @@ You can also retrieve all processed memories at any time: ```python Python # Retrieve all memories for a user -memories = client.get_all(user_id="user-123") +# Note: get_all now requires filters +memories = client.get_all(filters={"AND": [{"user_id": "user-123"}]}) ``` ```javascript JavaScript // Retrieve all memories for a user -const memories = await client.getAll({ user_id: "user-123" }); +// Note: getAll now requires filters +const memories = await client.getAll({ filters: {"AND": [{"user_id": "user-123"}]} }); ``` diff --git a/docs/platform/features/custom-instructions.mdx b/docs/platform/features/custom-instructions.mdx index 3c80ac8cf..6d6bae3c5 100644 --- a/docs/platform/features/custom-instructions.mdx +++ b/docs/platform/features/custom-instructions.mdx @@ -302,7 +302,7 @@ messages = [ # Add the messages and check extracted memories result = client.add(messages, user_id="test_user") -memories = client.get_all(user_id="test_user") +memories = client.get_all(filters={"AND": [{"user_id": "test_user"}]}) # Review if the right information was extracted for memory in memories: diff --git a/docs/platform/features/direct-import.mdx b/docs/platform/features/direct-import.mdx index 5217b473f..0e1cb5391 100644 --- a/docs/platform/features/direct-import.mdx +++ b/docs/platform/features/direct-import.mdx @@ -67,10 +67,14 @@ client.search("What is Alice's favorite sport?", user_id="alice") You can retrieve all memories using the `get_all` method. + +`get_all()` now requires filters to be specified. + + ```python Python -client.get_all(query="What is Alice's favorite sport?", user_id="alice") +client.get_all(filters={"AND": [{"user_id": "alice"}]}) ``` ```json Output diff --git a/docs/platform/features/graph-memory.mdx b/docs/platform/features/graph-memory.mdx index 64579df9f..4a7e4dcc6 100644 --- a/docs/platform/features/graph-memory.mdx +++ b/docs/platform/features/graph-memory.mdx @@ -187,12 +187,16 @@ console.log(results); When retrieving all memories, Graph Memory provides additional relationship context: + +`get_all()` now requires filters to be specified. + + ```python Python # Get all memories with graph context memories = client.get_all( - user_id="joseph", + filters={"AND": [{"user_id": "joseph"}]}, enable_graph=True ) @@ -202,7 +206,7 @@ print(memories) ```javascript JavaScript // Get all memories with graph context const memories = await client.getAll({ - user_id: "joseph", + filters: {"AND": [{"user_id": "joseph"}]}, enable_graph: true }); diff --git a/docs/platform/features/v2-memory-filters.mdx b/docs/platform/features/v2-memory-filters.mdx index d4fc204eb..b74757adf 100644 --- a/docs/platform/features/v2-memory-filters.mdx +++ b/docs/platform/features/v2-memory-filters.mdx @@ -1,515 +1,416 @@ --- -title: Memory Filters v2 -description: This guide covers the filtering system for retrieving and searching memories. You can filter by user sessions, agents, applications, content categories, and time ranges. +title: Memory Filters +description: Query and retrieve memories with powerful filtering capabilities. Filter by users, agents, content, time ranges, and more. --- -## Quick Start +> Memory filters provide a flexible way to query and retrieve specific memories from your memory store. You can filter by users, agents, content categories, time ranges, and combine multiple conditions using logical operators. -### Memories for a specific user +## When to use filters -```json +When working with large-scale memory stores, you need precise control over which memories to retrieve. Filters help you: + +* **Isolate user data**: Retrieve memories for specific users while maintaining privacy +* **Debug and audit**: Export specific memory subsets for analysis +* **Target content**: Find memories with specific categories or metadata +* **Time-based queries**: Retrieve memories within specific date ranges +* **Performance optimization**: Reduce query complexity by pre-filtering + + +Filters were introduced in v1.0.0 to provide precise control over memory retrieval. + + +## Filter structure + +Filters use a nested JSON structure with logical operators at the root: + +```python +# Basic structure { - "AND": [ - { "user_id": "u1" } - ] + "AND": [ # or "OR", "NOT" + { "field": "value" }, + { "field": { "operator": "value" } } + ] } ``` -### User memories across all runs - -```json -{ - "AND": [ - { "user_id": "u1" }, - { "run_id": "*" } - ] -} -``` - - -Excludes null run_id values - - - ---- - -## Filter Structure - -* Root must be **`AND`** or **`OR`** (or **`NOT`**) containing an **array** of conditions. -* A **condition** is either a simple equality `{ "user_id": "u1" }` or an operator clause `{ "created_at": { "gte": "..." } }`. - -```json -{ - "AND": [ - { "user_id": "u1" }, - { "run_id": "*" }, - { "created_at": { "lt": "2025-06-01T00:00:00Z" } }, - { "categories": { "in": ["finance", "health"] } } - ] -} -``` - -**Accepted shapes** - -```json -{ "AND": [ /* conditions... */ ] } -{ "OR": [ /* conditions... */ ] } -{ "NOT": [ /* conditions... */ ] } -``` - ---- - -## Available Fields - -Use these to scope memories to primary entities: - -| Field | Meaning | -| ---------- | ----------------------- | -| `user_id` | Filter by user/consumer | -| `agent_id` | Filter by AI agent | -| `app_id` | Filter by application | -| `run_id` | Filter by session/run | - ---- - -## Wildcards - -Wildcards (`"*"`) match **any non-null** value of that field. This means if a field is null, it won't be included in the results. - - -Asterisks (`*`) exclude null values - only non-null fields will be matched - - -```json -{ "AND": [ { "user_id": "*" } ] } // any record with a user_id -{ "AND": [ { "user_id": "*" }, { "run_id": "*" } ] } // require both non-null -{ "OR": [ { "user_id": "*" }, { "run_id": "*" } ] } // either non-null -``` - ---- - -## Operators and Fields - -**Available Fields** - -* **Entities**: `user_id`, `agent_id`, `app_id`, `run_id` -* **Time**: `created_at`, `updated_at`, `timestamp` -* **Content**: `categories`, `metadata`, `keywords` -* **Special**: `memory_ids` (array of IDs) - -**Operators** - -* `in`: Matches any of the values specified -* `gte`: Greater than or equal to -* `lte`: Less than or equal to -* `gt`: Greater than -* `lt`: Less than -* `ne`: Not equal to -* `contains`: Case-sensitive containment check -* `icontains`: Case-insensitive containment check -* `*`: Wildcard character that matches everything - -**Field Structures** - -```json -// Entity fields -{ "user_id": "u1" } -{ "agent_id": "a1" } -{ "app_id": "app1" } -{ "run_id": "run1" } - -// Time fields -{ "created_at": { "gte": "2025-01-01T00:00:00Z" } } -{ "updated_at": { "lt": "2025-02-01T00:00:00Z" } } - -// Categories (exact matching) -{ "categories": { "in": ["personal_information", "finance"] } } -// Categories (partial matching) -{ "categories": { "contains": "finance" } } - -// Metadata (exact key-value match) -{ "metadata": { "key": "value" } } - -// Keywords (text search) -{ "keywords": { "icontains": "budget" } } - -// Memory IDs -{ "memory_ids": ["m1", "m2", "m3"] } -``` - -**Notes** - -* `eq` is implied: `{ "user_id": "u1" }` ≡ `{ "user_id": { "eq": "u1" } }` -* `ne` includes **NULLs**: results where the field is either **not equal** or **missing** -* For `categories`, use `contains` for partial matching or `in` for exact matching - ---- - -## Examples - -### User and Agent Filters - -**All memories for a specific user** - -```json -{ "AND": [ { "user_id": "u1" } ] } -``` - -**All memories across all users (no agent/app/run)** - -```json -{ "AND": [ { "user_id": "*" } ] } -``` - - -Excludes null user_id values - - -**User memories across all runs** - -```json -{ "AND": [ { "user_id": "u1" }, { "run_id": "*" } ] } -``` - - -Excludes null run_id values - - -**All memories for a specific agent** - -```json -{ "AND": [ { "agent_id": "a1" } ] } -``` - -**Agent memories across all runs** - -```json -{ "AND": [ { "agent_id": "a1" }, { "run_id": "*" } ] } -``` - - -Excludes null run_id values - - -### Content and Text Filters - -**Search for text in user's memory content (case-insensitive)** - -```json -{ "AND": [ - { "user_id": "u1" }, - { "keywords": { "icontains": "pizza" } } -] } -``` - -**Search for text in user's memory content (case-sensitive)** - -```json -{ "AND": [ - { "user_id": "u1" }, - { "keywords": { "contains": "BudgetQ1" } } -] } -``` - -**User memories with specific categories** - -```json -{ "AND": [ - { "user_id": "u1" }, - { "categories": { "in": ["finance", "health"] } } -] } -``` - -**User memories with specific metadata** - -```json -{ "AND": [ - { "user_id": "u1" }, - { "metadata": { "foo": "bar" } } -] } -``` - -### Time-based Filters - -**Memories created after a specific date** - -```json -{ "AND": [ - { "user_id": "u1" }, - { "created_at": { "gt": "2025-01-01T00:00:00Z" } } -] } -``` - -**User memories within a date range** - -```json -{ "AND": [ - { "user_id": "u1" }, - { "created_at": { "gte": "2025-01-01T00:00:00Z" } }, - { "created_at": { "lt": "2025-02-01T00:00:00Z" } } -] } -``` - -**Memories updated within a time window** - -```json -{ "AND": [ - { "user_id": "u1" }, - { "updated_at": { "gte": "2025-05-01T00:00:00Z" } }, - { "updated_at": { "lte": "2025-05-31T23:59:59Z" } } -] } -``` - -### Advanced Filters - -**Memories from multiple users** - -```json -{ "AND": [ { "user_id": { "in": ["u1", "u2", "u3"] } } ] } -``` - - -**Memories from either user or run** - -```json -{ "OR": [ { "user_id": "u1" }, { "run_id": "run1" } ] } -``` - -**Memories that have both user and run (non-null)** - -```json -{ "AND": [ { "user_id": "*" }, { "run_id": "*" } ] } -``` - - -Excludes null user_id and run_id values - - -**User memories excluding specific categories** - -```json -{ "AND": [ - { "user_id": "u1" }, - { "NOT": { "categories": { "in": ["spam", "test"] } } } -] } -``` - -**User memories by specific IDs** - -```json -{ "AND": [ - { "user_id": "u1" }, - { "memory_ids": ["m1", "m2", "m3"] } -] } -``` - -**Complex filter: text + category + time** - -```json -{ "AND": [ - { "user_id": "u1" }, - { "keywords": { "icontains": "invoice" } }, - { "categories": { "in": ["finance"] } }, - { "created_at": { "gte": "2025-03-01T00:00:00Z" } } -] } -``` - -### Comprehensive Filters - -**All memories with non-null entities** - -```json -{ "AND": [ - { "user_id": "*" }, - { "agent_id": "*" }, - { "run_id": "*" }, - { "app_id": "*" } -] } -``` - - -Excludes null values for all entity fields - - -**All memories (including null entities)** - -```json -{ "OR": [ - { "user_id": "*" }, - { "agent_id": "*" }, - { "run_id": "*" }, - { "app_id": "*" } -] } -``` - ---- - -## Common Patterns - -**Single user memories** - -```json -{ "AND": [ { "user_id": "u1" } ] } -``` - -**User memories across all runs** - -```json -{ "AND": [ { "user_id": "u1" }, { "run_id": "*" } ] } -``` - - -Excludes null run_id values - - -**All user memories (no agent/app/run)** - -```json -{ "AND": [ { "user_id": "*" } ] } -``` - - -Excludes null user_id values - - -**Agent with specific users** - -```json -{ "AND": [ { "agent_id": "a1" }, { "user_id": { "in": ["u1", "u2"] } } ] } -``` - -**Search user's memory content (case-insensitive)** - -```json -{ "AND": [ - { "user_id": "u1" }, - { "keywords": { "icontains": "budget" } } -] } -``` - -**Memories within date range** - -```json -{ "AND": [ - { "user_id": "u1" }, - { "created_at": { "gte": "" } }, - { "created_at": { "lt": "" } } -] } -``` - -**Exclude specific categories** - -```json -{ "AND": [ - { "user_id": "u1" }, - { "NOT": { "categories": { "in": ["spam", "test"] } } } -] } -``` - -**Get user's specific memories by ID** - -```json -{ "AND": [ - { "user_id": "u1" }, - { "memory_ids": ["id1", "id2"] } -] } -``` - ---- +## Available fields and operators + +### Entity fields +| Field | Operators | Example | +|-------|-----------|---------| +| `user_id` | `=`, `!=`, `in`, `*` | `{"user_id": "user_123"}` | +| `agent_id` | `=`, `!=`, `in`, `*` | `{"agent_id": "*"}` | +| `app_id` | `=`, `!=`, `in`, `*` | `{"app_id": {"in": ["app1", "app2"]}}` | +| `run_id` | `=`, `!=`, `in`, `*` | `{"run_id": "*"}` | + +### Time fields +| Field | Operators | Example | +|-------|-----------|---------| +| `created_at` | `>`, `>=`, `<`, `<=`, `=`, `!=` | `{"created_at": {"gte": "2024-01-01"}}` | +| `updated_at` | `>`, `>=`, `<`, `<=`, `=`, `!=` | `{"updated_at": {"lt": "2024-12-31"}}` | +| `timestamp` | `>`, `>=`, `<`, `<=`, `=`, `!=` | `{"timestamp": {"gt": "2024-01-01"}}` | + +### Content fields +| Field | Operators | Example | +|-------|-----------|---------| +| `categories` | `=`, `!=`, `in`, `contains` | `{"categories": {"in": ["finance"]}}` | +| `metadata` | `=`, `!=` | `{"metadata": {"key": "value"}}` | +| `keywords` | `contains`, `icontains` | `{"keywords": {"icontains": "invoice"}}` | + +### Special fields +| Field | Operators | Example | +|-------|-----------|---------| +| `memory_ids` | `in` | `{"memory_ids": ["id1", "id2"]}` | + + +The `*` wildcard matches any non-null value. Records with null values for that field are excluded. + + +## Common filter patterns + +Use these ready-made filters to target typical retrieval scenarios without rebuilding logic from scratch. + + + + ```python + # Narrow to one user's memories + filters = {"AND": [{"user_id": "user_123"}]} + memories = client.get_all(filters=filters) + ``` + + + + ```python + # Wildcard skips null user_id entries + filters = {"AND": [{"user_id": "*"}]} + memories = client.get_all(filters=filters) + ``` + + + + ```python + # Pair a user filter with a run wildcard + filters = { + "AND": [ + {"user_id": "user_123"}, + {"run_id": "*"} + ] + } + memories = client.get_all(filters=filters) + ``` + + + +### Content search + +Find memories containing specific text, categories, or metadata values. + + + + ```python + # Case-insensitive match + filters = { + "AND": [ + {"user_id": "user_123"}, + {"keywords": {"icontains": "pizza"}} + ] + } + + # Case-sensitive match + filters = { + "AND": [ + {"user_id": "user_123"}, + {"keywords": {"contains": "Invoice_2024"}} + ] + } + ``` + + + + ```python + # Match against category list + filters = { + "AND": [ + {"user_id": "user_123"}, + {"categories": {"in": ["finance", "health"]}} + ] + } + + # Partial category match + filters = { + "AND": [ + {"user_id": "user_123"}, + {"categories": {"contains": "finance"}} + ] + } + ``` + + + + ```python + # Pin to a metadata attribute + filters = { + "AND": [ + {"user_id": "user_123"}, + {"metadata": {"source": "email"}} + ] + } + ``` + + + +### Time-based filtering + +Retrieve memories within specific date ranges using time operators. + + + + ```python + # Created in January 2024 + filters = { + "AND": [ + {"user_id": "user_123"}, + {"created_at": {"gte": "2024-01-01T00:00:00Z"}}, + {"created_at": {"lt": "2024-02-01T00:00:00Z"}} + ] + } + + # Updated recently + filters = { + "AND": [ + {"user_id": "user_123"}, + {"updated_at": {"gte": "2024-12-01T00:00:00Z"}} + ] + } + ``` + + + +### Multiple criteria + +Combine various filters for complex queries across different dimensions. + + + + ```python + # Expand scope to a short user list + filters = { + "AND": [ + {"user_id": {"in": ["user_1", "user_2", "user_3"]}} + ] + } + ``` + + + + ```python + # Return matches on either condition + filters = { + "OR": [ + {"user_id": "user_123"}, + {"run_id": "run_456"} + ] + } + ``` + + + + ```python + # Wrap negative logic with NOT + filters = { + "AND": [ + {"user_id": "user_123"}, + {"NOT": { + "categories": {"in": ["spam", "test"]} + }} + ] + } + ``` + + + + ```python + # Fetch a fixed set of memory IDs + filters = { + "AND": [ + {"user_id": "user_123"}, + {"memory_ids": ["mem_1", "mem_2", "mem_3"]} + ] + } + ``` + + + + ```python + # Require every entity field to be non-null + filters = { + "AND": [ + {"user_id": "*"}, + {"agent_id": "*"}, + {"run_id": "*"}, + {"app_id": "*"} + ] + } + ``` + + + +## Advanced examples + +Level up foundational patterns with compound filters that coordinate entity scope, tighten time windows, and weave in exclusion rules for high-precision retrievals. + + + + ```python + # Invoice memories in Q1 2024 + filters = { + "AND": [ + {"user_id": "user_123"}, + {"keywords": {"icontains": "invoice"}}, + {"categories": {"in": ["finance"]}}, + {"created_at": {"gte": "2024-01-01T00:00:00Z"}}, + {"created_at": {"lt": "2024-04-01T00:00:00Z"}} + ] + } + ``` + + + + ```python + # From specific agent, all users + filters = { + "AND": [ + {"agent_id": "finance_bot"}, + {"user_id": "*"} + ] + } + + # Any entity populated + filters = { + "OR": [ + {"user_id": "*"}, + {"agent_id": "*"}, + {"run_id": "*"}, + {"app_id": "*"} + ] + } + ``` + + + + ```python + # User memories from 2024, excluding spam and test + filters = { + "AND": [ + {"user_id": "user_123"}, + {"created_at": {"gte": "2024-01-01T00:00:00Z"}}, + {"NOT": { + "OR": [ + {"categories": {"in": ["spam"]}}, + {"categories": {"in": ["test"]}} + ] + }} + ] + } + ``` + + + +## Best practices + + +The root must be `AND`, `OR`, or `NOT` with an array of conditions. + + + +Use `"*"` to match any non-null value for a field. + + + +When you specify `user_id` only, other entity fields default to null. Use wildcards to include them. + ## Troubleshooting -### "I filtered by `user_id`, but I don't see items that have an `agent_id`." + + + **Problem**: Filtered by `user_id` but don't see agent memories. -This is the **implicit null-scoping** rule. When you write only `{ "user_id": "u1" }`, the system also enforces `agent_id = NULL`, `run_id = NULL`, `app_id = NULL`. If you want any agent, add `{ "agent_id": "*" }`. + **Solution**: Add a wildcard for `agent_id` so non-null entries return: + ```python + {"AND": [{"user_id": "user_123"}, {"agent_id": "*"}]} + ``` + -```json -{ "AND": [ { "user_id": "u1" }, { "agent_id": "*" } ] } -``` + + **Problem**: `ne` comparison pulls in records with null values. -### "My `ne` seems to return more than I expect." + **Solution**: Pair `ne` with a wildcard guard: + ```python + {"AND": [{"agent_id": "*"}, {"agent_id": {"ne": "old_agent"}}]} + ``` + -`ne` returns rows where the field is **not equal OR NULL**. If you need "not equal and **definitely present**", combine with a wildcard. + + **Solution**: Swap to `icontains` to normalize casing. + -```json -{ "AND": [ { "agent_id": "*" }, { "agent_id": { "ne": "a1" } } ] } -``` + + **Solution**: Use `gte` for the start and `lt` for the end boundary: + ```python + {"AND": [ + {"created_at": {"gte": "2024-01-01"}}, + {"created_at": {"lt": "2024-02-01"}} + ]} + ``` + -### "Case-insensitive search?" - -Use `icontains`. - -```json -{ "AND": [ { "keywords": { "icontains": "receipt" } } ] } -``` - -### "Between two dates?" - -Use `gte` and `lt` (or `lte`) together. - -```json -{ "AND": [ - { "user_id": "u1" }, - { "created_at": { "gte": "2025-01-01T00:00:00Z" } }, - { "created_at": { "lt": "2025-02-01T00:00:00Z" } } -] } -``` - -### "Complex logic with NOT" - -`NOT` can wrap a single condition or an array. Example: user `u1` but not category `spam` or `test`. - -```json -{ "AND": [ - { "user_id": "u1" }, - { "NOT": { "categories": { "in": ["spam", "test"] } } } -] } -``` - -### "Metadata matching isn't working." - -Ensure you match the **exact JSON shape** at the top level. - -```json -{ "AND": [ { "metadata": { "foo": "bar" } } ] } -``` - -### "I want all users, all agents, all runs." - -Be explicit with wildcards for **each** entity dimension. - -```json -{ "AND": [ { "user_id": "*" }, { "agent_id": "*" }, { "run_id": "*" } ] } -``` - ---- + + **Solution**: Match top-level metadata keys exactly: + ```python + {"metadata": {"source": "email"}} + ``` + + ## FAQ -**Q: Do I have to wrap my filter in `AND` or `OR`?** + + + Yes. The root must be a logical operator with an array. + -Yes. The root must be one of `AND`, `OR`, or `NOT`. + + Any non-null value. Nulls are excluded. + -**Q: What does the wildcard `"*"` match?** + + Unspecified fields default to NULL. Use `"*"` to include non-null values. + -Any **non-null** value for that field. + + No. Equality is the default: `{"user_id": "u1"}` works. + -**Q: Why are results "missing" unless I add wildcards?** + + Only top-level keys are supported. + -Because unspecified entity fields default to **`NULL`** due to restrictive scoping. + + Use `keywords` with `contains` (case-sensitive) or `icontains` (case-insensitive). + -**Q: Is `eq` required?** - -No—equality is the default. `{ "user_id": "u1" }` is enough. - -**Q: Does `ne` include NULLs?** - -Yes. Use `{ "field": "*" }` together with `ne` if you need "present and not equal". - -**Q: How do I search the memory text?** - -Use `keywords` with `contains` or `icontains`. - -**Q: Can I filter nested metadata keys?** - -Currently target **top-level** keys as shown: `{ "metadata": { "foo": "bar" } }`. \ No newline at end of file + + ```python + { + "AND": [ + {"user_id": "user_123"}, + {"OR": [ + {"categories": "finance"}, + {"categories": "health"} + ]} + ] + } + ``` + + diff --git a/docs/templates/feature_guide_template.mdx b/docs/templates/feature_guide_template.mdx index 9ed0a147d..a1644ef66 100644 --- a/docs/templates/feature_guide_template.mdx +++ b/docs/templates/feature_guide_template.mdx @@ -119,7 +119,7 @@ Walk through a real request/response. Include sample payloads and highlight nota ## Best practices - Keep criteria minimal—overfiltering hurts recall. -- Pair with Memory Filters v2 for hybrid scoring. +- Pair with Memory Filters for hybrid scoring. {/* DEBUG: verify CTA targets */}