修复策划 Agent 正文流式收尾

让最终 DesignView 等待临时正文播放完成后再提交正式消息

为非流式返回复用策划 Agent 的前端伪流式显示

保持 reasoning、GameAgent 和其他 Agent 路径不变
This commit is contained in:
2026-09-14 14:27:22 +08:00
parent 13e137191a
commit f7c8b9f217
+87 -7
View File
@@ -827,6 +827,11 @@ export function App({
useState('');
const planningV2TransientReplyTargetRef = useRef('');
const planningV2VisibleReplyRef = useRef('');
const designAgentPendingViewRef = useRef<{
clientTurnId: string;
projectPath: string;
view: DesignView;
} | null>(null);
const [planningV2Reasoning, setPlanningV2Reasoning] = useState('');
const planningV2TurnRef = useRef<{
projectPath: string;
@@ -1027,6 +1032,66 @@ export function App({
latestMessagesRef.current = conversation;
}
function commitDesignAgentView(view: DesignView, projectPath: string) {
const pendingTurnId = designAgentPendingViewRef.current?.clientTurnId;
designAgentPendingViewRef.current = null;
applyDesignView(view, projectPath);
setPlanningV2TransientReplyTarget('');
if (designAgentTurnRef.current?.clientTurnId === pendingTurnId) {
designAgentTurnRef.current = null;
}
}
function applyDesignAgentViewAfterTransient(
view: DesignView,
projectPath: string,
clientTurnId: string,
) {
let target = planningV2TransientReplyTargetRef.current;
const tracked = designAgentTurnRef.current;
if (!target.trim() && !view.running) {
const latestAssistantText = [...view.messages]
.reverse()
.find((message) => message.role !== 'user' && message.text.trim())
?.text.trim();
if (latestAssistantText) {
setPlanningV2TransientReplyTarget(latestAssistantText);
target = latestAssistantText;
}
}
if (
!view.running &&
tracked?.clientTurnId === clientTurnId &&
target.trim() &&
planningV2VisibleReplyRef.current !== target
) {
designAgentPendingViewRef.current = {
clientTurnId,
projectPath,
view,
};
return;
}
commitDesignAgentView(view, projectPath);
}
useEffect(() => {
const timer = window.setInterval(() => {
const pending = designAgentPendingViewRef.current;
if (!pending) {
return;
}
const target = planningV2TransientReplyTargetRef.current;
if (target && planningV2VisibleReplyRef.current !== target) {
return;
}
commitDesignAgentView(pending.view, pending.projectPath);
}, 50);
return () => window.clearInterval(timer);
// 收尾定时器只需注册一次;它读取 refs,避免随每次渲染重建。
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
async function hydrateDesignAgentSession(nextProjectPath: string) {
const invoke = resolveTauriInvoke();
if (!invoke || !nextProjectPath.trim()) {
@@ -1060,6 +1125,7 @@ export function App({
projectPath: nextProjectPath,
clientTurnId,
};
designAgentPendingViewRef.current = null;
await designAgentEventSubscriptionReady();
setChatAgentBusy(true);
setProjectSupervisorRuntimeError('');
@@ -1074,7 +1140,7 @@ export function App({
if (localProjectPathRef.current !== nextProjectPath) {
return;
}
applyDesignView(view, nextProjectPath);
applyDesignAgentViewAfterTransient(view, nextProjectPath, clientTurnId);
} catch (error) {
if (localProjectPathRef.current !== nextProjectPath) {
return;
@@ -1086,8 +1152,10 @@ export function App({
setProjectSupervisorRuntimeError(message);
setPlanGddError(message);
} finally {
designAgentTurnRef.current = null;
setPlanningV2TransientReplyTarget('');
if (!designAgentPendingViewRef.current) {
designAgentTurnRef.current = null;
setPlanningV2TransientReplyTarget('');
}
setChatAgentBusy(false);
}
}
@@ -1579,6 +1647,7 @@ export function App({
setProjectSupervisorRuntimeError('');
setPlanningV2Session(null);
setPlanningV2TransientReplyTarget('');
designAgentPendingViewRef.current = null;
setPlanningV2Reasoning('');
setPlanningV2Active(planningStartMode);
planningV2ActiveRef.current = planningStartMode;
@@ -2045,7 +2114,11 @@ export function App({
setPlanningV2TransientReplyTarget(payload.text);
}
if (payload.view) {
applyDesignView(payload.view, payload.projectPath);
applyDesignAgentViewAfterTransient(
payload.view,
payload.projectPath,
payload.clientTurnId,
);
}
})
.then((unlisten) => {
@@ -11863,6 +11936,7 @@ export function App({
projectPath: nextProjectPath,
clientTurnId,
};
designAgentPendingViewRef.current = null;
setPlanningV2TransientReplyTarget('');
setPlanningV2Reasoning('');
setChatAgentBusy(true);
@@ -11885,7 +11959,11 @@ export function App({
) {
return;
}
applyDesignView(view, nextProjectPath);
applyDesignAgentViewAfterTransient(
view,
nextProjectPath,
clientTurnId,
);
})
.catch((error) => {
if (
@@ -11907,8 +11985,10 @@ export function App({
) {
return;
}
designAgentTurnRef.current = null;
setPlanningV2TransientReplyTarget('');
if (!designAgentPendingViewRef.current) {
designAgentTurnRef.current = null;
setPlanningV2TransientReplyTarget('');
}
setChatAgentBusy(false);
setPlanGddDecisionBusy(false);
});