Skip to main content

Debug Session, Generation, and Trace History

This tutorial teaches a practical debugging workflow for first-time SOAT users. You will build a traceable conversation and keep a deterministic mapping between:

  • session_id
  • generation_id
  • trace_id

By the end, you will be able to:

  1. Start from a session and retrieve all messages.
  2. Track every generation ID for that session.
  3. Inspect each trace and trace tree.
  4. Reverse lookup from trace_id to generation_id and session_id using your debug ledger.

This workflow uses Sessions debugging links, Agent traces, Trace debugging joins, and Files examples.

Prerequisites

export SOAT_BASE_URL=http://localhost:5047

Step 1 - Login as admin

Use the Users examples login flow to get a token.

ADMIN_TOKEN=$(soat login-user --username admin --password Admin1234! | jq -r '.token')
export SOAT_TOKEN=$ADMIN_TOKEN

Step 2 - Create project, AI provider, agent, and session

Create the minimum resources from Projects examples, AI Providers examples, Agents examples, and Sessions examples.

This tutorial uses a local Ollama provider so it can run without external credentials. To connect xAI, OpenAI, Anthropic, or Amazon Bedrock instead, see Connect Third-Party LLMs.

PROJECT_ID=$(soat create-project --name "Debug Graph Demo" | jq -r '.id')

AI_PROVIDER_ID=$(soat create-ai-provider \
--project-id "$PROJECT_ID" \
--name "Local Ollama" \
--provider "ollama" \
--default-model "qwen2.5:0.5b" | jq -r '.id')

AGENT_ID=$(soat create-agent \
--project-id "$PROJECT_ID" \
--ai-provider-id "$AI_PROVIDER_ID" \
--name "Debug Assistant" \
--instructions "You are a concise debugging assistant." | jq -r '.id')

SESSION_ID=$(soat create-agent-session \
--agent-id "$AGENT_ID" \
--name "Debug Session" \
--auto-generate false | jq -r '.id')

echo "PROJECT_ID=$PROJECT_ID"
echo "AGENT_ID=$AGENT_ID"
echo "SESSION_ID=$SESSION_ID"

Step 3 - Run two generations and capture generation_id + trace_id

Use Sessions debugging links and Sessions async generation endpoints to produce assistant replies and capture the correlation IDs.

soat add-session-message \
--agent-id "$AGENT_ID" \
--session-id "$SESSION_ID" \
--message "Explain what a generation is in one sentence." > /dev/null

GEN_1=$(soat generate-session-response \
--agent-id "$AGENT_ID" \
--session-id "$SESSION_ID")

GEN_1_ID=$(printf '%s\n' "$GEN_1" | jq -r '.generation_id')
TRACE_1_ID=$(printf '%s\n' "$GEN_1" | jq -r '.trace_id')

soat add-session-message \
--agent-id "$AGENT_ID" \
--session-id "$SESSION_ID" \
--message "Now explain what a trace is in one sentence." > /dev/null

GEN_2=$(soat generate-session-response \
--agent-id "$AGENT_ID" \
--session-id "$SESSION_ID")

GEN_2_ID=$(printf '%s\n' "$GEN_2" | jq -r '.generation_id')
TRACE_2_ID=$(printf '%s\n' "$GEN_2" | jq -r '.trace_id')

printf '%s\n' "$GEN_1" | jq '{generation_id, trace_id, status}'
printf '%s\n' "$GEN_2" | jq '{generation_id, trace_id, status}'

Step 4 - Retrieve the full session message timeline

Use Sessions key concepts and Sessions examples to inspect the canonical conversation history.

soat list-agent-session-messages \
--agent-id "$AGENT_ID" \
--session-id "$SESSION_ID" | jq '.data[] | {position, role, content}'

Step 5 - Inspect traces for each generation

Use Traces key concepts, Trace ancestry model, and Traces examples to inspect metadata and tree structure.

soat get-trace --trace-id "$TRACE_1_ID" | jq '{id, agent_id, file_id, parent_trace_id, root_trace_id, step_count}'
soat get-trace-tree --trace-id "$TRACE_1_ID" | jq '{id, children: [.children[].id]}'

Step 6 - Download raw trace steps using file_id

Use Files key concepts and Files examples to inspect raw trace payloads.

TRACE_FILE_ID=$(soat get-trace --trace-id "$TRACE_1_ID" | jq -r '.file_id')
soat download-file-base64 --file-id "$TRACE_FILE_ID" \
| jq -r '.content' | base64 -d | jq '.[0]'

Step 7 - Build a reusable debug ledger (reverse lookup)

Use Trace debugging joins to resolve trace_id -> generation_id[] directly, then keep a lightweight ledger only for generation_id -> session_id correlation.

curl -s "$SOAT_URL/api/v1/traces/$TRACE_1_ID/generations" \
-H "Authorization: Bearer $ADMIN_TOKEN" | jq '{trace_id, generation_ids}'

cat > /tmp/debug-links.json <<EOF
[
{"session_id":"$SESSION_ID","generation_id":"$GEN_1_ID","trace_id":"$TRACE_1_ID"},
{"session_id":"$SESSION_ID","generation_id":"$GEN_2_ID","trace_id":"$TRACE_2_ID"}
]
EOF

# Reverse lookup example: trace_id -> generation_id + session_id
jq -r '.[] | select(.trace_id == "'"$TRACE_1_ID"'")' /tmp/debug-links.json

What you achieved

You now have a deterministic debugging workflow for:

  • session -> all messages
  • session -> all generation IDs
  • generation -> trace ID
  • trace -> generation IDs
  • trace -> raw steps and trace tree
  • trace -> session via your debug ledger

For direct module references, see Sessions debugging links, Agent traces, Trace debugging joins, and Files key concepts.