diff options
| author | Adam Malczewski <[email protected]> | 2026-06-12 18:26:00 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-06-12 18:26:00 +0900 |
| commit | 1764e3e5dff836255d121a933dd92542368346f9 (patch) | |
| tree | b835055de0f0f1fd9750741764dac8b30f7498bf /scripts/live-probe.ts | |
| parent | 4001274e3ba25a3946df1e9f2dc82ca6781cd2bf (diff) | |
| download | dispatch-web-1764e3e5dff836255d121a933dd92542368346f9.tar.gz dispatch-web-1764e3e5dff836255d121a933dd92542368346f9.zip | |
feat(chat): chat limit — bulk quarter-unload, 75% fresh-load window, show-earlier page-in
Long transcripts no longer grow unbounded: past the chat limit (default 256
chunks, localStorage dispatch.chatLimit) the oldest ceil(limit/4) committed
chunks are unloaded in ONE bulk pass — never one-per-delta (old Dispatch's
scroll-jump-per-step bug) — and only while the reader is stuck to the bottom
(scrolled-up readers defer the trim; it catches up in whole quarters). A fresh
page load windows to the newest floor(0.75*limit). Unloading is purely local
(IndexedDB cache + server keep everything); a hiddenBeforeSeq watermark keeps
history merges from resurrecting unloaded chunks, and a 'Show earlier messages'
affordance pages a quarter back in from the cache with scroll-anchor
preservation. Thinking-collapse render keys stay stable across trims via a
hiddenThinkingCount ordinal base.
- core/chunks/trim.ts: pure policy (trim/window/restore/normalize) + tests
- chat store: chatLimit + canUnload deps, windowed load, showEarlier()
- composition root: dispatch.chatLimit localStorage knob + unload gate wired
to smart-scroll isAtBottom()
- backend CR-5 OPENED (not a blocker): ?limit=/?beforeSeq= on
GET /conversations/:id (courier backend-handoff-chat-limit.md)
- scripts/live-probe.ts: fix pre-existing stale TurnMetricsEntry reads
(m1.usage -> total.usage) that crashed the probe; 17/17 live checks pass
Diffstat (limited to 'scripts/live-probe.ts')
| -rw-r--r-- | scripts/live-probe.ts | 20 |
1 files changed, 12 insertions, 8 deletions
diff --git a/scripts/live-probe.ts b/scripts/live-probe.ts index 2b2880b..7099b44 100644 --- a/scripts/live-probe.ts +++ b/scripts/live-probe.ts @@ -204,25 +204,28 @@ async function main() { record("turn 1 committed transcript has assistant text", committedText.length > 0); // ─── Metrics: LIVE token + timing ([email protected] usage/step-complete/done) ────── + // (TurnMetricsEntry is `{ turnId, steps, total }` — the turn aggregate lives on + // `total`, present once the live `done` folded.) const liveTurns = selectOrderedTurnMetrics(t1.metrics); const m1 = liveTurns[0]; + const m1Total = m1?.total ?? null; record( "turn 1 LIVE metrics: a turn with output tokens", - m1 !== undefined && m1.usage.outputTokens > 0, - m1 - ? `in=${m1.usage.inputTokens} out=${m1.usage.outputTokens} steps=${m1.steps.length}` - : "no turn", + m1Total !== null && m1Total.usage.outputTokens > 0, + m1Total + ? `in=${m1Total.usage.inputTokens} out=${m1Total.usage.outputTokens} steps=${m1?.steps.length}` + : "no finalized turn total", ); if (m1 !== undefined) { const anyGen = m1.steps.some((s) => s.genTotalMs !== undefined); const anyTtft = m1.steps.some((s) => s.ttftMs !== undefined); note( - `live timing: durationMs=${m1.durationMs ?? "—"}, ` + + `live timing: durationMs=${m1Total?.durationMs ?? "—"}, ` + `genTotalMs present=${anyGen}, ttftMs present=${anyTtft}`, ); record( "turn 1 LIVE metrics carries timing (durationMs or step genTotalMs)", - m1.durationMs !== undefined || anyGen, + m1Total?.durationMs !== undefined || anyGen, "requires the backend runtime to have a clock", ); } @@ -248,10 +251,11 @@ async function main() { applyDurableMetrics(initialMetricsState(), dm.turns), ); const d1 = durableMerged[0]; + const d1Total = d1?.total ?? null; record( "durable /metrics turn has token usage", - d1 !== undefined && d1.usage.outputTokens > 0, - d1 ? `out=${d1.usage.outputTokens} steps=${d1.steps.length}` : "no turn", + d1Total !== null && d1Total.usage.outputTokens > 0, + d1Total ? `out=${d1Total.usage.outputTokens} steps=${d1?.steps.length}` : "no turn total", ); } |
