fix(chat): show "User has stopped generation" indicator when user cancels #7312
fix(chat): show "User has stopped generation" indicator when user cancels #7312
Conversation
…cels - Add stopReason prop to MessageRenderer type - Pass stopReason through RendererComponent - Display "User has stopped generation" text when user clicks stop button Previously only a blinking dot was shown. Now users see clear feedback that generation was stopped by their action. Fixes ENG-3192
b975fe9 to
3624763
Compare
There was a problem hiding this comment.
cubic analysis
No issues found across 6 files
Linked issue analysis
Linked issue: ENG-3192: Show correct killed state for user stopping generation
| Status | Acceptance criteria | Notes |
|---|---|---|
| ✅ | Show "User has stopped generation" indicator when user clicks stop during generation | AIMessage renders Text when stopReason==USER_CANCELLED |
| ✅ | Indicator persists when navigating away and back to the conversation (saved convo load) | session_loading sets OverallStop with stop_reason for loaded messages |
| ✅ | Pass stopReason through message component rendering pipeline | MessageRenderer and RendererComponent accept and forward stopReason |
| ✅ | Display indicator in MessageTextRenderer when generation was user-cancelled | MessageTextRenderer appends 'User has stopped generation' when wasUserCancelled |
| ✅ | Backend: detect user-stopped messages when loading saved conversations and set stop_reason in packets | session_loading checks message text and sets stop_reason on OverallStop packet |
| ✅ | Replace blinking dot with stopped text when cancelled and no display content | AIMessage shows stopped Text when grouped/display content empty and stopped |
| ✅ | Update generation-stopped message text so detection works when building saved messages | process_message text changed to include 'Generation was stopped' phrase |
There was a problem hiding this comment.
Greptile Overview
Greptile Summary
This PR adds a "User has stopped generation" indicator that appears when users cancel AI message generation and persists when navigating away and back to the conversation.
Implementation approach:
Frontend (web/):
- Threads
stopReasonthrough the component hierarchy from AIMessage → RendererComponent → MessageTextRenderer - Extracts stop_reason from Stop packets and stores it in component state
- Conditionally renders "User has stopped generation" text when
stopReason === StopReason.USER_CANCELLED - Shows indicator in multiple places: when no content exists, when display groups are empty, and at the end of message text
Backend (backend/):
- During streaming: appends "Generation was stopped by the user." to the message when user cancels
- When loading saved conversations: uses string matching (
"Generation was stopped" in message) to detect previously cancelled messages and setsstop_reason="user_cancelled"in the OverallStop packet
Key architectural decision:
Rather than storing stop_reason in the database, the implementation infers it from message text when loading saved conversations. This works but is fragile - any change to the exact stop message text will break persistence.
The frontend changes are solid and properly handle all rendering scenarios. The backend detection logic is the main area of concern due to its reliance on string matching.
Confidence Score: 4/5
- Safe to merge with minor technical debt in the persistence approach
- The implementation correctly handles the user-cancelled state throughout the streaming and rendering pipeline. Frontend changes properly thread stopReason through components and display the indicator in all relevant scenarios. The main weakness is the backend's string-matching approach for detecting cancelled messages from the database, which is fragile but functional for the current use case. This is technical debt rather than a blocking bug.
- backend/onyx/server/query_and_chat/session_loading.py - Consider adding a stop_reason field to the database schema for more robust persistence
Important Files Changed
File Analysis
| Filename | Score | Overview |
|---|---|---|
| backend/onyx/chat/process_message.py | 5/5 | Minor text cleanup - changed "The generation was stopped by the user" to "Generation was stopped by the user" for consistency |
| backend/onyx/server/query_and_chat/session_loading.py | 3/5 | Added stop_reason detection using string matching on saved messages - fragile approach that depends on exact message text |
| web/src/app/chat/message/messageComponents/AIMessage.tsx | 5/5 | Added stopReason prop threading and conditional rendering for "User has stopped generation" indicator |
| web/src/app/chat/message/messageComponents/interfaces.ts | 5/5 | Added optional stopReason parameter to MessageRenderer interface |
| web/src/app/chat/message/messageComponents/renderMessageComponent.tsx | 5/5 | Thread stopReason through RendererComponent to child renderers |
| web/src/app/chat/message/messageComponents/renderers/MessageTextRenderer.tsx | 5/5 | Display "User has stopped generation" indicator when stopReason is USER_CANCELLED |
Sequence Diagram
sequenceDiagram
participant User
participant Frontend
participant Backend
participant DB
Note over User,DB: User Stops Generation During Streaming
User->>Frontend: Clicks stop button
Frontend->>Backend: Send stop signal
Backend->>Backend: Set completed_normally=False
Backend->>Backend: Append "Generation was stopped by the user."
Backend->>DB: Save message with stop text
Backend->>Frontend: Send OverallStop packet with stop_reason="user_cancelled"
Frontend->>Frontend: setStopReason(USER_CANCELLED)
Frontend->>Frontend: Render "User has stopped generation" indicator
Note over User,DB: User Returns to Conversation Later
User->>Frontend: Navigate to conversation
Frontend->>Backend: Request conversation history
Backend->>DB: Load chat messages
DB->>Backend: Return messages
Backend->>Backend: Check if "Generation was stopped" in message
Backend->>Backend: Set stop_reason="user_cancelled" in OverallStop packet
Backend->>Frontend: Send packets with stop_reason
Frontend->>Frontend: Render "User has stopped generation" indicator
Frontend->>User: Display persisted indicator
Description
Shows "User has stopped generation" indicator when user clicks the stop button during chat generation. The indicator persists when navigating away and back to the conversation.
Changes
How Has This Been Tested?
text below is italicized but that has been removed

Additional Options
Closes https://linear.app/onyx-app/issue/ENG-3192/show-correct-killed-state-for-user-stopping-generation
Summary by cubic
Show a clear “User has stopped generation” indicator when a user cancels a chat response, and persist it when returning to the conversation. Addresses ENG-3192.
Written for commit 3624763. Summary will update on new commits.