Skip to content

Commit b44b039

Browse files
fix: chat switch before req completion (#103)
1 parent 494c5a2 commit b44b039

1 file changed

Lines changed: 64 additions & 8 deletions

File tree

examples/playground-react/client/context/AppContext.jsx

Lines changed: 64 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,29 @@ export function AppProvider({ children }) {
9595
const undoTimeoutRef = useRef(null);
9696
const previousConfigRef = useRef(null);
9797
const messagesRef = useRef([]);
98+
const activeConversationIdRef = useRef(null);
99+
const currentPromptIdRef = useRef(null);
100+
const requestSeqRef = useRef(0);
101+
102+
useEffect(() => {
103+
activeConversationIdRef.current = activeConversationId;
104+
currentPromptIdRef.current = currentPromptId;
105+
}, [activeConversationId, currentPromptId]);
106+
107+
/**
108+
* Persists a message to a specific conversation in storage (even if not active).
109+
*/
110+
const persistMessageToConversation = useCallback((conversationId, msg) => {
111+
if (!conversationId || !msg) return false;
112+
const all = Storage.get('conversations');
113+
const idx = all.findIndex(c => c.id === conversationId);
114+
if (idx < 0) return false;
115+
const prev = all[idx].messages || [];
116+
all[idx].messages = [...prev, msg];
117+
all[idx].updatedAt = new Date().toISOString();
118+
Storage.set('conversations', all);
119+
return true;
120+
}, []);
98121

99122
// Load prompts from storage
100123
const refreshPrompts = useCallback(() => {
@@ -407,6 +430,10 @@ export function AppProvider({ children }) {
407430
createPrompt();
408431
}
409432

433+
const requestId = `req-${++requestSeqRef.current}`;
434+
const originConversationId = activeConversationIdRef.current;
435+
const originPromptId = currentPromptIdRef.current;
436+
410437
// Normalize role: default to 'user' to prevent accidental assistant messages
411438
// This fixes the bug where senderRole state might be corrupted
412439
const actualRole = (role === 'assistant') ? 'assistant' : 'user';
@@ -464,26 +491,55 @@ export function AppProvider({ children }) {
464491
});
465492
const data = await response.json();
466493

494+
const targetConversationId = originConversationId;
495+
const shouldApplyToActiveUI = targetConversationId && targetConversationId === activeConversationIdRef.current;
496+
467497
if (data.success) {
468-
const text = formatAssistantContentForDisplay(data.content);
498+
const assistantText = formatAssistantContentForDisplay(data.content);
469499
const meta = data.metadata ? { operation: data.metadata } : undefined;
470-
const assistantMsg = addMessage(text, 'assistant', meta);
471-
if (assistantMsg && meta && meta.operation) {
472-
setSelectedActivityMessageId(assistantMsg.id);
500+
const assistantMsg = {
501+
id: generateId(),
502+
text: assistantText ?? '',
503+
role: 'assistant',
504+
timestamp: new Date().toISOString(),
505+
...(meta && { metadata: meta })
506+
};
507+
508+
persistMessageToConversation(targetConversationId, assistantMsg);
509+
if (shouldApplyToActiveUI) {
510+
setMessages(prev => {
511+
const updated = [...prev, assistantMsg];
512+
messagesRef.current = updated;
513+
return updated;
514+
});
515+
if (meta?.operation) setSelectedActivityMessageId(assistantMsg.id);
473516
}
474517
} else {
475518
const meta = data.metadata ? { operation: data.metadata } : undefined;
476-
const assistantMsg = addMessage(`Error: ${data.error || 'No response'}`, 'assistant', meta);
477-
if (assistantMsg && meta?.operation) {
478-
setSelectedActivityMessageId(assistantMsg.id);
519+
const assistantMsg = {
520+
id: generateId(),
521+
text: `Error: ${data.error || 'No response'}`,
522+
role: 'assistant',
523+
timestamp: new Date().toISOString(),
524+
...(meta && { metadata: meta })
525+
};
526+
527+
persistMessageToConversation(targetConversationId, assistantMsg);
528+
if (shouldApplyToActiveUI) {
529+
setMessages(prev => {
530+
const updated = [...prev, assistantMsg];
531+
messagesRef.current = updated;
532+
return updated;
533+
});
534+
if (meta?.operation) setSelectedActivityMessageId(assistantMsg.id);
479535
}
480536
}
481537
} catch (error) {
482538
addMessage(`Error: ${error.message}`, 'assistant');
483539
} finally {
484540
setIsResponding(false);
485541
}
486-
}, [isResponding, currentPromptId, createPrompt, addMessage, config]);
542+
}, [isResponding, currentPromptId, createPrompt, addMessage, config, persistMessageToConversation]);
487543

488544
// Regenerate assistant message
489545
const regenerateMessage = useCallback(async (messageId) => {

0 commit comments

Comments
 (0)