I trace the Claude Agent SDK with LangSmith. How do I switch to Rius?
To switch to Rius, replace your LangSmith tracing with an observe wrapper on each task and one manual generation around the Claude Agent SDK query loop. The Claude Agent SDK drives the Claude Code runtime in a separate process, so no model client runs in your process and Rius auto-instrumentation has nothing to hook. Each task then arrives as a trace with an agent span, a model call, tokens and cost. Rius computes the cost on its side.
How it works
The Claude Agent SDK is the one framework in Rius that is traced manually. Two explicit pieces give you coverage:
- An
observewrapper with the AGENT kind makes each task the root span. - A manual generation wraps the
query()loop. You fill it from the run’sResultMessagewith the token usage, the real model id and the collected answer.
Rius then computes cost from the model and token counts, as it does for any generation. The costs are list-price estimates in US dollars.
If your LangSmith setup uses @traceable, the LangSmith migration guide maps it to Rius:
@traceablebecomes@rius.observe.@traceable(name="...")becomes@rius.observe(name="...").@traceable(run_type="llm")around a call you trace by hand becomesrius.start_as_current_generation(model=..., provider=...)withset_usage().- A LangSmith
thread_idin metadata becomeswith rius.session(thread_id):around the call. That context manager stampssession.idon every span inside it. - Other metadata and tags become span attributes.
For a wider view of the paths, see Migrate to Rius.
Set it up
- Create a Rius workspace and an API key. Keys start with
ri_. - Install the SDK. The base package is enough, and no extra applies. The
claudeCLI must be installed and authenticated.
pip install glassflow-rius claude-agent-sdk- Remove the LangSmith tracing from the code that runs the agent, such as
@traceableor aconfigure_claude_agent_sdk()call, and replace it with the wrapper and generation below. This is the setup from the Claude Agent SDK integration page:
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- Use a full model id such as
claude-haiku-4-5, not an alias such ashaiku, for both the CLI option and the generation. The pricing table matches real model ids only, so an alias gives a generation with no cost. - Keep
provider="anthropic"and pass the cache counts as they are. Anthropic reports an input count that excludes cache reads and writes, and Rius adds them for you when the provider isanthropic. - Scope each conversation with
rius.session(). The Claude Agent SDK’s ownsession_idmakes a natural Rius session id. - Run both backends side by side for one service while the rest keep reporting to LangSmith. Cut over when Rius shows what you need, then unset
LANGSMITH_TRACING, remove@traceableand revoke the LangSmith keys.
Run one task and open the trace in the console. You should see the root agent span and a generation with a full model id, tokens and cost.
What you get
A task looks like this in Rius:
handle-task AGENT 5.0s
└─ claude_agent_turn LLM 5.0s claude-haiku-4-5, tokens + cost- One trace per task, with the root agent span and one generation for the whole runtime turn.
- Model, token counts including cache reads and writes, and server-side cost on that generation.
- Sessions that group a conversation’s turns, and users if you set a user id.
- Alerts and agent liveness from the SDK.
The runtime’s inner work is not visible. 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. Auth is the CLI’s, so an exported ANTHROPIC_API_KEY takes precedence over a claude.ai login.
Some LangSmith features have no Rius equivalent: datasets, experiments and evaluators, feedback and annotation queues, Prompt Hub and Playground. Existing LangSmith traces stay in LangSmith, because Rius cannot import them.
When something else fits
- If you cannot change code yet, LangSmith’s OpenTelemetry export can point at Rius, but spans arrive without inputs, outputs or session grouping. Treat that as a bridge during evaluation, as the migration guide describes.
- If evaluations, datasets or annotation queues are central to your workflow, keep LangSmith for those pieces and run Rius for traces, cost and alerts.
- If other parts of your stack use other libraries or frameworks, check the integrations list, because many of them need no manual code.