From ae8d51500bf77805c7c5cb20ab0d763928d05105 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Wed, 2 Sep 2026 20:12:56 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AE=B0=E5=BD=95Direct=E5=9B=9E=E6=94=BE?= =?UTF-8?q?=E6=9C=89=E6=84=8F=E8=AE=BE=E8=AE=A1=E5=8F=96=E8=88=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 在partial持久化处说明普通assistant与中断标记语义。 在技术方案和决策日志记录全量回放与简单前缀的设计原因。 --- apps/ai-game-creator-shell/src/App.tsx | 3 +++ docs/project-memory/shared-memory/decision-log.md | 5 +++++ .../【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md | 2 +- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/ai-game-creator-shell/src/App.tsx b/apps/ai-game-creator-shell/src/App.tsx index a7cc70883..1d1431116 100644 --- a/apps/ai-game-creator-shell/src/App.tsx +++ b/apps/ai-game-creator-shell/src/App.tsx @@ -5405,6 +5405,9 @@ export function App({ messageId, message: { role: 'assistant', + // An interrupted partial is intentionally a normal assistant + // record so replay sees exactly what Codex emitted before the + // disconnect; the marker is product data, not UI metadata. content: `${text.trim()}\nunexpected interrupt happened here`, agentId: null, }, diff --git a/docs/project-memory/shared-memory/decision-log.md b/docs/project-memory/shared-memory/decision-log.md index a1e20d8cd..b346d5071 100644 --- a/docs/project-memory/shared-memory/decision-log.md +++ b/docs/project-memory/shared-memory/decision-log.md @@ -7893,3 +7893,8 @@ CI 上 `background_agent_runtime_recovers_stale_running_before_pending_task` 在 - `autonomous-game-build` 中,manifest `dependencies` 只作为上下文,不阻塞 ready;代码、设计、美术、音频和发布任务允许并行启动,child 不依赖固定回执顺序或固定 run 身份才能推进。 - 任务最终状态不再提前绑定平台画布、preview、static smoke 或发布产物检查;这些内容不参与该档位的完成判定,也不会因缺失而重置已完成任务。父 run 在任务图进入终态后直接收束并回复。 - 本档位仍沿用现有项目根和工具权限边界;本次调整只解除流程编排与平台产物验收前置,不新增第二套任务系统。 + +## 2026-09-02 DirectProject replay 取舍与 thread 原子判定 + +- DirectProject 的全量 replay、简单 `user:` / `assistant:` / `tool:` 前缀和普通 assistant partial(末尾 `unexpected interrupt happened here`)都是有意的当前产品合同:分别保证 AGC JSONL 事实源无损重建、保持 prompt 形状稳定且不引入 envelope breaking change、让模型明确知道上次输出在中断处结束。后续若调整任一项,必须先更新恢复合同与兼容策略。 +- replay 与 thread 创建必须使用同一临界区结果。`turn_gate` 内的 `thread_for()` 原子返回 `(CodexThreadLease, created)`;只有 `created=true` 时才读取项目 JSONL 并构造历史 prompt,复用已有 thread 时只发送当前 user,避免并发首请求重复注入历史。 diff --git a/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md b/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md index e19db9ecc..085b73844 100644 --- a/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md +++ b/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md @@ -212,7 +212,7 @@ Supervisor 认领该回执后,由父 run 自己为每个原 delivery 逐一创 - 模式升级:`agentMode` 扩为 `codex_app_server / codex_cli / provider`,新默认为 `codex_app_server`;V1.51 的一次性 `codex exec` 保留为显式兼容模式,HTTP Provider 保留为非 Responses 配置及故障回退模式。 - 进程与节点:External Runner 按“有效 Agent LLM 凭据/Responses 路由 + `projectId/agentId/sessionId/runId`”隔离长期 `codex app-server --stdio`,即每个权威节点 run 直接持有自己的 Codex CLI 子进程与 ephemeral thread,每次完整权威请求映射 turn。同一节点 turn 串行,节点之间进程级隔离;单节点连接失败不得使其它节点同时失去终态。Codex thread 不写 durable recovery;节点完成、重启、retry、handoff 和 finalization 仍只认 AGC 账本。 -- DirectProject replay:Codex thread 仍保持 `ephemeral=true`。`.agent/conversations/project.jsonl` 是聊天唯一事实源;仅当 app-server 连接没有可用的项目 thread(通常是进程重启或 thread 被淘汰)时,AGC 才读取全部 `user`、`assistant`、`tool` 记录,按原顺序渲染为简单 `user:` / `assistant:` / `tool:` 行,再追加本次新 user request,发送给新建 thread;已有 thread 的普通消息仍只发送新 user。app-server 意外中断时,已收到的 partial 文本按普通 `assistant` 消息追加,并在文本末尾追加 `unexpected interrupt happened here`;断开处理和下一次发送都可尝试写入,依赖普通 `messageId` 幂等。项目打开只读取历史,不因 user-only 记录自动重发;Direct 不提供 retry 入口。Runtime Agent 继续使用独立的 runtime/context 恢复链路,不读取 DirectProject 对话作为原生 thread history。 +- DirectProject replay:Codex thread 仍保持 `ephemeral=true`。`.agent/conversations/project.jsonl` 是聊天唯一事实源;仅当 app-server 连接没有可用的项目 thread(通常是进程重启或 thread 被淘汰)时,AGC 才读取全部 `user`、`assistant`、`tool` 记录,按原顺序渲染为简单 `user:` / `assistant:` / `tool:` 行,再追加本次新 user request,发送给新建 thread;已有 thread 的普通消息仍只发送新 user。这里的三项取舍是有意的产品合同:全量 replay 保证 AGC 事实源无损恢复;简单 role 前缀保持 prompt 形状稳定、避免引入 breaking envelope;partial 作为普通 `assistant` 记录保存并带 `unexpected interrupt happened here`,让模型明确知道上次输出在断开处结束,而不额外引入 UI metadata。app-server 意外中断时,已收到的 partial 文本按普通 `assistant` 消息追加;断开处理和下一次发送都可尝试写入,依赖普通 `messageId` 幂等。项目打开只读取历史,不因 user-only 记录自动重发;Direct 不提供 retry 入口。Runtime Agent 继续使用独立的 runtime/context 恢复链路,不读取 DirectProject 对话作为原生 thread history。 - LLM 配置:`apiKind` 始终只接受 `openai_responses`;非空 Key 转换为 app-server model provider,base URL 生效,Key 仅走专用环境变量;空 Key 只桥接用户 Codex `auth.json`,不继承环境 `CODEX_API_KEY`。设置面板在 app-server 模式继续显示并保存 model、effort、stream、全局/逐 Agent Key 与路由配置;`openai_chat / anthropic` 明确提示切 `provider`,不得悄悄忽略。`stream=true` 接入 app-server 文本 delta;`webSearchEnabled=true` 只允许 DirectProject 经客户端审核的 `agc_web_search` 使用,不得启用 Codex 原生 webSearch 或任意网络。 - 安全与取消:临时 cwd、隔离 `CODEX_HOME` 与 OS HOME、read-only、network off、never approval,并在启动前关闭 web/multi-agent/shell/browser/plugin/image 等原生能力;取消从 turn-start pending 阶段就跟踪且只 interrupt 当前 turn。已发送 turn 后连接断开或终态丢失进入 reconciliation,只关闭当前节点进程且不重放同一 request slot;明确 failed/interrupted 不按 transport 重试。 - remote-control 认证边界:没有 ChatGPT `auth.json` 的 API Key / provider-proxy app-server 在启动时设置 Codex 内部环境变量 `CODEX_INTERNAL_APP_SERVER_REMOTE_CONTROL_DISABLED=1`,让 remote-control 以 `desired_state=Disabled` 启动,避免上游进入 1Hz 认证重试;不再依赖需要 ChatGPT 登录态的 `remoteControl/disable` RPC。只有实际桥接 ChatGPT 登录态的 AuthBridge 保持 remote-control 可用。API Key 子进程同时使用 `RUST_LOG=warn` 收敛剩余预期噪音,不伪造 `auth.json` 或静默继续。