mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-03-15 10:57:25 +00:00
fix: session reconnect catch-up, always-on input, frozen session recovery (#524)
- WebSocketContext: emit 'websocket-reconnected' on onopen when it's a reconnect
(hasConnectedRef tracks first-connect vs. subsequent reconnects).
- useChatRealtimeHandlers: handle 'websocket-reconnected' via onWebSocketReconnect
callback; added to globalMessageTypes to bypass sessionId mismatch checks.
- ChatInterface: on reconnect, re-fetch JSONL session history so messages missed
during iOS background are shown immediately. Also resets isLoading and
canAbortSession so a dead/restarted session no longer freezes the UI forever.
- ChatComposer: remove disabled={isLoading} from textarea — users can always
type regardless of processing state; submit button still prevents double-send.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -109,6 +109,7 @@ function ChatInterface({
|
||||
scrollToBottom,
|
||||
scrollToBottomAndReset,
|
||||
handleScroll,
|
||||
loadSessionMessages,
|
||||
} = useChatSessionState({
|
||||
selectedProject,
|
||||
selectedSession,
|
||||
@@ -197,6 +198,23 @@ function ChatInterface({
|
||||
setPendingPermissionRequests,
|
||||
});
|
||||
|
||||
// On WebSocket reconnect, re-fetch the current session's messages from JSONL so missed
|
||||
// streaming events (e.g. from long tool calls while iOS had the tab backgrounded) are shown.
|
||||
// Also reset isLoading — if the server restarted or the session died mid-stream, the client
|
||||
// would be stuck in "Processing..." forever without this reset.
|
||||
const handleWebSocketReconnect = useCallback(async () => {
|
||||
if (!selectedProject || !selectedSession) return;
|
||||
const provider = (localStorage.getItem('selected-provider') as any) || 'claude';
|
||||
const messages = await loadSessionMessages(selectedProject.name, selectedSession.id, false, provider);
|
||||
if (messages && messages.length > 0) {
|
||||
setChatMessages(messages);
|
||||
}
|
||||
// Reset loading state — if the session is still active, new WebSocket messages will
|
||||
// set it back to true. If it died, this clears the permanent frozen state.
|
||||
setIsLoading(false);
|
||||
setCanAbortSession(false);
|
||||
}, [selectedProject, selectedSession, loadSessionMessages, setChatMessages, setIsLoading, setCanAbortSession]);
|
||||
|
||||
useChatRealtimeHandlers({
|
||||
latestMessage,
|
||||
provider,
|
||||
@@ -219,6 +237,7 @@ function ChatInterface({
|
||||
onSessionNotProcessing,
|
||||
onReplaceTemporarySession,
|
||||
onNavigateToSession,
|
||||
onWebSocketReconnect: handleWebSocketReconnect,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
Reference in New Issue
Block a user