How do I trace tool calls in AutoGen?
Rius traces AutoGen tool calls with no wrappers: the framework emits an execute_tool span for each tool call, and Rius nests it under the agent run. Call rius.init() and put one observe wrapper on your entrypoint, and each tool call appears inside that trace. Do not wrap AutoGen tool functions with observe, because that splits the tool into its own trace.
How it works
AutoGen (AgentChat, Python) emits create_agent, invoke_agent and execute_tool spans through the global tracer provider, which rius.init() installs. Rius records them as they arrive. Model calls go through the OpenAI client, so the openai integration adds a ChatCompletion generation with model, tokens and cost.
The tool spans nest under the agent run, which nests under your entrypoint. A run that calls one tool looks like this:
handle-ticket AGENT 2.8s
├─ create_agent support_agent 0ms
└─ invoke_agent support_agent 2.8s
├─ ChatCompletion LLM 2.6s
└─ execute_tool account_status 0msThe execute_tool span is named after the tool, so each tool you give an agent shows up under its own name.
A few details to expect, verified against autogen-agentchat 0.7.5:
- Framework spans arrive with status UNSET rather than OK on success. The trace status still reads Ok.
- Generation spans share the generic name
ChatCompletion. - AutoGen runs tools in a detached context. A tool function wrapped with
observecannot find the run, so its span splits off as a single-span trace.
There is no TypeScript integration for AutoGen. This page covers the Python framework.
Set it up
- Install the SDK with the
openaiextra, plus AutoGen. The AutoGen integration page covers this setup in full.
pip install "glassflow-rius[openai]" "autogen-agentchat" "autogen-ext[openai]"- Initialize Rius and wrap only your entrypoint with
observe. Pass the plain tool function to the agent, with no decorator on it:
import rius
from autogen_agentchat.agents import AssistantAgent
from autogen_ext.models.openai import OpenAIChatCompletionClient
from rius import SpanKind
rius.init(api_key="ri_...", service_name="my-agent")
def account_status(email: str) -> str:
"""Fetch a customer's account standing by email."""
return lookup(email)
@rius.observe(name="handle-ticket", kind=SpanKind.AGENT)
async def handle_ticket(ticket: str) -> str:
agent = AssistantAgent(
name="support_agent",
model_client=OpenAIChatCompletionClient(model="gpt-5-mini"),
tools=[account_status],
system_message="Answer support questions; check accounts with the tool.",
)
result = await agent.run(task=ticket)
return str(result.messages[-1].content)- To trace a tool-like step that is not an AutoGen tool, such as a helper your entrypoint calls directly, wrap it yourself. Use
observewith theTOOLkind and atool_name, as the tracing page describes. The span is namedexecute_toolfollowed by the tool name and nests under the current span. Replacefetch_invoicewith your own function:
@rius.observe(kind=SpanKind.TOOL, tool_name="fetch_invoice")
def fetch_invoice(invoice_id: str) -> dict:
...Call it from the body of handle_ticket, not from inside a tool function you pass to the agent. A bare observe with no kind gives a CHAIN span, so set the kind.
- Scope each conversation with
rius.session(), reusing your conversation id, so the traces of one conversation group together:
with rius.session(conversation_id):
await handle_ticket(ticket)- Run one request that calls a tool and open the trace in the console. You should see the root span, the
invoke_agentspan, theexecute_toolspan and theChatCompletiongeneration with model, tokens and cost.
What you get
- One trace per unit of work, with each tool call as an
execute_toolspan under theinvoke_agentspan for the run. - Each model call as a generation with model, tokens and cost, next to the tool span that follows it.
- Your own helpers recorded as tool spans, named
execute_toolplus the tool name, when you wrap them with theTOOLkind. - Conversations grouped by session, using the id you already have.
Cost is a list-price estimate in US dollars that Rius computes from the model and token counts. You never send a cost value.
When something else fits
If your agent runs on a framework other than AutoGen, or calls a model client directly, see Integrations for the matching recipe. If you work in TypeScript, AutoGen has no integration there, so trace its calls with the manual observe and generation helpers on the tracing page.