From 7abb3d6fd7d1f6e712c7bd1ba25c7b3eaaf23ef9 Mon Sep 17 00:00:00 2001 From: menghao Date: Tue, 11 Aug 2026 11:42:20 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8DNative=20Shell=E8=BF=90?= =?UTF-8?q?=E8=A1=8C=E6=A8=A1=E5=BC=8F=E4=B8=8EGoal=E7=BC=96=E8=BE=91?= =?UTF-8?q?=E4=B8=AD=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 仅在持久Goal编辑时立即中断旧Provider,保留普通steer安全边界。 固定隔离模拟Provider测试的agentMode,避免默认Codex app-server干扰。 同步Runtime技术方案、决策记录与测试隔离排障经验。 --- .../src-tauri/src/agent/runtime_protocol/steering.rs | 6 +++++- apps/ai-game-creator-shell/src-tauri/src/tests/mod.rs | 1 + apps/ai-game-creator-shell/src-tauri/src/tests/project.rs | 1 + .../src-tauri/src/tests/runtime_actions/policy.rs | 1 + docs/project-memory/shared-memory/decision-log.md | 1 + docs/project-memory/shared-memory/pitfalls.md | 7 +++++++ .../【技术方案】AI游戏创作Agent Runtime V1.1-2026-07-12.md | 2 ++ .../【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md | 2 +- 8 files changed, 19 insertions(+), 2 deletions(-) diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_protocol/steering.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_protocol/steering.rs index 566577b58..170a3bd53 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_protocol/steering.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_protocol/steering.rs @@ -894,7 +894,11 @@ pub(crate) fn steer_game_creator_agent_runtime_task_for_profile_at( Some(&format!("steerId={steer_id}")), )?; } - let provider_interrupted = false; + let provider_interrupted = if accepted_via == "goal-edit" { + interrupt_game_creator_agent_runtime_provider_request_at(root, &agent_id, run_id)? + } else { + false + }; ensure_game_creator_agent_runtime_steer_audit( root, &state, diff --git a/apps/ai-game-creator-shell/src-tauri/src/tests/mod.rs b/apps/ai-game-creator-shell/src-tauri/src/tests/mod.rs index 5e2dad361..5cbcb764e 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/tests/mod.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/tests/mod.rs @@ -1127,6 +1127,7 @@ fn write_mcp_runtime_test_config(config_dir: &Path, llm_base_url: &str, marker_p fs::create_dir_all(config_dir).expect("create MCP runtime test config dir"); let marker_arg = format!("--marker={}", marker_path.display()); let config = serde_json::json!({ + "agentMode": "provider", "agentLlm": { "code-prototype": { "apiKey": "mcp-runtime-test-key", diff --git a/apps/ai-game-creator-shell/src-tauri/src/tests/project.rs b/apps/ai-game-creator-shell/src-tauri/src/tests/project.rs index 71e092fb7..b3413364a 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/tests/project.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/tests/project.rs @@ -677,6 +677,7 @@ async fn background_agent_runtime_can_generate_platform_art_asset() { fs::write( config_dir.join(GAME_CREATOR_CONFIG_FILE_NAME), serde_json::json!({ + "agentMode": "provider", "editorApi": { "baseUrl": canvas_base_url, "apiKey": "editor-runtime-key" diff --git a/apps/ai-game-creator-shell/src-tauri/src/tests/runtime_actions/policy.rs b/apps/ai-game-creator-shell/src-tauri/src/tests/runtime_actions/policy.rs index f852192e0..f65168688 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/tests/runtime_actions/policy.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/tests/runtime_actions/policy.rs @@ -243,6 +243,7 @@ async fn background_agent_runtime_asset_generation_respects_project_policy() { fs::write( config_dir.join(GAME_CREATOR_CONFIG_FILE_NAME), serde_json::json!({ + "agentMode": "provider", "agentLlm": { "art-asset-plan": { "apiKey": "art-key", diff --git a/docs/project-memory/shared-memory/decision-log.md b/docs/project-memory/shared-memory/decision-log.md index 9e1df8c69..45e082088 100644 --- a/docs/project-memory/shared-memory/decision-log.md +++ b/docs/project-memory/shared-memory/decision-log.md @@ -7013,6 +7013,7 @@ ## 2026-08-10 Supervisor steer 改为 LLM 判定后的条件中断 - 决策:根 Project Supervisor 收到运行中消息后继续原 Run,先由独立 LLM 生成非终态回复并判断 `interruptCurrentProvider`。状态询问、解释和不冲突补充默认不中断;只有明确停止、改向或在途方案会过期时才可请求中断。过程回复持久进入原 conversation,但不得调用终态 `respond_to_user`。 +- 作用域:LLM 条件中断只属于无父级的根 Project Supervisor;普通专业 Agent / 静态委派 Agent 的 `runtime.steer` 继续只做 durable 入队,由运行循环在安全边界丢弃旧回复并重规划;持久 Goal 编辑作为控制面变更继续沿用 V1.13 的立即中断旧 Provider 语义。不得把根 Supervisor 的判定链或 Goal 编辑的强制中断扩散到所有 `runtime.steer` 调用方。 - 时序:steer durable 入队后不先通知 Runner。`false` 或判定失败才调用只唤醒的 `runtime.steer`;`true` 直接调用 `runtime.interrupt_for_steer_decision`。后者必须读取已持久化判定,并只中断 `appliedSteerCursor < steer.sequence` 的旧 Provider;新规划 Provider、工具和外部副作用不可被误杀。 - 失败:判定调用、协议解析或持久化失败时公开回复“继续当前任务”,在下一安全边界应用 steer,绝不退化为默认中断。External Runner 与本地进程内执行保持同一语义。 - 关联:`docs/technical/【技术方案】AI游戏创作Agent Runtime V1.1-2026-07-12.md` V1.53,以及 `docs/project-memory/shared-memory/pitfalls.md` 的“Supervisor steer 不能只有内部排队事件”。 diff --git a/docs/project-memory/shared-memory/pitfalls.md b/docs/project-memory/shared-memory/pitfalls.md index 45f3adf88..63bcb9e55 100644 --- a/docs/project-memory/shared-memory/pitfalls.md +++ b/docs/project-memory/shared-memory/pitfalls.md @@ -4625,6 +4625,13 @@ - 处理:pool key 必须包含 `projectId + agentId + sessionId + runId`,每个权威节点直接持有独立 app-server 子进程;同节点 turn 还要串行,不能向同一 thread 并发 `turn/start`。只发送当前 CLI schema 定义的字段;stderr 使用有界内存尾部并先脱敏再进入 Runner 诊断。 - 验证:至少两个节点并发各跑多轮,确认存在两个 app-server PID;终止其中一个后只有对应节点进入 reconciliation,另一个仍能收到 `turn/completed`。旧 AppData 缺 `agentMode` 且含非 Responses 路由时必须保留 `provider`,不能在项目自动恢复时批量失败。 +## 模拟 Provider 的隔离 AppData 测试必须显式固定执行模式(2026-08-11) + +- 现象:测试已经写入本地 mock `baseUrl / apiKey / model`,却收不到任何 HTTP 请求,日志反而显示 Codex app-server 启动或退出;Native shell 全量中多个后台 Agent 用例一起超时。 +- 原因:新安装和没有迁移上下文的隔离 AppData 默认使用 `codex_app_server`。只写 `agentLlm` 不能表达测试要走 HTTP Provider;直接切换 runtime config dir 的 fixture 也不会经过会自动补 `agentMode` 的测试 helper。 +- 处理:任何要断言模拟 HTTP Provider 请求的配置都必须显式写 `agentMode=provider`。测试 helper 可以统一补齐,但直接写隔离 AppData 的 fixture 仍须在自身 JSON 中声明,不能依赖仓库 `.env`、用户 AppData 或历史迁移。 +- 验证:先单跑失败用例确认请求命中 mock server,再执行完整 `npm run check:native-shells`;日志中不得出现该用例启动 Codex CLI/app-server,所有 Provider/MCP 请求数量和顺序按 fixture 闭合。 + ## 资源编辑恢复不能依赖当前 UI 快照或旧 API Key 指纹(2026-08-10) - 现象:应用重启后,任务视频或项目版本的编辑 operation 无法恢复;轮换 Developer API Key 后已有 operation 被误判为配置变化;目录中放入大量无关文件还能绕过 pending 扫描上限。派生视频再次编辑时若把 `assetObjectId` 当远端引用,生成会失败或指向错误身份。 diff --git a/docs/technical/【技术方案】AI游戏创作Agent Runtime V1.1-2026-07-12.md b/docs/technical/【技术方案】AI游戏创作Agent Runtime V1.1-2026-07-12.md index 07a0e2467..18497348a 100644 --- a/docs/technical/【技术方案】AI游戏创作Agent Runtime V1.1-2026-07-12.md +++ b/docs/technical/【技术方案】AI游戏创作Agent Runtime V1.1-2026-07-12.md @@ -1638,6 +1638,8 @@ V1.52 保留 V1.51 一次性 `codex_cli` 和原 HTTP `provider`,新增 `codex_ V1.53 把根 Project Supervisor 的 same-run steer 从“收到消息立即中断”改为“先回复并判断、按需中断”。用户消息仍先进入原 run 的 durable steer ledger 与 conversation;公开确认明确说明正在判断且当前任务继续运行。随后由独立 LLM turn 调用严格 `runtime_steer_decision`,一次返回自然语言 `reply`、`interruptCurrentProvider` 与安全原因。该回复按 steer 身份持久幂等,是制作过程中的非终态对话,不调用 `respond_to_user`,也不关闭 task、Goal、Run 或 finalization。 +- V1.53 的 LLM 条件中断只适用于无父级的根 Project Supervisor。普通专业 Agent / 静态委派 Agent 的 `runtime.steer` 继续只做 durable 入队,由运行循环在安全边界丢弃旧回复并重规划;持久 Goal 编辑作为控制面变更继续沿用 V1.13,在 durable steer 入队后立即中断当前旧 planning/final-reply Provider。不得把根 Supervisor 的判定链或 Goal 编辑的强制中断扩散到所有 `runtime.steer` 调用方。 + - 命令层在 durable 入队后不得先通知或唤醒 External Runner,避免 Runner 抢先消费 steer 后让判定快照漂移。判定为 `false` 或判定失败时,才发送只校验 ledger 并唤醒任务的 `runtime.steer`;该 RPC 必须固定返回 `providerInterrupted=false`。判定为 `true` 时直接发送 `runtime.interrupt_for_steer_decision`,由该 RPC 完成条件中断并唤醒同一 run。本地进程内路径遵循同一顺序。 - 状态询问、解释、鼓励、确认和不冲突补充默认不中断;只有明确停止、改向,或继续当前方案会产生明显过期结果时才允许 `true`。判定使用当前有效 `provider / codex_cli / codex_app_server` 模式;app-server 以独立 synthetic 节点运行,不能等待主节点的 turn gate。 - 条件中断必须先读取已持久化 decision,并只允许中断注册时 `appliedSteerCursor < steer.sequence` 的旧 planning/final-reply Provider。若旧请求已自然结束,或新 Provider 已消费该 steer 后启动,则返回 `providerInterrupted=false`,不得误杀新规划。工具、外部副作用、确认、process session、Git、receipt 和 finalization 始终不强杀,在下一安全边界消费 steer。 diff --git a/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md b/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md index 7f4d5f4bd..b209a6dd9 100644 --- a/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md +++ b/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md @@ -107,7 +107,7 @@ ### 2026-08-10 Supervisor 边做边聊与条件中断 - 根 Project Supervisor 的运行中消息继续进入当前 `taskId / sessionId / runId`,先持久显示“正在判断、当前任务继续”,再由独立 LLM 生成非终态语义回复并给出 `interruptCurrentProvider`。过程回复不能调用终态 `respond_to_user`,不能把制作 Run、Goal 或 task 提前完成。 -- steer 入队后不得先通知 Runner。判定为无需中断或判定失败时,`runtime.steer` 只校验 durable ledger、唤醒同一 Run 并固定保持 `providerInterrupted=false`;判定为需要改向时,只有 `runtime.interrupt_for_steer_decision` 可以读取持久 decision 后条件中断旧 Provider。已经消费该 steer 的新 Provider、工具和外部动作不得被中断。 +- 根 Project Supervisor 的 steer 入队后不得先通知 Runner。判定为无需中断或判定失败时,`runtime.steer` 只校验 durable ledger、唤醒同一 Run 并固定保持 `providerInterrupted=false`;判定为需要改向时,只有 `runtime.interrupt_for_steer_decision` 可以读取持久 decision 后条件中断旧 Provider。已经消费该 steer 的新 Provider、工具和外部动作不得被中断。普通专业 Agent / 静态委派 Agent 的 steer 只做 durable 入队并在安全边界重规划;持久 Goal 编辑属于控制面变更,入队后立即中断当前旧 planning/final-reply Provider。 - 状态询问、解释和不冲突补充默认继续当前 Provider;明确停止、改向或会让在途方案过期时才允许请求中断。判定失败时继续任务,并在下一安全边界消费消息,不得把失败等同于需要中断。 - UI 通过持久 conversation 展示关联回复,刷新后仍可见;返回的 `assistantReply / interruptDecision / decisionReason` 只用于本次命令结果与诊断,不形成第二个会话或第二个 Run。