🤖 fix: clear todos on stream end with smart reconnection handling #498
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Problem
TODOs were not being cleared when streams ended, causing stale todos to persist in the UI until the next user message. Additionally, on page reload, TODOs were incorrectly reconstructed from history even for completed streams.
The challenge: We need different behavior for two reload scenarios:
Solution
1. Clear TODOs on stream end
Modified
cleanupStreamState()to clearcurrentTodoswhen streams complete (end/abort/error). TODOs are now truly stream-scoped.2. Smart reconstruction on reload
Key insight: Check buffered events for
stream-startto detect active streams.loadHistoricalMessages()now acceptshasActiveStreamparameterWorkspaceStorechecks buffered events before loading history3. Improved separation of concerns
Centralized tool persistence logic in
processToolResult:contextparameter:"streaming" | "historical"loadHistoricalMessagesno longer knows about specific tool behaviorsImplementation
WorkspaceStore checks for active streams:
StreamingMessageAggregator handles context:
processToolResult decides based on tool + context:
Testing
Comprehensive test coverage for the full todo lifecycle:
✅ Clear todos on stream end
✅ Clear todos on stream abort
✅ Reconstruct todos when
hasActiveStream=true(reconnection)✅ Don't reconstruct todos when
hasActiveStream=false(completed)✅ Always reconstruct agentStatus (persists across sessions)
✅ Clear todos on new user message
All 146 message-related tests pass.
Behavior Matrix
Key Insight
The reconnection scenario is the critical edge case: when a user reloads during an active stream, historical messages contain completed tool calls from the current stream, and buffered events contain
stream-start. In this case, we should reconstruct TODOs to show work in progress.This is fundamentally different from reloading after stream completion, where TODOs should remain cleared.
Generated with
cmux