Skip to Content

What does Rius record when my agent calls the Claude Agent SDK?

Rius records each Claude Agent SDK task as an agent trace with one generation for the whole runtime turn, carrying the model, token counts, cost and the answer text. The Claude Agent SDK drives the Claude Code runtime in a separate process, so you add two small pieces of tracing code yourself and Rius fills in the rest. Tool calls and other work inside that runtime do not appear as spans.

How it works

The Claude Agent SDK runs the Claude Code runtime outside your process. No model client runs in your Python process, so auto-instrumentation has nothing to hook. Coverage is manual, in two pieces:

  • An observe wrapper makes each task the root AGENT span.
  • A manual generation wraps the query() loop. You fill it from the run’s ResultMessage when it arrives.

This is what lands in the trace:

In the Claude Agent SDKIn the Rius trace
A taskThe root AGENT span, from your observe wrapper
The whole runtime turnOne generation with model, tokens and cost
The runtime’s internal stepsNothing

On the generation, Rius records:

  • Input: the task text you pass as the generation’s input.
  • Output: the answer, which your code collects from the text blocks of each assistant message.
  • Requested model: the model id you set on the generation, with anthropic as its provider.
  • Response model: the real model id, taken from the ResultMessage’s model usage.
  • Tokens: input, output, cache read and cache write counts, taken from the ResultMessage’s usage.

Cost is not something you send. Rius computes it on the server from the requested model and the token counts, as for any generation. It is a list-price estimate in US dollars, not a billed amount.

Cache counts matter here. Anthropic reports an input token count that excludes cache reads and writes. Because the generation’s provider is anthropic, set_usage() adds the two cache counts to the input tokens for you. You pass the ResultMessage values as they are, with no arithmetic, and the computed cost tracks the ResultMessage’s own total_cost_usd. A trivial one-turn run can report 10 input tokens next to 24,000 cache tokens, so leaving the cache fields out would badly undercount.

A trace looks like this, from a real run of the example:

handle-task AGENT 5.0s └─ claude_agent_turn LLM 5.0s claude-haiku-4-5, tokens + cost

Set it up

  1. Install the SDK next to the Claude Agent SDK. The base package is enough, no extra applies. The claude CLI must be installed and authenticated, because the runtime uses whatever auth Claude Code has. An exported ANTHROPIC_API_KEY takes precedence over a claude.ai login.
pip install glassflow-rius claude-agent-sdk
  1. Wrap each task with observe as an AGENT span, and open a generation around the query() loop. Fill the generation’s usage and response model from the ResultMessage, and set its output to the collected answer.
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
  1. Use a full model id such as claude-haiku-4-5, not an alias such as haiku, for both the CLI option and the generation. The pricing table matches real model ids only, so an alias gives you a generation with no cost. Keep provider="anthropic" on the generation so the cache counts are added to the input tokens.

  2. Group a conversation by scoping each task with rius.session(). The Claude Agent SDK’s own session_id for resumable conversations works well as the Rius session id.

  3. Run one task and open the trace in the console. You should see the root AGENT span and the generation with a full model id, tokens and cost. A generation without cost means an alias was used as the model id.

The Claude Agent SDK integration is Python only today. The full recipe is on the Claude Agent SDK integration page.

What you get

  • One trace per task, with a root agent span you can name and filter on.
  • A single generation per runtime turn showing the requested model, the real response model, input, output, cache read and cache write tokens, and the question and answer text.
  • A cost estimate for that turn, computed by Rius from the model and the tokens, with cache reads and writes counted.
  • Conversation grouping through sessions when you wrap tasks in rius.session().

The limits to plan around:

  • The runtime’s inner work is invisible. Tool calls, sub-turns and file operations happen inside the Claude Code process and produce no spans. The generation records the turn’s totals only, so you cannot filter this agent’s traces by tool.
  • Coverage depends on your code. Rius sees only what you wrap, so a task without the observe wrapper and generation is not traced.

These limits were verified against claude-agent-sdk 0.2.148. For how the other integrations are set up, and which languages each one covers, see Integrations.

When something else fits

  • If you need spans for each tool call or sub-step, the Claude Agent SDK runtime does not expose them, so this integration will not show them. Trace those steps with your own code where you control them.
  • If your code calls the Anthropic API directly instead of driving the Claude Code runtime, the Anthropic client integration instruments those calls automatically, with no manual generation.

Still stuck? Get help

Last updated on