Traces
The trace page
Read one trace span by span, including the agent, tool and model spans of frameworks such as Strands Agents, see its logs and evaluation, and act on it with Evaluate, Add to dataset, Optimize and the More menu.
A trace is one request through your app, recorded as a tree of spans.
Header and tabs
The header shows the root operation, its service, start time and any reported status. It lists the trace id, wall time, span and log counts, subagents and errors, with links to the session and user. Tokens and cost appear only when the trace made model calls; ≈ marks an estimate.
A trace in a session also shows its turn number, arrows to the previous and next turn, and the latest session verdict.
The tabs are Conversation, Waterfall, Logs, Evaluation and Metadata. Conversation appears only for traces with agent spans, and opens first when the trace has 500 spans or fewer.
Back returns to the screen that opened the trace. From the trace list it drops your filters, which the browser back button keeps. There is no previous or next trace from the list.
Waterfall
The waterfall is one tree, built from the parent ids of the spans. Each row shows the span, its status, self time and wall time, plus tokens and cost for model calls.
An error stepper moves between failing spans, and type chips (LLM, Tool, HTTP, Function, DB, Agent, Log and Untraced) filter the tree. Critical path marks the chain of spans that gated the end of the trace. Expand all and Collapse all open or fold every row.
The page loads light previews of the spans, each text field cut at 4,096 characters, and fetches a span in full when you open it. One coding-agent turn can hold hundreds of calls that each carry the whole conversation; see Reading a turn.
Model and tool calls
An llm_call span shows the model and provider, temperature, max tokens and top p. Then come the messages by role, the completion, any thinking, and the raw request and response bodies.
Usage lists tokens in and out, reasoning tokens, cache reads and writes, time to first token and cost. Cost is the gen_ai.usage.cost_usd your instrumentation reported, or a price-sheet estimate marked ≈. The requested tool calls and the attributes follow.
A tool_call span shows the tool name, call id, duration, and its input and output as copyable JSON. A failed span shows the error type, message, source and stack.
Spans from agent frameworks
Agent frameworks on the OpenTelemetry GenAI conventions, such as Strands Agents, name each span's operation in gen_ai.operation.name. Their spans are typed by it, whether they reach SyntropyLabs through the SDK's OpenTelemetry bridge (from SDK 0.3.3) or are exported over OTLP to the trace service:
| Operation | Stored as | What it carries |
|---|---|---|
invoke_agent, invoke_swarm, invoke_graph | agent | Named by gen_ai.agent.name, else by the span name (invoke_agent refund-agent). The prompt is the user message and the completion the reply. It adds no tokens of its own, because they are those of the model calls inside it. |
execute_tool | tool_call | Named by the tool. The arguments come from gen_ai.tool.call.arguments or the gen_ai.tool.message event, the result from gen_ai.tool.call.result or the gen_ai.choice event. gen_ai.tool.status: error marks it failed. |
chat, generate_content, text_completion | llm_call | The model, messages, completion and tokens. |
execute_event_loop_cycle | internal | Neither a model call nor a tool call. The waterfall labels it Internal. |
Message content sent as blocks, such as [{"text": "Hi"}], is stored as its text. When the SDK also recorded the same model request with its own instrumentation, the SDK's span is the model call and the framework's span is stored as internal without tokens, so the call is counted once; EVALKIT_COUNT_FOREIGN_LLM=1 counts both. Through the bridge, a gen_ai.* span that names no operation stays a function_call, and before SDK 0.3.3 every one of these spans did, with its tokens dropped.
To export over OTLP without the SDK, point the OpenTelemetry exporter at https://api.syntropylabs.ai/v1/otlp (traces go to /v1/otlp/v1/traces) with the header Authorization: Bearer <environment key>. JSON and protobuf are accepted, gzip-compressed or not.
Logs
The Logs tab lists the log lines written inside this trace, oldest first, with the level and source of each. Filter by text or level. Show span opens the span that wrote a line.
Evaluation
The tab shows the overall score, or "no verdict" or "judge error", with the judge cost and time. Below come the judge's narrative and each evaluator's score; one that could not run reads "skipped", with the reason.
A score from an online rule is labeled as one, and Re-evaluate scores the trace again. Session verdicts are on the session line in the header. To agree or disagree with a judge, use Judge verdicts in an Annotate review; see Calibration and disagreements.
Every evaluation of the trace is kept. History, above the result, says which run you are reading ("Run 3 of 3 · 14 Oct 21:40 · 82 %"), steps to the older and newer runs and draws the score of each run as a line. All runs lists them newest first, with each run's change from the one before, its verdict, how many evaluators passed and how it was started: on request, by an online rule, through the API or by a simulation. An earlier run opens read-only, with Back to latest; evaluating again adds a run on top. A trace evaluated only before history was kept shows that one result as its single run.
Metadata
The Metadata tab lists the service, Environment, start time and SDK. It also counts LLM calls, tool calls and agents, and shows up to 40 attributes of the root span.
Actions
Evaluate, Add to dataset and Optimize are in the header, and the rest in the More menu. An action your plan lacks is disabled, and its tooltip says why.
| Action | What it does | Needs |
|---|---|---|
| Evaluate | Scores the trace now, on the Evaluation tab. | plan feature trace-evaluation, a Model |
| Add to dataset | Turns the trace into a linked dataset row. See Build a dataset from traces. | plan feature datasets |
| Optimize | Proposes changes to the system prompt and tool definitions from this trace, and how to verify them (below). | plan feature trace-optimization, a Model |
| Annotate | Opens your label: score types and a comment. See Work a queue and label from a trace. | plan feature rl-labeling |
| Open in playground | Opens the Playground, without the trace. | chat-playground or project-text |
| Comments | Opens the thread on this trace (below). | membership |
| Copy link | Copies the URL with the Environment and tab, not the selected span. | nothing |
Optimize
Choose an Analysis model and click Analyse. Optimize first reads what kind of trace it is. An agent or model run gets the prompt and tool review below. A request to a backend service with no model call gets the performance review. A request that does both gets both, side by side.
The performance review measures the request from its spans, with no model needed for the findings themselves: where the wall time went (database, outgoing HTTP, model calls, app code) and the critical path, then the same record read more than once, one query per item (N+1), calls run one after another that appear independent, slow queries against the rest of the request, errors and retries, large payloads and HTTP fan-out. Each finding shows its cost in milliseconds and as a share of wall time, the spans it rests on, a fix and how to verify it on the next trace of the same route. The model then explains each finding and sharpens its fix, citing only that finding’s spans, and may mark one as expected with its reason. With nothing standing out, the verdict is No changes needed.
The prompt and tool review reads the trace’s system prompt, its tools with their parameter schemas, the evaluator verdicts stored for it, and the turns those verdicts and the deterministic checks point at. A small trace goes in whole; a long one keeps those turns first and says what it shortened. Evaluate the trace first if you can: a failed evaluator with its reason is the strongest evidence Optimize has. When the trace recorded no system prompt or messages, a one-line note links to the SDK configuration; it is never reported as a problem.
The report has, in order:
- a verdict and a summary of what went wrong, or a plain statement that the trace shows nothing to fix
- the problems, each with a severity, what happened, its root cause and links to the turns, tool calls and verdicts it rests on
- the system prompt with the proposed changes applied, as a diff, and the reason for each change. Copy revised prompt copies it; Save as prompt version saves it to a new prompt or as the next version of an existing one in Prompts, without a label
- tool definition fixes, where the trace shows a tool misused
- how to verify: the steps in order, the impact to expect, the evaluators that should pass afterwards and what to re-run
- the deterministic checks, such as failed spans, token-heavy calls and ignored tool results, computed from the span data rather than by the model
Every suggestion is checked against the trace before it is shown: it must cite something in the trace, a prompt edit must quote text the prompt contains, a tool fix must name a tool and a parameter the agent has, and a step may only name evaluators that judged the trace. A suggestion that fails is left out and listed, with the reason, under suggestions left out.
A fix prompt for your coding agent follows, with a copy button. The report is saved, a failed re-run does not replace it, and Re-run analyzes the trace again. Optimize is not counted as judge spend.
Comments
Any organization member can read and post comments. A comment is markdown, 1–5,000 characters. Its author or an organization Owner or Admin can edit or delete it, and deleting removes it for everyone. Replies are new comments on the same subject; there are no nested threads.
Mention a member as @jane@acme.com or @"Jane Doe"; unknown names stay plain text. Each mentioned member gets one email linking to the trace and Environment, and a bell notification. The author is never emailed about their own comment, and an edit notifies only newly mentioned members.
When content was not captured
Content capture is off when the SDK starts with capture_content=False in Python or captureContent: false in TypeScript. The SDK then strips prompts, completions, bodies, thinking, tool arguments and results, database statements and log messages. Tokens, timing, cost and tool names remain.
Each stripped span carries evalkit.content_captured=false, and its panel says what did not arrive and how to turn capture on. A mask hook that strips text sets no marker. Evaluators that need the missing text are skipped, with the reason; timing and structure evaluators score normally. Add to dataset and Open in playground stay enabled.