Skip to main content
The AgentVista SDK gives you three ways to trace an agent. All three produce the same trace format in the AgentVista dashboard — choose whichever fits your codebase.

Decorator

@agentvista.trace_agent wraps an existing function without changing its signature or return value. The function name becomes the agent name in the dashboard.
import agentvista

agentvista.init(api_key="av_xxxxx")

@agentvista.trace_agent
def qualify_lead(lead: dict) -> dict:
    # your existing agent code — unchanged
    result = call_llm(lead)
    return result
You can also pass a custom name:
@agentvista.trace_agent("lead-qualifier")
def qualify_lead(lead: dict) -> dict:
    ...
When the decorated function raises an exception, the trace is automatically marked as failed and the exception message is recorded. The exception still propagates normally to the caller.

Child spans

Inside any active trace — whether started by @trace_agent or agentvista.run() — you can create child spans to break down the work into named steps.
import agentvista

agentvista.init(api_key="av_xxxxx")

@agentvista.trace_agent("lead-qualifier")
def qualify_lead(lead: dict) -> dict:
    with agentvista.span("fetch-crm-data", span_type="tool"):
        crm_data = fetch_from_crm(lead["id"])

    with agentvista.span("score-lead", span_type="llm"):
        score = call_llm(lead, crm_data)

    return score
Spans nest automatically: each span() call detects the active trace context and links itself as a child of the current span. agentvista.span() is a no-op when called outside an active trace, so you can safely leave span instrumentation in place even if init() has not been called.

Span types

Pass span_type to categorize the work each span represents. The AgentVista dashboard uses span types for filtering and visualization.
span_typeUse for
"agent"Sub-agent or nested orchestration step
"llm"A call to an LLM API
"tool"An external tool invocation (API call, file I/O, web search)
"http"An outbound HTTP request
"db"A database query
"custom"Anything else (default when span_type is omitted)

Distributed tracing

When an agent calls another service, you can propagate the current trace across the network boundary using W3C Trace Context headers.

Injecting a traceparent header

Call agentvista.inject_traceparent(headers) to add a traceparent header to an outgoing request. The function mutates and returns the headers dict.
import httpx
import agentvista

with agentvista.run("orchestrator") as r:
    headers = {}
    agentvista.inject_traceparent(headers)
    # headers now contains: {"traceparent": "00-<trace_id>-<span_id>-01"}

    response = httpx.post(
        "https://downstream-service/process",
        headers=headers,
        json={"data": "..."},
    )
inject_traceparent() is a no-op when called outside an active trace.

Extracting a traceparent header

In the downstream service, pass the incoming traceparent to agentvista.run() via incoming_traceparent. AgentVista will continue the same logical trace so all downstream spans appear in the same unified view.
import agentvista

# In a FastAPI or similar framework:
def process(request):
    incoming = request.headers.get("traceparent")

    with agentvista.run("downstream-agent", incoming_traceparent=incoming) as r:
        result = do_work()
        r.set_outcome(success=True)
You can also parse the header directly with agentvista.extract_traceparent(headers), which returns (trace_id, parent_span_id) or None if the header is missing or malformed.

Performance

  • record() returns in under 0.1 ms — there is no synchronous network call on the hot path.
  • Events are batched in memory and flushed to AgentVista every 2 seconds by a background thread.
  • Network failures are silently dropped. Your agents never crash due to observability errors.
  • Tracing state uses contextvars.ContextVar, which is both async-safe and thread-safe — safe to use in FastAPI, asyncio, and threaded servers without any extra configuration.