点击确认
This commit is contained in:
1 parent
1ff8860b98
commit
deb9993a64
3 files changed
+77
-47
No files matched your search
@@ -171,18 +171,18 @@ export function Step2Panel(props: Step2PanelProps) {
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
{isRoundTableRunning && isOrchestrating ? (
|
||||
{isRoundTableRunning ? (
|
||||
<button
|
||||
onClick={() => {
|
||||
setIsRoundTableRunning(false);
|
||||
onTriggerToast("⏸️ 会商模拟暂挂!智能体挂起...");
|
||||
onTriggerToast("⏸️ 会商已暂停");
|
||||
}}
|
||||
className="bg-amber-100 hover:bg-amber-200 text-amber-800 text-[10px] font-bold px-2.5 py-1 rounded-xl flex items-center gap-1 transition border border-amber-200/40 shadow-sm"
|
||||
>
|
||||
<Pause className="w-3.5 h-3.5" />
|
||||
挂起协商
|
||||
暂停会商
|
||||
</button>
|
||||
) : !isRoundTableRunning ? (
|
||||
) : (
|
||||
<button
|
||||
onClick={() => {
|
||||
setIsRoundTableRunning(true);
|
||||
@@ -193,7 +193,7 @@ export function Step2Panel(props: Step2PanelProps) {
|
||||
<Play className="w-3.5 h-3.5 fill-emerald-800" />
|
||||
恢复会商
|
||||
</button>
|
||||
) : null}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -280,6 +280,9 @@ export function useStep2Orchestration(
|
||||
const orchestrationCancelRef = useRef<boolean>(false);
|
||||
const step2InitRef = useRef<boolean>(false);
|
||||
const activeAbortersRef = useRef<Set<AbortController>>(new Set());
|
||||
/** 干预研审:暂停当前轮次后待执行的 leader prompt。 */
|
||||
const pendingInjectPromptRef = useRef<string | null>(null);
|
||||
const [injectFlushToken, setInjectFlushToken] = useState(0);
|
||||
// selectedModel / agentConfigs / agentNameToRole / threadIds / coordinatorName
|
||||
// 等等被 runOrchestration 在循环里反复读取。把它们打到 ref 上,可以让
|
||||
// runOrchestration 的 useCallback deps 大幅收窄,避免每次模型切换、agentConfigs
|
||||
@@ -1043,7 +1046,11 @@ export function useStep2Orchestration(
|
||||
useEffect(() => {
|
||||
if (currentStep !== 2) return;
|
||||
if (!isRoundTableRunning) {
|
||||
stopOrchestration();
|
||||
// 干预研审会先写入 pending 再置 false;此时 stop 已在 handler 里触发,
|
||||
// 避免 effect 再次 stop 误杀随后 flush 启动的 inject 编排。
|
||||
if (!pendingInjectPromptRef.current) {
|
||||
stopOrchestration();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (
|
||||
@@ -1061,6 +1068,21 @@ export function useStep2Orchestration(
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isRoundTableRunning]);
|
||||
|
||||
// 干预研审:当前轮次停止后 flush 待执行的 inject 编排(编排期间 UI 仍为「恢复会商」)。
|
||||
useEffect(() => {
|
||||
if (isOrchestrating) return;
|
||||
const pending = pendingInjectPromptRef.current;
|
||||
if (!pending) return;
|
||||
if (!threadIdsRef.current || !coordinatorNameRef.current) return;
|
||||
pendingInjectPromptRef.current = null;
|
||||
triggerToast("您的人工纠偏指令已同步至圆桌节点!");
|
||||
void runOrchestration(
|
||||
pending,
|
||||
threadIdsRef.current,
|
||||
coordinatorNameRef.current,
|
||||
);
|
||||
}, [isOrchestrating, injectFlushToken, runOrchestration, triggerToast]);
|
||||
|
||||
// ─── Public handlers ─────────────────────────────────────────────
|
||||
const handleInjectToRoundtable = useCallback(() => {
|
||||
if (!customAgentInput.trim()) return;
|
||||
@@ -1068,28 +1090,31 @@ export function useStep2Orchestration(
|
||||
triggerToast("⚠️ 圆桌尚未就绪,请稍候");
|
||||
return;
|
||||
}
|
||||
if (isOrchestratingRef.current) {
|
||||
triggerToast("⏳ 当前轮次仍在进行中,请等待或暂停后再发送");
|
||||
return;
|
||||
}
|
||||
|
||||
const userText = customAgentInput.trim();
|
||||
setCustomAgentInput("");
|
||||
|
||||
const prompt = `用户人工干预新指令:${userText}\n\n请结合当前讨论状态,决定是否继续派活或直接给出更新后的结论。`;
|
||||
pendingInjectPromptRef.current = prompt;
|
||||
|
||||
// 与 Step2Panel 右上角「暂停会商 / 恢复会商」联动:立即进入挂起态。
|
||||
setIsRoundTableRunning(false);
|
||||
stopOrchestration();
|
||||
|
||||
appendDialogue({
|
||||
sender: "用户 (插话干预)",
|
||||
avatarType: "human",
|
||||
content: `💡 (人工指令介入) ${userText}`,
|
||||
confidence: "最高指令",
|
||||
});
|
||||
triggerToast("您的人工纠偏指令已同步至圆桌节点!");
|
||||
|
||||
void runOrchestration(
|
||||
`用户人工干预新指令:${userText}\n\n请结合当前讨论状态,决定是否继续派活或直接给出更新后的结论。`,
|
||||
threadIdsRef.current,
|
||||
coordinatorNameRef.current,
|
||||
);
|
||||
}, [appendDialogue, customAgentInput, runOrchestration, triggerToast]);
|
||||
if (isOrchestratingRef.current) {
|
||||
triggerToast("⏸️ 会商已暂停,当前轮次结束后将处理您的干预指令");
|
||||
} else {
|
||||
triggerToast("⏸️ 会商已暂停,正在处理您的干预指令…");
|
||||
}
|
||||
setInjectFlushToken((n) => n + 1);
|
||||
}, [appendDialogue, customAgentInput, stopOrchestration, triggerToast]);
|
||||
|
||||
const submitClarification = useCallback(
|
||||
(rawAnswer: string) => {
|
||||
@@ -1237,6 +1262,7 @@ export function useStep2Orchestration(
|
||||
setArtifacts([]);
|
||||
seatStubMessagesRef.current = {};
|
||||
setSeatStubMessages({});
|
||||
pendingInjectPromptRef.current = null;
|
||||
deselectArtifact();
|
||||
step2InitRef.current = false;
|
||||
}, [abortAllInFlight, deselectArtifact, setArtifacts]);
|
||||
|
||||
@@ -351,37 +351,41 @@ export default function RoundtablePlanningPage() {
|
||||
新建任务
|
||||
</button>
|
||||
|
||||
<button
|
||||
id="start-clear-btn"
|
||||
onClick={() => {
|
||||
setCurrentStep(1);
|
||||
triggerToast("已切换至第一阶段:人机问答意图澄清");
|
||||
}}
|
||||
className="bg-primary text-white hover:bg-[var(--brand-900)] text-xs font-bold px-3 py-2 rounded-xl flex items-center gap-1.5 transition-all shadow-sm shadow-primary/10 active:scale-95"
|
||||
>
|
||||
<svg className="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2.5">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
|
||||
</svg>
|
||||
开始澄清
|
||||
</button>
|
||||
{currentStep !== 2 && (
|
||||
<>
|
||||
<button
|
||||
id="start-clear-btn"
|
||||
onClick={() => {
|
||||
setCurrentStep(1);
|
||||
triggerToast("已切换至第一阶段:人机问答意图澄清");
|
||||
}}
|
||||
className="bg-primary text-white hover:bg-[var(--brand-900)] text-xs font-bold px-3 py-2 rounded-xl flex items-center gap-1.5 transition-all shadow-sm shadow-primary/10 active:scale-95"
|
||||
>
|
||||
<svg className="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2.5">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
|
||||
</svg>
|
||||
开始澄清
|
||||
</button>
|
||||
|
||||
<button
|
||||
id="human-intervention-btn"
|
||||
onClick={() => {
|
||||
setRoles((prev) =>
|
||||
prev.map((r) =>
|
||||
r.id === 1
|
||||
? { ...r, status: r.status === "在线" ? "等待激活" : "在线" }
|
||||
: r,
|
||||
),
|
||||
);
|
||||
triggerToast("指挥专家状态变更!人工介入切换");
|
||||
}}
|
||||
className="bg-white hover:bg-slate-50 border border-slate-200 text-slate-700 text-xs font-bold px-3 py-2 rounded-xl flex items-center gap-1.5 transition-all dark:border-border dark:bg-secondary dark:text-foreground dark:hover:bg-accent"
|
||||
>
|
||||
<Users className="w-3.5 h-3.5 text-slate-500 dark:text-muted-foreground" />
|
||||
人工介入
|
||||
</button>
|
||||
<button
|
||||
id="human-intervention-btn"
|
||||
onClick={() => {
|
||||
setRoles((prev) =>
|
||||
prev.map((r) =>
|
||||
r.id === 1
|
||||
? { ...r, status: r.status === "在线" ? "等待激活" : "在线" }
|
||||
: r,
|
||||
),
|
||||
);
|
||||
triggerToast("指挥专家状态变更!人工介入切换");
|
||||
}}
|
||||
className="bg-white hover:bg-slate-50 border border-slate-200 text-slate-700 text-xs font-bold px-3 py-2 rounded-xl flex items-center gap-1.5 transition-all dark:border-border dark:bg-secondary dark:text-foreground dark:hover:bg-accent"
|
||||
>
|
||||
<Users className="w-3.5 h-3.5 text-slate-500 dark:text-muted-foreground" />
|
||||
人工介入
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
|
||||
<button
|
||||
id="save-draft-header-btn"
|
||||
|
||||
Reference in new issue
Block a user