Skip to Content

What does Rius record when my agent calls the OpenAI Agents SDK?

Rius records each model call your OpenAI Agents SDK agent makes as a generation with the model, tokens, cost and time to first token. The run and your tools appear as spans when you wrap the entrypoint and the tool bodies with observe. Handoffs get no span of their own, and generation spans share generic names. The integration is available in Python only.

How it works

The OpenAI Agents SDK drives the OpenAI client underneath, so the openai instrumentation captures its model calls without framework-specific code. The framework keeps the agent loop, tool executions and handoffs to itself, so those need observe wrappers to show up in the trace.

This is what lands in the trace:

In the frameworkIn the trace
Your entrypoint around Runner.run()The root AGENT span, from your observe wrapper
A model callAn LLM generation with model, tokens, cost and time to first token
A function toolA TOOL span, from your observe wrapper on the function body
A handoffNo span of its own

Rius computes the cost of each generation from the model and the token counts. You never send a cost value. Costs are list-price estimates in US dollars, not billed amounts.

A run that crosses a handoff looks like this:

handle-ticket AGENT 9.8s ├─ Response LLM 2.3s triage decides to hand off ├─ Response LLM 2.8s billing agent decides to call the tool ├─ execute_tool account_status TOOL 0ms └─ Response LLM 4.6s billing agent answers

The framework also has its own tracing, which uploads to the OpenAI platform and is independent of OpenTelemetry. Leaving it on does not interfere with Rius, but it reports to two backends. Turn it off with set_tracing_disabled(True) if Rius should be your only telemetry path.

Set it up

  1. Install the Rius SDK with the OpenAI extra, next to the framework. The extra installs the instrumentation, not the library itself. Full installation steps are on the OpenAI Agents SDK page.

    pip install "glassflow-rius[openai]" openai-agents
  2. Call rius.init, disable the framework’s own tracing if you want a single path, and wrap the entrypoint and each tool body with observe.

    import rius from agents import Agent, Runner, function_tool, set_tracing_disabled from rius import SpanKind rius.init(api_key="ri_...", service_name="my-agent") set_tracing_disabled(True) @function_tool @rius.observe(kind=SpanKind.TOOL) def account_status(email: str) -> str: """Fetch a customer's account standing by email.""" return lookup(email) support_agent = Agent( name="support_agent", instructions="Answer support questions; check accounts with the tool.", tools=[account_status], model="gpt-5-mini", ) @rius.observe(name="handle-ticket", kind=SpanKind.AGENT) def handle_ticket(ticket: str) -> str: result = Runner.run_sync(support_agent, ticket) return str(result.final_output)
  3. Keep the decorator order on tools: @function_tool outermost, observe on the function body. The framework reads the function signature for its tool schema, and the TOOL span parents under the run through ambient context.

  4. Scope each run with rius.session(), reusing your conversation or ticket id, so every turn of one conversation groups together.

  5. Run one request that calls a tool, then open the trace in the console. You should see the root AGENT span, the LLM generations with model, tokens and cost, and your named TOOL spans.

What you get

  • One generation per model call, with model, tokens, cost and time to first token.
  • A named run tree. Your entrypoint is the root AGENT span, and each tool you wrapped is a TOOL span under it.
  • Grouped conversations when you scope runs with rius.session().

These limits apply, verified against openai-agents 0.22.0:

  • Handoffs produce no span. A handoff shows only as consecutive generations that belong to different agents. If the boundaries matter, add an observe wrapper per agent entry, or use the framework’s RunHooks to open spans at agent boundaries.
  • Generation spans have generic names. Responses API calls are all named Response, so the span name does not tell you which agent spoke.
  • Hyphens in agent names are rewritten in the generated handoff tool name, and the framework warns on every run. Use underscores.
  • Streamed runs need usage enabled on the underlying client to carry token counts. Without token counts there is no cost. In the Agents SDK, set model_settings=ModelSettings(include_usage=True) on the agent. It maps to stream_options={"include_usage": True} on the underlying call.
  • There is no TypeScript integration for this framework.

When something else fits

  • If you need handoff boundaries as spans, add per-agent observe wrappers or RunHooks as described above.
  • If your agent is in TypeScript, there is no integration for this framework, so trace those calls with manual generations. The Integrations page lists what each language supports.

Still stuck? Get help

Last updated on