Skip to Content

How do I group the traces of one conversation into a session with AutoGen?

Rius groups the traces of one AutoGen conversation into a session when you wrap each run in rius.session() and pass your conversation id. Every span started inside the block carries that id as session.id, including the spans AutoGen emits itself. Each turn stays its own trace, and the session ties the turns together. AutoGen tracing in Rius is Python only.

How it works

  • A trace is one run of your entrypoint. Each turn of a chat is its own trace, and a session is the id you assign to tie those traces together.
  • rius.session(conversation_id) stamps session.id on every span started inside the block. That covers your observe root span, the create_agent and invoke_agent spans AutoGen emits, the ChatCompletion generation and the execute_tool spans.
  • The scope rides OpenTelemetry context, so it follows async work. You can open it around an await of your async entrypoint. Scopes nest, and the innermost wins.
  • Open the scope outside the observe-wrapped entrypoint, not inside it, so the root span carries the id as well.
  • You choose the id. Reuse a conversation id or ticket id you already have, or call rius.session() with no argument to mint a fresh UUID. The block yields the id, so you can log it or hand it to the next turn.
  • Do not wrap AutoGen tool functions with observe. The framework runs tools in a detached context, so the wrapper’s span splits off as its own single-span trace, outside your session. The execute_tool spans AutoGen emits already cover tools.

The AutoGen integration page covers the framework spans and the OpenAI generations. Tracing your code covers session scopes in full.

Set it up

  1. Install the SDK with the OpenAI integration and AutoGen, then call rius.init() once at startup. The AutoGen integration page has the full agent setup and the handle_ticket entrypoint used below.
pip install "glassflow-rius[openai]" "autogen-agentchat" "autogen-ext[openai]"
  1. Keep your entrypoint wrapped in observe with the AGENT kind, as on that page. This gives one trace per turn.

  2. Open a session scope around each call to that entrypoint, passing the same id for every turn of the conversation. conversation_id and handle_conversation are your own names.

import rius async def handle_conversation(conversation_id: str, tickets: list[str]) -> None: for ticket in tickets: with rius.session(conversation_id): await handle_ticket(ticket)
  1. If one process serves exactly one conversation, such as a CLI run or a batch job, set the id once instead. Use init(session_id=...) in Python or the RIUS_SESSION_ID environment variable. An active rius.session() scope overrides that default. Do not use a process-wide default in a server that handles many users, because every user’s traces would merge into one session. Scope each request instead.

  2. Run two turns of the same conversation, then open the traces in the console. Both should carry the same session.id.

What you get

  • One session per conversation. The turns are separate traces, each with its AGENT root span, the framework’s invoke_agent and execute_tool spans, and the ChatCompletion generation with model, tokens and cost.
  • A session that stays whole across deploys and replicas. The grouping rides on the traces, not on the process serving them, so a conversation that moves between replicas is still one session.
  • A way to check your setup. A trace with no session id is grouped as its own single-trace session. If an agent’s session count equals its trace count, nothing is setting session.id and those sessions are not meaningful groupings.
  • An id that matches one you already have, so you can find a conversation in Rius from your own logs. The concepts page defines sessions and how they relate to traces and instances.

For how sessions fit into watching an agent over time, see Monitor AI agents in production.

When something else fits

  • If a process handles exactly one conversation, a process-wide session_id or RIUS_SESSION_ID saves you from scoping every call.
  • If you also want to follow one person across conversations, add a user scope with rius.user() alongside the session. The user id then ties together all of that person’s sessions.

Still stuck? Get help

Last updated on