Skip to content

llm.trace — Span and Agent Trace

Auto-documented module: spanforge.namespaces.trace

The llm.trace.* namespace contains payload dataclasses for recording individual LLM calls, agent steps, and full agent runs (RFC-0001 §8).

Payload classes

ClassEvent typeDescription
SpanPayloadllm.trace.span.completedSingle unit of LLM work — model call, tool invocation, or sub-agent call
AgentStepPayloadllm.trace.agent.stepOne iteration of a multi-step agent loop
AgentRunPayloadllm.trace.agent.completedRoot summary for a complete agent run

SpanPayload — key fields

FieldTypeDescription
span_namestrHuman-readable name for the span
statusstr"ok", "error", or "timeout"
duration_msfloatEnd-to-end latency in milliseconds
token_usagedict | NoneSerialised TokenUsage (fields: input_tokens, output_tokens, total_tokens)
model_infodict | NoneSerialised ModelInfo (fields: system, name)
finish_reasonstr | NoneProvider finish reason ("stop", "length", "tool_calls"…)
streamboolWhether the response was streamed

Value objects

TokenUsage — token counts aligned with OTel gen_ai.usage.* semconv:

FieldTypeDescription
input_tokensintTokens consumed by the prompt
output_tokensintTokens produced in the completion
total_tokensint | NoneSum (or provider-reported total)

ModelInfo — model identity:

FieldTypeDescription
systemGenAISystemProvider enum value (e.g. GenAISystem.OPENAI)
namestrModel identifier (e.g. "gpt-4o")

Example

from spanforge import Event, EventType
from spanforge.namespaces.trace import (
    SpanPayload, TokenUsage, ModelInfo, GenAISystem
)

token_usage = TokenUsage(input_tokens=512, output_tokens=128, total_tokens=640)
model_info  = ModelInfo(system=GenAISystem.OPENAI, name="gpt-4o")

payload = SpanPayload(
    span_name="chat_completion",
    status="ok",
    duration_ms=340.5,
    token_usage=token_usage.to_dict(),
    model_info=model_info.to_dict(),
    finish_reason="stop",
    stream=False,
)

event = Event(
    event_type=EventType.TRACE_SPAN_COMPLETED,
    source="my-app@1.0.0",
    org_id="org_01HX",
    payload=payload.to_dict(),
)

AgentRunPayload — key fields

AgentRunPayload is the root summary emitted as llm.trace.agent.completed when an agent run finishes.

FieldTypeDescription
agent_run_idstrUnique run identifier
agent_namestrName passed to tracer.agent_run() or start_trace()
trace_idstrParent trace identifier
root_span_idstrRoot span for this run
total_stepsintNumber of steps completed
total_model_callsintNumber of LLM calls across all steps
total_tool_callsintNumber of tool invocations across all steps
total_token_usageTokenUsageAggregated input/output/total tokens
total_costCostBreakdownAggregated cost — includes both own steps and child run costs
statusstr"ok" or "error"
start_time_unix_nanointStart time (nanoseconds since epoch)
end_time_unix_nanointEnd time (nanoseconds since epoch)
duration_msfloatWall-clock duration in milliseconds
termination_reasonstr | NoneWhy the run ended (e.g. "max_steps", "budget_exceeded")

Child run cost rollup

In multi-agent workflows the total_cost field includes costs from nested child agent runs. When a child AgentRunContextManager exits, it automatically calls parent_run.record_child_run_cost(child_total_cost). The parent's to_agent_run_payload() sums child costs into total_cost.input_cost_usd and total_cost.output_cost_usd.

See llm.cost — Multi-agent cost rollup for a worked example.