diff --git a/frontend/packages/agent/src/app.js b/frontend/packages/agent/src/app.js index 9c6bb8f1..053c9218 100644 --- a/frontend/packages/agent/src/app.js +++ b/frontend/packages/agent/src/app.js @@ -1900,6 +1900,13 @@ window.marked = marked; // null), so any other event starts fresh. let thinkingTokensRow = null; let thinkingTokensText = null; + // Same coalescing trick for claude's generic `status` subtype (bare + // "still working" ticks with no detail beyond the label itself). Without + // this every tick got its own row, so a compaction (which emits a burst + // of these with no other signal) looked like a wall of identical noise + // rather than one "still going" line. + let statusRow = null; + let statusText = 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. @@ -1994,6 +2001,23 @@ window.marked = marked; api.row('note', parts.join(' · ')); return; } + // Bare `status` ticks (claude's own generic "still working" signal, + // no detail beyond the label) — collapse consecutive ticks into one + // updating row instead of a fresh note each, same pattern as + // `thinking_tokens` above. These are the only signal we get during a + // compaction pass (no dedicated "compacting…" event from claude), so + // without collapsing a compaction looked like a wall of identical + // `⚙ status` rows followed by silence. + if (v.subtype === 'status') { + const text = '⚙ status'; + if (statusRow && statusRow.isConnected + && statusRow.nextElementSibling === null) { + statusText.nodeValue = text; + } else { + [statusRow, statusText] = api.mutableRow('note', text); + } + 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.