From e3dd430e68653abe3017f00d4314effe4b936bc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=91=A3=E5=AE=8F=E5=87=AF?= Date: Thu, 28 May 2026 09:09:02 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8C=89=E9=92=AE=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/Step2Panel.tsx | 28 +++++-------- .../hooks/useStep2Orchestration.ts | 40 ++++++++++++++++--- .../pages/RoundtablePlanningPage.tsx | 2 +- 3 files changed, 44 insertions(+), 26 deletions(-) diff --git a/frontend-web/src/roundtable-planning/components/Step2Panel.tsx b/frontend-web/src/roundtable-planning/components/Step2Panel.tsx index b534d929..a0a947ec 100644 --- a/frontend-web/src/roundtable-planning/components/Step2Panel.tsx +++ b/frontend-web/src/roundtable-planning/components/Step2Panel.tsx @@ -15,7 +15,7 @@ * * 状态全部来自 `useStep2Orchestration` —— 本组件不调任何后端、不持久化。 */ -import { useCallback, useEffect, useRef, useState } from "react"; +import { useCallback, useRef, useState } from "react"; import { Cpu, FileIcon, @@ -89,7 +89,7 @@ export interface Step2PanelProps { // ─── Handlers ───────────────────────────────────────────────── onPauseRoundtable: () => void; onResumeRoundtable: () => void; - onRecordInjectMessage: () => void; + onHandleInjectToRoundtable: () => void; onSubmitClarification: (answer: string) => void; onSavePersona: (id: number) => void; onProceedToStep3: () => void; @@ -123,7 +123,7 @@ export function Step2Panel(props: Step2PanelProps) { setSelectedAgentId, onPauseRoundtable, onResumeRoundtable, - onRecordInjectMessage, + onHandleInjectToRoundtable, onSubmitClarification, onSavePersona, onProceedToStep3, @@ -134,24 +134,14 @@ export function Step2Panel(props: Step2PanelProps) { const { atBottom: step2AtBottom, scrollToBottom: scrollStep2ToBottom } = useAutoScroll(step2ScrollRef, [step2RoundtableDialogues]); - // 干预研审 → 暂停会商:与右上角按钮共用 onPauseRoundtable;乐观 UI 避免等父 state 刷新。 + // 干预研审:记录指令并自动恢复会商,右上角按钮状态由 isRoundTableRunning 驱动 const [pauseFlash, setPauseFlash] = useState(false); - const [optimisticPaused, setOptimisticPaused] = useState(false); - const showPausedUi = !isRoundTableRunning || optimisticPaused; - - useEffect(() => { - if (!isRoundTableRunning) { - setOptimisticPaused(false); - } - }, [isRoundTableRunning]); const handleInject = useCallback(() => { - setOptimisticPaused(true); - onPauseRoundtable(); - onRecordInjectMessage(); + onHandleInjectToRoundtable(); setPauseFlash(true); window.setTimeout(() => setPauseFlash(false), 1600); - }, [onPauseRoundtable, onRecordInjectMessage]); + }, [onHandleInjectToRoundtable]); const isSandboxStreaming = isOrchestrating || @@ -196,7 +186,7 @@ export function Step2Panel(props: Step2PanelProps) { ))} - {showPausedUi ? ( + {!isRoundTableRunning ? (
diff --git a/frontend-web/src/roundtable-planning/hooks/useStep2Orchestration.ts b/frontend-web/src/roundtable-planning/hooks/useStep2Orchestration.ts index 5d7c54ce..2def91ff 100644 --- a/frontend-web/src/roundtable-planning/hooks/useStep2Orchestration.ts +++ b/frontend-web/src/roundtable-planning/hooks/useStep2Orchestration.ts @@ -175,11 +175,11 @@ export interface UseStep2OrchestrationReturn { pauseRoundtable: () => void; /** 与 Step2Panel「恢复会商」按钮相同 —— 恢复自动研讨(含待处理的干预指令)。 */ resumeRoundtable: () => void; - /** 记录干预指令(不暂停);通常由 Step2Panel 在 pauseRoundtable 之后调用。 */ + /** 记录干预指令(不暂停不恢复);通常由 Step2Panel 在 pauseRoundtable 之后调用。 */ recordInjectMessage: () => void; /** 中断所有 in-flight SSE(给新建任务 / 加载草稿用)。 */ abortAllInFlight: () => void; - /** @deprecated 请用 pauseRoundtable + recordInjectMessage;保留兼容组合调用。 */ + /** 一键干预:记录指令 + 自动恢复会商 + 触发新一轮编排(替代 pause + record + resume 组合)。 */ handleInjectToRoundtable: () => void; /** 总控澄清回复 —— 把回答拼到 prompt 里再起一轮编排。 */ submitClarification: (rawAnswer: string) => void; @@ -1179,13 +1179,41 @@ export function useStep2Orchestration( confidence: "最高指令", }); pendingInjectPromptRef.current = `用户人工干预新指令:${userText}\n\n请结合当前讨论状态,决定是否继续派活或直接给出更新后的结论。`; - triggerToast("干预指令已记录,点击「恢复会商」后执行"); + triggerToast("干预指令已记录,会商已自动恢复执行"); }, [appendDialogue, customAgentInput, triggerToast]); const handleInjectToRoundtable = useCallback(() => { - pauseRoundtable(); - recordInjectMessage(); - }, [pauseRoundtable, recordInjectMessage]); + const userText = customAgentInput.trim(); + if (!userText) return; + if (!threadIdsRef.current || !coordinatorNameRef.current) { + triggerToast("⚠️ 圆桌尚未就绪,无法记录干预指令"); + return; + } + + // 中止当前编排(如有) + orchestrationCancelRef.current = true; + abortAllInFlight(); + // 强制标记非编排中,使后续 runOrchestration 可立即启动 + isOrchestratingRef.current = false; + setIsOrchestrating(false); + + setCustomAgentInput(""); + appendDialogue({ + sender: "用户 (插话干预)", + avatarType: "human", + content: `💡 (人工指令介入) ${userText}`, + confidence: "最高指令", + }); + + const prompt = `用户人工干预新指令:${userText}\n\n请结合当前讨论状态,决定是否继续派活或直接给出更新后的结论。`; + + // 确保处于运行状态(同步更新按钮 UI) + setIsRoundTableRunning(true); + triggerToast("干预指令已发送,会商继续执行"); + + // 直接启动新一轮编排 + void runOrchestration(prompt, threadIdsRef.current, coordinatorNameRef.current); + }, [customAgentInput, appendDialogue, abortAllInFlight, runOrchestration, triggerToast]); const submitClarification = useCallback( (rawAnswer: string) => { diff --git a/frontend-web/src/roundtable-planning/pages/RoundtablePlanningPage.tsx b/frontend-web/src/roundtable-planning/pages/RoundtablePlanningPage.tsx index ea94aee7..d775b5d8 100644 --- a/frontend-web/src/roundtable-planning/pages/RoundtablePlanningPage.tsx +++ b/frontend-web/src/roundtable-planning/pages/RoundtablePlanningPage.tsx @@ -498,7 +498,7 @@ export default function RoundtablePlanningPage() { openArtifactPreview={step2.openArtifactPreview} onPauseRoundtable={step2.pauseRoundtable} onResumeRoundtable={step2.resumeRoundtable} - onRecordInjectMessage={step2.recordInjectMessage} + onHandleInjectToRoundtable={step2.handleInjectToRoundtable} setClarificationDraft={step2.setClarificationDraft} setCustomAgentInput={step2.setCustomAgentInput} setAgentConfigs={step2.setAgentConfigs}