恢复策划 Agent 实时事件订阅(876529e66 误删)
- apps/ai-game-creator-shell/src/App.tsx 重新订阅 `design-agent-update`:本轮正文与工具提示回到 transient reply,`reasoningText` 回到 `planningV2Reasoning`,`view` 回到 applyDesignAgentViewAfterTransient;Rust 侧一直照旧发射这些事件,前端却不再监听 - 补回 designAgentEventSubscriptionReadyRef 的建/解函数与 designAgentEventSubscriptionResolveRef,让 `executeDesignAgentTurn` 等待监听器挂好再发起回合,开局事件不丢 - 新增 designAgentReasoningTurnRef:回合结束(designAgentTurnRef 清空)后仍认本轮 reasoning,最后一条思考不会被视图落盘前的空隙吃掉;切项目时随 resetChatState 清空
This commit is contained in:
@@ -33,6 +33,7 @@ import type {
|
||||
ChatMessage,
|
||||
DesignAgentInput,
|
||||
DesignClarificationRequest,
|
||||
DesignEvent,
|
||||
DesignView,
|
||||
InitLocalProjectResult,
|
||||
LauncherImportedAttachment,
|
||||
@@ -102,6 +103,10 @@ import {
|
||||
setAgcPluginProjectPath,
|
||||
startAvailableAgcPlugin,
|
||||
} from './services/pluginHost';
|
||||
import {
|
||||
canSubscribeTauriEvents,
|
||||
subscribeTauriEvent,
|
||||
} from './services/tauriEventSubscription';
|
||||
import type { HomeCreationType } from './view/home';
|
||||
import {
|
||||
type ProjectAgentResultSummary,
|
||||
@@ -243,6 +248,20 @@ export function App({
|
||||
const designAgentEventSubscriptionReadyRef = useRef<Promise<void> | null>(
|
||||
null,
|
||||
);
|
||||
const designAgentEventSubscriptionResolveRef = useRef<(() => void) | null>(
|
||||
null,
|
||||
);
|
||||
/**
|
||||
* 本轮策划回合的思考归属。
|
||||
*
|
||||
* 与 `designAgentTurnRef` 分开:那个记录回合本身,回合结束就清空;这个只用来判定
|
||||
* 「这条 reasoning 事件是不是本轮的」,回合结束后仍保留,最后一条思考不会在视图
|
||||
* 落盘前的空隙里被丢掉。切项目时随其它聊天状态一起清空。
|
||||
*/
|
||||
const designAgentReasoningTurnRef = useRef<{
|
||||
projectPath: string;
|
||||
clientTurnId: string;
|
||||
} | null>(null);
|
||||
// 项目开发工作台的普通项目固定使用 DirectProject,立项策划项目走策划聊天;两条
|
||||
// 链路各自独立,不通过兼容分支互相承载。
|
||||
const directProjectMode = !planningV2Active;
|
||||
@@ -419,6 +438,22 @@ export function App({
|
||||
return designAgentEventSubscriptionReadyRef.current ?? Promise.resolve();
|
||||
}
|
||||
|
||||
function createDesignAgentEventSubscriptionReady() {
|
||||
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;
|
||||
@@ -442,6 +477,83 @@ export function App({
|
||||
return () => window.clearInterval(timer);
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* 策划 Agent 的实时事件流:本轮流式正文、思考过程和回合中途的视图都靠它推给界面。
|
||||
*
|
||||
* 订阅建立是异步的,而回合由一个 invoke 发起;`designAgentEventSubscriptionReady()`
|
||||
* 让回合等监听器挂好再开始,避免开头几个事件丢掉。事件只认当前项目;有在跑的回合时
|
||||
* 还要认本轮 `clientTurnId`,迟到的上一轮事件不会画到这一轮上。
|
||||
*/
|
||||
useEffect(() => {
|
||||
const ready = createDesignAgentEventSubscriptionReady();
|
||||
if (!canSubscribeTauriEvents() || !planningV2Active) {
|
||||
resolveDesignAgentEventSubscriptionReady();
|
||||
return () => {
|
||||
if (designAgentEventSubscriptionReadyRef.current === ready) {
|
||||
designAgentEventSubscriptionReadyRef.current = null;
|
||||
createDesignAgentEventSubscriptionReady();
|
||||
}
|
||||
};
|
||||
}
|
||||
let cleanup: (() => void) | null = null;
|
||||
let disposed = false;
|
||||
void subscribeTauriEvent<DesignEvent>('design-agent-update', (event) => {
|
||||
const payload = event.payload;
|
||||
const tracked = designAgentTurnRef.current;
|
||||
if (
|
||||
payload.projectPath !== localProjectPathRef.current ||
|
||||
(tracked && payload.clientTurnId !== tracked.clientTurnId)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
(payload.kind === 'text' || payload.kind === 'tool') &&
|
||||
payload.text
|
||||
) {
|
||||
setPlanningV2TransientReplyTarget(payload.text);
|
||||
}
|
||||
if (payload.reasoningText != null) {
|
||||
const reasoningTurn = designAgentReasoningTurnRef.current;
|
||||
if (
|
||||
reasoningTurn?.projectPath === payload.projectPath &&
|
||||
reasoningTurn.clientTurnId === payload.clientTurnId
|
||||
) {
|
||||
setPlanningV2Reasoning(payload.reasoningText);
|
||||
}
|
||||
}
|
||||
if (payload.view) {
|
||||
applyDesignAgentViewAfterTransient(
|
||||
payload.view,
|
||||
payload.projectPath,
|
||||
payload.clientTurnId,
|
||||
);
|
||||
}
|
||||
})
|
||||
.then((unlisten) => {
|
||||
resolveDesignAgentEventSubscriptionReady();
|
||||
if (disposed) {
|
||||
unlisten();
|
||||
return;
|
||||
}
|
||||
cleanup = unlisten;
|
||||
})
|
||||
.catch(() => {
|
||||
resolveDesignAgentEventSubscriptionReady();
|
||||
});
|
||||
return () => {
|
||||
disposed = true;
|
||||
cleanup?.();
|
||||
resolveDesignAgentEventSubscriptionReady();
|
||||
if (designAgentEventSubscriptionReadyRef.current === ready) {
|
||||
designAgentEventSubscriptionReadyRef.current = null;
|
||||
createDesignAgentEventSubscriptionReady();
|
||||
}
|
||||
};
|
||||
// 订阅只跟着「是否走策划 Agent」这条链路;回调里的项目/回合判据都走 refs,
|
||||
// 把它们写进依赖会在每轮回复时重订事件。
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [planningV2Active]);
|
||||
|
||||
function applyPlanningV2CommandResult(
|
||||
result: PlanningSessionCommandResultV2,
|
||||
clientTurnId?: string,
|
||||
@@ -712,6 +824,10 @@ export function App({
|
||||
projectPath: nextProjectPath,
|
||||
clientTurnId,
|
||||
};
|
||||
designAgentReasoningTurnRef.current = {
|
||||
projectPath: nextProjectPath,
|
||||
clientTurnId,
|
||||
};
|
||||
designAgentPendingViewRef.current = null;
|
||||
await designAgentEventSubscriptionReady();
|
||||
setChatAgentBusy(true);
|
||||
@@ -1582,6 +1698,7 @@ export function App({
|
||||
planningV2ActiveRef.current = planningStartMode;
|
||||
designAgentLaneRef.current = planningStartMode;
|
||||
designAgentTurnRef.current = null;
|
||||
designAgentReasoningTurnRef.current = null;
|
||||
setDesignAgentView(null);
|
||||
}
|
||||
|
||||
@@ -2689,6 +2806,10 @@ export function App({
|
||||
projectPath: nextProjectPath,
|
||||
clientTurnId,
|
||||
};
|
||||
designAgentReasoningTurnRef.current = {
|
||||
projectPath: nextProjectPath,
|
||||
clientTurnId,
|
||||
};
|
||||
designAgentPendingViewRef.current = null;
|
||||
setPlanningV2TransientReplyTarget('');
|
||||
setPlanningV2Reasoning('');
|
||||
|
||||
Reference in New Issue
Block a user