Query sessions and turns

List agents and sessions, and read turns and their captured content with the Lens read API.

Use the Lens read application programming interface (API) to list sessions and read turns from code, for example to export failed turns or build your own reports. The Python examples use the Lens read client:

python -m pip install 'redis-agent-lens>=1.0.0'

The cURL examples use Bash and jq. Every operation is a GET request.

Authenticate

Export the Iris host, your instance ID, and a read key:

export LENS_URL='<iris-host>'
export LENS_INSTANCE_ID='<lens-instance-id>'
export LENS_API_KEY='<lens-read-key>'

The read client reads its key from LENS_API_KEY and sends it as a bearer token. Every operation is scoped to your instance:

import os

from redis_agent_lens import Lens

client = Lens(
    server_url=os.environ["LENS_URL"],
    instance_id=os.environ["LENS_INSTANCE_ID"],
)
LENS_API="${LENS_URL%/}/iris/data/v1beta1/lens/instances/$LENS_INSTANCE_ID"
AUTH="Authorization: Bearer $LENS_API_KEY"

List agents

List every agent with at least one retained session:

agents = client.list_agents()
for agent in agents.items:
    print(agent.agent_id)
curl --fail-with-body --silent --show-error "$LENS_API/agents" -H "$AUTH" \
  | jq -r '.items[].agentId'

List sessions

List one agent's sessions over a time range, newest activity first. This example lists the sessions with a failed turn in the last 24 hours, then follows the cursor to the next page:

page = client.list_sessions(agent_id="support-bot", range="24h", outcome=["FAILED"])
print(f"Showing {page.effective_range} of sessions")

sessions = list(page.items)
while page.next_cursor:
    page = client.list_sessions(
        agent_id="support-bot", range="24h", outcome=["FAILED"], cursor=page.next_cursor
    )
    sessions.extend(page.items)

for session in sessions:
    print(session.session_id, session.turn_count, session.last_seen)
curl --fail-with-body --silent --show-error -G "$LENS_API/sessions" -H "$AUTH" \
  --data-urlencode "agentId=support-bot" \
  --data-urlencode "range=24h" \
  --data-urlencode "outcome=FAILED" > sessions.json
jq '{effectiveRange, nextCursor, sessions: [.items[] | {sessionId, turnCount, lastSeen}]}' sessions.json
SESSION_ID=$(jq -er '.items[0].sessionId' sessions.json)
Parameter Description
agentId Required. The agent whose sessions to list.
range Required. A lookback duration such as 24h, 7d, or 30d.
sessionIdPrefix Sessions whose ID starts with this value, ignoring case. At least 2 characters.
userId Sessions with this user ID, ignoring case.
outcome Sessions with a turn that has any of these outcomes. Use UNSET for turns without an outcome.
limit Sessions per page, up to 200. Default 50.
cursor The nextCursor value from the previous page.

The Python client uses the same parameters in snake_case, such as agent_id and session_id_prefix.

Lens fits the range to your instance's retention. The response returns the range it used as effectiveRange, and the ranges your instance supports as availableRanges.

To read the next page, pass nextCursor with the same filters. When nextCursor is absent, you have the last page. A cursor expires after 5 minutes without use; start again from the first page.

Get a session

Read a session's threads, turn summaries, and outcome counts:

if not sessions:
    raise SystemExit("No matching sessions in the last 24 hours")

session = client.get_session(session_id=sessions[0].session_id)
for summary in session.turns:
    outcome = summary.outcome.value if summary.outcome else "no outcome"
    print(summary.trace_id, outcome, summary.duration_ms, summary.tokens.total)
curl --fail-with-body --silent --show-error "$LENS_API/sessions/$SESSION_ID" -H "$AUTH" > session.json
jq '[.turns[] | {traceId, outcome, durationMs, tokens: .tokens.total}]' session.json
TURN_ID=$(jq -er '.turns[0].traceId' session.json)

Each turn summary includes the turn ID, outcome, duration, number of steps, and token counts.

Get a turn

Read one turn by its ID. The response includes the turn's steps, token counts, outcome, and its context manifest: one entry per retrieval step, with what it fetched and what the prompt used.

turn = client.get_turn(turn_id=session.turns[0].trace_id)
for entry in turn.manifest.entries:
    print(f"{entry.source}: {entry.state.value}, fetched {entry.fetched_count}, used {entry.used_count}")
    for candidate in entry.candidates:
        print(f"  {candidate.id} score={candidate.score} used={candidate.used}")
curl --fail-with-body --silent --show-error "$LENS_API/turns/$TURN_ID" -H "$AUTH" > turn.json
jq '[.manifest.entries[] | {source, state, fetchedCount, usedCount}]' turn.json

Each manifest entry has one of these states:

State Meaning
ENTERED_PROMPT At least one result entered the prompt.
FETCHED_NOT_USED The source returned results, and none entered the prompt.
INVOKED_EMPTY The source returned no results.
NOT_INSTRUMENTED The turn recorded no prompt assembly, or the results had no text to match.

Each candidate in an entry includes its ID, score where the source provides one, and whether it entered the prompt.

Get captured content

Captured text, such as a retrieved document or a model prompt, is stored by content hash. Read it with the turn ID and the hash from the turn:

for entry in turn.manifest.entries:
    for candidate in entry.candidates:
        if candidate.content and candidate.content.hash:
            content = client.get_content(turn_id=turn.trace_id, hash=candidate.content.hash)
            print(candidate.id, content.availability.value, content.body)
HASH=$(jq -r '.manifest.entries[0].candidates[0].content.hash // empty' turn.json)
if [ -n "$HASH" ]; then
  curl --fail-with-body --silent --show-error "$LENS_API/turns/$TURN_ID/content/$HASH" -H "$AUTH" \
    | jq '{availability, body}'
fi

The response's availability is AVAILABLE with the text in body, or says why the text isn't available, such as EXPIRED or NOT_CAPTURED. See retention.

Get a Context Gateway tool result

Read the result of a Context Gateway tool call in a turn, by the step's ID. The turn lists these steps in contextRetrieverToolSteps:

for step in turn.context_retriever_tool_steps:
    result = client.get_context_retriever_result(turn_id=turn.trace_id, span_id=step.span_id)
    print(step.tool_name, result.outcome.value, result.classification.value)
for SPAN_ID in $(jq -r '.contextRetrieverToolSteps[].spanId' turn.json); do
  curl --fail-with-body --silent --show-error \
    "$LENS_API/turns/$TURN_ID/tools/$SPAN_ID/result" -H "$AUTH" \
    | jq '{spanId, outcome, classification}'
done

The result classifies what the tool returned, such as RECORDS or AGGREGATE, and includes the returned data.

Next steps

RATE THIS PAGE
Back to top ↑