ReadonlycacheInput tokens this round-trip was served from the provider's prompt cache, billed at the cached rate. A subset of inputTokens. A run whose first iteration writes the cache and whose later ones read it shows that here, which is how to tell a cache that is working from one that is being rewritten every turn. On a realtime audio turn this is the text and audio halves summed, as AiCallResult.cacheReadTokens is, because the gate prices the sum.
ReadonlycacheInput tokens this round-trip wrote into the provider's prompt cache, billed above the base rate. A subset of inputTokens. Reported beside the read count rather than folded into it because the two are priced in opposite directions — Anthropic charges 0.1x base for a read and 1.25x for a write — so a trace holding only reads cannot say why a call cost what it did. Always 0 on a realtime audio turn, which reports no cache write.
ReadonlyinputInput tokens this round-trip consumed, cached ones included. Zero where the provider reported no usage for it.
ReadonlyiterationWhich round-trip this is, counting from 1 across the whole call — every onTurn exchange included, so it matches AiCallResult.iterations on the last entry.
ReadonlylatencyWall-clock milliseconds this round-trip took, measured around the provider request. Retries are inside it: a round-trip the harness retried after a rate limit cost the caller the wait as well as the request, and reporting only the successful attempt would hide exactly the latency worth tracing. The entries therefore need not sum to AiCallResult.durationMillis, which also counts tool execution and hook time between them. On a realtime audio turn it is measured from the response being asked for to response.done, so the first entry includes streaming the audio up and later ones start where the tool outputs were sent back; a live session is not retried, so nothing here is a retry wait.
ReadonlyoutputOutput tokens this round-trip consumed.
ReadonlystopThe provider's stop reason for this round-trip, in its own spelling — AiCallResult.stopReason documents the vocabulary. Null when the provider sent none.
ReadonlysubstitutionsWhat the provider would not send as asked, each spelled out. A model that refuses a forced toolChoice is sent auto with the requirement stated in the system prompt instead; that is a real difference between the call that was written and the call that was made, and without this it is visible only in a server log the script cannot read. Empty on the ordinary round-trip, which is almost all of them, and always empty on a realtime audio turn — it describes a request body that transport never builds, so an empty list there says nothing rather than saying nothing was substituted.
ReadonlytoolThe ids of the tool calls the model requested on this round-trip, in order, which are the id values on the matching AiToolCallEvents. Empty when it answered instead. Ids rather than the calls themselves: a trace is a cost record, and the arguments are already on AiCallResult.toolCalls.
One model round-trip, as
AiCallResult.tracerecords it when the call settrace: true. The token counts are this round-trip's own, not the call's running totals.Example: ```javascript
const result = B.ai.call({ message: B.net.request.parameter("q"), tools: [lookup], trace: true });
B.out = result.trace.map(step => "iteration " + step.iteration + ": " + step.outputTokens + " out, " + step.latencyMillis + "ms, tools " + step.toolCallIds.join(",")).join("\n");