agent-ui: collapse streamed thinking_tokens ticks into one live row
claude streams a running 'estimated_tokens' counter as system/thinking_tokens events — many per turn (thousands in a long turn). renderStream rendered each as a '⚙ thinking_tokens' note, flooding the terminal scrollback. Coalesce consecutive ticks into a single '🧠 thinking … ~N tokens' note row that updates in place; reuse the row only while it's still the last one rendered (nextElementSibling == null) so any other event starts a fresh one. Closes #1818.
This commit is contained in:
parent
6bb976ec72
commit
63a79d76ba
2 changed files with 31 additions and 0 deletions
|
|
@ -71,6 +71,13 @@ suffix, so the terminal degrades cleanly against older event shapes.
|
|||
|
||||
1. Drops `system/init`, `rate_limit_event`, `result` (noise /
|
||||
handled elsewhere — `result` powers the `cost` badge).
|
||||
1a. `system/thinking_tokens` (claude streams a running
|
||||
`estimated_tokens` counter while thinking — many per turn) →
|
||||
collapses into a **single** `🧠 thinking … ~N tokens` `.note`
|
||||
row that updates in place. Consecutive ticks reuse the row only
|
||||
while it's still the last one rendered (`nextElementSibling ==
|
||||
null`); any other event after it makes the next tick start a
|
||||
fresh row. Avoids a note-per-tick scrollback flood.
|
||||
2. `subtype == "task_started" | "task_notification"` →
|
||||
`renderTaskEvent` (subagent activity gets the `⌁` glyph).
|
||||
3. `type == "assistant"` → walk `message.content[]`:
|
||||
|
|
|
|||
|
|
@ -1695,6 +1695,12 @@ window.marked = marked;
|
|||
}
|
||||
return false;
|
||||
}
|
||||
// Coalescing target for the live `thinking_tokens` counter.
|
||||
// Holds the row currently showing the running estimate so consecutive
|
||||
// ticks update in place instead of appending a note each. Reset
|
||||
// implicitly: we only reuse it while it's still the last row rendered
|
||||
// (see the nextElementSibling check), so any other event starts fresh.
|
||||
let thinkingTokensRow = null;
|
||||
function renderStream(v, api) {
|
||||
// Drop claude's result line and rate-limit — noise. TurnEnd
|
||||
// communicates pass/fail; rate-limit events are noisy status chatter.
|
||||
|
|
@ -1722,6 +1728,24 @@ window.marked = marked;
|
|||
api.row('note stderr', '✗ api error · ' + msg);
|
||||
return;
|
||||
}
|
||||
// Live thinking-token counter — claude streams many of these per
|
||||
// turn (a running `estimated_tokens` total while it thinks). Collapse
|
||||
// consecutive ticks into ONE in-place-updating row instead of a note
|
||||
// per tick. Reuse our row only while it's still the last one
|
||||
// in the scrollback; once any other event renders after it, the next
|
||||
// tick starts a fresh row.
|
||||
if (v.subtype === 'thinking_tokens') {
|
||||
const n = v.estimated_tokens;
|
||||
const label = '🧠 thinking … '
|
||||
+ (n != null ? '~' + Number(n).toLocaleString() + ' tokens' : '');
|
||||
if (thinkingTokensRow && thinkingTokensRow.isConnected
|
||||
&& thinkingTokensRow.nextElementSibling === null) {
|
||||
thinkingTokensRow.textContent = label;
|
||||
} else {
|
||||
thinkingTokensRow = api.row('note', label);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Other system subtypes (context_window_exceeded, etc.) — render a
|
||||
// muted note with the subtype label; reserve the loud orange `sys`
|
||||
// catch-all for truly unrecognised top-level types.
|
||||
|
|
|
|||
Loading…
Reference in a new issue