diff options
| author | Adam Malczewski <[email protected]> | 2026-06-10 10:34:37 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-06-10 10:34:37 +0900 |
| commit | 89ca80bac1e143a4ec5ba6e2e1d4998acce2553c (patch) | |
| tree | 7af49f5fd2385c02153accb5fdb0a6c43ba37229 /src/core/metrics/format.ts | |
| parent | f8bf715abc8a89ec0c6370b40403c509b1ce2870 (diff) | |
| download | dispatch-web-89ca80bac1e143a4ec5ba6e2e1d4998acce2553c.tar.gz dispatch-web-89ca80bac1e143a4ec5ba6e2e1d4998acce2553c.zip | |
feat(metrics): inline cache hit-rate badges (last turn + chat total)
Derive cache hit rate (cacheReadTokens / inputTokens) from data already
folded in core/metrics — no backend/contract change.
- core/metrics: computeCachePct + viewCacheRate (pct + success/warning/error
level by 66/33 thresholds + isHit); thread a running cumulativeUsage onto
each finalized turn-metrics row for the conversation total.
- ChatView: render two labelled, colour-coded percentage badges in the
turn-total bubble — "Last turn:" (that turn) and "Chat Total:" (cumulative).
- Honour backend caveats: absent cache fields -> 0, divide-by-zero guarded,
a legitimate 0% renders plainly (not "no data").
Diffstat (limited to 'src/core/metrics/format.ts')
| -rw-r--r-- | src/core/metrics/format.ts | 28 |
1 files changed, 27 insertions, 1 deletions
diff --git a/src/core/metrics/format.ts b/src/core/metrics/format.ts index 3a4078c..cc86976 100644 --- a/src/core/metrics/format.ts +++ b/src/core/metrics/format.ts @@ -1,5 +1,5 @@ import type { StepMetrics, TurnMetrics, Usage } from "@dispatch/wire"; -import type { StepMetricsView, TurnMetricsView } from "./types"; +import type { CacheRateView, StepMetricsView, TurnMetricsView } from "./types"; function formatTokens(n: number): string { return n.toLocaleString("en-US"); @@ -49,6 +49,32 @@ export function viewStepMetrics(step: StepMetrics, index: number): StepMetricsVi }; } +/** + * Cache hit rate as a 0..100 integer percentage: `cacheReadTokens / inputTokens`, + * clamped to [0,1]. Absent cache field counts as 0; a 0% rate is legitimate (not + * missing data). Returns 0 when there are no input tokens. + */ +export function computeCachePct(u: Usage): number { + const read = u.cacheReadTokens ?? 0; + if (u.inputTokens <= 0) return 0; + const rate = read / u.inputTokens; + const clamped = rate < 0 ? 0 : rate > 1 ? 1 : rate; + return Math.round(clamped * 100); +} + +/** Colour severity for a cache hit percentage (badge colour). */ +function cacheLevel(pct: number): "success" | "warning" | "error" { + if (pct >= 66) return "success"; + if (pct >= 33) return "warning"; + return "error"; +} + +/** Build a view of a cache hit rate (percentage + colour level + hit flag). */ +export function viewCacheRate(u: Usage): CacheRateView { + const pct = computeCachePct(u); + return { pct, level: cacheLevel(pct), isHit: (u.cacheReadTokens ?? 0) > 0 }; +} + /** Build a formatted view of a turn's aggregate metrics. */ export function viewTurnMetrics(turn: TurnMetrics): TurnMetricsView { const total = totalTokens(turn.usage); |
