Sessions

Add and retrieve conversation events, configure retention, and summarize older messages.

Session memory holds a conversation's transcript. Your application saves each message as an event, then retrieves the transcript when the user sends the next message. This gives the agent the history it needs to continue the conversation.

For example, a travel assistant can retrieve the cities a user mentioned earlier in the chat instead of asking again. Each chat has a session ID (sessionId) that ties its events together. The same ID lets your application retrieve the conversation later.

This page covers adding events, retrieving a conversation, and finding session IDs by owner or namespace. It also explains two settings that control the history: retention determines how long a session stays available, and summarization condenses older messages so they take less space in the model's context window.

Add session events

A session event represents one message from a user, assistant, or system. To append one, send POST /iris/data/v1/agent-memory/stores/{storeId}/sessions/{sessionId}/events, which creates the session if it does not exist. In Python, memory.conversation(owner=..., session_id=...) returns a conversation whose user and assistant methods append events. To start a session with a server-generated ID, send its first event to POST /iris/data/v1/agent-memory/stores/{storeId}/sessions instead. In Python, omit session_id and the SDK generates one; read it from conversation.session_id.

Redis Agent Memory adds the event ID and storage timestamp. The event fields are:

Field Who supplies it Purpose
eventId Server-generated. Identifies the event.
sessionId Client-supplied in the path, or server-generated when you create a session without one. Identifies the session that contains the event.
actorId Required from the client. Identifies the user, agent, or other actor that produced the event.
role Required from the client. Role of the message in the conversation.
content Required from the client. Message content, including its text.
createdAt Required from the client. Time the event occurred in the application.
systemTimestamp Server-generated. Time Redis Agent Memory stored the event.
metadata Optional from the client. Application-specific information associated with the event.
  1. Set the first event's actorId to the signed-in user's account ID from your application. Use the same ID each time this user returns. The server uses it as the session owner. Later events can identify other actors, such as the assistant. In Python, conversation.user sends the owner as actorId, and conversation.assistant sends the assistant_id passed to AgentMemory.from_env().
  2. Supply a sessionId, or omit it to let the server create one. Save the returned event.sessionId for later requests. See Identify users and conversations for examples.
  3. Set the message's role, content, and createdAt timestamp.
  4. Send the request.

These examples continue from the quickstart. Load the same .env connection values and reuse its user ID. Expand an example to copy a complete program that connects for you.

Each run repeats every write in the program. Session-event writes and memory creates with a new idempotency key add new records, so run cleanup or change the identifiers before rerunning.

conversation = memory.conversation(owner=OWNER_ID, session_id=SESSION_ID)
saved = conversation.user("I am vegetarian.")
print("Saved event", saved.event_id, "in", saved.session_id)
jq -n --arg owner "$OWNER_ID" --arg now "$(date -u +%Y-%m-%dT%H:%M:%SZ)" --arg key "$(uuidgen)" '{
  actorId: $owner,
  role: "USER",
  content: [{text: "I am vegetarian."}],
  createdAt: $now,
  idempotencyKey: $key
}' > event.json
curl --fail-with-body --silent --show-error \
  -X POST "$MEMORY_API/sessions/$SESSION_ID/events" -H "$AUTH" \
  -H 'Content-Type: application/json' --data-binary @event.json | jq .

Send each new message once, using the same session ID throughout the conversation.

The session's ownerId comes from the first event's actorId and is returned when you retrieve the session. In on-prem deployments with server-side ownership enforcement, the first event's actorId must match the authenticated user ID.

Retrieve conversation context

When the next message arrives, retrieve the session by its ID before calling the model:

transcript = conversation.transcript()
if transcript.owner != OWNER_ID:
    raise PermissionError("This session belongs to another user.")
print("Summary:", transcript.summary)
for event in transcript.events:
    print(event.role, event.actor_id, event.text)
curl --fail-with-body --silent --show-error \
  "$MEMORY_API/sessions/$SESSION_ID" -H "$AUTH" |
  jq '{ownerId, summary: .summary.text, events: [.events[] | {role, actorId, content}]}'
iris agent-memory sessions show travel-planning-session

The events array contains the retained conversation messages. If older events have been summarized, the response also includes summary.text. Pass both to the model with the current user message; in Python, transcript.as_messages() returns them as chat messages. See Build context for each agent turn for an example.

Your application must check that the current user can access this session before using it. The request selects a session by ID; it does not include an owner filter. Compare the returned ownerId (transcript.owner in Python) with the authenticated user, as the example does.

List sessions

To let a user reopen an earlier conversation, list their sessions and retrieve the selected session by ID. Use GET /iris/data/v1/agent-memory/stores/{storeId}/sessions, memory.sessions(owner) or memory.client.list_sessions in Python, or iris agent-memory sessions list. These rows do not contain events or generated summary text. See List and sort sessions for SDK examples and pagination.

Filter the list by owner or namespace.

For a user's personal conversations, set ownerId to that user's authenticated ID. A namespace-only query is suitable for shared conversations only after your application checks access to that namespace. Reserve includeAll=true for callers your application authorizes to list the whole store. See Authorize every memory request.

To list one user's session IDs:

for session_id in memory.sessions(OWNER_ID):
    print(session_id)
curl --fail-with-body --silent --show-error --get \
  "$MEMORY_API/sessions" -H "$AUTH" \
  --data-urlencode "ownerId=$OWNER_ID" | jq '.items[].sessionId'
iris agent-memory sessions list --owner quickstart-user

To list sessions in one namespace, filter by its stable ID. This example creates a personal namespace, starts a session in it, and lists that namespace's sessions. In an application, create the namespace once and save its ID.

created = memory.client.create_namespace(
    request={
        "name": "example-travel",
        "scope": models.NamespaceScope.PERSONAL,
        "owner_id": OWNER_ID,
    }
)
NAMESPACE_ID = created.namespace.namespace_id

trip = memory.conversation(
    owner=OWNER_ID, session_id="example-kyoto-trip", namespace_id=NAMESPACE_ID
)
trip.user("Plan two days in Kyoto.")

page = memory.client.list_sessions(namespace_id=NAMESPACE_ID)
for session in page.items:
    print(session.session_id, session.owner_id, session.namespace_id)
jq -n --arg owner "$OWNER_ID" \
  '{name: "example-travel", scope: "PERSONAL", ownerId: $owner}' > namespace.json
NAMESPACE_ID=$(curl --fail-with-body --silent --show-error \
  -X POST "$MEMORY_API/namespaces" -H "$AUTH" \
  -H 'Content-Type: application/json' --data-binary @namespace.json |
  jq -r '.namespace.namespaceId')

jq -n --arg owner "$OWNER_ID" --arg ns "$NAMESPACE_ID" \
  --arg now "$(date -u +%Y-%m-%dT%H:%M:%SZ)" --arg key "$(uuidgen)" '{
  actorId: $owner,
  role: "USER",
  content: [{text: "Plan two days in Kyoto."}],
  createdAt: $now,
  namespaceId: $ns,
  idempotencyKey: $key
}' > trip.json
curl --fail-with-body --silent --show-error \
  -X POST "$MEMORY_API/sessions/example-kyoto-trip/events" -H "$AUTH" \
  -H 'Content-Type: application/json' --data-binary @trip.json > /dev/null

curl --fail-with-body --silent --show-error --get \
  "$MEMORY_API/sessions" -H "$AUTH" \
  --data-urlencode "namespaceId=$NAMESPACE_ID" | jq '.items'

namespaceId matches the namespace ID exactly, including case. It excludes descendant namespaces, sessions with only the older namespace string label, and sessions without a namespace resource.

Add ownerId to return sessions that match both the namespace and the owner:

page = memory.client.list_sessions(namespace_id=NAMESPACE_ID, owner_id=OWNER_ID)
for session in page.items:
    print(session.session_id, session.updated_at)
curl --fail-with-body --silent --show-error --get \
  "$MEMORY_API/sessions" -H "$AUTH" \
  --data-urlencode "namespaceId=$NAMESPACE_ID" \
  --data-urlencode "ownerId=$OWNER_ID" | jq '.items'

To list all sessions, omit both filters and set includeAll=true:

page = memory.client.list_sessions(include_all=True, limit=20)
for session in page.items:
    print(session.session_id, session.owner_id)
print("Next page:", page.next_cursor)
curl --fail-with-body --silent --show-error --get \
  "$MEMORY_API/sessions" -H "$AUTH" \
  --data-urlencode 'includeAll=true' --data-urlencode 'limit=20' |
  jq '{sessions: [.items[] | {sessionId, ownerId}], nextCursor}'

Do not combine includeAll=true with either filter. A request without a filter must set includeAll=true.

The response contains session rows in items and no total count. If the response includes nextCursor, pass it as cursor with the same filters to fetch the next page. See the List Sessions API reference for pagination limits.

Configure session retention

The session-memory time to live (TTL) controls how long sessions remain available. Choose a duration that lets users resume conversations for as long as your application needs. When a session expires, its events are no longer available through session-memory retrieval.

In the Redis Cloud console, open your service's Configuration tab and select Edit. Set Short-term TTL under Memory configuration.

See memory configuration to configure the session-memory TTL in Redis Cloud.

Configure automatic summarization

As a conversation grows, its messages take more space in the model's context window. Automatic summarization replaces older messages with a shorter summary while keeping recent messages in full.

In the Redis Cloud console, open your service's Configuration tab and select Edit. Under Memory configuration, enable Automatic summarization and set:

  • Summarize after: The number of messages a session can contain before older messages are summarized.
  • Keep most recent: The number of recent messages that remain available in full.

For example, with Summarize after set to 20 and Keep most recent set to 10, Redis Agent Memory summarizes the older 10 messages when the session reaches 20 messages and retains the 10 most recent messages in full.

See automatic summarization to enable summarization and configure both thresholds in Redis Cloud.

For an example that combines session events with long-term recall, follow the developer guide. For complete schemas, see the session-memory application programming interface (API) reference.

To group a session and its extracted memories, use an optional namespace.

Try automatic summarization

These examples continue from the quickstart. Load the same .env connection values and reuse its user ID. Expand an example to copy a complete program that connects for you.

Each run repeats every write in the program. Session-event writes and memory creates with a new idempotency key add new records, so run cleanup or change the identifiers before rerunning.

Follow Configure automatic summarization. Set Summarize after to 6 and Keep most recent to 2 for this example. The retrieved session will contain a summary object and the two most recent events in events.

Add conversation turns

Add these events to the session from the quickstart to continue the conversation past the configured threshold:

turns = [
    ("assistant", "What dates are you traveling?"),
    ("user", "I arrive on October 10 and leave on October 18."),
    ("assistant", "Would you like formal or casual restaurants?"),
    ("user", "Mostly casual places near public transit."),
    ("assistant", "Do you have a preferred budget?"),
    ("user", "About 40 euros per person."),
]
for role, text in turns:
    add = conversation.user if role == "user" else conversation.assistant
    add(text)
add_event() {  # add_event ROLE ACTOR_ID TEXT
  jq -n --arg role "$1" --arg actor "$2" --arg text "$3" \
    --arg now "$(date -u +%Y-%m-%dT%H:%M:%SZ)" --arg key "$(uuidgen)" \
    '{actorId: $actor, role: $role, content: [{text: $text}], createdAt: $now, idempotencyKey: $key}' |
    curl --fail-with-body --silent --show-error \
      -X POST "$MEMORY_API/sessions/$SESSION_ID/events" -H "$AUTH" \
      -H 'Content-Type: application/json' --data-binary @- | jq -c '.event | {sessionId, eventId}'
}
add_event ASSISTANT travel-agent "What dates are you traveling?"
add_event USER "$OWNER_ID" "I arrive on October 10 and leave on October 18."
add_event ASSISTANT travel-agent "Would you like formal or casual restaurants?"
add_event USER "$OWNER_ID" "Mostly casual places near public transit."
add_event ASSISTANT travel-agent "Do you have a preferred budget?"
add_event USER "$OWNER_ID" "About 40 euros per person."

Run these writes once. Summarization runs in the background.

Retrieve the summarized session

Retrieve the session again. The Python and cURL examples check every 10 seconds, for up to two minutes, until a summary appears:

for _ in range(12):  # summarization runs in the background
    compacted = conversation.transcript()
    if compacted.summary:
        break
    time.sleep(10)
print("Summary:", compacted.summary)
print("Summarized up to event:", compacted.summarized_up_to)
for role, text in compacted.turns:
    print(role, text)
for _ in $(seq 12); do  # summarization runs in the background
  SESSION=$(curl --fail-with-body --silent --show-error \
    "$MEMORY_API/sessions/$SESSION_ID" -H "$AUTH")
  [ "$(jq '.summary != null' <<< "$SESSION")" = true ] && break
  sleep 10
done
jq '{summary, events: [.events[] | {role, content}]}' <<< "$SESSION"
iris agent-memory sessions show travel-planning-session

If summary is still missing, run the retrieval again. Compare summary.text with the recent events. The summary should preserve earlier trip decisions while recent turns remain available in full.

Note:

What to expect: A summary object that preserves details such as Tokyo, Kyoto, the travel dates, and food preferences. summarizedUpToEventId identifies the last event covered by the summary, while events contains the newer turns that remain in full. The exact summary text can vary.

RATE THIS PAGE
Back to top ↑