From 29afd18e67d323caf61d00fe781f021ac7d035c7 Mon Sep 17 00:00:00 2001 From: "Kai (Tam Nhu) Tran" <61256810+kaitranntt@users.noreply.github.com> Date: Sat, 4 Apr 2026 21:50:38 -0400 Subject: [PATCH] fix(ui): prevent first message disappearing in new chat session (#695) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When starting a new chat, loadHistory() races with chat.send — if history is fetched before the server persists the user message, it returns empty results and overwrites the optimistic message. Skip loadHistory() on the "" → newKey session transition since the optimistic user message is already in state. All other session transitions (switch, refresh) continue loading history normally. Closes #694 --- ui/web/src/pages/chat/hooks/use-chat-messages.ts | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/ui/web/src/pages/chat/hooks/use-chat-messages.ts b/ui/web/src/pages/chat/hooks/use-chat-messages.ts index c8cab068..6bee88fc 100644 --- a/ui/web/src/pages/chat/hooks/use-chat-messages.ts +++ b/ui/web/src/pages/chat/hooks/use-chat-messages.ts @@ -46,13 +46,19 @@ export function useChatMessages(sessionKey: string, agentId: string) { // Team task handling (extracted hook) const { teamTasks, setTeamTasks } = useChatTeamTasks(addLocalMessage); + // When transitioning from empty to a new session key (new-chat send flow), + // skip the next loadHistory() call. The optimistic user message is already + // in state, and loadHistory() would race with chat.send — potentially + // returning empty history before the server persists the message. + const skipNextHistoryRef = useRef(false); + // Reset streaming/run state when session changes const prevKeyRef = useRef(sessionKey); useEffect(() => { if (sessionKey === prevKeyRef.current) return; const wasEmpty = !prevKeyRef.current; prevKeyRef.current = sessionKey; - if (wasEmpty) return; // new-chat send flow, don't reset + if (wasEmpty) { skipNextHistoryRef.current = true; return; } // new-chat send flow, don't reset setStreamText(null); setThinkingText(null); setToolStream([]); setIsRunning(false); setActivity(null); setBlockReplies([]); setTeamTasks([]); @@ -76,7 +82,13 @@ export function useChatMessages(sessionKey: string, agentId: string) { useEffect(() => { let cancelled = false; if (sessionKey) { - loadHistory(); + // Skip loadHistory for new-chat flow (empty → key) to avoid racing + // with chat.send. The optimistic user message is already displayed. + if (skipNextHistoryRef.current) { + skipNextHistoryRef.current = false; + } else { + loadHistory(); + } ws.call<{ isRunning?: boolean; runId?: string; activity?: RunActivity }>(Methods.CHAT_SESSION_STATUS, { sessionKey }) .then((res) => { if (cancelled) return;