diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_actions/provider_batch_ledger.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_actions/provider_batch_ledger.rs index 0fba3b479..c4a692e45 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_actions/provider_batch_ledger.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_actions/provider_batch_ledger.rs @@ -290,6 +290,14 @@ pub(in crate::agent) fn validate_game_creator_agent_runtime_provider_action_batc } let mut waiting_confirmation_count = 0_usize; let mut rejected_count = 0_usize; + // planning v4 批次把 plan update 冻结进 standalone member 用于恢复;普通批次的成员则被下方 + // 分支要求不得携带 planning recovery material。期望值必须按批次类型分叉,否则「同一轮里既 + // 调 update_agent_plan 又调工具」的普通批次会同时踩中两条互斥规则。 + let expected_member_plan_update = batch + .planning_session_binding + .is_some() + .then(|| batch.plan.plan_update.clone()) + .flatten(); for (index, pending) in batch.actions.iter().enumerate() { validate_agent_runtime_pending_tool_action_record(root, pending)?; if pending.agent_id != batch.agent_id @@ -305,7 +313,7 @@ pub(in crate::agent) fn validate_game_creator_agent_runtime_provider_action_batc || pending.planned_repository_context_fingerprint != batch.planned_repository_context_fingerprint || pending.planning_session_binding != batch.planning_session_binding - || pending.provider_batch_plan_update != batch.plan.plan_update + || pending.provider_batch_plan_update != expected_member_plan_update || usize::try_from(pending.action_index).unwrap_or(usize::MAX) != index || pending.action != batch.plan.actions[index] { diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_actions/provider_request_builders.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_actions/provider_request_builders.rs index 22750e04b..262dac030 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_actions/provider_request_builders.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_actions/provider_request_builders.rs @@ -2057,17 +2057,18 @@ mod tests { vec!["准备委派".to_string()], ) .expect("start supervisor"); - let (_, _, supervisor_request, _, _) = build_game_creator_agent_background_tool_plan_request( - &root, - GAME_CREATOR_PROJECT_SUPERVISOR_AGENT_ID, - &supervisor_state.session_id, - &supervisor_state.run_id, - &supervisor_state.current_task, - &[], - 0, - &catalog, - ) - .expect("build supervisor request"); + let (_, _, supervisor_request, _, _) = + build_game_creator_agent_background_tool_plan_request( + &root, + GAME_CREATOR_PROJECT_SUPERVISOR_AGENT_ID, + &supervisor_state.session_id, + &supervisor_state.run_id, + &supervisor_state.current_task, + &[], + 0, + &catalog, + ) + .expect("build supervisor request"); assert!(!supervisor_request.messages[0] .content .contains(planning_brief_marker)); diff --git a/apps/ai-game-creator-shell/src-tauri/src/tests/collaboration/policy_batches.rs b/apps/ai-game-creator-shell/src-tauri/src/tests/collaboration/policy_batches.rs index 4921705a8..3ec30ca5a 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/tests/collaboration/policy_batches.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/tests/collaboration/policy_batches.rs @@ -1425,3 +1425,99 @@ async fn agent_runtime_file_tools_cannot_modify_collaboration_policy_or_advance_ } fs::remove_dir_all(root).ok(); } + +/// 回归:模型在同一轮里既调 update_agent_plan 又调协作工具时,普通批次必须能通过预检。 +/// +/// `provider_batch_plan_update` 只为 planning v4 的 standalone member 恢复而冻结,普通批次成员 +/// 一律保持 None;预检期望值若不按批次类型分叉,就会同时要求成员「等于 plan update」和「不得携带 +/// planning recovery material」,让「更新计划 + 委派专业 Agent」这一最常规动作直接失败。 +#[tokio::test] +async fn supervisor_collaboration_batch_keeps_plan_update_off_members() { + let root = unique_project_path(); + init_local_game_project_at( + &root, + "project-collaboration-plan-update", + "协作批次携带 plan update 测试", + ) + .expect("project init"); + write_supervisor_collaboration_policy_at( + &root, + supervisor_collaboration_mixed_policy_for_test(), + ) + .expect("write mixed collaboration policy"); + write_project_permission_policy_at( + &root, + ProjectPermissionPolicy { + denied_commands: Vec::new(), + confirm_commands: Vec::new(), + agent_policies: BTreeMap::new(), + }, + ) + .expect("write permissive tool policy"); + let run_id = "supervisor-collaboration-plan-update-run"; + let runtime = start_game_creator_agent_runtime_task_at( + &root, + GAME_CREATOR_PROJECT_SUPERVISOR_AGENT_ID, + "边更新计划边编排协作", + run_id, + "agent-chat", + "编排协作并同步计划", + vec!["收齐专业交付".to_string()], + ) + .expect("start supervisor runtime"); + let revision = read_game_creator_agent_runtime_project_revision(&root) + .expect("read revision before plan update batch"); + let repository_fingerprint = "d".repeat(64); + let mut plan = supervisor_collaboration_plan_for_test(vec![ + supervisor_collaboration_delegate_action_for_test("design-director", None), + supervisor_collaboration_delegate_action_for_test("art-director", None), + supervisor_collaboration_spawn_action_for_test(2), + ]); + plan.plan_update = Some(AgentRuntimePlanUpdate { + explanation: "拆解协作波次".to_string(), + steps: vec![ + AgentRuntimePlanUpdateStep { + step: "冻结根 Goal Contract".to_string(), + status: "completed".to_string(), + }, + AgentRuntimePlanUpdateStep { + step: "委派专业 Agent".to_string(), + status: "in_progress".to_string(), + }, + ], + }); + + let preparation = prepare_game_creator_agent_runtime_provider_action_batch( + &root, + &runtime, + "边更新计划边编排协作", + &plan, + &[], + &revision, + &repository_fingerprint, + ) + .await + .expect("prepare batch carrying plan update"); + let AgentRuntimeProviderActionBatchPreparation::Ready(batch) = preparation else { + panic!("collaboration wave must form ready durable batch"); + }; + assert!(batch.plan.plan_update.is_some()); + assert!(batch.planning_session_binding.is_none()); + assert!( + batch + .actions + .iter() + .all(|pending| pending.provider_batch_plan_update.is_none()), + "普通批次成员不得携带 planning recovery material", + ); + + let recovered = read_game_creator_agent_runtime_provider_action_batch( + &root, + GAME_CREATOR_PROJECT_SUPERVISOR_AGENT_ID, + run_id, + ) + .expect("read back batch carrying plan update"); + assert_eq!(recovered.batch_id, batch.batch_id); + assert_eq!(recovered.plan.plan_update, batch.plan.plan_update); + fs::remove_dir_all(root).ok(); +} diff --git a/docs/technical/【技术说明】AGC接第三方Provider的兼容性缺陷-2026-08-19.md b/docs/technical/【技术说明】AGC接第三方Provider的兼容性缺陷-2026-08-19.md new file mode 100644 index 000000000..b57d342d4 --- /dev/null +++ b/docs/technical/【技术说明】AGC接第三方Provider的兼容性缺陷-2026-08-19.md @@ -0,0 +1,305 @@ +# 【技术说明】AGC 接第三方 Provider 的兼容性缺陷 + +- 日期:2026-08-19 +- 分支:`feat/five_min_design`(HEAD `c2d527387`) +- 触发场景:在「做方案」入口输入「贪吃蛇」,项目总控 Agent 第一个请求就失败 +- 结论:**这不是策划链路的问题**。做游戏 / 做素材 / 做方案共用同一套 Provider 分发,任何一条路换成非官方端点都会立刻挂。共发现 4 个独立缺陷,均已取得直接证据;其中缺陷 4 是本分支自己引入的回归,同样会影响做游戏路径,已修复。 + +--- + +## 0. 摘要 + +| # | 缺陷 | 表现 | 性质 | +|---|---|---|---| +| 1 | 前端保存设置时把 `agentMode` 硬写成 `codex_app_server` | UI 里换 provider 只改了 `llm.*`,运行模式换不掉,且界面上看不到这个字段 | 产品缺陷 | +| 2 | `codex_app_server` 模式把第三方端点喂给 codex | apiKind≠openai_responses 时秒挂;否则 413 + 工具误用,180 秒超时后留下待核对的孤儿请求 | 模式前提未被约束 | +| 3 | `provider` 模式下 `tool_choice=required` 与 DeepSeek 思考模式互斥 | 首个 tool-plan 请求 400,整个 runtime 起不来 | 参数空间缺一个值 | +| 4 | 普通 action 批次带 plan update 时,两条预检规则互斥 | 「更新计划 + 委派专业 Agent」同一轮返回就报「批次成员身份或顺序不匹配」 | **本分支回归**(已修) | + +缺陷 1~3 叠加的结果:**当前代码里没有任何一组配置能让 DeepSeek 跑起来**。缺陷 4 与 provider 无关,换成 `gpt-5.6-terra` 打通 LLM 链路后才暴露出来。 + +--- + +## 1. 缺陷 1:`agentMode` 无法从 UI 切换 + +### 现象 + +在「Agent 设置 - 常用设置」里把 provider 换成 DeepSeek 并保存,配置文件里 `llm.baseUrl/model/apiKind` 都变了,但 `agentMode` 始终是 `codex_app_server`。界面上也找不到这个字段。 + +### 根因 + +[RuntimeConfigDialog.tsx:844](../../apps/ai-game-creator-shell/src/features/runtime-config/RuntimeConfigDialog.tsx:844) 的保存分支: + +```ts +const config = normalizeRuntimeConfigDraft( + { + ...runtimeConfigDraft, + agentMode: 'codex_app_server', // ← 无条件覆盖 draft + editorApi: ..., + mcpServers: ..., + }, + allowAdvancedExternalEditorConfig, +); +``` + +弹窗里没有对应控件,`defaultRuntimeConfigDraft`(同文件 :68)也把它写死。于是: + +- 用户改不了; +- 就算手工改了配置文件,**下一次在弹窗里点保存又会被写回 `codex_app_server`**,而且整个 `llm` 块会被弹窗草稿覆盖。 + +### 生效配置的位置 + +`writable_game_creator_config_path()`([config.rs:1367](../../apps/ai-game-creator-shell/src-tauri/src/config.rs:1367))→ runtime config dir → Tauri `app_config_dir`: + +``` +%APPDATA%\world.genarrative.ai-game-creator\game-creator.config.json +``` + +注意 `agentMode` 缺省值是 `codex_app_server`([main.rs:1252](../../apps/ai-game-creator-shell/src-tauri/src/main.rs:1252)),所以**旧配置文件里没有这个 key 时同样落到 codex 模式**。 + +--- + +## 2. 缺陷 2:`codex_app_server` 模式 + 第三方端点 + +### 2.1 分发关系 + +Provider 分发按全局 `agentMode` 分支([provider_retry.rs:1742](../../apps/ai-game-creator-shell/src-tauri/src/agent/runtime_protocol/provider_retry.rs:1742)),与入口(做游戏 / 做素材 / 做方案)无关。`codex_app_server` 模式下 AGC 不直连 LLM,而是拉起本机 `codex` 二进制当 app-server: + +``` +codex.exe app-server --stdio -c mcp_servers={} -c web_search="disabled" + -c agents.enabled=false + --disable apps --disable browser_use --disable computer_use --disable goals + --disable image_generation --disable plugins --disable shell_tool + --disable unified_exec --disable workspace_dependencies ... + -c model_provider="genarrative_agc" + -c model_providers.genarrative_agc.base_url="https://api.deepseek.com" + -c model_providers.genarrative_agc.env_key="GENARRATIVE_AGC_CODEX_API_KEY" + -c model_providers.genarrative_agc.wire_api="responses" +``` + +(取自 2026-08-19 13:35 / 13:44 / 13:48 三个存活进程的命令行。) + +### 2.2 `apiKind=openai_chat` → 秒挂 + +[codex_app_server.rs:463](../../apps/ai-game-creator-shell/src-tauri/src/agent/codex_app_server.rs:463) 的门禁在任何 HTTP 请求之前就返回 `InvalidConfig`: + +> `codex_app_server 仅支持 apiKind=openai_responses;当前 apiKind=openai_chat,请改用 provider 模式` + +**取证方式**:agent.db 里只留 `errorChars` + `errorSha256`(原文被 [loop_orchestration.rs:536](../../apps/ai-game-creator-shell/src-tauri/src/agent/generation/loop_orchestration.rs:536) 哈希掉了)。13:33:45 那次 run(`gameagent-a21e1b2a`)记录为 `errorChars=156`、`errorSha256=a9481526dab648ad70e7800446d9026a7abcde068f44c5c2bc5e466fd2b6850e`。按代码把公开错误串重建为 + +``` +agentLlm.project-supervisor 后台 Agent 工具计划调用 LLM 失败:kind=invalid-config fingerprint= chars=<原文字数> +``` + +后 sha256 完全命中,确认内层原文就是上面那句门禁。 + +### 2.3 `apiKind=openai_responses` → 413,然后超时 + +13:41 那次 run(`gameagent-edfa1ba1`)的 `agent.runtime.plan.provider_usage` 记录 `activeMillis: 180786`,正好等于当时的 `requestTimeoutMs: 180000`,随后写入 `agent.runtime.provider_request.needs_reconciliation` —— 也就是 UI 上的「待核对 / 确认孤立 Provider 请求后再恢复当前 run」。 + +codex 自己的 tracing 落在隔离 CODEX_HOME 里(`%TEMP%\genarrative-agc-codex-app-server-*\codex-home\logs_2.sqlite`),两类记录: + +**(a) 上游 413** + +``` +WARN codex_core::responses_retry ... model=deepseek-v4-flash: + stream disconnected - retrying ... + unexpected status 413 Payload Too Large: + 413 Request Entity Too Large +
openresty
+ , url: https://api.deepseek.com/responses +``` + +codex 组的请求体(自带 system prompt + 全套工具 schema)超过了 DeepSeek 网关的 body 上限。codex 把 413 归类成「stream disconnected」并重试——11 秒内 5 次,turn 永远走不到终态。 + +**(b) 模型把 `view_image` 当文件读取工具** + +52 条 `ERROR codex_core::tools::router`,形状一致: + +``` +tool_name=view_image +error=unable to locate image at `...\gameagent-1d26566b\memory\README.md`: (os error 2) +``` + +目标全是 `memory/README.md`、`memory/gameplay.md`、`memory/play-memory.md`、`exports/index.html` 等文本文件。原因是 AGC 要求「AGC Runtime 是唯一 ToolHost」,把 codex 侧能读文件的工具全 `--disable` 掉了,模型只好拿剩下的 `view_image` 去读 `.md`。每次失败后模型继续试,对话越滚越长,反过来把 (a) 的请求体喂得更大。 + +### 2.4 结论 + +`codex_app_server` 模式是围绕自家 `dev.genarrative.world/gpt/v1` + `gpt-5.6-sol` + AGC 独占 ToolHost 这套组合设计的。换第三方端点时 (a)(b) 都不是配置能绕开的:413 是对方网关的硬限制,工具误用是模型对着被裁剪过的 codex 工具集乱猜。 + +**当前代码没有任何地方阻止这种组合**——用户只会等 180 秒然后拿到一个「待核对」。 + +--- + +## 3. 缺陷 3:`provider` 模式 + DeepSeek 的 `tool_choice` + +把 `agentMode` 手工改成 `provider` 后重跑,14:03:38 仍然失败。这次原文有落盘(provider 模式会写 [logs/llm-raw](../../apps/ai-game-creator-shell/src-tauri/logs/llm-raw),文件 `1787148218861-33480-000001-upstream_status_failed.output.txt`): + +```json +{"error":{"message":"Thinking mode does not support this tool_choice", + "type":"invalid_request_error","code":"invalid_request_error"}} +``` + +### 复现矩阵(直接打 DeepSeek,非流式) + +| 请求 | 结果 | +|---|---| +| `tool_choice: "required"` | **400** Thinking mode does not support this tool_choice | +| `tool_choice: "auto"` | 200 | +| `tool_choice: "none"` | 200 | +| `tool_choice: "required"` + `reasoning.effort: "none"` | **200**,且正常返回 `function_call` | +| `tool_choice: "required"` + `reasoning.effort: "minimal"` | 400 | +| `tool_choice: "required"` + `thinking: {type:"disabled"}` | 400 | + +`/chat/completions` 与 `/responses` 两条 wire、`deepseek-v4-flash` 与 `deepseek-v4-pro` 两个模型表现完全一致。即:**DeepSeek 支持强制工具调用,但必须先关掉思考模式,而唯一能关掉它的开关是 `reasoning.effort: "none"`。** + +带 3 个工具、`effort=none`、`tool_choice=required` 连打 3 次,全部返回干净的 `function_call`(其中一次返回两个),行为稳定。 + +### 根因 + +两个硬约束正好互斥: + +1. Runtime 主循环的 tool-plan 请求写死 `LlmToolChoice::Required` + ([provider_tool_plan.rs:1482](../../apps/ai-game-creator-shell/src-tauri/src/agent/runtime_actions/provider_tool_plan.rs:1482)、 + [provider_request_builders.rs:462](../../apps/ai-game-creator-shell/src-tauri/src/agent/runtime_actions/provider_request_builders.rs:462) 与 :554、 + [autonomous_policy.rs:1971](../../apps/ai-game-creator-shell/src-tauri/src/agent/runtime_actions/autonomous_policy.rs:1971))。这是协议要求,Agent 必须返回工具调用。 +2. `reasoningEffort` 的取值只有 `default / low / medium / high / max` + ([platform-llm lib.rs:195](../../server-rs/crates/platform-llm/src/lib.rs:195)、[config.rs:145](../../apps/ai-game-creator-shell/src-tauri/src/config.rs:145)、 + [types.ts:605](../../apps/ai-game-creator-shell/src/app/types.ts:605))。**没有 `none`**,而 `default` 的语义是整个字段不发 → 思考模式默认开着。 + +于是第一个请求必挂。 + +--- + +## 4. 缺陷 4:普通 action 批次带 plan update 时预检自相矛盾(已修) + +换成 `gpt-5.6-terra` 后 LLM 链路终于通了(loop 1 成功冻结根 Goal Contract,计划推到 1/4),但 14:15:11 挂在第二步「委派 project-planning 产出 Fast GDD」。这一条与 provider 无关,是**本分支自己引入的回归**。 + +### 现象 + +agent.db 里这条错误没有被哈希,是明文: + +``` +Provider action 批次预检失败: +Agent Runtime Provider action 批次成员身份或顺序不匹配:index=0 +``` + +两轮的 `tool_plan.protocol` 记录: + +| loop | 模型返回的 function call | 结果 | +|---|---|---| +| 1 | `runtime_tool_agent_goal_contract` | ok | +| 2 | `update_agent_plan` + `runtime_tool_agent_delegate` | 预检失败 | + +即「更新计划 + 委派专业 Agent」同一轮返回——总控最常规的动作。 + +### 根因:两条校验规则互斥 + +[provider_batch_ledger.rs:316](../../apps/ai-game-creator-shell/src-tauri/src/agent/runtime_actions/provider_batch_ledger.rs:316) 对**每个**批次成员要求 `pending.provider_batch_plan_update == batch.plan.plan_update`; +同一函数 [:358](../../apps/ai-game-creator-shell/src-tauri/src/agent/runtime_actions/provider_batch_ledger.rs:358) 又对**非 planning** 批次成员要求该字段必须是 `None`("非 planning Provider action 批次成员不能携带 planning recovery material")。 + +而创建侧 [provider_action_batch.rs:636](../../apps/ai-game-creator-shell/src-tauri/src/agent/runtime_actions/provider_action_batch.rs:636) 只给 `plan.submit_gdd` 这一个工具填该字段,其余动作保持默认 `None`(同文件 :279)。 + +于是「非 planning 批次 + 该轮带 plan update」被同时要求"等于 Some"和"必须是 None",无解,前者先命中。 + +### 归属 + +``` +git log -S provider_batch_plan_update → 27c3eb847 立项策划:完成 M1B-2 GDD 提交与恢复 +master 中该标识符出现 0 次 +``` + +触发条件是「生成持久化批次 + 该轮带 plan update + 首动作不是 `plan.submit_gdd`」,**做游戏路径同样会撞**——违反本分支「做游戏/做素材与 master 一致」的准则。 + +测试没拦住的原因:`provider_batch_plan_update` 相关用例(pending_recovery.rs:2177 / 2552)全是 planning 提交路径的夹具,缺「非 planning 批次 + plan update」这个组合。 + +### 修法(已应用) + +预检期望值按批次类型分叉:planning v4 批次保持相等(该约束在 [:241](../../apps/ai-game-creator-shell/src-tauri/src/agent/runtime_actions/provider_batch_ledger.rs:241) 已对 `actions[0]` 校验过一次),非 planning 批次期望 `None`。 + +```rust +let expected_member_plan_update = batch + .planning_session_binding + .is_some() + .then(|| batch.plan.plan_update.clone()) + .flatten(); +``` + +创建侧与 :358 的语义本来自洽,不动。 + +回归测试:`tests::collaboration::policy_batches::supervisor_collaboration_batch_keeps_plan_update_off_members`。已验证去掉修复后该用例复现出与线上完全一致的错误串。 + +--- + +## 5. 附:MiniMax 的强制工具调用不可靠 + +作为备选测过 `api.minimaxi.com/anthropic` + `MiniMax-M3` + `tool_choice:{type:"any"}`(AGC 的 `Required` 在 anthropic wire 上映射成 `any`): + +- 请求本身 200,非流式与流式都通; +- 但 3 次试验只有 1 次真的返回 `tool_use`,另外 2 次是 `stop_reason: end_turn` 的纯文本。 + +也就是说 MiniMax 的 anthropic 兼容层**不强制**执行 `tool_choice: any`。AGC 有 format repair 兜底(`format_repair_attempts`),但会白烧轮次,不建议作为主力。 + +--- + +## 6. 影响面 + +- 三个入口(做游戏 / 做素材 / 做方案)共用同一套分发,缺陷 1~3 与入口无关; +- 缺陷 1 让绝大多数用户根本走不到 `provider` 模式; +- 缺陷 2 的失败形态最差:不是报错而是等满超时 + 留下待核对的孤儿请求 + 池化的 codex 进程; +- 缺陷 3 让 `provider` 模式对「思考型第三方模型」整体不可用(DeepSeek V4 全系); +- 缺陷 4 与 provider 无关,只要模型在同一轮里既更新计划又调用协作工具就会撞,做游戏路径同样中招。 + +--- + +## 7. 建议改动清单 + +### 已完成 + +0. **缺陷 4 的预检分叉 + 回归测试**(见 §4)。这是分支回归、且波及做游戏路径,不等排期,已直接修在工作区。 + +### P0 —— 让第三方 provider 可用 + +1. **`reasoningEffort` 增加 `none`** + - [platform-llm lib.rs:195](../../server-rs/crates/platform-llm/src/lib.rs:195):`LlmResponseReasoningEffort` 加 `None` 变体,`as_str()` 返回 `"none"`;注意仓库内对该枚举有多处 exhaustive match(`Max` 刚加时踩过),需一并补齐。 + - [config.rs:145](../../apps/ai-game-creator-shell/src-tauri/src/config.rs:145) `parse_game_creator_llm_reasoning_effort` 接受 `none`,同步 :155 的错误文案。 + - [types.ts:605](../../apps/ai-game-creator-shell/src/app/types.ts:605) `gameCreatorLlmReasoningEfforts` 加 `'none'`;RuntimeConfigDialog 的默认表(:40~:65)与下拉项同步。 + - 验收:`reasoningEffort: "none"` + DeepSeek + `provider` 模式,做方案能跑到第一个工具调用。 + +2. **保存设置时不要硬写 `agentMode`** + - [RuntimeConfigDialog.tsx:844](../../apps/ai-game-creator-shell/src/features/runtime-config/RuntimeConfigDialog.tsx:844):删掉那行覆盖。 + - 二选一:在常用设置里暴露「运行模式」选择;或按 `baseUrl` 推断(非官方端点自动落 `provider`)。推荐后者 + 高级设置里可覆盖。 + +### P1 —— 让失败可解释 + +3. **禁止「`codex_app_server` + 非官方 baseUrl」这一组合** + 在配置校验期([config.rs:350](../../apps/ai-game-creator-shell/src-tauri/src/config.rs:350) `game_creator_codex_app_server_llm_route_error` 附近)直接拒绝并给出明确文案,而不是让用户等 180 秒超时、再手工核对孤儿请求。 + +4. **超时后的资源回收** + turn 超时后 codex app-server session 仍留在池里(本次留下 3 个)。至少在 `needs_reconciliation` 时把对应 session 作废。 + +### P2 —— 排障体验 + +5. `reasoningEffort` 没有传到 codex(日志里 `codex.turn.reasoning_effort=default`),配置与实际行为不一致。 +6. 失败原文全部 sha256 化,本次定位缺陷 2 只能靠"按代码重建错误串再比对哈希"。建议 dev 构建下把公开错误串明文写进 agent.db,或至少把 `kind=` 留在 UI 的运行详情里。 + +--- + +## 8. 未验证 / 待确认 + +- 官方端点 + `provider` 模式:`gpt-5.6-terra` 已验证能跑通 loop 1(工具调用、Goal Contract 冻结、计划更新都正常),修掉缺陷 4 后能走多远还没实测。`gpt-5.6-sol` 未验证——仓库里 `apps/ai-game-creator-shell/game-creator.config.json` 的 key 打过去是 401(占位值)。 +- `effort=none` 下 DeepSeek 做策划的**质量**(本次只验证了协议层能跑通)。 +- DeepSeek 网关 413 的具体阈值,以及 `provider` 模式下 AGC 自组的请求体是否也会触顶(本次 provider 模式的请求约 39 KB,未触发)。 + +--- + +## 9. 现场证据索引 + +| 证据 | 位置 | +|---|---| +| 秒挂 run(openai_chat) | `~/Documents/Genarrative GameAgent/gameagent-a21e1b2a/.agent/agent.db` | +| 超时 + 待核对 run | `~/Documents/Genarrative GameAgent/gameagent-edfa1ba1/.agent/agent.db` | +| codex 侧 413 与 view_image 报错 | `%TEMP%\genarrative-agc-codex-app-server-*\codex-home\logs_2.sqlite`(表 `logs`,按 `level in ('ERROR','WARN')` 查) | +| provider 模式 400 原文 | `apps/ai-game-creator-shell/src-tauri/logs/llm-raw/1787148218861-33480-000001-upstream_status_failed.{input.json,output.txt}` | +| 缺陷 4 的批次预检失败 run | `~/Documents/Genarrative GameAgent/gameagent-9a524132/.agent/agent.db`(`agent.runtime.context.failed` 明文错误 + 两轮 `tool_plan.protocol` 的 `functionNames`) | +| 生效配置 | `%APPDATA%\world.genarrative.ai-game-creator\game-creator.config.json`(本次已手工把 `agentMode` 改为 `provider`,原件备份为同名 `.bak-agentmode`) |