Repository navigation
feat(runtime): show a turn's cost and context while it runs - #7074
Merged
Merged
Conversation
A tool that listens to a running turn could only report what it cost after the turn ended, so long agentic work looked frozen and then jumped at the end. Each model call now reports the price of that call on the route that served it and the prompt the provider billed, so a client can follow the work as it happens. The turn's own totals remain the record once it ends. The mobile control page shows that reading in its header, keeps each conversation's figure when you switch away and come back, and never presents a compaction pass as the conversation's spend.
Review fixes on top of the contributor's live-usage change, kept on the contributor's branch so the PR lands as itself. - Automatic compaction items no longer blank the conversation's figure, and a compaction pass is never presented as the conversation's spend. A compaction that owns a separate Runtime turn resets the figure like any new turn. - turn.completed replaces the token counts with the authoritative payload.turn.usage but keeps the priced-call estimates already observed, so the price no longer disappears at settlement. - The figure carries its turn id and replay high-water sequence per thread. A new turn resets it, so the next turn no longer accumulates onto the last one, and a replayed start, receipt or completion cannot reset or re-add it. - Money reads "~$0.10 partial" with a tooltip that names what it excludes (unpriced, child and compaction work); an unpriced call accrues tokens but never invents free money, and amounts require the matching *_priced flag. - The four tests that matched the page's source strings and the new code comments are removed to follow the repository's no-new-tests, no-new-comments rule for this change; the existing recovery-test receipt assertions stay. docs/RUNTIME_API.md and its zh_hans mirror describe the final behaviour. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Hmbown
pushed a commit
that referenced
this pull request
Oct 25, 2026
…queue fix Two landed changes had no [Unreleased] entry. - #7074 (@gaord): the Runtime API's turn.usage receipts now carry each call's priced cost and billed prompt size and the mobile control page shows live usage with a partial cost estimate. The contributor's PR did not touch the changelog and the merge range has no other mention, so this entry carries the credit. - #6561: a generic fatal engine error no longer turns on offline queueing by itself (7d84d0b). The environment-only authentication branch is unchanged. crates/tui/CHANGELOG.md is regenerated by scripts/sync-changelog.sh. Verified: scripts/release/check-versions.sh exits 0 after this change (workspace, npm and lockfile 0.10.2; 26 linked issue references checked in v0.10.1..HEAD) and sync-changelog reports the mirror up to date. Docs only; no source file changed. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Hmbown
pushed a commit
that referenced
this pull request
Oct 25, 2026
node web/scripts/check-facts.mjs failed at d4d50f7 and at e6c400e with "generated agent docs are stale". Two committed sources changed without their generated copies: - docs/RUNTIME_API.md (the #7074 merge) was newer than its sha256 and embedded content in web/data/agent-docs.generated.json. - the cloud-computer-dispatch summary in docs/features.toml, shortened in 46aa866 for the 120 character limit, was newer than web/data/features.generated.json. Regenerated with node web/scripts/derive-facts.mjs only (version=0.10.2 crates=30 providers=50 models=91 tools=79); no hand edit. The diff is those two files, 4 lines each. This clears the one baseline gate failure that the crate-split windows would otherwise inherit, so a later docs gate can tell its own failure from this one. Verified: node web/scripts/check-facts.mjs exits OK ("committed facts.generated.ts matches workspace") after this change; it printed FAIL before it. No cargo, no source file touched. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What and why
A client only learned a turn's cost and context when the turn ended, so a long
agentic run looked frozen and then jumped. The runtime already emits a usage
receipt per model call; those receipts now also carry:
billed_prompt_tokens— the prompt size the provider billed for that call(the last itemised request when retries were reported, else the call's input),
the same basis the context meter reads.
cost— that call priced on the route it was dispatched on, as{usd, cny, usd_priced, cny_priced}. It isnullwhen the route cannot priceevery token class the call used: an unpriced step is absent, not free.
The route is captured from
TurnStarted/RouteDispatchedin the turn monitor,so no store read happens on the hot path and the price always names the route
that served that step. The turn's authoritative totals still arrive with
turn.completed;GET /v1/threads/{id}/usageremains the record.runtime_mobile.htmluses the receipts for a usage reading in the chat header:it moves while the turn runs, is keyed per thread so switching away and back
does not restart it, dedupes replayed journal frames by
seq, and never adoptsa compaction turn's usage as the conversation's spend.
Docs:
docs/RUNTIME_API.mdanddocs/zh_hans/RUNTIME_API.mdaddturn.usageto the event list with these fields.
Issue
No-Issue: additive event fields and a mobile-page reading; no tracking issue.
How I tested it
scripts/dev-cargo.sh check -p codewhale-tui --lib --lockedscripts/dev-test.sh crates/tui/src/runtime_threads.rs runtime_threads::tests— 291 passedstep_receipts_carry_a_price_for_the_dispatched_route(real engine throughmonitor_turn: receipt is priced on its route and names the billed prompt),priced_step_usage_prices_a_metered_route_on_its_established_endpoint,billed_prompt_tokens_reads_the_last_itemised_requestthe_mobile_page_shows_a_turns_usage_while_it_runs(subscribes, keepsreceipts out of the event log, per-thread figure, replay dedupe, compaction)
scripts/dev-cargo.sh test -p codewhale-tui --test feature_registry --lockedrustfmt --checkclean on the touched Rust filesNot verified: no browser run of the mobile page; its script is syntax-checked
(
node --check) and covered by the structural test only.