diff --git a/docs/project-memory/shared-memory/decision-log.md b/docs/project-memory/shared-memory/decision-log.md index e6c7337b1..ac1fb0192 100644 --- a/docs/project-memory/shared-memory/decision-log.md +++ b/docs/project-memory/shared-memory/decision-log.md @@ -1,5 +1,20 @@ # 决策记录 +## 2026-08-13 `project-planning` 的 agentCatalog 登记机制定稿:与 `supervisor` 平级、不进 `groups`,「做游戏链路一行不动」得以成立 + +- 背景:D11(见下方同日「立项策划 D9 二次作废…」条)继承了 D9「`project-planning` 需登记 agentCatalog」的结论,但登记方式一直是待裁决项——`build.rs` 的 `validate_seed_task_catalog`(`apps/ai-game-creator-shell/src-tauri/build.rs:23-46`)要求编译出的 `(taskId, groupId, role)` 集合与 `shared_contracts::game_creation_app::new_game_creation_app_seed_tasks()` 完全相等,不等即 `panic!`,直接把 `project-planning` 塞进任何一个专业组会破坏这条一致性校验、污染 16 任务种子 DAG。本条只做只读取证与机制定稿,**不落地任何代码**,工作目录 `C:/wtp`(分支 `feat/plan-agent-catalog-registration`),只改文档。 +- 事实基线(详见技术方案 `docs/technical/【技术方案】立项策划Agent(Fast GDD)-2026-08-10.md` 第 3.1 节): + - 被 `build.rs` 比对的 `specialist_nodes` 集合只来自 `manifest.agent_catalog.groups[].roles[]`(`build_support/runtime_prompt_bundle.rs:387-398`),不遍历 `agentCatalog` 的其它顶层键。 + - `project-supervisor` 本身就是「catalog 成员但不是种子 DAG 任务」的既有先例:`runtime_adapter.rs` 的 `build_game_creator_runtime_agent_catalog`(`apps/ai-game-creator-shell/src-tauri/src/agent/runtime_adapter.rs:4-38`)先单独 push 一个 supervisor 的 `AgentDescriptor`,再遍历各组角色。 + - `AgentDescriptor::metadata()` 目前零生产调用,`game_creator_runtime_agent_catalog()` 唯一生产调用点(`runtime_state.rs:1491`,即 `normalize_game_creator_runtime_agent_id`)只做 `.get(agent_id).is_some()`;`AgentCatalog::iter()` 也零生产调用——当前没有任何代码枚举 runtime catalog,`project-planning` 登记后不会泄漏进「做游戏」团队清单或路由清单。 + - 但仅做 catalog 登记不足以让 D11 可执行:`prompt.rs` 的 `game_creator_agent_role_definition`(`apps/ai-game-creator-shell/src-tauri/src/agent/prompt.rs:661-679`)硬编码「非 supervisor 即 group 角色」二分,`project-planning` 落入 else 分支返回 `None`,两个调用方(`provider_request_builders.rs:536-539`、`prompt.rs:416-417`)都会把 `None` 转 `Err` 中断,报「未知 Agent 模板:project-planning」——这是本次调研发现的 **blocking** 缺口,不是 catalog 登记本身能解决的。 + - 另有两处 **needs_change**:`task_ops.rs` 的 `task.create`(`apps/ai-game-creator-shell/src-tauri/src/agent/runtime_tools/task_ops.rs:335-363`)在拿不到角色定义时把 group/role 静默兜底成 `Design`/`"Agent"`,会污染任务审计;`delegation.rs` 的 `agent.spawn_isolated` 校验(`apps/ai-game-creator-shell/src-tauri/src/agent/runtime_tools/delegation.rs:1396-1412`)只排除 `child-` 前缀和 supervisor 本体,`project-planning` 登记后会被任何持有该工具的 Agent 当作动态孵生模板,与 D11「只能由 Supervisor 通过 `agent.delegate` 静态委派」的设计意图不一致。 +- 决策:`project-planning` 在 `prompts/runtime/manifest.json` 的 `agentCatalog` 下登记为与 `supervisor` 平级、**不进 `groups` 数组**的独立条目(`id`/`taskId=project-planning`);descriptor metadata 取值——`groupId="project-planning"`(自引用伪 group id,绝不复用 `"design"`,避免与 design 组中文 label「策划组」语义碰撞)、不设 `groupLabel`(照抄 supervisor 先例)、`roleLabel` 跟随角色定义、`toolId="agent.runtime.project-planning"`(跟随 supervisor 的组外单节点命名族)、`capabilityAuthority="game-creator-tool-policy-snapshot"`(与全部现有条目相同,无需新值)。由此 `specialist_nodes`、16 任务种子 DAG、`new_game_creation_app_seed_tasks()`、`build.rs` 三者均不需要改动,「做游戏链路一行不动」得以成立。composition 复用现役 `runtime` composition,不需要单独配置;`briefPathName` 只是运行时文件名 token,缺文件不报错,但格式与全局唯一性仍受编译期 `validate_file_name`/`validate_agent_catalog` 约束。 +- 编译链路要改的位置(M1 落地范围,本轮不动):`build_support/runtime_prompt_bundle.rs` 的 `struct AgentCatalog` 加 `planning` 字段、`validate_agent_catalog` 镜像 supervisor 的单 role 约束/去重/防冲突集合/显式校验调用、`compile_manifest` 的 `catalog_task_ids` 链入 `planning.roles`、`render_agent_catalog` 镜像 supervisor 专属四个产物;`runtime_adapter.rs:4-38` 镜像 push 一段 `AgentDescriptor`;连带隐藏耦合 `pass_artifacts.rs` 的 `agent_role_memory_relative_path_for_task`(335-347 行)需加第三条 `project-planning` 分支,否则运行时报「未知 Agent 任务」。 +- **本轮范围声明(与 M1 的边界)**:本条只冻结登记机制、更新技术方案文档第 3.1 节与第 23.1 节,**不改 `manifest.json`、不改 `runtime_prompt_bundle.rs`、不改 `runtime_adapter.rs`、不改任何 `.rs` 文件**。理由:`project-planning` 目前没有 prompt、没有任何路径能调用它,现在注册 catalog 而不同步处理上面的 blocking 缺口,等于给发布产物加一个「看似已登记、一调用就硬失败」的死重身份;注册代码应与 M1 的 prompt/source 一起落地。 +- 保留待处置(M1 范围,非本条待裁决):`prompt.rs` 的 `game_creator_agent_role_definition` 角色身份合成缺口(blocking);`task_ops.rs` 的 group/role 误分类兜底(needs_change);`delegation.rs` 的 `agent.spawn_isolated` 放行面扩权(needs_change);`pass_artifacts.rs` 的内存路径解析缺口(M1 必须同步处理)。 +- 关联文档:`docs/technical/【技术方案】立项策划Agent(Fast GDD)-2026-08-10.md` 第 3.1 节(新增小节)、第 23.1 节(原「`project-planning` 的编译期 agentCatalog 登记方式与 `build.rs` 一致性校验」待裁决项已降级为「机制已定稿,代码落地属 M1」);关联决策:本文件下方同日「立项策划 D9 二次作废、D10 作废」条(D11、第 1.1 节「D11 新拓扑」第 6 条)。 + ## 2026-08-13 立项策划 D9 二次作废、D10 作废:改为 Supervisor 静态委派子 Agent(D11);静态委派澄清轮次与返工深度拆分定稿(WP1) - 背景:产品侧确认「做方案」入口不需要新增编排调度器概念,复用已有静态委派(`agent.delegate`)与 PR #165 已实现的子 Agent 澄清中转链路即可覆盖 D9/D10 试图解决的问题;同时实证发现静态委派返工深度门(`repair_of_delegation_id.is_some()` 即拒绝)对「质量返工」与「澄清 continuation」无差别拒绝,一次澄清会吃掉整条链唯一一次质量返工额度。两条问题合并处置。 diff --git a/docs/technical/【技术方案】立项策划Agent(Fast GDD)-2026-08-10.md b/docs/technical/【技术方案】立项策划Agent(Fast GDD)-2026-08-10.md index 9cee24232..5444632a1 100644 --- a/docs/technical/【技术方案】立项策划Agent(Fast GDD)-2026-08-10.md +++ b/docs/technical/【技术方案】立项策划Agent(Fast GDD)-2026-08-10.md @@ -78,7 +78,7 @@ M0 三个代码工作包无一行按 D6 编写,**不需要为新设计回退 - 第 22 节证据表:`trusted matcher 消费者`行结论句改写;新增 standard 路径 owner 验证、Runtime 直投两行 - 第 23.4 节:M0 完成状态改为「代码完成、文档待修订」 -**批二(原被「策划节点 `agentId` / source 命名」裁决阻塞;2026-08-13 命名裁决已完成,批二不再被命名阻塞,改由下方「D11 新拓扑」第 6 条 `build.rs` 一致性待裁决项阻塞)** +**批二(原被「策划节点 `agentId` / source 命名」裁决阻塞;2026-08-13 命名裁决已完成,批二不再被命名阻塞,一度改由下方「D11 新拓扑」第 6 条 `build.rs` 一致性待裁决项阻塞;该项已于 2026-08-13 定稿,见第 3.1 节与下方更新——批二不再被 catalog 一致性问题阻塞,但仍不在本轮范围内,另需等第 3.1 节新发现的 `prompt.rs` 角色身份合成缺口在 M1 处理后才具备可执行基础)** - 第 3 节注册表全部身份常量、第 4 节拓扑图、第 4.1 / 4.2 节(整节作废后重写)、第 4.3 节工具清单 - 第 5.1 / 5.2 节 checkpoint 触发点、第 6 节 Prompt 权威稿 @@ -86,7 +86,9 @@ M0 三个代码工作包无一行按 D6 编写,**不需要为新设计回退 - 第 12 节 submit dispatch 段、第 13.1 / 13.3 节 `agentId` 常量、第 14 节 activeQuestion 相关五行恢复语义 - 第 18.1 节前端入口 -2026-08-13 更新:命名裁决已冻结——策划子 Agent `agentId=project-planning`,Supervisor 侧承载「做方案」入口的新可信 source 为 `project-supervisor-plan`。批二不再被命名阻塞。但 D11 把策划节点从「ready-task 工作流节点」改成「静态委派子 Agent」,批二这些小节的具体写法(尤其第 3 节注册表、第 4 节拓扑图)必须按 D11 新拓扑而非 D9 旧拓扑重写,且新增了「D11 新拓扑」第 6 条列出的 `build.rs` agentCatalog 一致性前置——`project-planning` 如何登记进编译期 seed task catalog 而不触发 `validate_seed_task_catalog`(`apps/ai-game-creator-shell/src-tauri/build.rs:23-46`)panic 尚未裁决,批二涉及注册表落笔前必须先冻结这一点。本轮文档修订范围不含批二,此处只记录状态变化。 +2026-08-13 更新:命名裁决已冻结——策划子 Agent `agentId=project-planning`,Supervisor 侧承载「做方案」入口的新可信 source 为 `project-supervisor-plan`。批二不再被命名阻塞。但 D11 把策划节点从「ready-task 工作流节点」改成「静态委派子 Agent」,批二这些小节的具体写法(尤其第 3 节注册表、第 4 节拓扑图)必须按 D11 新拓扑而非 D9 旧拓扑重写,且新增了「D11 新拓扑」第 6 条列出的 `build.rs` agentCatalog 一致性前置——`project-planning` 如何登记进编译期 seed task catalog 而不触发 `validate_seed_task_catalog`(`apps/ai-game-creator-shell/src-tauri/build.rs:23-46`)panic,此前尚未裁决,批二涉及注册表落笔前必须先冻结这一点。本轮文档修订范围不含批二,此处只记录状态变化。 + +2026-08-13 二次更新:`build.rs` agentCatalog 一致性问题已定稿(见第 3.1 节)——`project-planning` 登记为与 `supervisor` 平级、不进 `groups` 数组的独立条目,`specialist_nodes` 只读 `groups[].roles[]`,`build.rs`/种子 DAG/`new_game_creation_app_seed_tasks()` 均不需要改动。批二不再被这一具体问题阻塞。但第 3.1 节调研同时发现一个新的、更靠后的执行层缺口:`prompt.rs` 的 `game_creator_agent_role_definition`(`apps/ai-game-creator-shell/src-tauri/src/agent/prompt.rs:661-679`)目前不认识 `project-planning`,仅做 catalog 登记不足以让静态委派可执行,需 M1 补一个平行于 supervisor 特判的分支(清单见第 3.1 节)。批二仍不在本轮范围内,此处只记录状态变化,不落笔批二内容。 #### Goal Contract:四方案作废,替换为三条已验证约束 @@ -99,7 +101,7 @@ M0 三个代码工作包无一行按 D6 编写,**不需要为新设计回退 #### `M0A-3` 门禁与完成定义 - 批一全部合入,且本文不再存在自相矛盾的表述(同一事实在两处给出不同结论即视为未完成)。 -- 命名裁决冻结并写入决策记录后(2026-08-13 已完成),批二全部合入——**但改由 `build.rs` agentCatalog 一致性裁决阻塞**(见第 1.1 节「D11 新拓扑」第 6 条与第 23.1 节待裁决项),该裁决冻结前批二仍不得落笔。 +- 命名裁决冻结并写入决策记录后(2026-08-13 已完成),批二全部合入——`build.rs` agentCatalog 一致性问题已于 2026-08-13 定稿(见第 3.1 节与第 23.1 节),批二不再被这一具体问题阻塞;但第 3.1 节同时查实了 M1 执行层的一个新缺口(`prompt.rs` 角色身份合成不认识 `project-planning`,见第 3.1 节「登记前必须先处理的代码改动」),批二注册表相关小节落笔前仍需以此为准,避免写出「登记即可用」的失真表述。批二本身依旧不在本轮(`M0A-3`)范围内。 - decision log 与 pitfalls 同步补记:D6 作废理由、autonomous 下父子皆不可提问且硬闯会瘫痪整条工作流、`M0A-2` owner 验证不可复用;2026-08-13 起还需同步补记 D9 二次作废、D10 作废、D11 新拓扑与 WP1 澄清轮次/返工深度拆分定稿(已完成,见 decision-log 2026-08-13 条)。 - **仅文档工作包,不含任何代码改动**;合入只表示设计基线恢复自洽,不表示任何功能可用。 @@ -120,7 +122,7 @@ D9/D10 描述的「manifest ready-task 调度器在 Supervisor 下游启动策 3. **多轮不失忆,但转述保真不由 Runtime 校验。** 委派的 `target_session_id` 每轮都解析为 `resolve_agent_conversation_session_id_at(root, target_agent_id, None, true)`(`apps/ai-game-creator-shell/src-tauri/src/project/conversation.rs:860-875`),传 `None` 时走 `catalog.active_session_id`(`conversation.rs:849-850`)——即每一轮委派都落在同一条持久 active session 上;而 prompt history 按 `(agent_id, session_id)` 组装(`apps/ai-game-creator-shell/src-tauri/src/context_compaction.rs:453-490` 的 `prepare_game_creator_agent_runtime_prompt_history`),`run_id` 只用于 `observation_start` 的覆盖计数过滤。因此 continuation 子 Agent 是「新 run、同 session」,能看到自己前几轮的完整对话。**但残留风险如实记录**:用户的答案本身不在子 Agent 的 session 里(物理落在 Supervisor 那边),子 Agent 只能依赖 Supervisor 把已确认答案重新组织进新的委派 task 文本;Runtime 只校验 `questionsSha256`/`answersSha256` 的哈希绑定,**不校验转述内容与已确认答案的语义一致性**,转述保真完全依赖 Supervisor 侧 LLM 的行为质量。委派 task 有硬上限 `AGENT_RUNTIME_TASK_MAX_CHARS = 4_000`(`apps/ai-game-creator-shell/src-tauri/src/agent/runtime_driver.rs:147`),超限直接 `Err`,不会静默截断丢失内容。 4. **产物路径与 `.agent/planning/**` 不冲突,且有结构性保证而非文档层自律。** `normalize_static_delegate_expected_artifact`(`apps/ai-game-creator-shell/src-tauri/src/delegation.rs:1981-1998`)拒绝首段为 `.agent` 的相对路径,因此 `.agent/planning/**` 在委派发起阶段就无法进入 `expectedArtifacts`,不需要额外的文档层面约束。`game/fast_gdd.md` 不在 `.agent` 下,可以正常登记。定稿:`expectedArtifacts=["game/fast_gdd.md"]`,质性标准写进 `acceptanceCriteria`,`verification_required=false`——策划节点没有 verify/smoke 类工具,无法产生可供 Runtime 复核的验证凭证。 5. **前置依赖:D11 的“最多 3 轮问询”依赖 WP1 先落地,是强制前置,不是并行工作包。** WP1(澄清轮次 `clarification_round` 与返工深度 `repair_depth` 拆分,详见下方及 decision-log 2026-08-13 条)正在另一个 worktree 并行实现。在 WP1 落地前,`repair_of_delegation_id.is_some()` 即拒绝(`apps/ai-game-creator-shell/src-tauri/src/delegation.rs:1119-1121`),澄清 continuation 与质量返工共用同一条「深度最多为 1」判据,D11 描述的多轮问询实际上限只有 1 轮,且这 1 轮一旦用掉,同一条委派链就再也做不了任何质量返工。本文档把 WP1 列为 D11 生效的强制前置条件,不得默认「等 WP1 完成再补上限」这种弱化表述。 -6. **未决前置:`project-planning` 的编译期 agentCatalog 登记方式,会撞上 `build.rs` 一致性校验。** `project-planning` 目前不在编译期 agentCatalog 里;而 `build.rs` 的 `validate_seed_task_catalog`(`apps/ai-game-creator-shell/src-tauri/build.rs:23-46`)要求编译出的 `(taskId, groupId, role)` 集合与 `shared_contracts::game_creation_app::new_game_creation_app_seed_tasks()` 逐项相等,不等直接 `panic!`。如何登记 `project-planning` 而不破坏这条一致性校验——是否需要给 `new_game_creation_app_seed_tasks()` 新增一条不落入 16 任务 DAG 的条目、还是该 catalog 本身需要拆分——是 D11 的**未决前置**,本文档只挂为待裁决项(见第 23 节),不假装已有结论。 +6. **登记机制已定稿(原「未决前置」,2026-08-13 处置完成):`project-planning` 的编译期 agentCatalog 登记方式,不会撞上 `build.rs` 一致性校验。** `project-planning` 目前不在编译期 agentCatalog 里;`build.rs` 的 `validate_seed_task_catalog`(`apps/ai-game-creator-shell/src-tauri/build.rs:23-46`)要求编译出的 `(taskId, groupId, role)` 集合与 `shared_contracts::game_creation_app::new_game_creation_app_seed_tasks()` 逐项相等,不等直接 `panic!`;但该集合只来自 `manifest.agent_catalog.groups[].roles[]`(`build_support/runtime_prompt_bundle.rs:387-398`),不遍历 `agentCatalog` 其它顶层键。结论:`project-planning` 登记为与 `supervisor` 平级、不进 `groups` 数组的独立条目(先例即 `supervisor` 自己——它是 catalog 成员但不是种子 DAG 任务,`runtime_adapter.rs:4-38`),`new_game_creation_app_seed_tasks()` 不需要新增条目,该 catalog 本身也不需要拆分。完整机制、descriptor 元数据取值与编译链路改动清单见第 3.1 节。**但登记只解决 catalog 成员资格,不解决可执行性**——第 3.1 节调研同时发现一个新的、真正阻塞可执行的缺口:`prompt.rs` 的 `game_creator_agent_role_definition`(`prompt.rs:661-679`)硬编码「非 supervisor 即 group 角色」二分,不认识 `project-planning`,需 M1 补一个平行分支;这才是仍然待处置(M1 范围)的前置,不是本条描述的 catalog 登记方式本身。 WP1 定稿的澄清轮次/返工深度语义(供 D11 依赖,权威定义见 decision-log 2026-08-13 条,不在本节重复展开):`repair_depth` 上限维持 1 不放松,`clarification_round` 上限按 source 区分——`source == AGENT_RUNTIME_SUPERVISOR_GAME_CHAT_SOURCE`(`apps/ai-game-creator-shell/src-tauri/src/agent/runtime_driver.rs:109`)时取 1,其它 source(含 D11 的 `project-planning` 委派链)取 3;两个维度都是运行时沿 `repair_of_delegation_id` 链上推断的派生值,不新增 `StaticDelegateDeliveryRecord` 持久字段。 @@ -136,9 +138,9 @@ WP1 定稿的澄清轮次/返工深度语义(供 D11 依赖,权威定义见 | ~~D6~~ | **2026-08-12 作废**,由 D9 取代。原文:“立项策划 Agent”是 Project Supervisor 通道的第三 persona,以持久 source 区分,复用 `standard` profile,不注册新的 agentCatalog 身份。作废理由见第 1.1 节;其中“复用 `standard` profile”这一结论方向被 D9 继承,但成立理由完全不同。 | | D7 | 本期不实现知识图谱;`basis`、知识 provider trait、composition 槽位可以预留,但 v1 数据必须为 `null`,空字段不渲染。 | | D8 | GDD 不含引擎字段;平台事实固定由 Runtime 注入,Agent 不得向用户提问或修改。 | -| ~~D9~~ | **2026-08-13 二次作废**,由 D11 取代。原文:“取代 D6。立项策划是独立 `agentId` 的下游工作流节点,由 manifest ready-task 调度器在 Supervisor 下游启动,需登记 agentCatalog;Project Supervisor 以新的可信 source 承载「做方案」入口并保持唯一顶层 root;父子 run profile 必须同为 `standard`——不是为了复用顶层通道,而是因为 `autonomous-game-build` 对 `user.input_request` 的禁令按 profile 生效、父子皆不可提问,且子 Run 不能切换父 Run 的 profile。” 作废理由见第 1.1 节「D11 新拓扑」。**“立项策划是独立 `agentId` 的下游工作流节点”这一结论方向被 D11 继承**,但调度机制被 D11 推翻:不再由 manifest ready-task 调度器启动,改为 Project Supervisor 通过 `agent.delegate` 发起的静态委派子 Agent;「父子 run profile 必须同为 `standard`」这条论证随之失效——D11 拓扑下策划节点天然带 `parent_agent_id`/`parent_run_id`,其 `user.input_request` 直接被执行层 `validate_user_input_action_owner`(`user_input.rs:367-394`)拒绝,不再依赖“父子皆不可提问、子 Run 不能切换父 Run profile”这条 profile 层面的间接论证;「需登记 agentCatalog」被继承但登记方式生变,仍是待裁决项(见第 23 节)。 | +| ~~D9~~ | **2026-08-13 二次作废**,由 D11 取代。原文:“取代 D6。立项策划是独立 `agentId` 的下游工作流节点,由 manifest ready-task 调度器在 Supervisor 下游启动,需登记 agentCatalog;Project Supervisor 以新的可信 source 承载「做方案」入口并保持唯一顶层 root;父子 run profile 必须同为 `standard`——不是为了复用顶层通道,而是因为 `autonomous-game-build` 对 `user.input_request` 的禁令按 profile 生效、父子皆不可提问,且子 Run 不能切换父 Run 的 profile。” 作废理由见第 1.1 节「D11 新拓扑」。**“立项策划是独立 `agentId` 的下游工作流节点”这一结论方向被 D11 继承**,但调度机制被 D11 推翻:不再由 manifest ready-task 调度器启动,改为 Project Supervisor 通过 `agent.delegate` 发起的静态委派子 Agent;「父子 run profile 必须同为 `standard`」这条论证随之失效——D11 拓扑下策划节点天然带 `parent_agent_id`/`parent_run_id`,其 `user.input_request` 直接被执行层 `validate_user_input_action_owner`(`user_input.rs:367-394`)拒绝,不再依赖“父子皆不可提问、子 Run 不能切换父 Run profile”这条 profile 层面的间接论证;「需登记 agentCatalog」被继承但登记方式生变,登记机制已于 2026-08-13 定稿(见第 3.1 节与第 23.1 节),代码落地留给 M1。 | | ~~D10~~ | **2026-08-13 作废**,由 D11 取代。原文:“策划节点**不得**直接调用 `user.input_request`——注意这不是 Runtime 拦得住的:standard ready-task 调度器不写 parent,该调用会被放行,因此必须由 exact allowlist 主动排除并以回归钉死。禁止的理由是产品约束:直接提问会把问答落进策划节点自己的会话,Supervisor 上下文里什么都没有。问询改走「Runtime 直投」:策划节点提交结构化决策字段,Runtime 创建 **owner 为 Project Supervisor** 的 pending,会话消息落 Supervisor 会话、结构化 observation 落策划节点,二者是同一 `AgentRuntimeUserInputRecord` 的两路投影。Supervisor 的 Provider 不参与提问。” 作废理由:D10 存在的唯一前提——「ready-task 节点无 parent,Runtime 拦不住,必须靠 exact allowlist 自律排除」——在 D11 新拓扑下不成立。策划节点改为委派子 Agent 后天然带 `parent_agent_id`/`parent_run_id`,`user.input_request` 被执行层 `validate_user_input_action_owner`(`user_input.rs:367-394`)直接拒绝,是 Runtime 兜底而非产品自律(但广告层仍放行,模型看得见、会去调,只是必失败,见第 19 节第 2 条改写)。「问询改走 Runtime 转发、Supervisor 会话与结构化 observation 两路投影」这一方向被 D11 继承,但落地机制不是同一套代码:D10 设想的是为 D9 拓扑新造的「Runtime 直投」,D11 复用的是 PR #165 已实现的 `AGC_NEEDS_USER_INPUT_V1` 终态信封 + Supervisor 中转链路,两者实现路径不同。 | -| D11 | **取代 D9,并连带作废 D10。** 立项策划节点改为 Project Supervisor 通过 `agent.delegate` 发起的**静态委派子 Agent**(`agentId=project-planning`),不再由 ready-task 调度器启动;问询改为复用 PR #165 已实现的中转链路:子 Agent 以 `AGC_NEEDS_USER_INPUT_V1` 终态信封退出 → Supervisor 认领 → Supervisor 在自己的 runtime/session 上建 `waiting-for-user-input` pending → 用户在 Supervisor 会话内作答 → 答案经 `questionsSha256`/`answersSha256` 绑回 delivery → Supervisor 发起 continuation 子 Agent 续跑。**最多 3 轮问询依赖 WP1(澄清轮次与返工深度拆分,见第 1.1 节)先落地,是强制前置,不是并行工作包**;WP1 落地前上限只有 1 轮,且用掉后连一次质量返工都做不了。完整支撑事实(6 条,均带 `file:line`)见第 1.1 节「D11 新拓扑」;未决前置(`project-planning` 的 agentCatalog 登记方式与 `build.rs` 一致性校验)见第 23 节。 | +| D11 | **取代 D9,并连带作废 D10。** 立项策划节点改为 Project Supervisor 通过 `agent.delegate` 发起的**静态委派子 Agent**(`agentId=project-planning`),不再由 ready-task 调度器启动;问询改为复用 PR #165 已实现的中转链路:子 Agent 以 `AGC_NEEDS_USER_INPUT_V1` 终态信封退出 → Supervisor 认领 → Supervisor 在自己的 runtime/session 上建 `waiting-for-user-input` pending → 用户在 Supervisor 会话内作答 → 答案经 `questionsSha256`/`answersSha256` 绑回 delivery → Supervisor 发起 continuation 子 Agent 续跑。**最多 3 轮问询依赖 WP1(澄清轮次与返工深度拆分,见第 1.1 节)先落地,是强制前置,不是并行工作包**;WP1 落地前上限只有 1 轮,且用掉后连一次质量返工都做不了。完整支撑事实(6 条,均带 `file:line`)见第 1.1 节「D11 新拓扑」;`project-planning` 的 agentCatalog 登记方式与 `build.rs` 一致性校验已于 2026-08-13 定稿(见第 3.1 节、第 23.1 节),代码落地留给 M1;M1 的真正前置是第 3.1 节新发现的 `prompt.rs` 角色身份合成缺口。 | ## 3. 合同名称注册表 @@ -147,7 +149,7 @@ WP1 定稿的澄清轮次/返工深度语义(供 D11 依赖,权威定义见 | UI 阶段名 | `立项策划` | | 英文称呼 | `plan phase` | | 工作流节点名 | `立项策划 Agent`(2026-08-12:不再是 persona,见 D9) | -| **策划节点 agentId** | `project-planning`(登记 agentCatalog;`project-` 前缀标明项目级、不属任何专业组,故不与 design 组的 `design-director` / `design-foundation` 混淆) | +| **策划节点 agentId** | `project-planning`(登记 agentCatalog;`project-` 前缀标明项目级、不属任何专业组,故不与 design 组的 `design-director` / `design-foundation` 混淆;登记机制定稿见第 3.1 节,本轮只冻结机制、代码留给 M1) | | **策划节点 durable source** | `agent-ready-task-scheduler`(复用现役 standard ready-task 调度器,不新增 source) | | **Supervisor 入口 durable source** | `project-supervisor-plan`(与 `-gui` / `-cli` / `-game-chat` 同族;2026-08-12 取代原预留值 `project-supervisor-plan-chat`,**旧字符串作废不得沿用**,避免字面未变而语义已改导致接错代码路径) | | Rust source 常量 | `AGENT_RUNTIME_SUPERVISOR_PLAN_SOURCE` | @@ -189,6 +191,79 @@ WP1 定稿的澄清轮次/返工深度语义(供 D11 依赖,权威定义见 `requestKind=plan-decision-checkpoint` 只对已通过 exact plan binding 的回答后解释请求合法;非 plan lifecycle、普通 tool-plan/final-reply 或 action batch 出现该 kind 一律失败关闭。checkpoint success 无 action batch,不能借新 kind 扩大 action 工具面。 +### 3.1 `project-planning` 的 agentCatalog 登记机制定稿(2026-08-13,机制冻结,代码留给 M1) + +本节处置第 1.1 节「D11 新拓扑」第 6 条与第 23.1 节「`project-planning` 的编译期 agentCatalog 登记方式与 `build.rs` 一致性校验」这一待裁决项。结论:**机制成立(`works_with_changes`)**——`project-planning` 可以在不改 `build.rs`、不改 16 任务种子 DAG、不改 `new_game_creation_app_seed_tasks()` 的前提下登记进编译期 agentCatalog;但「登记进 catalog」只解决**成员资格**,不解决**能否真正跑起来**——role 身份合成还卡着一个独立的硬编码二分,必须在 M1 一并处理,不能只做本节描述的登记就当作 D11 可执行。 + +**登记位置**:`prompts/runtime/manifest.json`(`apps/ai-game-creator-shell/src-tauri/prompts/runtime/manifest.json`)的 `agentCatalog` 下新增一个与 `supervisor` 平级、**不放进 `groups` 数组**的独立条目(内部 `id`/`taskId` 冻结为 `project-planning`,外层键名未冻结): + +```json +"agentCatalog": { + "supervisor": { /* 不动 */ }, + "planning": { + "id": "project-planning", + "label": "立项策划", + "role": "Project Planning", + "briefPathName": "project-planning.md", + "roles": [ + { + "id": "project-planning", + "role": "Project Planning", + "taskId": "project-planning", + "toolId": "agent.runtime.project-planning", + "briefPathName": "project-planning.md" + } + ] + }, + "groups": [ /* 现有 6 组不动 */ ] +} +``` + +**为什么必须这样、且不影响「做游戏链路一行不动」**:`build.rs` 的 `validate_seed_task_catalog`(`apps/ai-game-creator-shell/src-tauri/build.rs:23-46`)把编译出的 `(taskId, groupId, role)` 集合与 `shared_contracts::game_creation_app::new_game_creation_app_seed_tasks()` 做逐项相等比对,不等即 `panic!`;而这个被比对的 `specialist_nodes` 集合只来自 `manifest.agent_catalog.groups[].roles[]`(`build_support/runtime_prompt_bundle.rs:387-398`),不遍历 `agentCatalog` 的其它顶层键。`project-planning` 挂在 `groups` 数组之外的平级条目上,天然不进入 `specialist_nodes`,因此 `build.rs`、种子 DAG、`new_game_creation_app_seed_tasks()` 三者都不需要改动,约束 A「做游戏链路一行不动」成立。 + +**先例**:`project-supervisor` 本身就是这个模式的既有先例——它是 agentCatalog 成员,但不是种子 DAG 任务。`runtime_adapter.rs` 的 `build_game_creator_runtime_agent_catalog`(`apps/ai-game-creator-shell/src-tauri/src/agent/runtime_adapter.rs:4-38`)先单独 `push` 一个 `project-supervisor` 的 `AgentDescriptor`(5-18 行),再遍历 `GAME_CREATOR_AGENT_GROUP_DEFINITIONS` push 各组角色(19-35 行);`project-planning` 应照此同构镜像,在 supervisor 之后、group 循环之外再 `push` 一段。 + +**descriptor 元数据取值**(`AgentDescriptor::with_metadata`): + +| 字段 | 取值 | 依据 | +| --- | --- | --- | +| `groupId` | `"project-planning"`(自引用伪 group id) | 照抄 supervisor 先例(`groupId: "supervisor"`);**绝不能填 `"design"`**——`design` 组中文 label 是「策划组」,与「立项策划」语义高度相似,填成 `design` 会让 `project-planning` 被任何按 `groupId` 过滤或按 label 展示的代码误认成 16 任务 DAG 里 design 组的成员 | +| `groupLabel` | 不设置 | supervisor 的 descriptor 本就没有这个 key(只有 `groupId`/`roleLabel`/`toolId`/`capabilityAuthority`),同构省略;顺带避开「策划组」字符串碰撞 | +| `roleLabel` | 跟随 `project-planning` 自己的角色定义(如 `"Project Planning"`) | 无特殊约束,随角色定义走 | +| `toolId` | `"agent.runtime.project-planning"` | 跟随 supervisor 的「组外单节点」命名族 `agent.runtime.`,而非组内角色的 `agent.role.brief..` 族——后者会误导成「某组角色 brief 生成工具」 | +| `capabilityAuthority` | `"game-creator-tool-policy-snapshot"` | 与现有全部条目(supervisor、16 个组内角色、两个 run profile)取值相同;全仓库检索确认这是无差异的 App 级常量声明,不是 per-agent 差异化字段,没有理由为 `project-planning` 发明新值 | + +全仓库检索确认:`AgentDescriptor::metadata()` 这个 accessor 目前零生产调用;`game_creator_runtime_agent_catalog()` 唯一生产调用点 `runtime_state.rs:1491`(即 `normalize_game_creator_runtime_agent_id`)只做 `.get(agent_id).is_some()`,不 touch `.metadata()`;`AgentCatalog::iter()` 也零生产调用。也就是说上表五个字段今天是纯「写入态」,没有消费方;但正因为没人读,今天怎么填就是给未来消费方定下的先例,必须按上表小心填,不能因为「反正没人读」就随意取值。 + +**编译链路要改的确切位置**(均属 M1 落地范围,本轮不动): + +1. `build_support/runtime_prompt_bundle.rs:108-113` 的 `struct AgentCatalog` 需新增字段 `planning: AgentGroup`(顶层 `#[serde(deny_unknown_fields)]`,manifest.json 加了 `planning` 键而这里不加字段会编译期反序列化报错)。 +2. 同文件 `validate_agent_catalog`(692-758 行)里所有硬编码只处理 `supervisor` 的地方要镜像 `planning`:693-695 行「必须恰好 1 个 role」的约束;700 行 briefPathName 去重的 `once(&catalog.supervisor).chain(...)` 要把 `&catalog.planning` 串进去;708 行 `generated_names` 占位防冲突集合要追加 `"PROJECT_PLANNING"`;728-733 行的显式单独调用 `validate_agent_group(&catalog.supervisor, ...)` 之后要紧跟一行 `validate_agent_group(&catalog.planning, ...)`(否则 `planning` 的 id/taskId/toolId/briefPathName 格式与跨组重复检查全部被跳过);738 行 alias 循环只遍历 `catalog.groups`,不需要改(`planning` 和 `supervisor` 一样不参与 `agent_role_alias_id` 别名机制)。 +3. `compile_manifest` 的 `catalog_task_ids` 构造(297-310 行)要把 `manifest.agent_catalog.planning.roles.iter()` 链进去,否则未来若给 `project-planning` 配 `roleOverlay` 会在 314 行误报「引用了未知 agentId」。 +4. `specialist_nodes` 构造(387-398 行)**只读 `manifest.agent_catalog.groups`,不改、也不能改**——这正是 `planning` 放在 `groups` 数组外、不污染种子 DAG 校验的关键。 +5. `render_agent_catalog`(972-1009 行)要给 `planning` 镜像 supervisor 专属的四个产物:`GAME_CREATOR_PROJECT_PLANNING_AGENT_ID`、`GAME_CREATOR_PROJECT_PLANNING_MEMORY_PATH`(`memory/agents/{planning.brief_path_name}` 格式)、`PROJECT_PLANNING_AGENT_ROLES` 数组、`static PROJECT_PLANNING_AGENT_DEFINITION`——这些静态名是 `runtime_adapter.rs` 里 push 段要引用的名字来源。 +6. `runtime_adapter.rs:4-38` 的 `build_game_creator_runtime_agent_catalog` 新增一段与 5-18 行完全对称的 `AgentDescriptor::try_new(...).with_metadata(...)` push,用上表元数据取值。 + +composition/brief 相关的强制要求: + +- **不需要新配置 composition**。`manifest.json` 的 `compositions` 只有 `runtime`/`supervisor`/`supervisorChat` 三个固定字段,supervisor 之所以多出后两套是因为它是唯一「非孤立、带完整拼装」的身份,不是「配 composition」这件事本身的通用要求。`project-planning` 作为委派子 Agent,天然复用 `runtime` composition(孤立子 Agent 通用模板),不配不报错——校验(`validate_composition` 516-545 行)只针对三个固定字段做,不遍历 `agentCatalog`。 +- `briefPathName` 只是运行时文件名 token(`memory/agents/**` 长期记忆、`.agent/passes/**` 单轮 brief 快照两类文件复用),不是指向仓库预先存在文件的引用;格式要求(`.md` 结尾、裸文件名、首字符字母数字、只含字母数字/`-`/`_`/`.`)在 `validate_file_name`(839-857 行)编译期强制,且 `project-planning` 组级 briefPathName(如 `project-planning.md`)不得与现有 7 个(supervisor + 6 组)任何一个重名;但**缺文件不会导致任何失败**——`read_previous_agent_role_brief` 等读取路径都把「文件不存在」当 `Ok(None)` 正常分支处理,这是 Agent 第一次跑之前的正常状态。 + +**登记前必须先处理的代码改动**(本节按调研如实列出,不粉饰——只在 catalog 里登记 `project-planning` 不足以让它可执行): + +- **blocking**:`prompt.rs` 的 `game_creator_agent_role_definition`(`apps/ai-game-creator-shell/src-tauri/src/agent/prompt.rs:661-679`)是把 `agent_id` 合成出 `(group_definition, role_definition)` 身份信息的唯一函数,目前只做「`agent_id == GAME_CREATOR_PROJECT_SUPERVISOR_AGENT_ID` 则特判,否则遍历 `GAME_CREATOR_AGENT_GROUP_DEFINITIONS` 的 group.roles」这个二分——`project-planning` 落进 else 分支后遍历不到任何组角色,返回 `None`。它的两个调用方都是 `.ok_or_else(...)?` 直接把 `None` 转成 `Err` 中断: + - `provider_request_builders.rs:536-539`(`build_game_creator_background_agent_context`)——`agent.delegate` 派发后台任务后,Runtime 驱动每一轮实际执行都要经过这里,`project-planning` 第一轮就会硬失败,报「未知 Agent 模板:project-planning」; + - `prompt.rs:416-417`(`build_game_creator_role_agent_context_for_session`)——直接对话式 chat 的身份/上下文构建函数,同样的失败方式。 + + 也就是说,**仅做本节描述的 catalog 登记,D11 的静态委派在执行层面完全跑不起来**;`game_creator_agent_role_definition` 需要一个平行于 supervisor 特判的 `project-planning` 分支,这是 M1 必须一并落地的代码,不属于本轮「不改任何 .rs」的范围。 +- **needs_change**:`task_ops.rs` 的 `task.create` 工具(`apps/ai-game-creator-shell/src-tauri/src/agent/runtime_tools/task_ops.rs:335-363`)在拿不到角色定义、且调用方未显式传 `group`/`role` 时,把 group 兜底成 `Design`、role 兜底成 `"Agent"`,而不是报错或识别「无 group」。`task.create` 对所有 `agent_id`统一开放,`project-planning` 一旦调用它且未显式带参数,会被静默记成「Design 组 / Agent 角色」任务写进 manifest.json,污染 6 组任务审计和按 group 聚合的面板,且无任何报错提示误分类。 +- **needs_change**:`delegation.rs` 的 `agent.spawn_isolated` 校验(`apps/ai-game-creator-shell/src-tauri/src/agent/runtime_tools/delegation.rs:1396-1412`)只排除 `child-` 前缀和 supervisor 本体,其余 catalog 成员一律放行为合法的 isolated 模板。`project-planning` 登记后会自动满足这个放行条件,于是任何持有 `agent.spawn_isolated` 权限的 Agent(不只是 Project Supervisor)都能拿它当模板动态孵生隔离子实例——这与 D11「`project-planning` 只应由 Supervisor 通过 `agent.delegate` 静态委派」的设计意图不一致,是登记后新增的隐性能力扩权,需要在 M1 与「blocking」项一并处理,不能默认「反正没人这么调」。 +- **benign(不阻塞,仅记录)**:前端 `projectProfessionalAgentLabel`(`apps/ai-game-creator-shell/src/features/agent-runtime/model.ts:1496-1529`)的关键字匹配落不到 `project-planning`,会退化成直接显示原始 `agentId`。纯展示层缺口,不影响功能,M1 顺手补一条分支即可。 +- 未来提醒(写入代码前必须核对,本轮不改):`pass_artifacts.rs` 的 `agent_role_memory_relative_path_for_task`(`apps/ai-game-creator-shell/src-tauri/src/agent/generation/pass_artifacts.rs:335-347`)也是「先特判 supervisor、再遍历 group」的同构硬编码,若不加第三条 `project-planning` 分支,运行时对它调用会落入 346 行的 `Err("未知 Agent 任务")`。 +- 排雷提示(供未来维护者,非本轮改动项):全仓库检索确认,当前没有任何生产代码枚举 runtime `AgentCatalog`(`.iter()` 零生产调用),前端「团队」清单(`agentPresentation.ts` 的 `groupConfigs`)与 `agent.route_manifest`(`delivery.rs`)都是硬编码字面量/精确字符串判断,结构上不会把 `project-planning` 带进「做游戏」团队清单或路由清单。但**未来如果有人写「遍历 AgentCatalog 生成 UI 团队卡片/prompt 团队成员清单/任何 route 白名单」这类代码,必须显式按 `groupId ∈ {design, balance, art, audio, code, publishing}` 六个真实组过滤,或显式排除 `project-planning`(和 `supervisor`)这两个组外单节点**——这也是坚持 `groupId` 必须自引用为 `"project-planning"`、不能复用 `"design"` 的根本原因。 + +**本轮范围声明**:以上登记机制与代码改动清单均属 **M1 实现范围**,本轮(`M0A-3` 文档工作包)只冻结机制、不落地任何代码——不改 `manifest.json`、不改 `runtime_prompt_bundle.rs`、不改 `runtime_adapter.rs`、不改任何 `.rs` 文件。理由:`project-planning` 目前没有 prompt、没有任何路径能调用它,现在就注册 catalog 而不同步处理上面的 blocking 项,等于给发布产物加死重(一个「看似已登记、实则一调用就硬失败」的 Agent 身份),注册代码应与 M1 的 prompt/source 一起落地。 + ## 4. Runtime 拓扑与可信边界 ```mermaid @@ -1612,7 +1687,7 @@ D9 之后,root 是未变的 Project Supervisor,它在 `standard` 下天然 - **checkpoint handoff 私有持久化**——原有待裁决项,不受拓扑变更影响,继续保留。 - ~~**策划节点 `agentId` / source 命名**~~——**2026-08-13 已裁决冻结**:策划子 Agent `agentId=project-planning`;Supervisor 侧承载「做方案」入口的新可信 source 取全新常量名 `project-supervisor-plan`(不沿用历史 `project-supervisor-plan-chat` 字面,避免语义改变后接错旧代码路径)。第 1.1 节批二不再被本项阻塞,改由下方新增的 `build.rs` 一致性待裁决项阻塞。 - **plan run 是否允许 steer**——`steering.rs` 的 steer 门按可信 source 判定,steer 替换协议会终止旧根并另起 replacement root run,与第 5.1 节的 session CAS、`roundsUsed` 与 `activeQuestion` 存在未验证交互,第 14 节恢复矩阵没有这条路径。**D11 新拓扑下问题形态变化但未消解**:策划节点不再是 ready-task 工作流节点,而是 Supervisor 的委派子 Agent,与 game-chat 动态美术委派子 Agent 面临同一类「父 Supervisor 被 steer 时下游委派子 Agent 如何收束」问题(参见 2026-08-11 game-chat 动态美术 child 通用 retry 失败关闭的裁决,decision-log 同日条),但委派子 Agent 的收束机制(静态委派 delivery/claim 生命周期)与 ready-task 工作流节点的收束机制并不相同,不能直接照搬旧结论,需重新验证。 -- **`project-planning` 的编译期 agentCatalog 登记方式与 `build.rs` 一致性校验(2026-08-13 新增)**——`project-planning` 目前不在编译期 agentCatalog 里;`build.rs` 的 `validate_seed_task_catalog`(`apps/ai-game-creator-shell/src-tauri/build.rs:23-46`)要求编译出的 `(taskId, groupId, role)` 集合与 `shared_contracts::game_creation_app::new_game_creation_app_seed_tasks()` 完全相等,不等即 `panic!`。如何登记 `project-planning` 而不破坏这条一致性校验——是否需要 `new_game_creation_app_seed_tasks()` 新增一条不落入 16 任务 DAG 的独立条目,还是该一致性校验本身需要按「是否属于 16 任务 DAG」拆分——尚未裁决,是第 1.1 节批二(尤其第 3 节注册表)的新阻塞点,本文档只记录问题,不假装已有结论。 +- ~~**`project-planning` 的编译期 agentCatalog 登记方式与 `build.rs` 一致性校验**~~——**2026-08-13 机制已定稿**(见第 3.1 节):`project-planning` 在 `agentCatalog` 下登记为与 `supervisor` 平级、不进 `groups` 数组的独立条目,`specialist_nodes` 只读 `manifest.agent_catalog.groups[].roles[]`(`build_support/runtime_prompt_bundle.rs:387-398`),因此 `build.rs` 的 `validate_seed_task_catalog`(`apps/ai-game-creator-shell/src-tauri/build.rs:23-46`)、16 任务种子 DAG、`new_game_creation_app_seed_tasks()` 均不需要改动。批二不再被 catalog 一致性问题阻塞;但登记机制定稿过程中查实了一个新的、真正的**待裁决/待处置项**(不是同一个问题的延续,是第 3.1 节调研发现的独立缺口):`prompt.rs` 的 `game_creator_agent_role_definition`(`apps/ai-game-creator-shell/src-tauri/src/agent/prompt.rs:661-679`)是把 `agent_id` 合成出角色身份的唯一函数,目前硬编码「非 `project-supervisor` 即 group 角色」的二分,`project-planning` 落入 else 分支会返回 `None`,其两个调用方(`provider_request_builders.rs:536-539`、`prompt.rs:416-417`)都会把 `None` 转成 `Err` 中断执行,报「未知 Agent 模板:project-planning」。也就是说**仅做 catalog 登记不足以让 D11 的静态委派可执行**,还需要在 `game_creator_agent_role_definition` 里补一个平行于 supervisor 特判的 `project-planning` 分支——这是 M1 落地范围,第 3.1 节已列出完整改动清单(含另外两处 needs_change:`task_ops.rs` 的 group/role 兜底误分类、`delegation.rs` 的 `agent.spawn_isolated` 放行面),本文档不再假装这只是「登记方式未裁决」,而是明确记录为「机制已定稿、代码待 M1 落地」。 ### 23.2 M0-3:统一 owner 产物验证与可玩验收边界(PR 工作包 `M0A-2`)