diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/controller/useDirectProjectChatController.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/controller/useDirectProjectChatController.ts index 2eb9ae155..dfcf38435 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/controller/useDirectProjectChatController.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/controller/useDirectProjectChatController.ts @@ -39,10 +39,7 @@ import { isDirectCodexTurnAlreadyRunningError, isDirectCodexTurnInterruptedError, } from '../conversation/directCodexConversation'; -import { - DIRECT_CODEX_SESSION_KEEPALIVE_MS, - withDirectCodexSessionRefresh, -} from '../conversation/directCodexSession'; +import { DIRECT_CODEX_SESSION_KEEPALIVE_MS } from '../conversation/directCodexSessionKeepalive'; import { type DirectCodexTurnAttachment, toDirectCodexTurnAttachments, @@ -569,23 +566,22 @@ export function useDirectProjectChatController({ currentPlatformSessionGeneration, ); try { - await withDirectCodexSessionRefresh(() => - invoke('chat_with_game_creator_direct_codex', { - projectPath: nextProjectPath, - clientTurnId: input.clientTurnId, - userItem: input.userItem, - analyticsAttemptId: runAnalytics.nextAttempt(), - ...(input.creationType ? { creationType: input.creationType } : {}), - }), - ); + await invoke('chat_with_game_creator_direct_codex', { + projectPath: nextProjectPath, + clientTurnId: input.clientTurnId, + userItem: input.userItem, + analyticsAttemptId: runAnalytics.nextAttempt(), + ...(input.creationType ? { creationType: input.creationType } : {}), + }); } finally { runAnalytics.settle(); } // 清单刷新统一交给 startTurn 的 finally:成功与报错路径都覆盖,且只读一次。 // TODO(Direct 命令接单化,未实施):下面这个 catch 现在兼职"接单被拒"与"回合失败"两种回执。 - // 计划(`docs/adr/【ADR】DirectProject命令接单化-2026-09-23.md`,草案)是让命令只负责接单、 - // 整轮结果只由订阅事件的载荷回答:届时这里只剩接单被拒,文案改成这条消息下面的本地助手 - // 气泡,状态行改由 reducer 供数据,而 invoke 拒绝驱动的认证重试作废。 + // 计划(`docs/adr/【ADR】DirectProject命令接单化-2026-09-23.md`)是让命令只负责接单:整轮结果 + // 只由订阅事件的载荷回答,拒单则返回 typed 错误——届时这里只剩"拒单",认得的前置 / 参数类按变体 + // 给与用户消息同级的提示且不上报,认不得的错误原样抛出交给既有捕获链路,状态行改由 reducer 供数。 + // invoke 拒绝驱动的认证重试已按该 ADR 删除(`directCodexSessionKeepalive.ts` 只保留会话保活)。 } catch (error) { if ( isDirectCodexTurnAlreadyRunningError(error) || @@ -663,10 +659,11 @@ export function useDirectProjectChatController({ setTurnCancelling(true); setComposerNotice('正在终止当前回合'); try { - const result = await withDirectCodexSessionRefresh(() => - invoke('cancel_direct_codex_turn', { + const result = await invoke( + 'cancel_direct_codex_turn', + { projectPath, - }), + }, ); const message = result?.message?.trim(); if (result?.outcome === 'released') { diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/conversation/directCodexSession.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/conversation/directCodexSession.ts deleted file mode 100644 index 458a39e41..000000000 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/conversation/directCodexSession.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { - currentPlatformSessionGeneration, - requestPlatformSessionRefresh, -} from '../../../../services/platformSession'; - -/** - * 平台 access token 很短命。DirectProject 一个回合可能横跨图片生成、构建和浏览器验证, - * 所以回合运行期间由客户端保持原生会话新鲜;`platformSession.ts` 的 singleflight - * 会把这里的刷新与 401 触发的刷新合并成同一次请求。 - */ -export const DIRECT_CODEX_SESSION_KEEPALIVE_MS = 5 * 60 * 1000; - -function isDirectCodexAuthenticationRequired(error: unknown) { - const message = error instanceof Error ? error.message : String(error); - return ( - message.includes('authentication-required') || - message.includes('codex-app-server-error:unauthorized') || - /kind=codex-app-server-unauthorized(?=\s|$)/.test(message) || - message.includes('登录已失效') - ); -} - -/** - * 跑一轮 DirectProject 请求:只有 401/登录失效才刷新会话重试一次,其它错误原样抛出。 - * - * 刷新期间账号代际变化(换号、登出)时必须放弃重试:带着旧身份的请求重放会把上一账号 - * 的回合打进新账号的对话历史。 - */ -export async function withDirectCodexSessionRefresh( - operation: () => Promise, -) { - const generation = currentPlatformSessionGeneration(); - try { - return await operation(); - } catch (error) { - if (!isDirectCodexAuthenticationRequired(error)) throw error; - if (currentPlatformSessionGeneration() !== generation) throw error; - const refresh = await requestPlatformSessionRefresh(); - if (refresh.status === 'failed') throw error; - if ( - refresh.status !== 'refreshed' || - currentPlatformSessionGeneration() !== refresh.generation - ) { - throw new Error('登录账号已变化,原对话请求已停止'); - } - return operation(); - } -} diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/conversation/directCodexSessionKeepalive.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/conversation/directCodexSessionKeepalive.ts new file mode 100644 index 000000000..c47154f57 --- /dev/null +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/conversation/directCodexSessionKeepalive.ts @@ -0,0 +1,6 @@ +/** + * 平台 access token 很短命。DirectProject 一个回合可能横跨图片生成、构建和浏览器验证, + * 所以回合运行期间由客户端保持原生会话新鲜;`platformSession.ts` 的 singleflight + * 会把这里的刷新与 401 触发的刷新合并成同一次请求。 + */ +export const DIRECT_CODEX_SESSION_KEEPALIVE_MS = 5 * 60 * 1000;