diff --git a/frontend-web/src/core/threads/hooks.ts b/frontend-web/src/core/threads/hooks.ts index 6d34117b..a84e1c32 100644 --- a/frontend-web/src/core/threads/hooks.ts +++ b/frontend-web/src/core/threads/hooks.ts @@ -785,7 +785,10 @@ export function useThreadStream({ } as typeof thread) : thread; - return [mergedThread, sendMessage, isUploading] as const; + // 第 4 个返回值 `onStreamThreadId` = 底层 useStream 当前实际绑定的线程 id(新建/未保存时为 null)。 + // 调用方据此判断「流是否已切到全新线程」,避免在切换会话的那一帧把消息发进上一个会话 + // (submit 的 threadId 选项仅在 hook 线程为 null/undefined 时才生效)。 + return [mergedThread, sendMessage, isUploading, onStreamThreadId] as const; } export function useThreads( diff --git a/frontend-web/src/pages/AgentChatPage.tsx b/frontend-web/src/pages/AgentChatPage.tsx index 12c09a2b..19008977 100644 --- a/frontend-web/src/pages/AgentChatPage.tsx +++ b/frontend-web/src/pages/AgentChatPage.tsx @@ -130,7 +130,7 @@ export default function AgentChatPage({ }, [isNewThread, threadId, agent_id]); const { showNotification } = useNotification(); - const [thread, sendMessage] = useThreadStream({ + const [thread, sendMessage, , streamThreadId] = useThreadStream({ threadId: isNewThread ? undefined : threadId, assistantId: agent_id, context: { ...settings.context, agent_id }, @@ -229,13 +229,19 @@ export default function AgentChatPage({ // 纯绑定任务深链(3qfx/xdfx,无闸门):进入新建对话即自动发出任务开场信息。 // 每次新建对话都带(与 rwfx 闸门「开始问答」发出等价);ref 防止同一会话内重复发出。 + // + // 必须等 `streamThreadId == null`(底层 stream 已切到全新线程)才发:从已有会话点「新建对话」时, + // `isNewThread` 先翻 true,但 useThreadStream 的 onStreamThreadId 要慢一帧才重置为 null。 + // 若在那一帧就 submit,hook 仍绑定上一个会话,submit 的 threadId 选项被忽略 → 开场信息发进 + // 上一个对话(表现为「一直在同一个聊天框里发消息」)。等它归零再发即落到新建线程。 useEffect(() => { if (!taskAutoSendText) return; if (!isNewThread) return; + if (streamThreadId != null) return; if (taskAutoSentRef.current) return; taskAutoSentRef.current = true; handleSubmit({ text: taskAutoSendText, files: [] }); - }, [taskAutoSendText, isNewThread, handleSubmit]); + }, [taskAutoSendText, isNewThread, streamThreadId, handleSubmit]); const handleClarificationSubmit = useCallback( (answer: string) => {