暂停修改
This commit is contained in:
1 parent
525218f9a7
commit
dffb8a955b
1 file changed
+65
-29
@@ -436,7 +436,6 @@ export default function RoundtablePlanningPage() {
|
|||||||
const [step2RoundtableDialogues, setStep2RoundtableDialogues] = useState<any[]>([]);
|
const [step2RoundtableDialogues, setStep2RoundtableDialogues] = useState<any[]>([]);
|
||||||
|
|
||||||
// Inputs for Step 2 conversation simulation controls
|
// Inputs for Step 2 conversation simulation controls
|
||||||
const [roundTableSpeed, setRoundTableSpeed] = useState<string>("正常");
|
|
||||||
const [isRoundTableRunning, setIsRoundTableRunning] = useState<boolean>(true);
|
const [isRoundTableRunning, setIsRoundTableRunning] = useState<boolean>(true);
|
||||||
const [customAgentInput, setCustomAgentInput] = useState<string>("");
|
const [customAgentInput, setCustomAgentInput] = useState<string>("");
|
||||||
// Whether the roundtable visualizer + constraint console panel is collapsed.
|
// Whether the roundtable visualizer + constraint console panel is collapsed.
|
||||||
@@ -465,6 +464,7 @@ export default function RoundtablePlanningPage() {
|
|||||||
// early-returned because the ref was already set; net result: the async
|
// early-returned because the ref was already set; net result: the async
|
||||||
// landed but its setState got skipped, leaving intentThreadId null forever).
|
// landed but its setState got skipped, leaving intentThreadId null forever).
|
||||||
const step1InitGenRef = useRef<number>(0);
|
const step1InitGenRef = useRef<number>(0);
|
||||||
|
const intentAborterRef = useRef<AbortController | null>(null);
|
||||||
|
|
||||||
// Multi-agent orchestration state (lives only for one step-2 visit).
|
// Multi-agent orchestration state (lives only for one step-2 visit).
|
||||||
const [threadIds, setThreadIds] = useState<ThreadIdMap | null>(null);
|
const [threadIds, setThreadIds] = useState<ThreadIdMap | null>(null);
|
||||||
@@ -516,6 +516,17 @@ export default function RoundtablePlanningPage() {
|
|||||||
activeAbortersRef.current.clear();
|
activeAbortersRef.current.clear();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const stopIntentStream = useCallback(() => {
|
||||||
|
if (intentAborterRef.current) {
|
||||||
|
try {
|
||||||
|
intentAborterRef.current.abort();
|
||||||
|
} catch {
|
||||||
|
/* noop */
|
||||||
|
}
|
||||||
|
intentAborterRef.current = null;
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
// Toast auto-dismiss logic
|
// Toast auto-dismiss logic
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (showToast) {
|
if (showToast) {
|
||||||
@@ -524,6 +535,11 @@ export default function RoundtablePlanningPage() {
|
|||||||
}
|
}
|
||||||
}, [showToast]);
|
}, [showToast]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (currentStep === 1) return;
|
||||||
|
stopIntentStream();
|
||||||
|
}, [currentStep, stopIntentStream]);
|
||||||
|
|
||||||
// Auto-follow the streamed conversations: track scroll position, stop
|
// Auto-follow the streamed conversations: track scroll position, stop
|
||||||
// following when the user scrolls up, expose a `回到底部` button that
|
// following when the user scrolls up, expose a `回到底部` button that
|
||||||
// re-engages auto-follow. Same hook for both steps.
|
// re-engages auto-follow. Same hook for both steps.
|
||||||
@@ -1172,6 +1188,7 @@ export default function RoundtablePlanningPage() {
|
|||||||
// Stop anything in flight before swapping state out.
|
// Stop anything in flight before swapping state out.
|
||||||
orchestrationCancelRef.current = true;
|
orchestrationCancelRef.current = true;
|
||||||
abortAllInFlight();
|
abortAllInFlight();
|
||||||
|
stopIntentStream();
|
||||||
setIsOrchestrating(false);
|
setIsOrchestrating(false);
|
||||||
setIsInitializing(false);
|
setIsInitializing(false);
|
||||||
setPendingClarification(null);
|
setPendingClarification(null);
|
||||||
@@ -1201,7 +1218,7 @@ export default function RoundtablePlanningPage() {
|
|||||||
// doesn't change and the effect wouldn't re-fire.
|
// doesn't change and the effect wouldn't re-fire.
|
||||||
runStep1Init();
|
runStep1Init();
|
||||||
triggerToast("✨ 已开始新任务,请在第一步与任务理解智能体澄清需求");
|
triggerToast("✨ 已开始新任务,请在第一步与任务理解智能体澄清需求");
|
||||||
}, [abortAllInFlight, runStep1Init]);
|
}, [abortAllInFlight, runStep1Init, stopIntentStream]);
|
||||||
|
|
||||||
// ── Draft helpers ──────────────────────────────────────────────────────
|
// ── Draft helpers ──────────────────────────────────────────────────────
|
||||||
// Build a fresh snapshot of the current in-memory session. Called by every
|
// Build a fresh snapshot of the current in-memory session. Called by every
|
||||||
@@ -1307,6 +1324,7 @@ export default function RoundtablePlanningPage() {
|
|||||||
// Cancel anything in-flight before swapping state out from under it.
|
// Cancel anything in-flight before swapping state out from under it.
|
||||||
orchestrationCancelRef.current = true;
|
orchestrationCancelRef.current = true;
|
||||||
abortAllInFlight();
|
abortAllInFlight();
|
||||||
|
stopIntentStream();
|
||||||
setIsOrchestrating(false);
|
setIsOrchestrating(false);
|
||||||
setIsInitializing(false);
|
setIsInitializing(false);
|
||||||
setPendingClarification(null);
|
setPendingClarification(null);
|
||||||
@@ -1347,7 +1365,7 @@ export default function RoundtablePlanningPage() {
|
|||||||
setCurrentStep(draft.furthestStep);
|
setCurrentStep(draft.furthestStep);
|
||||||
triggerToast(`📂 已加载草稿:${draft.name}`);
|
triggerToast(`📂 已加载草稿:${draft.name}`);
|
||||||
},
|
},
|
||||||
[drafts, abortAllInFlight],
|
[drafts, abortAllInFlight, stopIntentStream],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleDeleteDraft = useCallback(
|
const handleDeleteDraft = useCallback(
|
||||||
@@ -1470,11 +1488,14 @@ export default function RoundtablePlanningPage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
setIsIntentSending(true);
|
setIsIntentSending(true);
|
||||||
|
const aborter = new AbortController();
|
||||||
|
intentAborterRef.current = aborter;
|
||||||
try {
|
try {
|
||||||
const res = await streamIntent({
|
const res = await streamIntent({
|
||||||
threadId: intentThreadId,
|
threadId: intentThreadId,
|
||||||
message: trimmed,
|
message: trimmed,
|
||||||
model: DEFAULT_MODEL,
|
model: DEFAULT_MODEL,
|
||||||
|
signal: aborter.signal,
|
||||||
onTextDelta: (delta) => {
|
onTextDelta: (delta) => {
|
||||||
setInteractiveMessages(prev =>
|
setInteractiveMessages(prev =>
|
||||||
prev.map(m => (m.id === agentMsgId ? { ...m, content: (m.content ?? "") + delta } : m)),
|
prev.map(m => (m.id === agentMsgId ? { ...m, content: (m.content ?? "") + delta } : m)),
|
||||||
@@ -1529,16 +1550,36 @@ export default function RoundtablePlanningPage() {
|
|||||||
triggerToast(`❌ 智能体调用失败: ${res.content}`);
|
triggerToast(`❌ 智能体调用失败: ${res.content}`);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("intent stream failed:", err);
|
if ((err as Error).name === "AbortError" || aborter.signal.aborted) {
|
||||||
setInteractiveMessages(prev =>
|
setInteractiveMessages(prev =>
|
||||||
prev.map(m =>
|
prev.map(m =>
|
||||||
m.id === agentMsgId
|
m.id === agentMsgId
|
||||||
? { ...m, content: `(错误) ${(err as Error).message}`, streaming: false } as any
|
? {
|
||||||
: m,
|
...m,
|
||||||
),
|
content: (m.content ?? "").trim()
|
||||||
);
|
? `${m.content ?? ""}\n\n(已暂停)`
|
||||||
triggerToast(`❌ 发送失败: ${(err as Error).message}`);
|
: "(已暂停)",
|
||||||
|
streaming: false,
|
||||||
|
} as any
|
||||||
|
: m,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
triggerToast("⏸️ 已暂停任务理解回复");
|
||||||
|
} else {
|
||||||
|
console.error("intent stream failed:", err);
|
||||||
|
setInteractiveMessages(prev =>
|
||||||
|
prev.map(m =>
|
||||||
|
m.id === agentMsgId
|
||||||
|
? { ...m, content: `(错误) ${(err as Error).message}`, streaming: false } as any
|
||||||
|
: m,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
triggerToast(`❌ 发送失败: ${(err as Error).message}`);
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
if (intentAborterRef.current === aborter) {
|
||||||
|
intentAborterRef.current = null;
|
||||||
|
}
|
||||||
setIsIntentSending(false);
|
setIsIntentSending(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -2603,6 +2644,18 @@ export default function RoundtablePlanningPage() {
|
|||||||
{isIntentSending ? "发送中" : "发送"}
|
{isIntentSending ? "发送中" : "发送"}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
{isIntentSending && (
|
||||||
|
<button
|
||||||
|
id="pause-intent-btn"
|
||||||
|
type="button"
|
||||||
|
onClick={() => stopIntentStream()}
|
||||||
|
className="bg-amber-100 hover:bg-amber-200 text-amber-800 text-xs font-bold px-3 py-2.5 rounded-xl flex items-center gap-1.5 transition border border-amber-200/40 shadow-sm active:scale-95"
|
||||||
|
>
|
||||||
|
<Pause className="w-3 h-3" />
|
||||||
|
暂停
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
|
||||||
<button
|
<button
|
||||||
id="suggest-followup-btn"
|
id="suggest-followup-btn"
|
||||||
onClick={handleAgentFollowUp}
|
onClick={handleAgentFollowUp}
|
||||||
@@ -2676,23 +2729,6 @@ export default function RoundtablePlanningPage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2.5">
|
<div className="flex items-center gap-2.5">
|
||||||
{/* Interactive speed controls */}
|
|
||||||
<div className="flex items-center bg-slate-50 border border-slate-200 rounded-xl p-0.5 text-[10px] shrink-0 font-bold font-sans shadow-inner">
|
|
||||||
<span className="px-2 text-slate-400 font-semibold selection:bg-transparent">研商步长</span>
|
|
||||||
<button
|
|
||||||
onClick={() => { setRoundTableSpeed("慢速"); triggerToast("🐌 已切换为 0.5x 慢速拟合监听模式"); }}
|
|
||||||
className={`px-1.5 py-0.5 rounded transition ${roundTableSpeed === "慢速" ? "bg-white text-primary font-extrabold shadow-sm" : "text-slate-500 hover:text-slate-800"}`}
|
|
||||||
>慢速</button>
|
|
||||||
<button
|
|
||||||
onClick={() => { setRoundTableSpeed("正常"); triggerToast("⏱️ 已恢复为 1.0x 标准协商状态值"); }}
|
|
||||||
className={`px-1.5 py-0.5 rounded transition ${roundTableSpeed === "正常" ? "bg-white text-primary font-extrabold shadow-sm" : "text-slate-500 hover:text-slate-800"}`}
|
|
||||||
>正常</button>
|
|
||||||
<button
|
|
||||||
onClick={() => { setRoundTableSpeed("极速"); triggerToast("🚀 已并行为 2.5x 极速算力重算模式"); }}
|
|
||||||
className={`px-1.5 py-0.5 rounded transition ${roundTableSpeed === "极速" ? "bg-white text-primary font-extrabold shadow-sm" : "text-slate-500 hover:text-slate-800"}`}
|
|
||||||
>极速</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Suspend / resume button visibility:
|
{/* Suspend / resume button visibility:
|
||||||
- Show "挂起协商" only while a run is actually in flight
|
- Show "挂起协商" only while a run is actually in flight
|
||||||
(isOrchestrating + still nominally running). When the
|
(isOrchestrating + still nominally running). When the
|
||||||
|
|||||||
Reference in new issue
Block a user