From efa11b23e5ddf72e46ebeeeca09f83f682bc99ad Mon Sep 17 00:00:00 2001 From: Philip Zeyliger Date: Sun, 8 Feb 2026 06:22:54 +0000 Subject: [PATCH] shelley: refresh conversations list on reconnect Prompt: When shelley comes back from a reconnection, it needs to refresh the conversations list, since it could have missed updates. When the SSE stream reconnects after a disconnection, conversation list updates may have been missed. Refresh the full conversations list on reconnect to ensure the sidebar is up to date. Uses a hasConnectedRef to distinguish initial connection from reconnects, avoiding a redundant fetch on first load. Co-authored-by: Shelley --- ui/src/App.tsx | 10 ++++++++++ ui/src/components/ChatInterface.tsx | 11 ++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/ui/src/App.tsx b/ui/src/App.tsx index ac000d4977fc925f093a53d5a2b55827aff2123b..7bb1242e622292c9e1ddd62d755f403352537c1a 100644 --- a/ui/src/App.tsx +++ b/ui/src/App.tsx @@ -294,6 +294,15 @@ function App() { } }; + const refreshConversations = async () => { + try { + const convs = await api.getConversations(); + setConversations(convs); + } catch (err) { + console.error("Failed to refresh conversations:", err); + } + }; + const startNewConversation = () => { // Save the current conversation's cwd to localStorage so the new conversation picks it up if (currentConversation?.cwd) { @@ -468,6 +477,7 @@ function App() { openDiffViewerTrigger={diffViewerTrigger} modelsRefreshTrigger={modelsRefreshTrigger} onOpenModelsModal={() => setModelsModalOpen(true)} + onReconnect={refreshConversations} /> diff --git a/ui/src/components/ChatInterface.tsx b/ui/src/components/ChatInterface.tsx index ac76ef89885689c9620f0ff618789a0b00256cd5..066fee08dd8db8054c0e38ba08b97ce57da0289a 100644 --- a/ui/src/components/ChatInterface.tsx +++ b/ui/src/components/ChatInterface.tsx @@ -457,6 +457,7 @@ interface ChatInterfaceProps { openDiffViewerTrigger?: number; // increment to trigger opening diff viewer modelsRefreshTrigger?: number; // increment to trigger models list refresh onOpenModelsModal?: () => void; + onReconnect?: () => void; } function ChatInterface({ @@ -475,6 +476,7 @@ function ChatInterface({ openDiffViewerTrigger, modelsRefreshTrigger, onOpenModelsModal, + onReconnect, }: ChatInterfaceProps) { const [messages, setMessages] = useState([]); const [loading, setLoading] = useState(true); @@ -607,6 +609,7 @@ function ChatInterface({ const periodicRetryRef = useRef(null); const heartbeatTimeoutRef = useRef(null); const lastSequenceIdRef = useRef(-1); + const hasConnectedRef = useRef(false); const userScrolledRef = useRef(false); // Load messages and set up streaming @@ -638,8 +641,9 @@ function ChatInterface({ if (heartbeatTimeoutRef.current) { clearTimeout(heartbeatTimeoutRef.current); } - // Reset sequence ID when conversation changes + // Reset sequence ID and connection tracking when conversation changes lastSequenceIdRef.current = -1; + hasConnectedRef.current = false; }; }, [conversationId]); @@ -926,6 +930,11 @@ function ChatInterface({ eventSource.onopen = () => { console.log("Message stream connected"); + // Refresh conversations list on reconnect (may have missed updates while disconnected) + if (hasConnectedRef.current) { + onReconnect?.(); + } + hasConnectedRef.current = true; // Reset reconnect attempts and clear periodic retry on successful connection setReconnectAttempts(0); setIsDisconnected(false);