Skip to main content
A trace represents one complete execution of your agent or request flow. A span is a single step inside that trace. Together, they give you an end-to-end picture of what happened, how long each step took, and where things went wrong.

What is a trace?

Every time your agent runs, AgentVista records it as a trace. A trace captures the top-level facts about that execution:
FieldTypeDescription
trace_idUUIDUnique identifier for this execution, generated by the SDK
agent_namestringThe agent that produced this trace
statusstringrunning, completed, failed, or timed_out
started_atdatetimeWhen the run began
ended_atdatetimeWhen the run finished
duration_msintegerTotal wall-clock time in milliseconds
successbooleanOptional user-defined success signal
outcomestringOptional outcome label (e.g. "qualified", "resolved")
total_tokensintegerSum of tokens across all LLM spans in this trace
total_cost_usddecimalSum of LLM costs across all spans
success and outcome are not set automatically — you define what success means for your agent. See Outcomes for how to attach these signals.

What is a span?

A span represents one step within a trace — an LLM call, a tool invocation, a database query, or any other unit of work. Spans form a tree: every span (except the root) has a parent_span_id pointing to the span that created it.
FieldTypeDescription
span_idUUIDUnique identifier for this span
trace_idUUIDThe trace this span belongs to
parent_span_idUUIDThe parent span, or null for the root span
typestringThe kind of work this span represents (see below)
namestringA human-readable label you assign
statusstringrunning, completed, failed, or timed_out
started_atdatetimeWhen this step began
ended_atdatetimeWhen this step finished
duration_msintegerTime spent in this step
LLM spans carry additional fields:
FieldTypeDescription
modelstringThe model used (e.g. "claude-sonnet-4-20250514")
input_tokensintegerTokens in the prompt
output_tokensintegerTokens in the completion
total_tokensintegerSum of input and output
cost_usddecimalCost for this call
All span types can carry input_data, output_data, error_message, and metadata as JSON payloads.

Span types

AgentVista recognizes six span types. Each type tells the dashboard how to display the span and which fields are relevant.

agent

The root span of a trace. Created automatically when you use @trace_agent or with agentvista.run(...). Represents the full lifetime of your agent’s execution.

llm

An individual LLM call. Captures the model, token counts, cost, and latency for each completion request.

tool

A tool invocation — any external function, API call, or service your agent calls as part of its reasoning. Use this to track web searches, code execution, database lookups triggered by the agent, and so on.

http

An outbound HTTP request to an external service. Useful for tracking calls to third-party APIs, webhooks, or downstream microservices.

db

A database query or write operation. Helps you see whether slow agent runs are caused by the model or by database latency.

custom

Any step that doesn’t fit the above categories. Use custom spans for arbitrary business logic, caching layers, queue operations, or anything else you want to time and observe.

How spans form a tree

Spans are linked by parent_span_id. The root span (type agent) has no parent. Every span created inside the root becomes its child, and so on recursively.
trace_id: a1b2c3d4

└── [agent] "lead-qualifier"          parent_span_id: null

    ├── [llm] "classify-intent"       parent_span_id: <agent span_id>

    ├── [tool] "search-crm"           parent_span_id: <agent span_id>
    │   │
    │   └── [db] "contacts-lookup"    parent_span_id: <tool span_id>

    └── [llm] "generate-response"     parent_span_id: <agent span_id>
The AgentVista dashboard renders this tree as a waterfall timeline — each span appears as a horizontal bar positioned by its started_at time, indented by its depth in the tree. You can see at a glance which steps ran in parallel, which were sequential, and where time was spent.

Unified traces

A single trace can contain both AI spans (agent, llm, tool) and infrastructure spans (http, db, custom) — this is AgentVista’s core differentiator. When your agent makes a tool call that triggers a database query, those spans appear in the same waterfall, so you can see whether a slow run was caused by the model, a downstream API, or the database.
[agent] "support-bot"                        0ms ─────────────────── 2400ms
  [llm] "extract-intent"                     10ms ──── 340ms
  [tool] "fetch-ticket"                             400ms ─────── 900ms
    [http] "GET /api/tickets/8821"                  400ms ─── 700ms
    [db] "SELECT * FROM tickets WHERE id=..."               700ms ── 880ms
  [llm] "generate-reply"                                        920ms ──────── 2350ms

Distributed tracing across services

If your agent calls downstream services that are also instrumented, you can stitch their spans into the same trace using W3C traceparent headers. The upstream service injects the header; the downstream service reads it and continues the same trace_id.
import agentvista

# Upstream service: inject the traceparent into outgoing headers
headers = {}
agentvista.inject_traceparent(headers)
response = requests.get("https://my-service.example.com/run", headers=headers)

# Downstream service: continue the same trace
incoming_tp = request.headers.get("traceparent")
with agentvista.run("downstream-service", incoming_traceparent=incoming_tp) as r:
    # Spans created here share the same trace_id as the upstream call
    ...

Creating spans in your code

Use agentvista.span(name, span_type) as a context manager inside any active trace. The SDK automatically links spans to the correct parent and records timing.
import agentvista

agentvista.init(api_key="av_xxxxx")

@agentvista.trace_agent("lead-qualifier")
def qualify_lead(lead_data):
    with agentvista.span("classify-intent", span_type="llm"):
        intent = call_llm(lead_data["message"])

    with agentvista.span("search-crm", span_type="tool"):
        with agentvista.span("contacts-lookup", span_type="db"):
            contact = db.query("SELECT * FROM contacts WHERE email = ?", lead_data["email"])

    with agentvista.span("generate-response", span_type="llm"):
        return call_llm(f"Respond to this lead: {intent}")
agentvista.span() is a no-op when called outside an active trace. You can safely add spans to library code without worrying about whether a trace is running.
If an exception is raised inside a span() block, the span is automatically marked failed and the exception message is recorded in error_message. The exception still propagates normally — AgentVista never suppresses errors.