You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
🤖 fix: reset todos on stream end and persist correctly on reload
## Problem
1. **Todos not resetting on stream end**: Todos persisted after stream completion instead of being cleared
2. **Incorrect persistence on reload**: TODOs were reconstructed from history even for completed streams, causing stale todos to reappear
3. **Missing reconnection logic**: No distinction between reloading during an active stream vs after completion
## Solution
### Reset todos on stream end
- Modified `cleanupStreamState()` to clear `currentTodos` when stream completes (end/abort/error)
- Todos are now truly stream-scoped - cleared immediately when streams end
### Smart reconstruction on reload
- Added `hasActiveStream` parameter to `loadHistoricalMessages()`
- **WorkspaceStore** checks buffered events for `stream-start` to detect active streams
- **Active stream reconnection** (hasActiveStream=true): Reconstruct TODOs from history ✅
- **Completed stream reload** (hasActiveStream=false): Don't reconstruct TODOs ✅
- **agentStatus** always reconstructed (persists across sessions) ✅
### Simplified UI
- Removed filtering logic from `PinnedTodoList` - no longer needed since todos auto-clear
- Cleaner component with fewer moving parts
## Implementation
**StreamingMessageAggregator.loadHistoricalMessages():**
```typescript
loadHistoricalMessages(messages: CmuxMessage[], hasActiveStream: boolean = false): void {
// ... add messages to map ...
// Reconstruct based on tool type and stream state
const shouldReconstructTodos = part.toolName === "todo_write" && hasActiveStream;
const shouldReconstructStatus = part.toolName === "status_set";
if (shouldReconstructTodos || shouldReconstructStatus) {
this.processToolResult(part.toolName, part.input, part.output);
}
}
```
**WorkspaceStore.handleChatMessage():**
```typescript
// Check if there's an active stream in buffered events
const pendingEvents = this.pendingStreamEvents.get(workspaceId) ?? [];
const hasActiveStream = pendingEvents.some(
(event) => "type" in event && event.type === "stream-start"
);
aggregator.loadHistoricalMessages(historicalMsgs, hasActiveStream);
```
## Testing
✅ **Todo reset on stream end** - todos cleared on completion
✅ **Todo reset on stream abort** - todos cleared on interruption
✅ **Active stream reconnection** - todos reconstructed with hasActiveStream=true
✅ **Completed stream reload** - todos NOT reconstructed with hasActiveStream=false
✅ **agentStatus persistence** - always reconstructed regardless of stream state
✅ **User message clears todos** - existing behavior maintained
All 146 tests pass ✅
## Behavior After This PR
**During streaming:**
- Todos update in real-time as `todo_write` is called
- UI shows all todos (pending, in_progress, completed)
**On stream end:**
- Todos cleared immediately
- UI shows nothing (clean slate)
**On reload - active stream (reconnection):**
- Backend sends buffered `stream-start` event
- TODOs reconstructed from historical tool calls ✅
- Stream continues with todos visible
**On reload - completed stream:**
- No buffered stream events
- TODOs NOT reconstructed ✅
- UI remains clean
**On new user message:**
- Todos cleared for fresh start
- Existing behavior unchanged
---
_Generated with `cmux`_
0 commit comments