Skip to content

Batch AI events during conversation restoration.#12597

Draft
vorporeal wants to merge 1 commit into
masterfrom
david/batched-ai-events-during-conversation-restore
Draft

Batch AI events during conversation restoration.#12597
vorporeal wants to merge 1 commit into
masterfrom
david/batched-ai-events-during-conversation-restore

Conversation

@vorporeal

@vorporeal vorporeal commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Description

Viewing a large cloud agent conversation could beachball the UI for ~30s. When a viewer joins a shared session, the event loop replays the entire event backlog on the main thread, and every replayed message delta emits a BlocklistAIHistoryModel event that fans out to ~22 subscriber types via flush_effects. Profiling showed ~92% of the freeze was this per-delta subscriber fanout. This got much more noticeable recently because opening a running cloud conversation now attaches to the live session (#11097) and orchestrated sessions are shareable (#11465), so the replay path runs far more often.

This PR coalesces history-model events during viewer catch-up so subscribers see one fanout for the whole backlog instead of one per replayed delta:

  • warpui_core: adds ModelContext::capture_emitted_events_for_model, which runs a closure and extracts events queued for a target model instead of leaving them for delivery.
  • BlocklistAIController: while a coalescing window is active (event-backlog catch-up or an existing-conversation replay), shared-session response handling captures history events into a buffer with last-write-wins dedupe for high-volume events (UpdatedStreamingExchange per exchange, todo list, conversation status/metadata/usage, active conversation). All other events are preserved in order. The buffer is flushed as one batch when the window ends.
  • Viewer EventLoop: begins coalescing when joining with a backlog, tracks AgentConversationReplayStarted/Ended brackets, and flushes at catch-up completion.

Deferring is safe because events are already delivered asynchronously via flush_effects, payloads carry IDs that handlers use to re-read current model state, and the deduped variants' snapshot fields keep the latest payload.

The behavior is gated behind FeatureFlag::CoalesceSharedSessionCatchUpEvents (dogfood-only for now) so we can validate internally before rolling it out.

Plan: https://staging.warp.dev/drive/notebook/k3sdmZpC3ZnRo0SJz6iLAT
Conversation: https://staging.warp.dev/conversation/f0493bea-7990-4f61-9e46-bb9cb3f559ce

Testing

  • I have manually tested my changes locally with ./script/run
  • Manually opened a large running cloud agent conversation as a viewer: no extended beachball during catch-up, transcript renders correctly once caught up, and live streaming updates continue normally afterwards.
  • cargo check, ./script/format, and cargo clippy --workspace --all-targets --all-features --tests -- -D warnings pass.
  • cargo nextest run -p warp -E 'test(event_loop) or test(shared_session)': 175 tests pass.

Agent Mode

  • Warp Agent Mode - This PR was created via Warp's AI Agent Mode

Co-Authored-By: Oz oz-agent@warp.dev

@cla-bot cla-bot Bot added the cla-signed label Jun 12, 2026

Copy link
Copy Markdown
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant