|
|
|
@@ -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>
|
|
|
|
|