From 87329c8810253ae78491abeb9cb1d21e107fc9ef Mon Sep 17 00:00:00 2001 From: Akash! Date: Thu, 25 Jun 2026 19:11:56 +0530 Subject: [PATCH] =?UTF-8?q?fix(ask-ai):=20resolve=20stream=20subscription?= =?UTF-8?q?=20race=20condition=20on=20new=20thread=E2=80=A6=20(#21916)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Resolves a race condition in the Ask AI feature where the first assistant reply in a newly created thread does not stream into the UI and only appears after sending a second message. ### What's Changed - **Immediate Thread Subscription:** Updated `useAgentChat.ts` to immediately set `currentAiChatThread` to the newly generated `threadId` instead of deferring it until after the `SEND_CHAT_MESSAGE` mutation finishes. - **The Bug:** Previously, the backend worker processed the AI chat job so quickly that the stream completed and fired the `message-persisted` event *before* the frontend established the SSE subscription. - **The Fix:** By setting the thread ID immediately, the `useAgentChatSubscription` hook now properly connects and listens to the SSE stream before the backend begins emitting chunks, guaranteeing the first message streams seamlessly. ### How to Test 1. Open the Ask AI panel and start a completely new thread. 2. Send an initial message (e.g., "Hello!"). 3. Observe that the AI's response successfully streams into the chat without needing a workaround or page refresh. Closes #21694 --------- Co-authored-by: Etienne <45695613+etiennejouan@users.noreply.github.com> --- .../src/modules/ai/hooks/useAgentChat.ts | 20 ++----------------- 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/packages/twenty-front/src/modules/ai/hooks/useAgentChat.ts b/packages/twenty-front/src/modules/ai/hooks/useAgentChat.ts index e1cbed6694..e381c5c13b 100644 --- a/packages/twenty-front/src/modules/ai/hooks/useAgentChat.ts +++ b/packages/twenty-front/src/modules/ai/hooks/useAgentChat.ts @@ -1,7 +1,7 @@ import { CombinedGraphQLErrors } from '@apollo/client/errors'; import { useApolloClient } from '@apollo/client/react'; import { useStore } from 'jotai'; -import { useCallback, useState } from 'react'; +import { useCallback } from 'react'; import { type ExtendedUIMessage } from 'twenty-shared/ai'; import { isDefined, isValidUuid } from 'twenty-shared/utils'; import { v4 } from 'uuid'; @@ -44,8 +44,6 @@ export const useAgentChat = ( const setCurrentAiChatThread = useSetAtomState(currentAiChatThreadState); const store = useStore(); - const [, setPendingThreadIdAfterFirstSend] = useState(null); - const setAgentChatUploadedFiles = useSetAtomState( agentChatUploadedFilesState, ); @@ -87,7 +85,7 @@ export const useAgentChat = ( } if (draftKey === AGENT_CHAT_NEW_THREAD_DRAFT_KEY) { - setPendingThreadIdAfterFirstSend(threadId); + setCurrentAiChatThread(threadId); } setAgentChatInput(''); @@ -184,14 +182,6 @@ export const useAgentChat = ( } dispatchBrowserEvent(AGENT_CHAT_REFETCH_MESSAGES_EVENT_NAME); - - setPendingThreadIdAfterFirstSend((pendingId) => { - if (isDefined(pendingId)) { - setCurrentAiChatThread(pendingId); - } - - return null; - }); } catch (error) { const restoredDraftKey = draftKey === AGENT_CHAT_NEW_THREAD_DRAFT_KEY ? threadId : draftKey; @@ -225,12 +215,6 @@ export const useAgentChat = ( dispatchBrowserEvent(AGENT_CHAT_RESTORE_EDITOR_CONTENT_EVENT_NAME, { content: contentToSend, }); - - if (draftKey === AGENT_CHAT_NEW_THREAD_DRAFT_KEY) { - setCurrentAiChatThread(threadId); - } - - setPendingThreadIdAfterFirstSend(null); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [