Stop Processing¶
This content was migrated from
Documentation/STOP_PROCESSING.mdand verified against the current codebase. Review for accuracy.
Purpose¶
The Stop Processing pattern enables users to cancel an in-progress response by clicking a Stop button. The system cleanly aborts the LLM stream, restores the user's original message to the input box, and removes the partial response from the chat view.
How It Works¶
When the user clicks Stop, three things happen simultaneously:
- Frontend aborts the SSE fetch request (immediate cancellation of the network stream).
- Frontend restores the user's original message to the input box and removes the partial response — so they can fix typos and resend.
- Backend sets a Redis stop flag that the streaming service checks cooperatively.
Redis Stop Flag¶
The backend uses a simple Redis key to signal cancellation:
| Detail | Value |
|---|---|
| Key pattern | chat_stop:{chat_id} |
| Value | "1" |
| TTL | 60 seconds (auto-cleanup if not explicitly cleared) |
| Service | TaskTrackingService in swisper/services/task_tracking.py |
The streaming service (swisper/services/streaming.py) checks the flag before yielding each chunk:
if await self.task_tracking_service.check_stop_flag(chat_id):
await self.task_tracking_service.clear_stop_flag(chat_id)
# Send final stop response and break
This is cooperative cancellation — the backend doesn't force-kill the LLM call. It stops yielding chunks to the frontend and clears the flag for future messages.
New Chat Handling¶
For new chats where the chat record doesn't exist in the database yet:
- No backend stop call is needed (no chat ID to flag).
- The frontend simply aborts the fetch request.
- Navigation to the chat page only happens when
done=true— so stopping early keeps the user on the "new chat" page with no 404 errors.
Message Restoration (UX)¶
The key UX improvement: when the user clicks Stop, their original message is restored to the input box. This lets them fix typos and resend without retyping. Previously, the message was lost on stop — frustrating for long prompts.
Key Code Locations¶
| Component | Path |
|---|---|
| Stop flag service | apps/backend/swisper/services/task_tracking.py — set_stop_flag(), check_stop_flag(), clear_stop_flag() |
| Streaming check | apps/backend/swisper/services/streaming.py — checks flag in streaming loop |
| Orchestration check | apps/backend/swisper/services/orchestration.py — checks flag during graph execution |
| Frontend stop handler | apps/frontend/src/features/chat/hooks/use-stream-message.tsx |