Why is my Claude Agent SDK agent slow to respond?
Rius shows whether a slow Claude Agent SDK run is slow in your code or inside the Claude Code runtime, using the root span and the single model-turn span. Open the slowest trace, compare the two durations, then add a duration alert so the next slow run reaches you before a user reports it.
How it works
The Claude Agent SDK drives the Claude Code runtime in a separate process, so Rius records it with manual tracing. Each task becomes a root AGENT span from your observe wrapper, and the whole runtime turn becomes one generation (the span for a model call) with the model, tokens and cost. The Claude Agent SDK integration page shows a real trace:
handle-task AGENT 5.0s
└─ claude_agent_turn LLM 5.0s claude-haiku-4-5, tokens + costThe two durations tell you where to look first:
- Root and generation are about equal. The time is spent inside the runtime turn. Tool calls, sub-turns and file operations run inside the Claude Code process and produce no spans, so the trace cannot split that turn further. Compare the generation’s tokens and model with a faster run. A turn with more input or output tokens did more work.
- The root is clearly longer than the generation. The extra time is in your own function, before or after the
query()loop. - There is a root span but no generation. The manual generation is not set up, so the model turn is not recorded. Add it as shown below.
For how this framework compares with other integrations, see the support matrix. The Claude Agent SDK is the one that needs manual tracing.
Set it up
- Trace each task with a root span and wrap the
query()loop in a generation. Use a full model id, not an alias, so cost is computed.
pip install glassflow-rius claude-agent-sdkimport 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- Open Traces and look at the latency column. The strip above the list shows latency percentiles for the traces that match your filters. Filter to your agent and sort out the slow runs.
- For single steps, open the Spans tab, pick Agent or LLM in the All kinds menu and click the Duration header to sort. See Exploring traces for the filters.
- Open the slowest trace. In the waterfall, compare the
handle-taskspan with theclaude_agent_turnspan. The Map tab has a latency lens that shows the same thing as a graph. - Use the compare-runs tool on the trace to set it beside a faster run of the same agent and see where latency moved.
- Call
handle_taskinsiderius.session(), opened before the call, so a conversation’s tasks group together. Use an id you choose up front: the SDK’s ownsession_idonly arrives in the messages after the root span has started. Pasting a session ID into the Spans search lists every span in that session, which shows whether slowness builds up across tasks.
What you get
- A clear split between your code and the runtime turn, from the root and generation durations in each trace.
- Model, token counts and cost on the generation, so you can tell slow runs that did heavy work from slow runs that did not.
- Latency percentiles (p50, p95, p99) for finished traces on the Home page, described in Usage and cost. A run still in progress does not stretch them.
- A repeatable catch: create a custom alert on the duration rule and filter it by Service or Agent so it measures whole runs. Send it to a webhook, email or Slack channel.
- A place to start for the wider routine in Monitor AI agents in production.
When something else fits
- If you need to know which tool call or sub-turn inside the runtime is slow, this integration cannot tell you, because the runtime’s inner steps produce no spans. Wrap the code you own in
observeto time those parts. - If your agent calls a model client directly, or uses a framework with its own integration, the model calls and steps arrive as spans automatically. Check the integrations page for your setup.