feat(task-deeplink): 首次进入且任务无历史时自动发送,无需手动点开始回答/覆盖

新增「首次进入且该任务无聊天对话」信号 taskAutoStart:TaskFxIndexResolver 在
「无历史 → /new」时注入 state,用户主动点「新建对话」则不带。

- 3qfx/xdfx:taskAutoStart 时自动发出开场词(一次性 ref,不受 mount 时 threadId
  抖动影响、不会重复发),不显示「开始回答」按钮;用户主动新建对话才显示按钮手动发。
- rwfx:闸门 autoStartWhenEmpty = autoStartWhenPurposeEmpty && taskAutoStart,即仅
  首次无对话历史时目的树为空才自动开始;目的树有数据始终弹「覆盖并开始问答」确认(不误删 B 系统数据)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
吉鑫升andClaude Opus 4.8 committed 2026-06-19 09:51:50 +08:00
1 parent 6aaa4c841e
commit 0bd4524334
2 files changed
+29 -6

No files matched your search

+26 -5
View File
@@ -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({
</div>
<div className="flex items-center">
{/* 3qfx/xdfx 任务深链:新建对话进问答页后,点此发出任务开场信息开始问答(不自动发)。 */}
{taskStartText && isLandingState && (
{/* 3qfx/xdfx 任务深链:用户主动「新建对话」进问答页后,点此发出任务开场信息开始问答。
首次进入且无历史(taskAutoStart)会自动发,不显示此按钮。 */}
{taskStartText && isLandingState && !taskAutoStart && (
<Button
size="sm"
className="mr-1 bg-[var(--color-main)] text-white shadow-sm hover:bg-[var(--brand-950)]"
@@ -333,7 +352,9 @@ export default function AgentChatPage({
<TaskPurposePanel
taskId={taskId}
onStart={handleGateStart}
autoStartWhenEmpty={autoStartWhenPurposeEmpty}
// rwfx:仅「首次进入且无聊天对话历史」(taskAutoStart) 时,目的树为空才自动开始;
// 用户主动新建对话则需手动点「开始问答」。目的树有数据始终弹「覆盖并开始问答」确认。
autoStartWhenEmpty={!!autoStartWhenPurposeEmpty && taskAutoStart}
/>
)}
@@ -320,7 +320,9 @@ export function TaskFxIndexResolver({ taskBase }: { taskBase: string }) {
if (hasThreads && latestThreadId) {
navigate(`${chatsBase}/${latestThreadId}`, { replace: true });
} else {
navigate(`${chatsBase}/new`, { replace: true });
// 首次进入、该任务尚无聊天对话 → /new 并打 taskAutoStart 标记:3qfx/xdfx 直接自动发开场词,
// rwfx 目的树为空时自动开始(用户主动「新建对话」走 TaskConversationsList 的 navigate,不带此标记)。
navigate(`${chatsBase}/new`, { replace: true, state: { taskAutoStart: true } });
}
}, [isLoading, hasThreads, latestThreadId, chatsBase, navigate]);