Repository navigation
feat(widgets): value colors in dollars, tokens and counts on the cost, token and compaction widgets - #47
Draft
eric-engberg wants to merge 74 commits into
Draft
feat(widgets): value colors in dollars, tokens and counts on the cost, token and compaction widgets#47eric-engberg wants to merge 74 commits into
eric-engberg wants to merge 74 commits into
Conversation
Pin down the parts of Tokens Input, Output, Cached and Total the existing tests left open: Input and Output render nothing when neither the transcript metrics nor the context_window totals have a count, a zero transcript count wins over the context_window totals, a zero context_window total is hidden by the zero hide state, non-zero counts and the preview sample stay visible with that state on, a global token number format wins over the widget's own, and each widget's name, description, color, category, editor row, hide state and supported options.
Tokens Input, Output, Cached and Total were the same class apart from where the count comes from, and their label, name, color, description and preview sample. Each carried its own copy of the render (preview sample, missing count, zero hide state, number format, raw or labeled value), the zero hide state, the editor row, the category and the supported options. TokenCountWidget now holds all of that; each widget names its label and preview sample and reads its count. Behavior is unchanged.
Session Cost shows what a session has cost so far, but not how fast it's spending. Session Cost Rate divides the session cost by time, the agent's hourly rate: `Rate: $5.00/hr`. By default it divides by the time Claude spent working (the API duration Claude Code reports), which reads as the rate for the hours it actually worked. A `t` keybind switches to clock time, the whole session including time spent waiting for the user, which reads as the burn rate. It shows nothing until a full minute of the chosen time has passed, since a rate over the first seconds swings wildly.
Claude Code reports each session's cost and time as running totals. Keep each session's totals per Claude Code profile in the daily state file, with where they stood when the UTC day began (zero for a session that started today, otherwise the last totals seen yesterday, or the first seen today), and work out today's totals across the profile's sessions: cost, active time (parallel sessions add up) and clock time (the time any session was running, counted once). Unchanged totals aren't rewritten more than once a minute.
When a line shows Daily Cost Rate, each render records its session's totals under the Claude Code profile (CLAUDE_CONFIG_DIR, or default) and passes today's totals to widgets as dailyCost. With the widget's billed spend option on, the usage prefetch also fetches the extra usage state and works out today's billed spend; without it, the widget triggers no usage fetch at all.
Session Cost Rate shows one session's cost per hour; Daily Cost Rate
shows it across all of today's Claude Code sessions ("Rate Today:
$6.20/hr"). It divides Claude Code's own session costs by default; the
b keybind switches to today's billed spend (as Extra Usage Today shows
it, including claude.ai and other machines). The t keybind switches from
active time (Claude working, parallel sessions adding up) to clock time
(the time any session was running). It shows nothing until a full minute
of the chosen time has passed.
…n' into feat/amount-value-colors
…t/amount-value-colors # Conflicts: # docs/USAGE.md
…amount-value-colors # Conflicts: # docs/USAGE.md # src/utils/usage-prefetch.ts # src/utils/widget-manifest.ts # src/widgets/index.ts
Value colors only knew percents: break points and the gradient's end were whole percents, stepped by 5 and shown with a % sign. A scale can now name a unit (dollars, dollars per hour, tokens or a count), and everything the editor shows or takes follows it: "$5" and "$2.50", "100k" and "1.5M", "3". Each unit sets its step, its range, how many decimals a value can have (dollars go to the cent) and how a typed value reads (tokens take "250k" or "1.5M"). A scale can also set where its gradient ends by default, since an amount has no 100%. Percent scales are unchanged, except that the editor's lowest sample is now half the mid break point rounded down rather than to the nearest, so a count's mid of 1 keeps a sample of 0 below it. formatColoredValue takes an optional suffix, drawn in the widget color like the label, for text after the value.
… and Compaction Counter Value colors (v) come to the widgets that count an amount, with break points in its unit: - Session Cost: green below $5, yellow below $20, red from $20. - Session Cost Rate and Daily Cost Rate: $5/hr and $15/hr. - Tokens Input: 10k and 50k; Tokens Output: 100k and 1M; Tokens Cached and Tokens Total: 10M and 100M. Uncached input stays in the thousands over a session while cache reads add up every turn, so one pair of break points can't fit all four. - Compaction Counter (l, since v cycles its value): 1 and 3, on the count or the auto, manual or unknown count. Its label, trigger split and tokens reclaimed keep the widget color, and the reclaimed value has no value colors. Each gradient ends at the widget's high break point by default. Off, every widget draws exactly the text it did before.
# Conflicts: # src/widgets/CompactionCounter.ts # src/widgets/SessionCost.ts # src/widgets/TokensCached.ts # src/widgets/TokensInput.ts # src/widgets/TokensOutput.ts # src/widgets/TokensTotal.ts # src/widgets/shared/token-count-widget.ts # src/widgets/shared/value-coloring.ts
…t/amount-value-colors
…amount-value-colors
…t/daily-cost-rate
# Conflicts: # src/widgets/DailyCostRate.ts
|
# Conflicts: # src/utils/usage-prefetch.ts
# Conflicts: # docs/USAGE.md
# Conflicts: # docs/USAGE.md
# Conflicts: # docs/USAGE.md
It names its label like the other labeled widgets, so the label editor offers it.
# Conflicts: # docs/USAGE.md
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.



Based on #46 (value colors on the percent widgets), and merges #16 (the shared token count base), #35 (Session Cost Rate) and #37 (Daily Cost Rate), which add or reshape widgets this PR colors. Review the two commits after those merges. It goes upstream after #41, #46 and those three.
What
Value colors come to the widgets that count an amount rather than a percent, with break points in that amount's own unit:
vvvvvlEach one opens the same editor as the percent widgets, which now shows break points, samples and typed values in the widget's unit:
$7.50,250kor1.5M,3.Why
#46 covered the widgets measured against a whole. The rest of the numbers on a status line, what a session costs, how fast it spends and how many tokens it has used, are just as worth reading at a glance. They have no 100%, though, so their break points need to be amounts.
The token break points come from measuring the 23 sessions on my machine, with each API response counted once:
A single pair of break points would leave Input always green and Cached always red, so each widget has its own. With these, 15 to 22 of the 23 sessions stay green on each widget, and only the largest reach yellow or red.
Counting each response once is what upstream's open fix for over-counted tokens does (sirmalloc#595, for sirmalloc#549). Today the token widgets count a response once per content block, which on these sessions comes to 2.6 to 3.7 times the real count (medians of 164 for Input and 6.1M for Cached). Until that fix lands, the colors arrive earlier in a session than these numbers suggest; the break points are set for the corrected counts, so they won't need changing when it does.
How
A scale can name its unit (
ValueUnitinvalue-units.ts): percent (the default, so the existing scales don't change), dollars, dollars per hour, tokens, or a count. The unit sets:$, and tokens in full or withkorM;Break points stay one decimal place apart: 1, or a cent for dollars.
A scale can set where its gradient ends by default. An amount has no 100%, so every widget here ends its gradient at its high break point.
Compaction Counter uses
l(va(l)ue colors), sincevalready cycles its value. It colors the count, or the auto, manual or unknown count. Its icon or label, its trigger split and the tokens reclaimed keep the widget color. For that,formatColoredValuetakes an optional suffix, drawn like the label. The reclaimed value is tokens, not a count, so it has no value colors.Where the code lives:
The editor's lowest sample is now half the mid break point rounded down rather than to the nearest. That keeps a sample of 0 below a count's mid of 1. On a percent scale it can move that sample by one, e.g. 43% to 42%.
Nothing changes until value colors are turned on. Off, every widget draws exactly the text it did before.
Demo
Piped through the real pipeline at three levels, with made-up amounts: a payload with the session cost and times, and a transcript with the token usage and compactions. Daily Cost Rate sees only this session, so it's shown on clock time, apart from Session Cost Rate on Claude's active time.
Powerline
Plain
The editor walkthrough:
7.50.l, in compactions.At the end the preview shows all three in their colors.
Powerline
Plain
Testing
value-units.test.ts(6): each unit's display and typed values, including$2.50,1.5Mand a float product like1.005k, and the rounding helpers.value-coloring.test.ts(6 new):Mid has to start below high ($20).);value-colors-editor.test.ts(3 new): a dollar scale's rows, samples, hint and typed7.50; its gradient ending at $20; and a count's sample keeping 0 below mid.amount-value-colors.test.ts(42):preservesRenderedColors, and unchanged output with value colors off;bun testgives 3155 pass, 0 fail (Bun 1.4.2).bun run lintis clean. A 12-run loop of the editor Ink tests had no failures. The first commit alone also passes lint and tests (3113).runtime-check.sh -c amount-value-colors, with the demo's mid level seeded, showed Bun 1.4.2 and Node 26.10.0 agreeing byte for byte in plain and Powerline modes. The TUI opens and exits under both.