How do I see one whole conversation in an agent built with the Claude Agent SDK?
Rius shows a whole Claude Agent SDK conversation as one session: scope each task with rius.session() and the traces for that conversation list together. The SDK’s own session_id makes a natural Rius session id. Each task appears as a trace with a root agent span and one generation for the model turn, with tokens and cost.
How it works
The Claude Agent SDK drives the Claude Code runtime in a separate process, so no model client runs in your process and nothing is recorded on its own. Coverage comes from two pieces you add:
- An
observewrapper makes each task the rootAGENTspan. - A manual generation wraps the
query()loop and is filled from the run’sResultMessage: token usage, the real model id and the collected answer. Rius computes cost from those, as a list-price estimate in US dollars.
The conversation itself is the third piece. A session groups traces by session.id, so every task you scope to the same session id belongs to the same conversation. Without a session.id, each trace is its own session.
A task looks like this in the trace:
handle-task AGENT 5.0s
└─ claude_agent_turn LLM 5.0s claude-haiku-4-5, tokens + costThe runtime’s inner work, such as tool calls, sub-turns and file operations, happens inside the Claude Code process and produces no spans. The generation records the turn’s totals only. See the Claude Agent SDK integration for the full list of what lands where.
Set it up
- Install the SDK next to the Claude Agent SDK. The base package is enough, and the
claudeCLI must be installed and authenticated.
pip install glassflow-rius claude-agent-sdk- Trace each task with an
AGENTroot and a generation filled from the result. Use a full model id, not an alias such ashaiku, because cost is computed from the requested model and an alias produces a generation with no cost. Keepprovider="anthropic"so the cache counts are added to the input tokens for you.
import rius
from claude_agent_sdk import (
AssistantMessage, ClaudeAgentOptions, ResultMessage, TextBlock, query,
)
from rius import SpanKind
rius.init(api_key="ri_...", service_name="my-agent")
MODEL = "claude-haiku-4-5"
@rius.observe(name="handle-task", kind=SpanKind.AGENT)
async def handle_task(task: str) -> str:
options = ClaudeAgentOptions(model=MODEL, max_turns=1)
parts = []
with rius.start_as_current_generation(
"claude_agent_turn", model=MODEL, provider="anthropic", input=task
) as gen:
async for message in query(prompt=task, options=options):
if isinstance(message, AssistantMessage):
parts.extend(
b.text for b in message.content if isinstance(b, TextBlock)
)
elif isinstance(message, ResultMessage):
usage = message.usage or {}
gen.set_usage(
input_tokens=usage.get("input_tokens"),
output_tokens=usage.get("output_tokens"),
cache_read_input_tokens=usage.get("cache_read_input_tokens"),
# Anthropic's payload still calls the write count "cache creation"
cache_write_input_tokens=usage.get("cache_creation_input_tokens"),
)
models = list((message.model_usage or {}).keys())
if models:
gen.set_response_model(models[0])
answer = "".join(parts)
gen.set_output(answer)
return answer-
Tie the tasks of one conversation together. Call
handle_taskinsiderius.session()with the same id for every task, so every trace of that conversation carries the samesession.id. Open the scope before the call, so the root span carries it too. The SDK’ssession_idis a natural id for a resumed conversation, but it only arrives with the first task’s messages, so a conversation that starts in your code needs an id you choose up front. -
If each process handles exactly one conversation, you can set a process-wide session instead:
export RIUS_SESSION_ID=your-conversation-id- Run a conversation, open Traces in the console and open one trace. The Session link in the trace header opens the Spans tab filtered to that session. You can also paste the session ID into the Spans search box to list every span in it. A generation with no cost means an alias was used as the model id.
What you get
- One session id that groups every task of a conversation, found from the trace header or the Spans search box. The trace exploration page shows how to read the tree and the span details.
- Per task, a waterfall with the root
AGENTspan and oneLLMgeneration showing the model, input and output tokens, cache tokens and estimated cost. - Your own
session_idas the join key, so a resumed conversation continues the same session. - The same traces in the wider views for agents and cost described in Monitor AI agents in production.
The Claude Agent SDK is the one manual integration in the integrations list: the task root, the generation, the usage and the session are all yours to add.
When something else fits
- If you need the runtime’s tool calls and sub-turns as separate spans, this integration does not record them. Each turn is one generation with totals only.
- If you want to trace Claude Code sessions themselves rather than an agent you built, the Rius coding-agent plugin does that, and it is a separate setup from this one.