fix(roundtable): 模型容错提示顺序前置 + 回看历史时残留「加载中」气泡强制收尾
- 第二步模型自动容错:系统提示气泡改为插入到失败气泡正前方,使「已切换其他 模型」先于新模型重答过程显示(旧实现追加到列表末尾,反而排在答案之后)。 - 加载历史草稿(hydrateFromDraft)时把任何残留 streaming 的气泡强制收尾为静止 态(去加载光标、角标改「已结束」、空正文补「(已结束)」),避免用户点聊天 记录回看时误以为研讨仍在进行。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
6b963fd918
commit
6dd1f9c017
1 file changed
+43
-25
@@ -1205,24 +1205,6 @@ export function useStep2Orchestration(
|
|||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
|
||||||
* 模型自动容错通知(前台):后端切到下一个模型重跑本轮时调用。弹 toast + 在时间线插一条
|
|
||||||
* 「系统提示」气泡,让用户看到「『X』模型异常 → 已切换『Y』继续」。
|
|
||||||
*/
|
|
||||||
const notifyModelSwitch = useCallback(
|
|
||||||
(info: ModelSwitchInfo) => {
|
|
||||||
const who = info.agentName || "智能体";
|
|
||||||
triggerToast(`⚠️「${info.failedModel}」模型${info.reason},已自动切换「${info.nextModel}」继续`);
|
|
||||||
appendDialogue({
|
|
||||||
sender: "系统提示",
|
|
||||||
avatarType: "amber",
|
|
||||||
content: `⚠️ 模型容错:「${who}」所用模型「${info.failedModel}」${info.reason},已自动切换到「${info.nextModel}」继续。`,
|
|
||||||
confidence: "模型容错",
|
|
||||||
});
|
|
||||||
},
|
|
||||||
[appendDialogue, triggerToast],
|
|
||||||
);
|
|
||||||
|
|
||||||
const phaseLabel = useCallback(
|
const phaseLabel = useCallback(
|
||||||
(
|
(
|
||||||
phase: StreamPhase,
|
phase: StreamPhase,
|
||||||
@@ -1339,17 +1321,38 @@ export function useStep2Orchestration(
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成某气泡的 onModelSwitch 处理器:弹提示 + 把该气泡里「失败尝试已累计的半截内容」清空
|
* 生成某气泡的 onModelSwitch 处理器:弹提示 + 在该失败气泡**正前方**插入一条「系统提示」
|
||||||
* (随后新模型的流式增量会重新填进同一气泡),并把状态标为「模型切换中…」。
|
* 气泡(「『X』模型异常 → 已切换『Y』继续」),同时把失败气泡里「已累计的半截内容」清空
|
||||||
|
* (随后新模型的流式增量会重新填进同一气泡)并标为「模型切换中…」。
|
||||||
|
*
|
||||||
|
* 顺序很关键:系统提示插在失败气泡之前 → 用户**先**看到「已切换其他模型」、**再**看到新
|
||||||
|
* 模型重答的过程(旧实现把提示气泡追加到列表末尾,反而排在新模型答案之后,顺序颠倒)。
|
||||||
|
* 插「之前」而非「移到末尾」也保住并行批次里各席位气泡的相对次序。
|
||||||
*/
|
*/
|
||||||
const makeModelSwitchHandler = useCallback(
|
const makeModelSwitchHandler = useCallback(
|
||||||
(bubbleId: number, isParallel: boolean) => (info: ModelSwitchInfo) => {
|
(bubbleId: number, isParallel: boolean) => (info: ModelSwitchInfo) => {
|
||||||
notifyModelSwitch(info);
|
const who = info.agentName || "智能体";
|
||||||
|
triggerToast(`⚠️「${info.failedModel}」模型${info.reason},已自动切换「${info.nextModel}」继续`);
|
||||||
if (isParallel) parallelStreamRef.current.delete(bubbleId);
|
if (isParallel) parallelStreamRef.current.delete(bubbleId);
|
||||||
setDialogueContent(bubbleId, "");
|
const systemBubble: Step2Dialogue = {
|
||||||
setDialogueConfidence(bubbleId, "模型切换中…");
|
id: Date.now() + Math.random(),
|
||||||
|
sender: "系统提示",
|
||||||
|
avatarType: "amber",
|
||||||
|
content: `⚠️ 模型容错:「${who}」所用模型「${info.failedModel}」${info.reason},已自动切换到「${info.nextModel}」继续。`,
|
||||||
|
time: nowTime(),
|
||||||
|
confidence: "模型容错",
|
||||||
|
};
|
||||||
|
setStep2RoundtableDialogues((prev) => {
|
||||||
|
const idx = prev.findIndex((d) => d.id === bubbleId);
|
||||||
|
// 失败气泡找不到(异常兜底):仍按旧行为在末尾追加系统提示。
|
||||||
|
if (idx < 0) return [...prev, systemBubble];
|
||||||
|
const cleared = { ...prev[idx], content: "", confidence: "模型切换中…" };
|
||||||
|
const next = [...prev];
|
||||||
|
next.splice(idx, 1, systemBubble, cleared);
|
||||||
|
return next;
|
||||||
|
});
|
||||||
},
|
},
|
||||||
[notifyModelSwitch, setDialogueContent, setDialogueConfidence],
|
[triggerToast],
|
||||||
);
|
);
|
||||||
|
|
||||||
// ─── §6 并行流式:全接收 / 惰性渲染 / 节流 ───────────────────────────────
|
// ─── §6 并行流式:全接收 / 惰性渲染 / 节流 ───────────────────────────────
|
||||||
@@ -3093,7 +3096,22 @@ export function useStep2Orchestration(
|
|||||||
// 需要 ref 立刻可读到作业的真实线程,否则读到旧值导致接管失败。
|
// 需要 ref 立刻可读到作业的真实线程,否则读到旧值导致接管失败。
|
||||||
threadIdsRef.current = snapshot.threadIds;
|
threadIdsRef.current = snapshot.threadIds;
|
||||||
coordinatorNameRef.current = snapshot.coordinatorName;
|
coordinatorNameRef.current = snapshot.coordinatorName;
|
||||||
setStep2RoundtableDialogues(snapshot.step2RoundtableDialogues);
|
// 历史快照是**静止记录**:任何残留「流式/加载中」的气泡(用户中途点了「停止」,
|
||||||
|
// 或草稿在流式期间被自动保存)都强制收尾为静止态。否则用户点聊天记录回看时,这些
|
||||||
|
// 气泡仍显示「调度中 / 等待响应 / 正在输出…」+ 加载光标,让人误以为还在进行(其实早已结束)。
|
||||||
|
// streaming===true 与「加载中」文案一一对应(finalizeDialogue 收尾时必置 false),故据此即可精确识别。
|
||||||
|
setStep2RoundtableDialogues(
|
||||||
|
snapshot.step2RoundtableDialogues.map((d) => {
|
||||||
|
if (!d.streaming) return d;
|
||||||
|
const hasText = (d.content ?? "").trim().length > 0;
|
||||||
|
return {
|
||||||
|
...d,
|
||||||
|
streaming: false,
|
||||||
|
content: hasText ? d.content : "(已结束)",
|
||||||
|
confidence: "已结束",
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
);
|
||||||
setLastLeaderContent(snapshot.lastLeaderContent);
|
setLastLeaderContent(snapshot.lastLeaderContent);
|
||||||
setHasConsensus(snapshot.hasConsensus);
|
setHasConsensus(snapshot.hasConsensus);
|
||||||
setConsensusPercentage(snapshot.consensusPercentage);
|
setConsensusPercentage(snapshot.consensusPercentage);
|
||||||
|
|||||||
Reference in new issue
Block a user