修复策划 Agent 事件监听时序

让策划 Agent 回合在调用 Runtime 前等待 design-agent-update 监听注册完成

覆盖普通消息、澄清、重试和阶段批准入口

保持 GameAgent、Direct/Codex 与退役入口行为不变
This commit is contained in:
2026-09-14 14:11:43 +08:00
parent fd88e516b8
commit 13e137191a
+47 -8
View File
@@ -596,6 +596,12 @@ export function App({
projectPath: string;
clientTurnId: string;
} | null>(null);
const designAgentEventSubscriptionReadyRef = useRef<Promise<void> | null>(
null,
);
const designAgentEventSubscriptionResolveRef = useRef<(() => void) | null>(
null,
);
// 做方案入口独立成链:立项策划需要委派、澄清 pending 与 GDD 审批,这些只存在于
// Supervisor Runtimedirect-codex 是单回合「生成→试玩→修」循环,没有对应机制。
// 因此策划入口不走产品默认的 direct-codex,做游戏与做素材保持 master 的新默认。
@@ -849,6 +855,22 @@ export function App({
}
}
function designAgentEventSubscriptionReady() {
if (!designAgentEventSubscriptionReadyRef.current) {
designAgentEventSubscriptionReadyRef.current = new Promise<void>(
(resolve) => {
designAgentEventSubscriptionResolveRef.current = resolve;
},
);
}
return designAgentEventSubscriptionReadyRef.current;
}
function resolveDesignAgentEventSubscriptionReady() {
designAgentEventSubscriptionResolveRef.current?.();
designAgentEventSubscriptionResolveRef.current = null;
}
useEffect(() => {
const timer = window.setInterval(() => {
const target = planningV2TransientReplyTargetRef.current;
@@ -1038,6 +1060,7 @@ export function App({
projectPath: nextProjectPath,
clientTurnId,
};
await designAgentEventSubscriptionReady();
setChatAgentBusy(true);
setProjectSupervisorRuntimeError('');
setPlanningV2TransientReplyTarget('');
@@ -1992,8 +2015,14 @@ export function App({
}, [planningV2Active]);
useEffect(() => {
const ready = designAgentEventSubscriptionReady();
if (!canSubscribeTauriEvents() || !planningV2Active) {
return;
resolveDesignAgentEventSubscriptionReady();
return () => {
if (designAgentEventSubscriptionReadyRef.current === ready) {
designAgentEventSubscriptionReadyRef.current = null;
}
};
}
let cleanup: (() => void) | null = null;
let disposed = false;
@@ -2020,16 +2049,23 @@ export function App({
}
})
.then((unlisten) => {
resolveDesignAgentEventSubscriptionReady();
if (disposed) {
unlisten();
return;
}
cleanup = unlisten;
})
.catch(() => undefined);
.catch(() => {
resolveDesignAgentEventSubscriptionReady();
});
return () => {
disposed = true;
cleanup?.();
resolveDesignAgentEventSubscriptionReady();
if (designAgentEventSubscriptionReadyRef.current === ready) {
designAgentEventSubscriptionReadyRef.current = null;
}
};
// applyDesignView 读的是 refs 和当前项目路径,
// 把它写进依赖会在每轮回复时重订事件。
@@ -11831,12 +11867,15 @@ export function App({
setPlanningV2Reasoning('');
setChatAgentBusy(true);
setPlanGddDecisionBusy(true);
void invoke<DesignView>('decide_design_phase', {
projectPath: nextProjectPath,
clientTurnId,
requestId,
approved,
})
void designAgentEventSubscriptionReady()
.then(() =>
invoke<DesignView>('decide_design_phase', {
projectPath: nextProjectPath,
clientTurnId,
requestId,
approved,
}),
)
.then((view) => {
if (
localProjectPathRef.current !== nextProjectPath ||