Turn Inspector¶
The turn inspector is the panel that explains a single turn: which nodes ran, how long each took, what prompt the model actually received, what it produced, and what the turn retrieved or called along the way.
It is one component with three hosts. The same blocks, in the same order, with the same behaviour, appear in:
| Host | Where | How you select a turn |
|---|---|---|
| Chat Window | Window ▸ Tryll ▸ Chat |
Click an assistant bubble |
| Agent Log | Window ▸ Tryll ▸ Agent Log |
Click a received turn row |
| Dialog Lab | Window ▸ Tryll ▸ Dialog Lab |
Click a grid cell |
This page is the reference for the panel itself. Each host page covers only what is specific to that host — how turns get selected there, and what else that window does.
Prerequisite: diagnostics must be on
The inspector renders the debug_info payload a turn carries, which requires
enable_diagnostics at CreateAgent. That flag is structural — it cannot be turned
on for an agent that already exists.
You do not normally set it yourself. Chat enables it for the agent it creates, and the Agent Log holds a diagnostics-demand lease so agents created while it is open request diagnostics too. Neither writes to your scene or assets. The consequence is that the Agent Log must be open before an agent is created to get depth on that agent's turns — see Use the Agent Log.
The one thing to understand first: everything is node-attributed¶
A Tryll turn is a graph run, not a single model call. A turn can run a classifier, then a retriever, then a generator — each with its own parameters, its own prompt, and its own output.
So every block below the Route breadcrumb reads per node execution, not per turn. A graph
with two Retrieve nodes shows two hit tables. A graph with a classifier and a generator
shows two prompt subsections, each with its own heading (#2 answer (GenerateNode) [default]).
Click a node chip in the Route breadcrumb to narrow the entire panel to that one node — its parameters, its prompt, its retrieval hits, its raw JSON. Click the same chip again to go back to the whole turn. This is the fastest way to answer "what exactly did the classifier see?" in a multi-node graph, and it is the primary navigation control of the panel.
Block reference¶
| Block | Shown when | Starts | Copy |
|---|---|---|---|
| Route | Always | Expanded | — |
| Timing | Always | Expanded | — |
| Parameters | Diagnostics present | Collapsed | — |
| Checks | Dialog Lab only, with authored checks | Expanded | — |
| Prompt & output | A node produced a prompt or output | Expanded | ✅ |
| Retrieval | The turn ran a Retrieve node |
Expanded | — |
| Tool calls | The turn ran a ToolCall node |
Expanded | — |
| Errors | The turn ended in error or cancellation | Expanded | — |
| Raw JSON | Always | Collapsed | ✅ |
A block with nothing to say is hidden, not rendered empty. If you do not see Retrieval, the turn did not retrieve.
Route¶
The execution order, as a breadcrumb of node name [exit taken] chips — one chip per node
execution, so a node entered twice appears twice.
Chips are selectable: click one to scope the whole panel to that node, click it again to
clear the scope. The scoped chip is highlighted and the Route header's trailing text changes
to <node> only.
"Other branch" exits (not_found, triggered, no_tool_called) are coloured distinctly
from errors — they are usually correct behaviour, not failures.
If the turn never executed, the block says so rather than rendering an empty breadcrumb.
Timing¶
A stacked bar of per-node duration, plus the turn total in the header.
- Each node gets a segment sized by its own
duration_s. Nodes that took no measurable time render grey at zero width — a model-free node likeBranchorTransformnormally does. - Time to first token is marked separately: the delay before the first token arrived, which is the number that governs perceived responsiveness.
- Pause-related figures (
paused_duration_s,pause_count) appear for turns that paused.
Parameters¶
The parameters each node actually ran with, dumped from the turn's diagnostics.parameters
grouped under a heading per node.
This is the parameters the server records into diagnostics, not every field on the node.
Some node fields are deliberately not recorded. When a value is an array — a ToolCall
node's tools signatures, for instance — the elements stack down the value column rather
than collapsing to a bare count.
Starts collapsed, because on most turns it restates configuration you already know.
Checks¶
Dialog Lab only. The authored deterministic checks for that step — Must Contain, Must Not
Contain, Regex Forbid, Max Words — with pass/fail per check. The header shows
N failed or all passed.
The other two hosts have no authored checks, so the block is absent there rather than empty.
Prompt & output¶
The block most often worth opening. For each node that prompted a model, it shows the rendered prompt in the form actually sent — system, user and assistant messages as the model received them — followed by what that node generated.
This is where projection becomes visible: history replay, {{#instructions}} blocks,
knowledge components and Mustache slot substitution have all already happened in what you see
here. If a prompt does not contain what you expected, this block is where that shows up.
Copy on the header lifts the transcript to the clipboard without expanding the section. When a node scope is active it copies the scoped node only, matching what is on screen.
Dialog Lab: two-sided prompt diff
Pinning two cells in the Lab (⇧-click, or the ⊙ in a column header) turns this block into
a line diff — green + for lines only in the selected cell, red − for lines only in the
other. The red side is usually the interesting one: it shows what a variant dropped.
Each node is diffed against its own counterpart, and a node that ran on only one side is
called out as such.
Retrieval¶
One subsection per Retrieve node execution. The header is a funnel —
input.query → raw_result_count → filtered_count → result_count — with threshold,
top_k and the storage name.
The body is the hit table: each retrieved chunk with its distance, in server order (which for
Hybrid retrieval is RRF rank). Rows beyond the threshold are dimmed rather than removed, so
you can see the near-misses that did not make it in. A null distance renders as —.
See Retrieve and Embedded String Storage.
Tool calls¶
For each ToolCall node execution: which function the model called, the arguments it passed,
and the result that came back — as JSON. The header shows the call count and the exit taken.
Two things gate what appears here, and both are configuration rather than defects:
- The node's
disposition. Whether a result is returned to the model at all, and whether the client is notified, is decided byToolCallParams.disposition. A disposition that does not return results leaves the result side empty. See Tool Call. - Server config
include_interaction_in_diagnostics. Tool-call results are joined through the turn's interaction components. With this off, the panel explains that rather than silently rendering a short list.
Errors¶
Present only for turns that ended in error or cancellation, carrying the terminal status and the error detail. The header shows the status.
Raw JSON¶
The escape hatch: the complete debug_info payload the turn carried, pretty-printed.
Everything above is a purpose-built view over this — so anything the panel has no dedicated
block for is still reachable here.
Copy on the header puts the formatted JSON on the clipboard.
Two things currently live here and nowhere else:
- Intent classification. There is no dedicated block for
ClassifyIntent/ClassifyIntentLLMyet. Whether classification matched, and against what, is visible in Raw JSON. (Note this is separate from whether the Agent Log shows a classification event at all, which depends on the node'snotify_clientparameter — see Use the Agent Log.) - Variable replacements and engine/scheduler counters, including the KV-reuse figures that often explain why one sample was slower than another.
When a block is missing or the panel is thin¶
The panel distinguishes these cases rather than rendering an empty section. If you see less than you expected, it is one of:
| What you see | Why |
|---|---|
| "Created before diagnostics capture" | The agent existed before the Agent Log opened. Recreate it, or create new agents while the window is open. |
| "Unsupported schema" | The turn's debug_info is not schema_version 2. Raw JSON may still be offered. |
| "Turn was not executed" | Dialog Lab: a seeded turn (injected without running the graph), or a turn after an error in the same column. |
| A block simply absent | The turn did not do that thing — no Retrieve node ran, no tool was called, no error occurred. |
| Tool-call results empty | The node's disposition does not return results, or include_interaction_in_diagnostics is off server-side. |
Host differences¶
The panel is the same in all three windows and in both engines. What differs is its framing:
| Chat | Agent Log | Dialog Lab | |
|---|---|---|---|
| Default visibility | Visible | Collapsed | Visible |
| Width persisted | Per window, independently of the other hosts | Per window | Per window |
| Checks block | — | — | ✅ |
| Prompt diff (pinning) | — | — | ✅ |
| Non-turn rows | — | Sent / system rows use a different, simpler inspector | — |
In the Agent Log, only received turn rows open this panel. Sent rows and system rows are
selectable too, but they open simpler panels showing the wire payload, deferred variable
batches, and the server's Ack or error — see
Use the Agent Log.
Unity and Unreal parity
Both engines implement the same nine blocks in the same order. Chrome — fonts, splitter behaviour, scrollbar feel — differs, and that is expected.
Related¶
- How-to: Test an Agent in the Editor — the Chat Window
- How-to: Use the Agent Log — per-agent send/receive narrative
- How-to: Compare Dialog Variants — Dialog Lab
- Concepts: Projection and token budgets — why the rendered prompt looks the way it does
- Concepts: Slots and inter-node value passing — how nodes hand values to each other
- Reference: Agent Parameters —
enable_diagnosticsand the rest ofCreateAgentRequest