diff options
| author | Adam Malczewski <[email protected]> | 2026-06-12 01:10:56 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-06-12 01:10:56 +0900 |
| commit | 0e71903cc1419d20fbd593fd7330defdc4628af2 (patch) | |
| tree | c669251424f49f6d8e5b3ec17e03f486d46740a1 /src/core/metrics/format.test.ts | |
| parent | 6bd7b39f6f53dd8f3743347a1cb72c2f74424dd8 (diff) | |
| download | dispatch-web-0e71903cc1419d20fbd593fd7330defdc4628af2.tar.gz dispatch-web-0e71903cc1419d20fbd593fd7330defdc4628af2.zip | |
feat(chat): old-Dispatch composer layout — textarea + send + status bar
Restore the ergonomic composer from old Dispatch: an auto-resizing textarea
(1→7 lines) with a fixed-width Send button beside it, and a status bar BELOW
holding a status icon · context-window fill bar (escalating success/warning/
error color) · compact token count (current / limit · pct%).
The bar reuses the latest turn's contextSize as current usage and HARDCODES a
1,000,000-token window limit as a placeholder (real per-model limit is the next
backend ask). Absorbs the standalone ContextSizeBadge (removed). Pure helpers
computeContextUsage + formatCompactTokens added to core/metrics (tested).
540 tests green.
Diffstat (limited to 'src/core/metrics/format.test.ts')
| -rw-r--r-- | src/core/metrics/format.test.ts | 44 |
1 files changed, 44 insertions, 0 deletions
diff --git a/src/core/metrics/format.test.ts b/src/core/metrics/format.test.ts index 7c143d7..6a4bd38 100644 --- a/src/core/metrics/format.test.ts +++ b/src/core/metrics/format.test.ts @@ -2,8 +2,10 @@ import type { StepId, StepMetrics, TurnMetrics } from "@dispatch/wire"; import { describe, expect, it } from "vitest"; import { computeCachePct, + computeContextUsage, computeExpectedCachePct, computeTps, + formatCompactTokens, formatContextSize, viewCacheRate, viewExpectedCache, @@ -323,3 +325,45 @@ describe("formatContextSize", () => { expect(formatContextSize(0)).toBe("0 tokens in context"); }); }); + +describe("formatCompactTokens", () => { + it("renders sub-1k counts as-is", () => { + expect(formatCompactTokens(0)).toBe("0"); + expect(formatCompactTokens(812)).toBe("812"); + }); + + it("renders thousands with one decimal (rounded ≥100k)", () => { + expect(formatCompactTokens(12300)).toBe("12.3k"); + expect(formatCompactTokens(150000)).toBe("150k"); + }); + + it("renders millions with one decimal", () => { + expect(formatCompactTokens(1_200_000)).toBe("1.2M"); + expect(formatCompactTokens(1_000_000)).toBe("1.0M"); + }); +}); + +describe("computeContextUsage", () => { + it("computes an unrounded clamped percent against the limit", () => { + const u = computeContextUsage(34102, 1_000_000); + expect(u.current).toBe(34102); + expect(u.max).toBe(1_000_000); + expect(u.percent).toBeCloseTo(3.4102, 4); + }); + + it("treats unknown contextSize as current 0", () => { + const u = computeContextUsage(undefined, 1_000_000); + expect(u.current).toBe(0); + expect(u.percent).toBe(0); + }); + + it("clamps percent to [0,100] and over-limit reads 100", () => { + expect(computeContextUsage(2_000_000, 1_000_000).percent).toBe(100); + }); + + it("max null (no/zero limit) ⇒ percent null", () => { + expect(computeContextUsage(5000, null).percent).toBeNull(); + expect(computeContextUsage(5000, 0).percent).toBeNull(); + expect(computeContextUsage(5000, null).max).toBeNull(); + }); +}); |
