Large raw_output snapshots from tool_call_update notifications caused
O(N²) traffic through the event pipeline, multi-GB transient allocations
and WKWebView crashes. The fix turns cumulative snapshots into bounded
incremental deltas and removes redundant payload copies.
- Add ToolCallOutputCache keyed by tool_call_id with a 8KB tail
fingerprint and total length. Detects cumulative extensions by
matching the cached tail at the expected offset in the incoming
snapshot, so it works even when the full output grows into the MB
range. Emits suffix deltas with raw_output_append=true; falls back
to a truncated replacement when content diverges.
- Cap any single emitted raw_output chunk at 64KB (MAX_SINGLE_EMIT_BYTES)
with a UTF-8 char-boundary-safe tail and ANSI-sequence-safe trimming.
Apply the same cap to emit_terminal_output_update.
- Bound the cache at 256 entries with FIFO eviction, and clear entries
when the tool call reaches completed / failed / cancelled / error.
- Seed the cache via a dedicated seed() method on SessionUpdate::ToolCall
so the initial event never emits an accidental append.
- Share emit payloads as Arc<serde_json::Value> across broadcast
receivers and skip the Tauri-side clone: serialize once and hand the
same Arc to both the webview emit and the WebSocket broadcaster.
- Add 14 unit tests covering boundary cases: identity, prefix extension
past the cached tail, divergence, oversized deltas, multibyte UTF-8
truncation, final-status cleanup, FIFO eviction, seed semantics, and
ANSI-safe trimming.