From 3e76689c247b56fed7e8f7201df10a5237b03210 Mon Sep 17 00:00:00 2001 From: cyrus Date: Thu, 26 Mar 2026 18:40:18 +0530 Subject: [PATCH] feat: replace optimistic message removal with error response handling - Updated error handling in `threadSlice` to add agent responses instead of removing user messages. - Simplified Redux actions by consolidating error handling logic for failed message transmissions. - Ensured conversation flow consistency by providing fallback error messages to users. --- src/pages/Conversations.tsx | 66 ++++++++++--------------------------- src/store/threadSlice.ts | 12 ++++--- 2 files changed, 24 insertions(+), 54 deletions(-) diff --git a/src/pages/Conversations.tsx b/src/pages/Conversations.tsx index 9dfeec93d..aabe07a57 100644 --- a/src/pages/Conversations.tsx +++ b/src/pages/Conversations.tsx @@ -44,7 +44,6 @@ import { setLastViewed, setPanelWidth, setSelectedThread, - updateMessagesForThread, } from '../store/threadSlice'; import type { ThreadMessage } from '../types/thread'; @@ -344,31 +343,19 @@ const Conversations = () => { }, onError: event => { if (event.thread_id !== selectedThreadIdRef.current) return; - if (event.error_type !== 'cancelled') { - setSendError(event.message); - } setIsSending(false); setActiveToolCall(null); - dispatch(setActiveThread(null)); - // Remove the optimistic user message on error - dispatch((innerDispatch, getState) => { - const state = getState() as { - thread: { messagesByThreadId: Record }; - }; - const persistedMessages = state.thread.messagesByThreadId[event.thread_id] || []; - const lastUserIdx = [...persistedMessages] - .reverse() - .findIndex(m => m.sender === 'user'); - if (lastUserIdx !== -1) { - const actualIdx = persistedMessages.length - 1 - lastUserIdx; - const updated = persistedMessages.filter((_, i) => i !== actualIdx); - innerDispatch(updateMessagesForThread({ threadId: event.thread_id, messages: updated })); - if (event.thread_id === selectedThreadIdRef.current) { - innerDispatch(setSelectedThread(event.thread_id)); - } - } - }); + if (event.error_type !== 'cancelled') { + dispatch( + addInferenceResponse({ + content: 'Something went wrong — please try again.', + threadId: event.thread_id, + }) + ); + } else { + dispatch(setActiveThread(null)); + } }, }).then(fn => { if (mounted) cleanup = fn; @@ -633,32 +620,13 @@ const Conversations = () => { // Pass the original sending thread ID to ensure response goes to correct thread dispatch(addInferenceResponse({ content: finalContent, threadId: sendingThreadId })); - } catch (err) { - // Remove the user message from persistent storage on error - // We'll use a thunk-like approach to access current state - dispatch((innerDispatch, getState) => { - const state = getState() as { - thread: { messagesByThreadId: Record }; - }; - const persistedMessages = state.thread.messagesByThreadId[sendingThreadId] || []; - const currentMessages = persistedMessages.filter(m => m.id !== userMessage.id); - innerDispatch( - updateMessagesForThread({ threadId: sendingThreadId, messages: currentMessages }) - ); - - // Also remove from current view if this is the selected thread - if (sendingThreadId === selectedThreadId) { - innerDispatch(setSelectedThread(sendingThreadId)); - } - }); - - const msg = - err && typeof err === 'object' && 'error' in err - ? String((err as { error: unknown }).error) - : 'Failed to get response'; - setSendError(msg); - // Clear active thread on error - dispatch(setActiveThread(null)); + } catch { + dispatch( + addInferenceResponse({ + content: 'Something went wrong — please try again.', + threadId: sendingThreadId, + }) + ); } finally { clearTimeout(safetyTimeout); setIsSending(false); diff --git a/src/store/threadSlice.ts b/src/store/threadSlice.ts index fefd58f08..14aa0767c 100644 --- a/src/store/threadSlice.ts +++ b/src/store/threadSlice.ts @@ -114,11 +114,13 @@ export const sendMessage = createAsyncThunk( return data; } catch (error) { - // Remove optimistic user message on failure - const state = (getState() as { thread: ThreadState }).thread; - const messages = state.messagesByThreadId[threadId] || []; - const filteredMessages = messages.filter(m => m.id !== userMessage.id); - dispatch(updateMessagesForThread({ threadId, messages: filteredMessages })); + // Add an error message as an agent response so the conversation flow continues + dispatch( + addInferenceResponse({ + content: 'Something went wrong — please try again.', + threadId, + }) + ); const msg = error && typeof error === 'object' && 'error' in error