Skip to content

feat(tui): split each token-meter band into new and cache-read work - #1068

Merged
edwin-zvs merged 1 commit into
mainfrom
meter-cached-band
Aug 1, 2026
Merged

feat(tui): split each token-meter band into new and cache-read work#1068
edwin-zvs merged 1 commit into
mainfrom
meter-cached-band

Conversation

@edwin-zvs

Copy link
Copy Markdown
Contributor

What

A turn's prompt side is mostly context the provider already holds, so a meter column that reads as 90k of work can be 80k of re-sent conversation. The meter had no way to say which — cached input was deliberately excluded from the total to avoid double-counting, and then discarded.

Now it rides along. TokenSample gains a cached field: a subset of tokens (so tokens - cached is the new work), #[serde(default)] so records written before it existed load as 0. It's populated by both the live usage path and the boot-time transcript scan, so a restarted client draws the same columns it had before.

Each model's band then splits in two — its new work at the base, the cache-served remainder directly above it, in the same hue pushed toward black (blend_color(Black, base, 0.45)).

  • Bar height is unchanged: it stays billed volume. Cached is shading, not an addend.
  • Legend rates are unchanged: still tokens-per-second of billed volume.
  • Hover names the exact cached figure per model (opus 90.0k (80.0k cached)), which is the only place the shaded part gets a number.
  • A zero part draws no band at all, and a harness over-reporting cached is clamped to the sample so the subtraction can't underflow.

The recessed shade has to be a color, not Modifier::DIM: one terminal cell can hold a model's own new/cached boundary, and there the two parts are the glyph's foreground and its background — an attribute would dim both or neither. ColumnCell/column_cells/stacked_eighths are now generic over the band key so the same machinery draws a same-model boundary exactly like a cross-model one.

Also: more margin between legend columns (1 → 3). A rate sits against its cell's right edge and the next cell opens with a dot, so a single space of separation read as one run of text rather than as columns. The gap is a named constant folded into the cell width, so the rate anchor, the column count, and the inter-column spacing stay consistent.

Spec

specs/0167-fleet-token-meter.md gains "Cached input is a subset, and it shades a band rather than growing it" — the subset contract, why height stays billed volume, why same hue and why a color rather than an attribute, and what a harness reporting no cache figure looks like. The legend-grid section picks up the per-cell margin, and "The stack must survive the cell grid" is reworded from series boundary to band boundary to cover the same-model case.

Tests

New unit coverage for: the split not changing column height, each model keeping its two parts adjacent, a zero part producing no band, over-reported cached being clamped, seeded history keeping its cached share, the cached color being darker on every channel while holding hue, and a same-model boundary encoding as fg-over-bg. Legend tests assert against the gap constant rather than a literal.

Binaries

Touches crates/cli, crates/daemon, crates/protocol → the user-visible change is in construct.

A turn's prompt side is mostly context the provider already holds, so a
column that reads as 90k of work can be 80k of re-sent conversation. The
meter had no way to say which: cached input was deliberately excluded
from the total to avoid double-counting, and then thrown away.

Carry it instead. `TokenSample` gains a `cached` field — a subset of
`tokens`, additive on the wire — fed by the live usage path and by the
boot-time transcript scan, so a restarted client draws the same columns.
Each model's band then splits in two: its new work at the base and the
cache-served remainder directly above it, in the same hue pushed toward
black. Bar height stays billed volume and the legend's rates are
unchanged; only the shading is new. Hover names the exact cached figure
per model.

The recessed shade has to be a color rather than DIM: a single cell can
hold a model's own new/cached boundary, where the two parts are the
glyph's foreground and its background, and an attribute would dim both
or neither.

Also widen the legend's inter-column margin from one column to three.
A rate sits against its cell's right edge and the next cell opens with a
dot, so one space of separation read as one run of text rather than as
columns.
@edwin-zvs
edwin-zvs merged commit cb342b4 into main Aug 1, 2026
1 check passed
@edwin-zvs
edwin-zvs deleted the meter-cached-band branch August 1, 2026 05:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant