Python SDK

Decorators & module API

Prefer not to pass a client around? Initialize one global client and use the module-level functions and decorators. They all route through the client created by rollout.init().

One global client

Call rollout.init() once at startup. It creates and stores a global client; the module-level helpers and decorators all use it. It takes the same arguments as the Rollout constructor and reads the same environment variables.

startup.py
import mv37.rollout as rolloutrollout.init(api_key="...", agent_name="support_agent", environment="production")

The decorator set

Every decorator accepts an optional name (defaulting to the function name) and works on sync and async functions.

DecoratorWhat it does
@rollout.agentAgent entry point — opens a fresh trace per call, captures input/output, flushes, and re-raises errors.
@rollout.traceOpens a trace per call.
@rollout.spanOpens a typed span (requires an active trace).
@rollout.toolRecords a tool.call / tool.result pair.
@rollout.taskOpens a task span — a multi-step unit of work.

Note

Use @agent at the outermost entry point of a run — it owns the trace and flushes when the call returns. Use @tracewhen you want a trace per call but don't need the agent-boundary behavior (input/output capture is off by default on @span and @task, on by default for @tool).

A traced function

Decorate an entry point to open a trace per call, and decorate tools to capture their inputs and outputs. Inside the call, rollout.current_trace() returns the active trace so you can attach messages from anywhere.

decorated.py
import mv37.rollout as rollout@rollout.tool("get_weather")def get_weather(city: str) -> dict:    return {"city": city, "temp": 21}@rollout.trace("support_agent")def handle_request(text: str) -> str:    rollout.current_trace().message(role="user", content=text)    weather = get_weather("Paris")  # recorded as a tool span    return f"It's {weather['temp']}°C."

Context managers

rollout.trace(...) and rollout.span(...)also work as plain context managers when you don't want to decorate a whole function.

context.py
with rollout.trace("support_agent") as trace:    with rollout.span("retrieval") as span:        span.record_input({"query": "orders"})

Reaching the active trace

rollout.current_trace() and rollout.current_span() return the active objects (or None), so you can attach messages, feedback, usage, or signals from helper functions deep inside a call without threading the trace through every argument.

current.py
def record_outcome(ok: bool) -> None:    trace = rollout.current_trace()    if trace is not None:        trace.signal("resolved", ok)