From c65127f791c385c1d3bb66cb2f1b17e50e66af22 Mon Sep 17 00:00:00 2001 From: Xubin Ren <52506698+Re-bin@users.noreply.github.com> Date: Mon, 17 Aug 2026 12:32:17 +0800 Subject: [PATCH] refine(tui): clarify model telemetry --- tui/src/app.test.ts | 5 +++-- tui/src/footer-hints.test.ts | 19 ++++++++++++++++--- tui/src/footer-hints.ts | 34 ++++++++++++++++++++-------------- 3 files changed, 39 insertions(+), 19 deletions(-) diff --git a/tui/src/app.test.ts b/tui/src/app.test.ts index 09cde1a29..97f328c30 100644 --- a/tui/src/app.test.ts +++ b/tui/src/app.test.ts @@ -1381,8 +1381,9 @@ describe("NanobotTui layout", () => { const footer = setup.captureCharFrame().split("\n").find((line) => line.includes("Ready · 1.7s")) || "" expect(footer).toContain("Ready · 1.7s") expect(footer).toContain("50 tok/s") - expect(footer).toContain("cache 75%") - expect(footer).toContain("↑1.2k ↓80") + expect(footer).toContain("1.2K in · 80 out") + expect(footer).toContain("75% cached") + expect(footer).not.toContain("TTFT") expect(footer).not.toContain("enter send") app.accept({ event: "reasoning_delta", chat_id: "chat", text: "hidden" }) diff --git a/tui/src/footer-hints.test.ts b/tui/src/footer-hints.test.ts index 17c95fc73..40e7af4b1 100644 --- a/tui/src/footer-hints.test.ts +++ b/tui/src/footer-hints.test.ts @@ -29,7 +29,7 @@ describe("footerHints", () => { expect(active.chunks).toHaveLength(0) }) - test("shows measured throughput, cache ratio, token counts, and TTFT", () => { + test("shows measured throughput, explicit token directions, and cache ratio", () => { const result = footerTelemetry({ prompt_tokens: 1200, completion_tokens: 80, @@ -41,10 +41,23 @@ describe("footerHints", () => { }, 120, theme) expect(result.chunks.map(({ text }) => text).join("")) - .toBe("50 tok/s · cache 75% · ↑1.2k ↓80 · TTFT 250ms") + .toBe("50 tok/s · 1.2K in · 80 out · 75% cached") expect(result.chunks[0]?.fg?.toInts().slice(0, 3)).toEqual([239, 142, 48]) }) + test("uses familiar compact units for large token counts", () => { + const result = footerTelemetry({ + prompt_tokens: 4_500_000, + completion_tokens: 19_000, + cached_tokens: 3_600_000, + generation_ms: 135_714, + measured_completion_tokens: 19_000, + }, 120, theme) + + expect(result.chunks.map(({ text }) => text).join("")) + .toBe("140 tok/s · 4.5M in · 19K out · 80% cached") + }) + test("degrades telemetry instead of guessing missing provider metrics", () => { const compact = footerTelemetry({ prompt_tokens: 1000, @@ -53,7 +66,7 @@ describe("footerHints", () => { }, 60, theme) const unsupported = footerTelemetry({ prompt_tokens: 1000, completion_tokens: 20 }, 60, theme) - expect(compact.chunks.map(({ text }) => text).join("")).toBe("cache 0%") + expect(compact.chunks.map(({ text }) => text).join("")).toBe("0% cached") expect(unsupported.chunks).toHaveLength(0) }) }) diff --git a/tui/src/footer-hints.ts b/tui/src/footer-hints.ts index 3b2996331..906a40c4c 100644 --- a/tui/src/footer-hints.ts +++ b/tui/src/footer-hints.ts @@ -1,6 +1,5 @@ import { RGBA, StyledText, TextAttributes, type TextChunk } from "@opentui/core" -import { formatTokenCount } from "./context-panel" import type { TokenUsage } from "./protocol" export interface FooterHint { @@ -53,6 +52,14 @@ export function footerTelemetry( const estimated = (usage.estimated_tokens || 0) > 0 ? "~" : "" parts.push(`${estimated}${value} tok/s`) } + if (width >= 72) { + const prompt = usage.prompt_tokens + const completion = usage.completion_tokens + if (typeof prompt === "number" || typeof completion === "number") { + parts.push(`${formatTelemetryTokens(prompt || 0)} in`) + parts.push(`${formatTelemetryTokens(completion || 0)} out`) + } + } if ( typeof usage.cached_tokens === "number" && typeof usage.prompt_tokens === "number" @@ -61,19 +68,7 @@ export function footerTelemetry( const hitRate = Math.min(100, Math.max(0, Math.round( usage.cached_tokens * 100 / usage.prompt_tokens, ))) - parts.push(`cache ${hitRate}%`) - } - if (width >= 72) { - const prompt = usage.prompt_tokens - const completion = usage.completion_tokens - if (typeof prompt === "number" || typeof completion === "number") { - parts.push(`↑${formatTokenCount(prompt || 0)} ↓${formatTokenCount(completion || 0)}`) - } - } - if (width >= 112 && typeof usage.ttft_ms === "number") { - const requests = Math.max(1, usage.timed_requests || 1) - const average = usage.ttft_ms / requests - parts.push(`TTFT ${average < 1000 ? `${Math.round(average)}ms` : `${(average / 1000).toFixed(1)}s`}`) + parts.push(`${hitRate}% cached`) } if (width >= 128 && typeof usage.cost_usd === "number" && usage.cost_usd > 0) { parts.push(`$${usage.cost_usd < 0.01 ? usage.cost_usd.toFixed(4) : usage.cost_usd.toFixed(2)}`) @@ -81,6 +76,17 @@ export function footerTelemetry( return footerMetrics(parts, theme) } +function formatTelemetryTokens(value: number): string { + const count = Math.max(0, value) + for (const [threshold, suffix] of [[1_000_000_000, "B"], [1_000_000, "M"], [1_000, "K"]] as const) { + if (count < threshold) continue + const scaled = count / threshold + const compact = scaled >= 10 ? Math.round(scaled) : Math.round(scaled * 10) / 10 + return `${compact}${suffix}` + } + return String(Math.round(count)) +} + function footerMetrics(parts: readonly string[], theme: FooterHintTheme): StyledText { const chunks: TextChunk[] = [] parts.forEach((text, index) => {