修复普通 action 批次带 plan update 时预检自相矛盾

批次预检对每个成员要求 provider_batch_plan_update 等于 batch.plan.plan_update,
而同一函数的另一条规则又要求非 planning 批次成员不得携带该字段;创建侧只为
plan.submit_gdd 填值,其余动作保持 None。于是「同一轮既调 update_agent_plan
又调工具」的普通批次同时踩中两条互斥规则,报「批次成员身份或顺序不匹配」。
该字段随 M1B-2 引入,master 无此标识符,做游戏路径同样中招。

预检期望值改为按批次类型分叉:planning v4 保持相等(:241 已对 actions[0]
校验过一次),非 planning 期望 None。创建侧与非 planning 分支语义本自洽,不动。

补一条走完 prepare 到读回的回归用例;去掉修复后可复现线上同一条错误串。

顺带 cargo fmt 掉上次 master 合并带进来的一处未格式化代码,并补一份第三方
Provider 兼容性缺陷说明。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-20 03:46:28 +00:00
parent c2d5273873
commit 400595756b
4 changed files with 422 additions and 12 deletions
@@ -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]
{
@@ -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));
@@ -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();
}
@@ -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=<sha256(原文)> 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:
<html><head><title>413 Request Entity Too Large</title></head>
<hr><center>openresty</center></html>
, 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. 现场证据索引
| 证据 | 位置 |
|---|---|
| 秒挂 runopenai_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` |