Restore chat status/subscription when loading a chat#1333
Restore chat status/subscription when loading a chat#1333dobesv wants to merge 1 commit intokagent-dev:mainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR improves chat reload/switching behavior by restoring the UI status from stored tasks and (when appropriate) resubscribing to an in-progress A2A task’s SSE stream so the UI reflects the real runtime state rather than assuming “idle”.
Changes:
- Introduces a
StreamEventunion type for A2A SSE events and updates message handling to accept it. - Adds
tasks/resubscribesupport to the UI A2A client for reconnecting to in-progress task streams. - Updates
ChatInterfaceinitialization to derive chat status from task state and auto-resubscribe for “submitted/working” tasks, while reusing a shared stream-consumption helper.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| ui/src/lib/messageHandlers.ts | Adds StreamEvent type and updates handler signature to accept all SSE event shapes. |
| ui/src/lib/a2aClient.ts | Adds resubscribeToTask() JSON-RPC call and refactors proxy URL creation. |
| ui/src/components/chat/ChatInterface.tsx | Restores chat status on load and resubscribes to live updates when a task is still running. |
Comments suppressed due to low confidence (1)
ui/src/components/chat/ChatInterface.tsx:170
- On resubscribe failure you set
chatStatus("ready"), but the streaming UI state (isStreaming/streamingContent) is not cleared here. If the resubscribe stream delivered some events before failing,handleMessageEventmay have setisStreamingtrue and appended partial content, leaving the UI in a stuck/incorrect state.
Consider resetting streaming state in this failure path (similar to the send-message error handler) before returning control to the user.
setStoredMessages(extractMessagesFromTasks(refreshed.data));
setTokenStats(extractTokenStatsFromTasks(refreshed.data));
}
}
setChatStatus("ready");
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const controller = new AbortController(); | ||
| abortControllerRef.current = controller; | ||
|
|
There was a problem hiding this comment.
attemptResubscribe writes to the shared abortControllerRef.current and then unconditionally clears it in finally. If another stream is started while this resubscribe is in-flight (e.g. user sends a message before initializeChat finishes), the resubscribe can overwrite the ref and later clear it, breaking cancel/cleanup for the newer request and potentially leaving a stream running.
Consider: (1) abort any existing controller before replacing it, and/or (2) only clear abortControllerRef.current if it still points at this function's controller (identity check) in the finally block.
Previously the UI would just assume a chat was idle when loading it. This fetches the chat status and displays an appropriate state. It will resubscribe for live updates in some cases as well. This makes the experience a lot nicer when switching between chats or reloading the page while looking at a chat. Signed-off-by: Dobes Vandermeer <dobes.vandermeer@newsela.com>
c1485b6 to
0e92736
Compare
|
I've been using this for a while today and it's a big improvement although I still feel like I'm not always getting updates to the chat unless I actually sent the last message without navigating away and back. So maybe this still has something missing. |
|
Verifying locally now |

Previously the UI would just assume a chat was idle when loading it. This fetches the chat status and displays an appropriate state. It will resubscribe for live updates in some cases as well.
This makes the experience a lot nicer when switching between chats or reloading the page while looking at a chat.