Collections and memories both accept a metadata object — arbitrary structured
attributes you attach at write time and read back on every response.
{
"memory_id": "018f3c2a-7e19-7f04-b3d6-2a9c5e81f742",
"content": { "kind": "text", "text": "Customer reported slow exports." },
"metadata": { "source": "zendesk", "priority": 2, "escalated": false }
}Values may be strings, numbers or booleans. Nested objects and arrays are not accepted.
Limits
| Limit | Value |
|---|---|
| Keys per object | 64 |
| Key length | 64 UTF-8 bytes |
| String value length | 1024 UTF-8 bytes |
| Whole object, canonical JSON | 32768 bytes |
Exceeding any of these fails with
invalid_request.
Filtering is not available
The v1 API accepted a filter DSL ($eq, $gte, $in, $contains, $and) on
search. That capability is not part of the initial public v2 surface, and there
is no equivalent to migrate to. Until it returns:
- Partition with collections. Search runs inside exactly one collection, so splitting by tenant, source or time gives you the same isolation a filter would — enforced by the API rather than by a query clause.
- Filter after retrieval. Every hit in the response's
dataarray carriesmemory_id; fetch withmemory.getand apply your own predicate to the returnedmetadata. This costs a round trip per hit and cannot restore results retrieval never returned, so prefer partitioning when the attribute is known in advance.
Metadata remains useful without filtering: it round-trips intact, so it is the right place for provenance, external ids and anything your application needs alongside a result.