perf(server): cut chatty tool-update frames by 90% - #8368
Conversation
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
d532cc5 to
8995244
Compare
ApprovabilityVerdict: Not approved Macroscope's review found this PR not approvable — The production thread WebSocket path now batches live events and intentionally suppresses intermediate tool-update frames, changing delivery timing and observable stream behavior for existing subscribers. The marker-aware buffering and sequence-preservation logic make this more than a small isolated optimization. You can add or adjust custom eligibility rules. Learn more. |
What changed
The thread WebSocket stream now coalesces live
tool.updatedevents in a bounded 50 ms window. It keeps the newest update per tool call, lets completion supersede preceding updates, and preserves sequence and synchronization-marker ordering.Why
Chatty tools can emit many updates for one call. The server previously sent every update as a separate frame even though clients ultimately render the newest state and completion. This creates avoidable remote traffic and frame processing.
Measured impact
Compared with
main-latest.jsonfrom main commit230c5d4a, using twenty deterministic updates followed by completion:The broader measured-turn scenario reduced live messages from 11 to 8 for both Codex and Claude. Snapshot traffic remains within 0.1% of main. Every enforced ceiling passes.
Validation
vp test run apps/server/test/ActivityPayloadProjection.test.ts, 21 tests passedapps/server/src/server.test.tsvp exec tsgo -p apps/server/tsconfig.json --noEmitChecklist
Generated with GPT-5.6 Sol through the Codex harness.
Note
Medium Risk
Changes real-time orchestration WebSocket delivery semantics (fewer frames, same identity rules as snapshot slimming), so ordering edge cases around sync markers and parallel tool calls need careful review.
Overview
Live thread subscriptions now batch
thread.activity-appendedevents through a 50 ms / 512-event window and runcoalesceLiveToolUpdatedEventsbefore projecting payloads, so chattytool.updatedtraffic collapses to the latest update per tool call (per turn + lifecycle identity).tool.completedstill wins over earlier updates for the same call, and non-tool events, anonymous activities, and cross-turn identities are left alone.The WebSocket path mirrors the existing shell coalescing pattern: events are buffered as raw **
OrchestrationEvent**s,synchronizedmarkers flush the pending window without being reordered ahead of in-flight updates, and survivors keep sequence order for client dedup. Snapshots still usedropSupersededToolUpdatedActivitieson persisted activities; this change targets live streaming only.Unit tests cover coalescing rules; an integration test asserts
subscribeThreaddelivers sequence 4 after three buffered updates for onetoolCallId.Reviewed by Cursor Bugbot for commit 8995244. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Coalesce live
tool.updatedevents insubscribeThreadto cut WS frames by 90%coalesceLiveToolUpdatedEventsto keep only the latesttool.updatedper tool call (per turn) and let anytool.completedsupersede earlier updates in the same batchcoalesceThreadLiveStreamgroups incoming live events by a 50ms / 512-event window, applies coalescing per segment, and projects events after coalescing so sequence numbers stay correctsubscribeThreadnow queues rawOrchestrationEventobjects and flushes atsynchronizedmarkers (includingrequestCompletionMarker, snapshot, and catch-up replay) so coalescing never crosses a flush boundarytool.updatedframe, those are dropped within each 50ms window. TheTHREAD_TOOL_UPDATE_COALESCE_WINDOWandTHREAD_TOOL_UPDATE_COALESCE_MAX_CHUNKconstants control the trade-offMacroscope summarized 8995244.