[docs] Minor Docs fixes ( enhancements , restructure ) (#3748)

This commit is contained in:
Parth Sharma
2025-11-13 11:58:36 -08:00
committed by GitHub
parent 3297ec1a46
commit 2bca30ebe6
10 changed files with 507 additions and 506 deletions
+6 -2
View File
@@ -75,14 +75,18 @@ await client.search("What is Alice's favorite sport?", { user_id: "alice" });
Retrieve all memories for a user asynchronously.
<Callout type="warning" title="Filters Required">
`get_all()` now requires filters to be specified.
</Callout>
<CodeGroup>
```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"}]} });
```
</CodeGroup>
@@ -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"}]} });
```
</CodeGroup>
@@ -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:
+5 -1
View File
@@ -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.
<Callout type="warning" title="Filters Required">
`get_all()` now requires filters to be specified.
</Callout>
<CodeGroup>
```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
+6 -2
View File
@@ -187,12 +187,16 @@ console.log(results);
When retrieving all memories, Graph Memory provides additional relationship context:
<Callout type="warning" title="Filters Required">
`get_all()` now requires filters to be specified.
</Callout>
<CodeGroup>
```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
});
+389 -488
View File
@@ -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
<Callout type="info" icon="info-circle" color="#7A5DFF">
Filters were introduced in v1.0.0 to provide precise control over memory retrieval.
</Callout>
## 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": "*" }
]
}
```
<Note>
Excludes null run_id values
</Note>
---
## 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.
<Note>
Asterisks (`*`) exclude null values - only non-null fields will be matched
</Note>
```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": "*" } ] }
```
<Note>
Excludes null user_id values
</Note>
**User memories across all runs**
```json
{ "AND": [ { "user_id": "u1" }, { "run_id": "*" } ] }
```
<Note>
Excludes null run_id values
</Note>
**All memories for a specific agent**
```json
{ "AND": [ { "agent_id": "a1" } ] }
```
**Agent memories across all runs**
```json
{ "AND": [ { "agent_id": "a1" }, { "run_id": "*" } ] }
```
<Note>
Excludes null run_id values
</Note>
### 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": "*" } ] }
```
<Note>
Excludes null user_id and run_id values
</Note>
**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": "*" }
] }
```
<Note>
Excludes null values for all entity fields
</Note>
**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": "*" } ] }
```
<Note>
Excludes null run_id values
</Note>
**All user memories (no agent/app/run)**
```json
{ "AND": [ { "user_id": "*" } ] }
```
<Note>
Excludes null user_id values
</Note>
**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": "<from>" } },
{ "created_at": { "lt": "<to>" } }
] }
```
**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"]}` |
<Callout type="warning" icon="exclamation-triangle" color="#F7B731">
The `*` wildcard matches any non-null value. Records with null values for that field are excluded.
</Callout>
## Common filter patterns
Use these ready-made filters to target typical retrieval scenarios without rebuilding logic from scratch.
<AccordionGroup>
<Accordion title="Single user">
```python
# Narrow to one user's memories
filters = {"AND": [{"user_id": "user_123"}]}
memories = client.get_all(filters=filters)
```
</Accordion>
<Accordion title="All users">
```python
# Wildcard skips null user_id entries
filters = {"AND": [{"user_id": "*"}]}
memories = client.get_all(filters=filters)
```
</Accordion>
<Accordion title="User across all runs">
```python
# Pair a user filter with a run wildcard
filters = {
"AND": [
{"user_id": "user_123"},
{"run_id": "*"}
]
}
memories = client.get_all(filters=filters)
```
</Accordion>
</AccordionGroup>
### Content search
Find memories containing specific text, categories, or metadata values.
<AccordionGroup>
<Accordion title="Text search">
```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"}}
]
}
```
</Accordion>
<Accordion title="Categories">
```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"}}
]
}
```
</Accordion>
<Accordion title="Metadata">
```python
# Pin to a metadata attribute
filters = {
"AND": [
{"user_id": "user_123"},
{"metadata": {"source": "email"}}
]
}
```
</Accordion>
</AccordionGroup>
### Time-based filtering
Retrieve memories within specific date ranges using time operators.
<AccordionGroup>
<Accordion title="Date range">
```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"}}
]
}
```
</Accordion>
</AccordionGroup>
### Multiple criteria
Combine various filters for complex queries across different dimensions.
<AccordionGroup>
<Accordion title="Multiple users">
```python
# Expand scope to a short user list
filters = {
"AND": [
{"user_id": {"in": ["user_1", "user_2", "user_3"]}}
]
}
```
</Accordion>
<Accordion title="OR logic">
```python
# Return matches on either condition
filters = {
"OR": [
{"user_id": "user_123"},
{"run_id": "run_456"}
]
}
```
</Accordion>
<Accordion title="Exclude categories">
```python
# Wrap negative logic with NOT
filters = {
"AND": [
{"user_id": "user_123"},
{"NOT": {
"categories": {"in": ["spam", "test"]}
}}
]
}
```
</Accordion>
<Accordion title="Specific memory IDs">
```python
# Fetch a fixed set of memory IDs
filters = {
"AND": [
{"user_id": "user_123"},
{"memory_ids": ["mem_1", "mem_2", "mem_3"]}
]
}
```
</Accordion>
<Accordion title="All entities populated">
```python
# Require every entity field to be non-null
filters = {
"AND": [
{"user_id": "*"},
{"agent_id": "*"},
{"run_id": "*"},
{"app_id": "*"}
]
}
```
</Accordion>
</AccordionGroup>
## 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.
<AccordionGroup>
<Accordion title="Multi-dimensional filtering">
```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"}}
]
}
```
</Accordion>
<Accordion title="Cross-entity relationships">
```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": "*"}
]
}
```
</Accordion>
<Accordion title="Nested NOT/OR logic">
```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"]}}
]
}}
]
}
```
</Accordion>
</AccordionGroup>
## Best practices
<Callout type="tip" icon="lightbulb" color="#26A17B">
The root must be `AND`, `OR`, or `NOT` with an array of conditions.
</Callout>
<Callout type="tip" icon="lightbulb" color="#26A17B">
Use `"*"` to match any non-null value for a field.
</Callout>
<Callout type="warning" icon="exclamation-triangle" color="#E74C3C">
When you specify `user_id` only, other entity fields default to null. Use wildcards to include them.
</Callout>
## Troubleshooting
### "I filtered by `user_id`, but I don't see items that have an `agent_id`."
<AccordionGroup>
<Accordion title="Missing results with 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": "*"}]}
```
</Accordion>
```json
{ "AND": [ { "user_id": "u1" }, { "agent_id": "*" } ] }
```
<Accordion title="ne operator returns too much">
**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"}}]}
```
</Accordion>
`ne` returns rows where the field is **not equal OR NULL**. If you need "not equal and **definitely present**", combine with a wildcard.
<Accordion title="Case-insensitive search">
**Solution**: Swap to `icontains` to normalize casing.
</Accordion>
```json
{ "AND": [ { "agent_id": "*" }, { "agent_id": { "ne": "a1" } } ] }
```
<Accordion title="Date range between two dates">
**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"}}
]}
```
</Accordion>
### "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": "*" } ] }
```
---
<Accordion title="Metadata filter not working">
**Solution**: Match top-level metadata keys exactly:
```python
{"metadata": {"source": "email"}}
```
</Accordion>
</AccordionGroup>
## FAQ
**Q: Do I have to wrap my filter in `AND` or `OR`?**
<AccordionGroup>
<Accordion title="Do I need AND/OR/NOT?">
Yes. The root must be a logical operator with an array.
</Accordion>
Yes. The root must be one of `AND`, `OR`, or `NOT`.
<Accordion title="What does * match?">
Any non-null value. Nulls are excluded.
</Accordion>
**Q: What does the wildcard `"*"` match?**
<Accordion title="Why use wildcards?">
Unspecified fields default to NULL. Use `"*"` to include non-null values.
</Accordion>
Any **non-null** value for that field.
<Accordion title="Is = required?">
No. Equality is the default: `{"user_id": "u1"}` works.
</Accordion>
**Q: Why are results "missing" unless I add wildcards?**
<Accordion title="Can I filter nested metadata?">
Only top-level keys are supported.
</Accordion>
Because unspecified entity fields default to **`NULL`** due to restrictive scoping.
<Accordion title="How to search text?">
Use `keywords` with `contains` (case-sensitive) or `icontains` (case-insensitive).
</Accordion>
**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" } }`.
<Accordion title="Can I nest AND/OR?">
```python
{
"AND": [
{"user_id": "user_123"},
{"OR": [
{"categories": "finance"},
{"categories": "health"}
]}
]
}
```
</Accordion>
</AccordionGroup>