- Add tokio watch channel for cancellation signaling - Implement cancel_chat command - Add cancellation checks in streaming loop and before tool execution - Stop button (■) replaces Send button (↑) during generation - Preserve partial streaming content when cancelled - Clean UX: no error messages on cancellation - Backend properly stops streaming and prevents tool execution Closes Story 13
2.9 KiB
2.9 KiB
Story 13: Stop Button
User Story
As a User I want a Stop button to cancel the model's response while it's generating So that I can immediately stop long-running or unwanted responses without waiting for completion
The Problem
Current Behavior:
- User sends message → Model starts generating
- User realizes they don't want the response (wrong question, too long, etc.)
- No way to stop it - must wait for completion
- Tool calls will execute even if user wants to cancel
Why This Matters:
- Long responses waste time
- Tool calls have side effects (file writes, searches, shell commands)
- User has no control once generation starts
- Standard UX pattern in ChatGPT, Claude, etc.
Acceptance Criteria
- Stop button (⬛) appears in place of Send button (↑) while model is generating
- Clicking Stop immediately cancels the backend request
- Tool calls that haven't started yet are NOT executed after cancellation
- Streaming stops immediately
- Partial response generated before stopping remains visible in chat
- Stop button becomes Send button again after cancellation
- User can immediately send a new message after stopping
- Input field remains enabled during generation
Out of Scope
- Escape key shortcut (can add later)
- Confirmation dialog (immediate action is better UX)
- Undo/redo functionality
- New Session flow (that's Story 14)
Implementation Approach
Backend
- Add
cancel_chatcommand callable from frontend - Use
tokio::select!to race chat execution vs cancellation signal - Check cancellation before executing each tool
- Return early when cancelled (not an error - expected behavior)
Frontend
- Replace Send button with Stop button when
loadingis true - On Stop click: call
invoke("cancel_chat")and setloading = false - Keep input enabled during generation
- Visual: Make Stop button clearly distinct (⬛ or "Stop" text)
Testing Strategy
-
Test Stop During Streaming:
- Send message requesting long response
- Click Stop while streaming
- Verify streaming stops immediately
- Verify partial response remains visible
- Verify can send new message
-
Test Stop Before Tool Execution:
- Send message that will use tools
- Click Stop while "thinking" (before tool executes)
- Verify tool does NOT execute (check logs/filesystem)
-
Test Stop During Tool Execution:
- Send message with multiple tool calls
- Click Stop after first tool executes
- Verify remaining tools do NOT execute
Success Criteria
Before:
- User sends message → No way to stop → Must wait for completion → Frustrating UX
After:
- User sends message → Stop button appears → User clicks Stop → Generation cancels immediately → Partial response stays → Can send new message
Related Stories
- Story 14: New Session Cancellation (same backend mechanism, different trigger)
- Story 18: Streaming Responses (Stop must work with streaming)