Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ Some IDs come from your application; others come from Redis Agent Memory:
| Session `ownerId` | The server copies it from the first event's `actorId`. | There is no separate `ownerId` input on a session-event request. Later actors do not change the session owner. |
| Long-term memory `ownerId` | Your application for direct creation; extraction inherits the session owner. | Use the current user's stable ID for personal memories and owner filters. |
| `eventId` | The server. | Save it from the event response if you need to refer to that event. |
| Long-term memory `id` | Your application for direct creation; the server during extraction. | Supply a stable record ID when creating a memory directly. |
| `namespaceId` | The server when it creates a namespace. | Save it and use it in `namespaceRef`. Supply the user's `ownerId` when creating a personal namespace. |
| Long-term memory `memoryId` | Your application for direct creation; the server during extraction. | Supply a stable record ID when creating a memory directly. |
| `namespaceId` | The server when it creates a namespace. | Save it and send it as `namespaceId`. Supply the user's `ownerId` when creating a personal namespace. |
| Event `createdAt` | Your application. | Send when the message occurred; it is a required event input. |
| Event `systemTimestamp` | The server. | Records when the event was stored. |
| Memory `createdAt` and `updatedAt` | The server. | Use the returned timestamps when displaying or sorting memories. |
Expand All @@ -57,13 +57,13 @@ For on-prem deployments, see [Server-side ownership enforcement](/content/operat

Your application must decide which memories the user can access. Put these checks in trusted backend code before sending a request to Redis Agent Memory. Store access alone does not restrict a caller to one user's memories. Cloud store credentials also require these application checks; a Redis Cloud account user is not your application's end user.

* For personal searches, set the `ownerId` filter from the authenticated user's ID. For session listing, use `filterOwnerId`. A request from `user-42` must not be able to select `user-99` as its owner.
* For personal searches, set the `ownerId` filter from the authenticated user's ID. For session listing, use `ownerId`. A request from `user-42` must not be able to select `user-99` as its owner.
* For shared memories, check which shared namespaces that user can access, then restrict the query to those namespace IDs. Do not add a personal owner filter to that shared query: it would hide shared memories written by other users.
* For requests that retrieve or change a record by ID, check that the record belongs to the user or to a shared namespace they can access. These endpoints do not all accept an owner filter; a session or memory ID is not proof of permission.

Use the authenticated user on every request to choose the owner filter or the permitted shared namespaces. Search filters limit results; they do not authenticate the user. For examples, see [Namespaces](/content/develop/ai/context-engine/agent-memory/namespaces/_index.md).

Keep mandatory owner restrictions separate from optional search conditions. Combining an owner and another filter with `filterOp: "any"` matches either condition; it does not require the owner to match. `includeAll` on a list request is also a selection option, not permission to enumerate a store.
Keep mandatory owner restrictions separate from optional search conditions. Combining an owner and another filter with `op: "ANY"` matches either condition; it does not require the owner to match. `includeAll` on a list request is also a selection option, not permission to enumerate a store.

## Build context for each agent turn

Expand Down Expand Up @@ -183,7 +183,7 @@ The ingestion-hook `503` retry error and `422` stopped error also have distinct

Create memories directly when your application already has information to store, such as a preference submitted through a form. Set the owner and a stable record ID. Creating an eligible record with the same ID again replaces it; access checks and protection for document-managed records still apply. Check the bulk response for per-record errors. Direct creation does not apply automatic extraction or sensitive-data exclusions.

See [Long-term memory]({{< relref "/develop/ai/context-engine/agent-memory/long-term-memory" >}}) for creation methods, search fields, retention, and extraction controls.
See [Long-term memory]({{< relref "/develop/ai/context-engine/agent-memory/memories" >}}) for creation methods, search fields, retention, and extraction controls.

For unstructured documents, use [MemoryETL](/content/develop/ai/context-engine/agent-memory/memory-etl.md) to configure an extractor, submit a revision, and track its outputs. Source links let you trace extracted memories back to document or session inputs.

Expand All @@ -203,7 +203,7 @@ See [Custom memory types]({{< relref "/develop/ai/context-engine/agent-memory/lo

Namespaces are optional. Add them when your application needs to group conversations and memories by user, project, or team.

For example, create a personal `travel` namespace and save its `namespaceId`. Use that ID in `namespaceRef` when starting a session or creating long-term memories. You will also use this ID to search for memories in that namespace. Names and paths can change when you rename a namespace, but its ID stays the same.
For example, create a personal `travel` namespace and save its `namespaceId`. Use that ID as `namespaceId` when starting a session or creating long-term memories. You will also use this ID to search for memories in that namespace. Names and paths can change when you rename a namespace, but its ID stays the same.

See [Namespaces]({{< relref "/develop/ai/context-engine/agent-memory/namespaces" >}}) for hierarchy, placement, search filters, and management.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ A document-input transform replaces its decoded text:
| `session.append` | `actorId`, `role`, `content`, `createdAt`, and `metadata`. Session identity, owner, and placement stay fixed. |
| `memory.create` | Editable text, type, session, owner, namespace placement, topics, and attributes. Record count, order, and IDs stay fixed. |

Do not supply both `namespace` and `namespaceRef`. Transformed records must still pass authorization and validation.
Use `namespaceId` for namespace placement. Transformed records must still pass authorization and validation.

For `memory.create`, `session.builtin`, `session.custom`, and `document.chunk`, `decision: review` can decide each operation separately:

Expand Down Expand Up @@ -221,12 +221,12 @@ export HOOK_TEST_MEMORY_ID="hook-test-$(openssl rand -hex 12)"
export HOOK_TEST_REQUEST_ID="hook-request-$(openssl rand -hex 12)"
jq -n --arg id "$HOOK_TEST_MEMORY_ID" --arg owner "$OWNER_ID" \
--arg key "$HOOK_TEST_REQUEST_ID" \
'{idempotencyKey:$key,memories:[{id:$id,ownerId:$owner,text:"[reject] synthetic webhook test"}]}' > hook-test.json
'{idempotencyKey:$key,memories:[{memoryId:$id,ownerId:$owner,text:"[reject] synthetic webhook test"}]}' > hook-test.json
curl --fail-with-body --silent --show-error --request POST \
--header "Authorization: Bearer $API_KEY" \
--header "X-Iris-User-Token: ${USER_TOKEN:-}" \
--header 'Content-Type: application/json' --data @hook-test.json \
"$AGENT_MEMORY_URL/v1/stores/$STORE_ID/long-term-memory" | jq
"$AGENT_MEMORY_URL/iris/data/v1/agent-memory/stores/$STORE_ID/memories" | jq
```

With `memory.create` selected, inspect the per-record result and verify that the rejected record was not created. Use a new key for changed input; editing `hook-test.json` under the same key conflicts.
Expand Down Expand Up @@ -325,16 +325,16 @@ if [ -n "${HOOK_EVENT_ID:-}" ]; then
curl --fail-with-body --silent --show-error \
--header "Authorization: Bearer $API_KEY" \
--header "X-Iris-User-Token: ${USER_TOKEN:-}" \
"$AGENT_MEMORY_URL/v1/stores/$STORE_ID/ingestion-hooks/events/$HOOK_EVENT_ID" | jq
"$AGENT_MEMORY_URL/iris/data/v1/agent-memory/stores/$STORE_ID/ingestion-hook-events/$HOOK_EVENT_ID" | jq
else
cursor=''
while :; do
page=$(curl --fail-with-body --silent --show-error --get \
--header "Authorization: Bearer $API_KEY" \
--header "X-Iris-User-Token: ${USER_TOKEN:-}" \
--data-urlencode 'limit=20' --data-urlencode "cursor=$cursor" \
"$AGENT_MEMORY_URL/v1/stores/$STORE_ID/ingestion-hooks/events") || exit 1
printf '%s\n' "$page" | jq .statuses
"$AGENT_MEMORY_URL/iris/data/v1/agent-memory/stores/$STORE_ID/ingestion-hook-events") || exit 1
printf '%s\n' "$page" | jq .items
cursor=$(printf '%s' "$page" | jq -r '.nextCursor // empty')
[ -n "$cursor" ] || break
done
Expand Down
47 changes: 23 additions & 24 deletions content/develop/ai/context-engine/agent-memory/long-term-memory.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,18 @@ See [memory configuration]({{< relref "/operate/iris/agent-memory/create-service

## Memory fields

When you create a memory directly, you must supply `id`, `text`, and `ownerId`. The server sets `createdAt` and `updatedAt`. During automatic extraction, the server creates the memory ID and content and copies the session owner into `ownerId`. Use that same stable user ID when querying personal memories; see [Authorize every memory request](/content/develop/ai/context-engine/agent-memory/developer-guide.md#authorize-every-memory-request).
When you create a memory directly, you must supply `memoryId`, `text`, and `ownerId`. The server sets `createdAt` and `updatedAt`. During automatic extraction, the server creates the memory ID and content and copies the session owner into `ownerId`. Use that same stable user ID when querying personal memories; see [Authorize every memory request](/content/develop/ai/context-engine/agent-memory/developer-guide.md#authorize-every-memory-request).

A long-term memory record includes:

| Field | Purpose |
|:------|:--------|
| `id` | Unique identifier for the memory. |
| `memoryId` | Unique identifier for the memory. |
| `text` | Memory content used for retrieval. |
| `memoryType` | Built-in or custom memory type. |
| `sessionId` | Session associated with the memory. |
| `ownerId` | User or entity associated with the memory. |
| `namespaceRef` | Optional namespace ID and its current name and path. |
| `namespaceId` | Optional stable namespace ID. |
| `attributes` | Custom memory fields and their values. |
| `topics` | Topic tags used to categorize the memory. |
| `createdAt` | Time the memory was created. |
Expand All @@ -65,9 +65,9 @@ curl --fail-with-body --silent --show-error \
--header "Authorization: Bearer $API_KEY" \
--header 'Content-Type: application/json' \
--data @- \
"$AGENT_MEMORY_URL/v1/stores/$STORE_ID/long-term-memory/search" <<JSON | jq
"$AGENT_MEMORY_URL/iris/data/v1/agent-memory/stores/$STORE_ID/memories/search" <<JSON | jq
{
"text": "What dietary requirements and food preferences does the user have?",
"query": "What dietary requirements and food preferences does the user have?",
"filter": {
"ownerId": {
"eq": "$OWNER_ID"
Expand All @@ -80,7 +80,7 @@ JSON

### Filter and sort without semantic search

Omit `text` to retrieve records by filters without a semantic query. For example, retrieve the user's most recently updated memories:
Omit `query` to retrieve records by filters without a semantic query. For example, retrieve the user's most recently updated memories:

{{< multitabs id="filter-only-memory-search" tab1="Python" tab2="TypeScript" tab3="curl" >}}

Expand Down Expand Up @@ -112,30 +112,30 @@ curl --fail-with-body --silent --show-error \
--header "Authorization: Bearer $API_KEY" \
--header 'Content-Type: application/json' \
--data "$(jq -n --arg owner "$OWNER_ID" \
'{filter: {ownerId: {eq: $owner}}, sortBy: "updatedAt", sortOrder: "desc", limit: 10}')" \
"$AGENT_MEMORY_URL/v1/stores/$STORE_ID/long-term-memory/search" | jq
'{filter: {ownerId: {eq: $owner}}, sortBy: "updatedAt", sortOrder: "DESC", limit: 10}')" \
"$AGENT_MEMORY_URL/iris/data/v1/agent-memory/stores/$STORE_ID/memories/search" | jq
```

{{< /multitabs >}}

Use the client and identifiers from the [quickstart](/content/develop/ai/context-engine/agent-memory/quickstart.md). Add the Python snippet inside the `with` block and the TypeScript snippet inside `run`.

`sortBy` accepts `createdAt` or `updatedAt` only when `text` is absent. `sortOrder` accepts `asc` or `desc`, defaults to `desc`, and requires `sortBy`. Semantic searches remain ranked by similarity and cannot use these sort fields. `limit` accepts 1–100 and defaults to 10. Pass `nextPageToken` as `pageToken` with the same query to continue.
`sortBy` accepts `createdAt` or `updatedAt` only when `query` is absent. `sortOrder` accepts `ASC` or `DESC`, defaults to descending, and requires `sortBy`. Semantic searches remain ranked by similarity and cannot use these sort fields. `limit` accepts 1–100 and defaults to 50. Pass `nextCursor` as `cursor` with the same query to continue.

Top-level filters use `filterOp: "all"` (AND) by default; `"any"` uses OR. To restrict a query to a user, keep the owner condition mandatory. Do not use `"any"` with separate owner and namespace conditions when both must match. These retrieval filters do not replace application access checks.
Filter conditions use `filter.op: "ALL"` (AND) by default; `"ANY"` uses OR. To restrict a query to a user, keep the owner condition mandatory. Do not use `"ANY"` with separate owner and namespace conditions when both must match. These retrieval filters do not replace application access checks.

Set `filter.unnamespaced: true` to match records with neither the older `namespace` string label nor a namespace resource. It cannot be combined with `namespace` or `namespaceRef`, and remains mandatory even with `filterOp: "any"`.
Set `filter.unnamespaced: true` to match records with neither the older `namespace` string label nor a namespace resource. It cannot be combined with `namespaceId`, and remains mandatory even with `op: "ANY"`.

[MemoryETL](/content/develop/ai/context-engine/agent-memory/memory-etl.md) outputs are included in search by default. Set top-level `excludeDocumentManaged: true` to omit them. Returned `documentManaged` records cannot be overwritten through generic memory creation or PATCH requests; use the document-ingestion workflow to manage their content.

For custom fields, use `filter.attributes`, keyed by the field name, with the operators described in [`AttributeFilterClause`](/content/develop/ai/context-engine/agent-memory/api-reference.md#operation/SearchLongTermMemory). Combine it with `memoryType` to select the registered custom type.

For example, this search request combines the owner, type, and dietary requirement with `filterOp: "all"`. A `list` clause requires every listed value to be present:
For example, this search request combines the owner, type, and dietary requirement with `op: "ALL"`. A `list` clause requires every listed value to be present:

```json
{
"filterOp": "all",
"filter": {
"op": "ALL",
"ownerId": {"eq": "<user-id>"},
"memoryType": {"eq": "trip_preference"},
"attributes": {"dietary_requirements": {"list": ["vegetarian"]}}
Expand Down Expand Up @@ -215,8 +215,8 @@ curl --fail-with-body --silent --show-error --request POST \
--header "Authorization: Bearer $API_KEY" \
--header 'Content-Type: application/json' \
--data "$(jq -n --arg owner "$OWNER_ID" --arg now "$(date -u +'%Y-%m-%dT%H:%M:%SZ')" \
'{sessionId:"trip-preference-session",actorId:$owner,role:"USER",content:[{text:"I am visiting Tokyo and Kyoto next month. I am vegetarian."}],createdAt:$now}')" \
"$AGENT_MEMORY_URL/v1/stores/$STORE_ID/session-memory/events" | jq
'{actorId:$owner,role:"USER",content:[{text:"I am visiting Tokyo and Kyoto next month. I am vegetarian."}],createdAt:$now}')" \
"$AGENT_MEMORY_URL/iris/data/v1/agent-memory/stores/$STORE_ID/sessions/trip-preference-session/events" | jq
```

{{< /multitabs >}}
Expand Down Expand Up @@ -262,9 +262,9 @@ curl --fail-with-body --silent --show-error \
--header "Authorization: Bearer $API_KEY" \
--header 'Content-Type: application/json' \
--data @- \
"$AGENT_MEMORY_URL/v1/stores/$STORE_ID/long-term-memory/search" <<JSON | jq
"$AGENT_MEMORY_URL/iris/data/v1/agent-memory/stores/$STORE_ID/memories/search" <<JSON | jq
{
"text": "What are the requirements for the user's trip?",
"query": "What are the requirements for the user's trip?",
"filter": {
"ownerId": {
"eq": "$OWNER_ID"
Expand Down Expand Up @@ -357,7 +357,7 @@ If your application already has structured trip data, write it directly using th

```python
direct_result = agent_memory.bulk_create_long_term_memories(memories=[{
"id": "trip-form-1",
"memoryId": "trip-form-1",
"text": "The user plans to visit Tokyo and Kyoto next month and requires vegetarian food.",
"owner_id": USER_ID,
"memory_type": "trip_preference",
Expand Down Expand Up @@ -399,10 +399,10 @@ curl --fail-with-body --silent --show-error \
--header "Authorization: Bearer $API_KEY" \
--header 'Content-Type: application/json' \
--data @- \
"$AGENT_MEMORY_URL/v1/stores/$STORE_ID/long-term-memory" <<JSON | jq
"$AGENT_MEMORY_URL/iris/data/v1/agent-memory/stores/$STORE_ID/memories" <<JSON | jq
{
"memories": [{
"id": "trip-form-1",
"memoryId": "trip-form-1",
"text": "The user plans to visit Tokyo and Kyoto next month and requires vegetarian food.",
"ownerId": "$OWNER_ID",
"memoryType": "trip_preference",
Expand Down Expand Up @@ -479,9 +479,8 @@ curl --fail-with-body --silent --show-error \
--header "Authorization: Bearer $API_KEY" \
--header 'Content-Type: application/json' \
--data @- \
"$AGENT_MEMORY_URL/v1/stores/$STORE_ID/session-memory/events" <<JSON | jq
"$AGENT_MEMORY_URL/iris/data/v1/agent-memory/stores/$STORE_ID/sessions/$SESSION_ID/events" <<JSON | jq
{
"sessionId": "$SESSION_ID",
"actorId": "$OWNER_ID",
"role": "USER",
"content": [
Expand Down Expand Up @@ -535,9 +534,9 @@ curl --fail-with-body --silent --show-error \
--header "Authorization: Bearer $API_KEY" \
--header 'Content-Type: application/json' \
--data @- \
"$AGENT_MEMORY_URL/v1/stores/$STORE_ID/long-term-memory/search" <<JSON | jq
"$AGENT_MEMORY_URL/iris/data/v1/agent-memory/stores/$STORE_ID/memories/search" <<JSON | jq
{
"text": "Where is the user staying in Tokyo?",
"query": "Where is the user staying in Tokyo?",
"filter": {
"ownerId": {
"eq": "$OWNER_ID"
Expand Down
Loading
Loading