Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.trodo.ai/docs/llms.txt

Use this file to discover all available pages before exploring further.

Understanding these core concepts will help you get the most out of Trodo’s observability platform.

How a trace is structured

A single agent execution produces a tree of spans. wrapAgent creates the root — the run — and everything that runs inside it becomes a child span: provider SDK calls, tool executions, retrieval steps, nested sub-steps.
run: support-agent                                         kind: run
├─ llm openai.chat.completions                             kind: llm
│   prompt · completion · tokens · cost · model
├─ tool lookup_order                                       kind: tool
│   input · output · toolName
├─ retrieval vector-search                                 kind: retrieval
│   query · topK · results
└─ llm openai.chat.completions                             kind: llm
    second LLM call in the same run
Auto-instrumentation creates the llm, tool, and retrieval child spans automatically when you use supported frameworks (OpenAI, Anthropic, LangChain, LlamaIndex, Vercel AI SDK, Bedrock, Cohere, Gemini, Vertex, Mistral). For everything else, you wrap calls with the typed helpers — trodo.tool(), trodo.llm(), trodo.retrieval(), trodo.trace() — or emit spans directly with withSpan.

Runs

A run is a single execution of your agent from start to finish. One call to wrapAgent (Node) or wrap_agent (Python) produces one run. It captures:
  • Inputs — the initial state and parameters passed to your agent.
  • Outputs — the final result produced by your agent.
  • Spans — the nested operations within the execution.
  • Timing — duration and timing of each operation.
  • Metadata — additional context like environment, version, custom tags.
  • Rollups — total tokens, total cost, span count, tool count, error count — all summed from child spans, never written by you.
Runs are built on OpenTelemetry, the industry-standard observability framework. Each run has a unique run_id and contains one or more spans organised hierarchically.

What you set vs. what’s rolled up

You set on the runAuto-rolled from spans
agentName, distinctId, conversationIdduration_ms
setInput / setOutput / setMetadatatotal_tokens_in, total_tokens_out
setErrorSummarytotal_cost
span_count, tool_count, error_count
status (ok / error / running)

Run ID

The run_id is Trodo’s identifier for a specific agent execution. wrapAgent returns it alongside the result:
const { result, runId } = await trodo.wrapAgent('my-agent', async (run) => { ... });
Use it to:
  • Query and filter traces in the dashboard.
  • Attach feedback after a run finishes.
  • Link multi-turn conversations via a shared conversationId.
  • Propagate the run across service boundaries (see Propagation).

Distinct ID

A distinctId is the identifier of the end-user whose action triggered the run. Pass it to wrapAgent and every run for that user is filterable in the dashboard, attributable in the user timeline, and groupable for cohort analysis.
await trodo.wrapAgent('my-agent', fn, { distinctId: 'user-42' });

Conversation ID

A conversationId is an optional string you attach to multiple runs so Trodo can treat them as part of the same multi-turn flow. When you pass the same non-empty conversationId across several runs, the dashboard surfaces a Conversation · N indicator on the runs list, and the conversation view shows every turn stacked in order. Conversation IDs are never inferred — you must pass them explicitly:
await trodo.wrapAgent('chat', fn, { distinctId: 'user-42', conversationId: 'thread-abc' });

Spans

Spans are the building blocks of a run. Each span represents a single operation within your agent’s execution:
  • An LLM generation call.
  • A tool or function invocation.
  • A retrieval / vector search.
  • A nested agent stage.
  • Any custom operation you want to track.
Spans are hierarchical — a parent span can contain multiple child spans. The resulting tree represents your agent’s execution flow and makes it easy to see:
  • Which operations happened in what order.
  • How long each operation took.
  • Where errors occurred in the execution path.
  • What inputs each step received and what outputs it produced.

Span kinds

A span’s kind is a type tag that determines which fields the dashboard renders and which rollups the run inherits. Six kinds:
KindUsed forFeeds run rollups
llmModel calls (OpenAI, Anthropic, Bedrock, …)total_tokens_in, total_tokens_out, total_cost
toolFunctions the agent invoked (search, DB, API)tool_count
retrievalVector search, KB lookup, RAG retriever
agentA nested sub-step rendered as an “agent stage”
chainA chain / graph step (LangChain, LangGraph)
functionGeneric instrumented function call

LLM span fields

LLM spans carry the most structured data. For every supported provider, Trodo auto-populates these fields from the response — you don’t set them manually unless you’re calling the provider via raw HTTP.
FieldWhat it isAuto-captured?
modelThe requested model ID (e.g. gpt-4o-mini)Yes
providerThe vendor (e.g. openai, anthropic)Yes
input_tokensPrompt tokens consumedYes (from response usage)
output_tokensCompletion tokens producedYes
costUSD cost, computed from tokens + modelYes (server-side pricing table)
temperatureSampling temperature usedYes (from request body)
inputPrompt messagesYes
outputCompletion contentYes
error_type / error_messageException details if the call threwYes (on throw)

Tool span fields

FieldWhat it isAuto-captured?
toolNameThe tool/function name (e.g. search_kb)Yes (LangChain, LlamaIndex, OpenAI Assistants tool calls)
inputArguments the tool was called withYes for framework-managed tools; manual otherwise
outputReturn value / tool resultYes for framework-managed tools; manual otherwise

Retrieval span fields

Retrieval spans have no required fields beyond name. Convention is to record the query as input and a summary of results (count, top IDs) as output so the dashboard waterfall shows what was searched and what came back.

Universal span fields

Every span, regardless of kind, carries:
FieldWhat it is
nameFree-text label (e.g. chat.completions, search_kb)
kindOne of the six kinds above
statusok on success, error on thrown exception
duration_msWall-clock time from start to end
attributesFree-form key/value metadata (e.g. customer_tier, region)

parent_run_id

Links two runs together. Use when a sub-agent has its own lifecycle (own name, own rollups) but is triggered by another agent. Lives on the child run. The parent shows in the dashboard as “run X triggered sub-run Y”, and you can navigate between them. See Recipes → Sub-agents for the pattern.

Propagation

How the SDK knows which run a span belongs to — without you passing runId everywhere.
  • In-process. Node uses AsyncLocalStorage, Python uses contextvars. Every withSpan, tool(), llm(), retrieval(), trace(), or auto-instrumented provider call inside wrapAgent (or inside any function it awaits) attaches automatically. Context survives await, imports, helper functions — the whole async chain inside the process.
  • Cross-service. Trodo’s SDK attaches an X-Trodo-Run-Id header to outbound HTTP when you use propagationHeaders(). The receiving service’s middleware (expressMiddleware, fastapi_middleware) reads it and calls joinRun so its spans land on the caller’s run. See Recipes → Cross-service.
  • Out-of-context. If you emit spans from a file outside an active wrapAgent — worker threads, process pools, queue consumers — you must capture the runId in the parent, pass it across the boundary, and call joinRun(runId, fn) in the child. See Tracing → Spans outside wrapAgent.

Projects and sites

A site is the top-level container in Trodo. It groups:
  • All runs from your agent(s) for a given environment.
  • The users tracked in that environment.
  • The dashboards, clusters, and monitors built on top of those runs.
Each site has:
  • A site ID — used when calling trodo.init() and for SDK authentication.
  • A dashboard for viewing and analysing data.
Most teams run one site per application per environment — e.g. my-app-prod, my-app-staging. Separating environments by site keeps prod dashboards clean and makes staging experimentation safe.

Tracer provider

The tracer provider is the OpenTelemetry component responsible for creating and managing spans, exporting them to Trodo’s OTLP endpoint, and handling batching and retries. You normally never interact with it directly — trodo.init() sets it up. Two cases where it matters:
  • Dual export. You already run an OTel provider (Honeycomb, Datadog, Jaeger). Trodo attaches its own span processor alongside yours — both backends receive every span. See Recipes → Dual export.
  • Advanced custom instrumentation. Use trodo.getTracer() to get the underlying OTel tracer if you want to emit spans via the raw OTel API. They flow through to Trodo like any other span.

Next steps