From 0bd45243349c4e80a040dc13e2c97ada58f6d2ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=89=E9=91=AB=E5=8D=87?= Date: Fri, 19 Jun 2026 09:51:50 +0800 Subject: [PATCH] =?UTF-8?q?feat(task-deeplink):=20=E9=A6=96=E6=AC=A1?= =?UTF-8?q?=E8=BF=9B=E5=85=A5=E4=B8=94=E4=BB=BB=E5=8A=A1=E6=97=A0=E5=8E=86?= =?UTF-8?q?=E5=8F=B2=E6=97=B6=E8=87=AA=E5=8A=A8=E5=8F=91=E9=80=81=EF=BC=8C?= =?UTF-8?q?=E6=97=A0=E9=9C=80=E6=89=8B=E5=8A=A8=E7=82=B9=E5=BC=80=E5=A7=8B?= =?UTF-8?q?=E5=9B=9E=E7=AD=94/=E8=A6=86=E7=9B=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增「首次进入且该任务无聊天对话」信号 taskAutoStart:TaskFxIndexResolver 在 「无历史 → /new」时注入 state,用户主动点「新建对话」则不带。 - 3qfx/xdfx:taskAutoStart 时自动发出开场词(一次性 ref,不受 mount 时 threadId 抖动影响、不会重复发),不显示「开始回答」按钮;用户主动新建对话才显示按钮手动发。 - rwfx:闸门 autoStartWhenEmpty = autoStartWhenPurposeEmpty && taskAutoStart,即仅 首次无对话历史时目的树为空才自动开始;目的树有数据始终弹「覆盖并开始问答」确认(不误删 B 系统数据)。 Co-Authored-By: Claude Opus 4.8 (1M context) --- frontend-web/src/pages/AgentChatPage.tsx | 31 ++++++++++++++++--- .../task-components/TaskFxWorkspace.tsx | 4 ++- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/frontend-web/src/pages/AgentChatPage.tsx b/frontend-web/src/pages/AgentChatPage.tsx index 9761cede..b8da2890 100644 --- a/frontend-web/src/pages/AgentChatPage.tsx +++ b/frontend-web/src/pages/AgentChatPage.tsx @@ -2,6 +2,7 @@ import { BotIcon, PlusSquare } from "lucide-react"; import { useParams, useRouter } from "next/navigation"; +import { useLocation } from "react-router-dom"; import { useRouteBase } from "@/core/route-base"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; @@ -92,6 +93,11 @@ export default function AgentChatPage({ taskBind && !taskGate && taskContext && taskContext.agentId === agent_id ? (taskContext.openingText?.trim() ?? "") : ""; + // 「首次进入且该任务无历史」信号:由 TaskFxIndexResolver 在「无聊天对话 → /new」时注入 + // (用户主动点「新建对话」不带)。3qfx/xdfx 据此自动发出开场词、跳过「开始回答」按钮; + // rwfx 据此决定目的树为空时是否自动开始(仍由 TaskPurposePanel 在有数据时弹覆盖确认)。 + const location = useLocation(); + const taskAutoStart = !!(location.state as { taskAutoStart?: boolean } | null)?.taskAutoStart; // If ChatPage stashed an opening message for this agent, skip the landing // screen on first render so the user doesn't see a flash of the welcome UI @@ -230,12 +236,24 @@ export default function AgentChatPage({ handleSubmit({ text: pending.text, files: [] }); }, [agent_id, threadId, isNewThread, handleSubmit]); - // 纯绑定任务深链(3qfx/xdfx):新建对话进问答页 landing 后,由 header 右上角「开始回答」按钮 - // 手动触发发出开场信息(见下方 header)。不再自动发,从根上避免新建对话竞态导致的重复发送。 + // 纯绑定任务深链(3qfx/xdfx):用户主动「新建对话」进 landing 后,由 header 右上角「开始回答」 + // 按钮手动触发发出开场信息(见下方 header)。手动场景不自动发,避免新建对话竞态导致的重复发送。 const handleTaskStart = useCallback(() => { if (taskStartText) handleSubmit({ text: taskStartText, files: [] }); }, [handleSubmit, taskStartText]); + // 首次进入且该任务无历史(taskAutoStart):3qfx/xdfx 直接自动发出开场信息,无需手动点「开始回答」。 + // autoStartedRef 一次性、不随 threadId 抖动重置,故只发一次(首次进入是干净 mount,无上一会话之忧)。 + const autoStartedRef = useRef(false); + useEffect(() => { + if (!taskAutoStart) return; + if (!taskStartText) return; + if (!isNewThread) return; + if (autoStartedRef.current) return; + autoStartedRef.current = true; + handleSubmit({ text: taskStartText, files: [] }); + }, [taskAutoStart, taskStartText, isNewThread, handleSubmit]); + const handleClarificationSubmit = useCallback( (answer: string) => { setHasStartedConversation(true); @@ -292,8 +310,9 @@ export default function AgentChatPage({
- {/* 3qfx/xdfx 任务深链:新建对话进问答页后,点此发出任务开场信息开始问答(不自动发)。 */} - {taskStartText && isLandingState && ( + {/* 3qfx/xdfx 任务深链:用户主动「新建对话」进问答页后,点此发出任务开场信息开始问答。 + 首次进入且无历史(taskAutoStart)会自动发,不显示此按钮。 */} + {taskStartText && isLandingState && !taskAutoStart && (