From 27311cd97ff99d3b367a53244c74efddc6ce4f4a Mon Sep 17 00:00:00 2001 From: Rohit C Prasad Date: Tue, 28 Jul 2026 11:48:21 -0700 Subject: [PATCH] Usage popover: 'Uncached input' when a cache split exists Input rows then read as components: uncached + cache reads + cache writes = Total input; plain 'Input' stays for cacheless backends. --- surfaces/gui/e2e/usage-chip.spec.ts | 3 ++- surfaces/gui/src/components/Composer.tsx | 22 ++++++++++++++-------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/surfaces/gui/e2e/usage-chip.spec.ts b/surfaces/gui/e2e/usage-chip.spec.ts index 807ac6ea..bfb98750 100644 --- a/surfaces/gui/e2e/usage-chip.spec.ts +++ b/surfaces/gui/e2e/usage-chip.spec.ts @@ -32,7 +32,8 @@ test("usage chip appears after a turn and opens the breakdown popover", async ({ await expect(pop).toContainText("9.8k of 200k · 5%"); await expect(pop).toContainText("Session totals"); await expect(pop).toContainText("Claude Opus 4.8 · Anthropic"); - await expect(pop).toContainText("Input"); + // Cache split present → the input rows read as components of Total input. + await expect(pop).toContainText("Uncached input"); await expect(pop).toContainText("Cache reads"); await expect(pop).toContainText("Cache writes"); // Total input = fresh 1k + cache_read 8k + cache_write 800 (cumulative billed input). diff --git a/surfaces/gui/src/components/Composer.tsx b/surfaces/gui/src/components/Composer.tsx index 0e353a6a..5d638ee1 100644 --- a/surfaces/gui/src/components/Composer.tsx +++ b/surfaces/gui/src/components/Composer.tsx @@ -658,15 +658,21 @@ function UsageChip({
{labelFor(id)}
+ {/* Every row is a session sum. With a cache split, the input rows are + the three BILLING CLASSES of input (each priced differently) and + read as components: uncached + cache reads + cache writes = total. + Without one (Ollama, compat vendors), plain "Input" says it all. */}
- {stat("Input", t.input)} - {t.cache_read > 0 && stat("Cache reads", t.cache_read)} - {t.cache_write > 0 && stat("Cache writes", t.cache_write)} - {/* Cumulative billed input volume = fresh + cache reads + cache - writes (each class bills at its own rate). Shown only when a - cache split exists — otherwise it would duplicate Input. */} - {t.cache_read + t.cache_write > 0 && - stat("Total input", t.input + t.cache_read + t.cache_write)} + {t.cache_read + t.cache_write > 0 ? ( + <> + {stat("Uncached input", t.input)} + {stat("Cache reads", t.cache_read)} + {stat("Cache writes", t.cache_write)} + {stat("Total input", t.input + t.cache_read + t.cache_write)} + + ) : ( + stat("Input", t.input) + )} {stat("Output", t.output)}