Files
qwen-code/docs/design/token-usage-hierarchy.md
T
qqqys 9d2ee877c2 feat(web-shell): plot per-request speed and failures in token usage (#16111)
* feat(web-shell): show request success rate and distinct model colors in token usage

The token usage panel tracked failed API calls but never showed them, and
models were hard to tell apart: the first two series colors were both blue,
every share bar started from the same blue, and the card had no color mark.

- Add a success rate to the overview and to each model card, with a status
  icon (ok / warning below 100% / error below 90%) and the failed count.
  Each retry counts as its own call, as in `api.totalErrors`.
- Add session output speed to the overview, weighted over all timed models.
- Replace the model palette with six categorical colors checked for
  color-vision-deficiency separation, with dark-theme steps. Colors follow
  the order models were first used, so a model keeps its color when the
  token ranking changes; models past the sixth share a neutral color.
- Add a stacked per-model share bar with a legend, and a color strip on
  each model card. Share text keeps the foreground color.

* feat(web-shell): plot per-request speed and failures in token usage

Token usage showed one average output speed per model, so a slowdown
mid-session or a few slow outliers looked the same as a steady rate,
and failed calls had no time or kind.

- Core keeps, per model in the stats buckets, the latest 200 timed
  responses (time, first token, generation window, output tokens,
  subagent) and failed calls by status code or error type with the
  latest 50. Session replay rebuilds both from stored events.
- The daemon stats route returns them as optional `timingSamples` and
  `failures`; older daemons omit them.
- Web Shell adds a speed-over-time chart: one dot per request in the
  model's color, a five-point median line, a toggle to first-token
  latency, failure marks, a nearest-request tooltip on hover or tap,
  and a legend that hides series.
- Model cards add an output-speed spread (p50, p10-p90 on a shared
  scale) and failures by kind.
- Add the design doc in English and Chinese, and point the token usage
  hierarchy doc at it for the model palette.
2026-11-02 08:26:53 +00:00

8.0 KiB

Token usage hierarchy

English | 简体中文

Problem and scope

The session Token Usage panel repeats metrics in tall cards, making comparison difficult. Change presentation and disclosure while preserving numeric values, token normalization, daemon routes, polling and SDK contracts. Use the requested shorter labels “Cache” and “Reasoning” in place of “Cached input” and “Reasoning (included in total output)”.

Design

Place the session total above a rounded two-column overview, with “Total tokens” inline after the number and refresh/time on the right, including when the header wraps. Use foreground text for the total label with at least 4.5:1 text contrast. The primary columns are Input and Total output. Use fixed 28px text for the session total and 24px for primary overview values. Input retains the complete normalized count without subtracting cached tokens; its caption shows cache count and cached/input percentage. Output retains a reasoning-count caption. Preserve zero values. Use normal 12px foreground sans-serif captions and omit inclusion notices.

Sort models by normalized total consumption in descending order. Use fixed 15px bold names, 14px shares and solid bars in the model's color; Token usage trend and model colors defines the palette, the success rate and the speed timeline. Omit rank tiles, per-model token-total lines, click disclosures and row-hover backgrounds. One shared Tooltip provider groups the panel so moving promptly between rows skips another 300ms delay. Below the name, an always-visible three-column grid shows per-model API timing inline, because comparing these values across models is a primary reason to open the panel. Cells flow in order: average first-token latency and, when generation duration is positive, output speed and average generation time for timed streams, followed by request count and average latency. Models without streamed timing show only request count and average latency in the first row. Keep the original arithmetic and availability conditions. Grid labels use foreground mixed 70% with the card so they reach at least 4.5:1 contrast; values use fixed 13px monospace and stay on one line. Labels and values retain their full localized text in HTML title attributes so ellipsized text remains available at narrow panel widths. Use local foreground colors for authored focus indicators (including Refresh) so they contrast at least 3:1 against their adjacent card in light and dark themes; keep the global theme tokens unchanged.

Above each bar, show “Input xxx (cache rate: xxx) · Total output xxx”. Hide the separate cache count and reasoning from the inline row. Keep it on one line with ellipsis on overflow. Hover, keyboard focus and touch always expose input, cache count with ratio, output and reasoning, one complete metric per tooltip line, whether the row fits or is clipped. Use an ordinary arrow cursor for the metric row. Put the consumption share at the far right of the track; hovering, focusing or tapping the track shows “Token share: percentage”. Tapped share tooltips remain open until dismissal; their noninteractive content does not intercept taps on adjacent metric rows. Keep actual shares, including an over-reported source above 100%, without silently clamping the displayed number. Keep the bar row's top margin, model-list gap and model-heading bottom margin at zero. All fonts remain fixed during sidebar resizing. By model, By agent and Tools headings share the same size, weight and color.

Keep “By agent” collapsed initially. Always place “Main Agent” first, then individual subagents in descending normalized-total order without type groups or aggregate headers. Derive Main Agent from session model totals minus reported subagent usage: normalize input and total per source before subtracting them, and subtract cache and reasoning separately. Clamp the remaining total to zero, input to remaining total, cache to input and reasoning to output; derive output as remaining total minus input. Main Agent is the remainder outside attributed subagents and is not added to the overview. An empty sources array shows Main Agent; an omitted field hides the section because older daemons cannot distinguish attribution.

Use the same card for every agent: original name at the left and a differing localized type at the far right of the header, truncated with its full HTML title when needed. Compare name/type text without case sensitivity and show identical text once in the entire card; preserve a different localized type. Keep fixed 12px text, foreground type labels with at least 4.5:1 contrast, pale rounded borders and horizontal padding aligned with the section heading. Each share uses the session model aggregate as denominator. Keep actual invocation IDs in subagent cards' HTML title attributes and React keys; Main Agent has a separate frontend marker without a fabricated daemon source ID. Omit ordinals, nested disclosures and inclusion notices.

Affected files and constraints

Update TokenUsagePanel.tsx, its CSS Module and focused tests, client/i18n.tsx and the browser E2E spec. Reuse the shared portal-aware Tooltip primitives, TokenSummary for the overview, and TokenDetails for model/agent rows. Add no dependencies or backend changes. Preserve unavailable/loading/error/retry states, session mismatch protection and optional legacy source/tool sections. Retain the two-child agent header's right alignment.

Keep punctuation in the language catalog, including full-width Chinese punctuation. Keep Token Usage translations in a dedicated interactive-only dictionary, replaced with an empty stub in the read-only transcript build. Guard that the transcript contains no Token Usage keys or lookups, while the interactive entry retains English and Chinese copy.

Validation and acceptance

Run build, typecheck, bundle, focused tests, lint/format and Chromium browser tests: 1200px English light, Chinese light and English dark, plus 390px English touch light and Chinese touch in light and dark themes. This matrix does not claim WebKit coverage. Cover normalized model sorting with fixtures whose raw and normalized orders disagree, cached-only input, legacy totals, zero values, Main Agent remainder bounds (assert cache and reasoning caps through the complete tooltip, including a zero remainder), entire-card duplicate-name checks (including localized type capitalization) and source-ID HTML titles. Pin cached-only Main Agent subtraction and negative input/cache/reasoning floors, complete overview captions, and tooltip label/value pairs in both locales. Verify streamed timing values in the always-visible timing grid and their absence when unavailable in both locales, with no Info button on model cards. Verify visible-content constraints, untruncated timing values at 390px and full HTML titles for clipped timing labels and values when dragging to the minimum panel width (including a 449.0 tok/s fixture), small-text/focus contrast, matching heading styles, colored-text contrast, long-name truncation, far-right type alignment on wide cards, grouped tooltip timing, share-tap persistence and adjacent-row access, tooltip hover/focus/touch behavior, and fixed fonts while actually dragging the sidebar narrower and wider, and right-aligned refresh metadata after wrapping at 320px with a fixed clock for repeatable layout checks. Pause automatic polling before page load in the manual refresh test. Verify that the initial response is visible and exactly one read has occurred, then require the click to produce exactly one new request and updated visible values. Confirm that suppressing the manual handler makes this assertion fail.

Capture a real saved session through the local bundled daemon without new model prompts or mocked stats, and compare overview/agent values with the response. Inspect desktop and touch screenshots and preserve the user's running preview. Screenshots do not verify provider billing; touch emulation does not replace physical-device or cross-browser testing.

Open questions

None.