策划 Agent Runtime V2 完成 P2 产物闭环

新增单 Agent GDD 策略、版本产物和审批命令

补齐问询计数、上下文进度和输出校验边界

注册 Planning V2 Tauri 命令并纳入私有产物路径

更新 Runtime V2 技术方案与项目决策记录
This commit is contained in:
2026-09-03 10:04:48 +00:00
parent d70f635eae
commit 12da570d28
8 changed files with 2324 additions and 8 deletions
@@ -9,7 +9,9 @@ mod models;
mod planning_approval; mod planning_approval;
mod planning_coordinator; mod planning_coordinator;
mod planning_hydrate; mod planning_hydrate;
mod planning_policy_v2;
mod planning_provider_usage; mod planning_provider_usage;
mod planning_session_v2;
mod planning_storage; mod planning_storage;
mod planning_submit; mod planning_submit;
mod provider_control; mod provider_control;
@@ -28,7 +30,9 @@ pub(in crate::agent) use models::*;
pub(crate) use planning_approval::*; pub(crate) use planning_approval::*;
pub(crate) use planning_coordinator::*; pub(crate) use planning_coordinator::*;
pub(crate) use planning_hydrate::*; pub(crate) use planning_hydrate::*;
pub(crate) use planning_policy_v2::*;
pub(crate) use planning_provider_usage::*; pub(crate) use planning_provider_usage::*;
pub(crate) use planning_session_v2::*;
pub(crate) use planning_storage::*; pub(crate) use planning_storage::*;
pub(crate) use planning_submit::*; pub(crate) use planning_submit::*;
pub(in crate::agent) use provider_control::*; pub(in crate::agent) use provider_control::*;
@@ -658,7 +658,7 @@ fn validate_plan_platform_facts(value: &PlanPlatformFacts) -> Result<(), Plannin
Ok(()) Ok(())
} }
fn validate_plan_game(game: &PlanGddGame) -> Result<(), PlanningStorageError> { pub(crate) fn validate_plan_game(game: &PlanGddGame) -> Result<(), PlanningStorageError> {
validate_text(&game.title, "game.title", 1, 80)?; validate_text(&game.title, "game.title", 1, 80)?;
validate_text(&game.genre.primary, "game.genre.primary", 1, 40)?; validate_text(&game.genre.primary, "game.genre.primary", 1, 40)?;
if let Some(fusion) = &game.genre.fusion { if let Some(fusion) = &game.genre.fusion {
@@ -2493,6 +2493,10 @@ fn main() {
chat_with_game_creator_role_agent, chat_with_game_creator_role_agent,
chat_with_game_creator_role_agent_stream, chat_with_game_creator_role_agent_stream,
chat_with_game_creator_direct_codex, chat_with_game_creator_direct_codex,
start_planning_session_v2,
continue_planning_session_v2,
decide_planning_artifact_v2,
hydrate_planning_session_v2,
start_game_creator_agent_runtime_task, start_game_creator_agent_runtime_task,
start_game_creator_supervisor_runtime_task, start_game_creator_supervisor_runtime_task,
compact_game_creator_agent_runtime_context, compact_game_creator_agent_runtime_context,
@@ -305,6 +305,7 @@ pub(crate) fn list_local_project_files_at(
if is_agent_runtime_private_control_path(&relative_path) if is_agent_runtime_private_control_path(&relative_path)
|| is_agent_checkpoint_control_path(&relative_path) || is_agent_checkpoint_control_path(&relative_path)
|| is_agent_workbench_control_path(&relative_path) || is_agent_workbench_control_path(&relative_path)
|| is_agent_planning_storage_path(&relative_path)
{ {
continue; continue;
} }
@@ -408,10 +409,11 @@ pub(crate) fn reject_agent_runtime_private_control_path(
/// the planning Agent needs `file.read`/`file.list` observations while its /// the planning Agent needs `file.read`/`file.list` observations while its
/// durable writer is still the only component allowed to mutate the sidecar. /// durable writer is still the only component allowed to mutate the sidecar.
pub(crate) fn is_agent_planning_storage_path(normalized_path: &str) -> bool { pub(crate) fn is_agent_planning_storage_path(normalized_path: &str) -> bool {
normalized_path.eq_ignore_ascii_case(".agent/planning") let normalized_path = normalized_path.to_ascii_lowercase();
|| normalized_path normalized_path == ".agent/planning"
.to_ascii_lowercase() || normalized_path.starts_with(".agent/planning/")
.starts_with(".agent/planning/") || normalized_path == ".agent/planning-v2"
|| normalized_path.starts_with(".agent/planning-v2/")
} }
pub(crate) fn is_agent_planning_managed_write_path(normalized_path: &str) -> bool { pub(crate) fn is_agent_planning_managed_write_path(normalized_path: &str) -> bool {
@@ -424,7 +426,7 @@ pub(crate) fn reject_agent_planning_storage_write_path(
) -> Result<(), String> { ) -> Result<(), String> {
if is_agent_planning_managed_write_path(normalized_path) { if is_agent_planning_managed_write_path(normalized_path) {
return Err( return Err(
"`.agent/planning/**` 与 `game/fast_gdd.md` 只能由立项策划 Runtime 专用存储层写入,通用文件写入被拒绝" "`.agent/planning/**`、`.agent/planning-v2/**` 与 `game/fast_gdd.md` 只能由立项策划 Runtime 专用存储层写入,通用文件写入被拒绝"
.to_string(), .to_string(),
); );
} }
@@ -20,7 +20,7 @@
- 背景:现有“做方案”依赖 `project-supervisor-plan` 根 Run、`project-planning` 子 Run、静态委派、delivery、Acceptance Graph 和审批前 evidence。新策划 Agent 只需要单 Agent 会话、问询、GDD 和审批;继续在旧 Runtime 上逐条放宽会保留身份/编排耦合。未来策划 Agent 可能支持无限多轮、MCP 和 Skill,需要避免把当前 8 题/GDD/no-tools 固化为 Runtime 根结构。 - 背景:现有“做方案”依赖 `project-supervisor-plan` 根 Run、`project-planning` 子 Run、静态委派、delivery、Acceptance Graph 和审批前 evidence。新策划 Agent 只需要单 Agent 会话、问询、GDD 和审批;继续在旧 Runtime 上逐条放宽会保留身份/编排耦合。未来策划 Agent 可能支持无限多轮、MCP 和 Skill,需要避免把当前 8 题/GDD/no-tools 固化为 Runtime 根结构。
- 决策:新增独立 `PlanningSessionRuntime`,复用 Provider/流式、会话持久化、项目锁、原子写和基础错误恢复;当前启用 `mode=gdd`、最多展示 8 个有效问题、GDD 审批和用户修改。新建“做方案”会话不创建 Supervisor root、planning child、delegation 或 acceptance evidence。V2 使用独立 `.agent/planning-v2/` 与 V2 schema,继续输出 `game/fast_gdd.md`;不自动转换旧会话。 - 决策:新增独立 `PlanningSessionRuntime`,复用 Provider/流式、会话持久化、项目锁、原子写和基础错误恢复;当前启用 `mode=gdd`、最多展示 8 个有效问题、GDD 审批和用户修改。新建“做方案”会话不创建 Supervisor root、planning child、delegation 或 acceptance evidence。V2 使用独立 `.agent/planning-v2/` 与 V2 schema,继续输出 `game/fast_gdd.md`;不自动转换旧会话。
- 兼容性:Session 保存 `mode`、可空 `questionLimit``capabilities.tools/skills`;完整会话记录与 Provider 请求上下文分离;消息模型预留 tool/skill 事件类型但本期不执行 MCP/Skill。无限问询、上下文摘要、多产物和能力执行以后作为策略/能力层扩展,不重新引入 Supervisor 身份模型。 - 兼容性:Session 保存 `mode`、可空 `questionLimit``capabilities.tools/skills`;完整会话记录与 Provider 请求上下文分离;消息模型预留 tool/skill 事件类型但本期不执行 MCP/Skill。无限问询、上下文摘要、多产物和能力执行以后作为策略/能力层扩展,不重新引入 Supervisor 身份模型。
- 当前进度:P0 合同冻结已完成,已固定 `planning-session.v2``planning-message.v2``planning-turn-result.v2``plan-gdd.v2``plan-approval.v2`、四个 V2 command、`questionLimit=8` 及旧链路 `legacy-cutover.json` 封存边界;P1 尚未开 - 当前进度:P0 合同冻结、P1 会话内核和 P2 GDD/审批核心已落地;P3 正式入口/UI 接入与 P5 旧链路退役尚未开
- 退役:V2 切换时旧链路直接封存;所有未完成旧会话投影为 `legacy_retired` 失败,禁止继续问询、审批、恢复或 continuation。旧 GDD、approval、conversation 和 `.agent/planning` 文件只读保留;旧入口 caller 关闭,但不删除旧代码、旧测试或旧数据。 - 退役:V2 切换时旧链路直接封存;所有未完成旧会话投影为 `legacy_retired` 失败,禁止继续问询、审批、恢复或 continuation。旧 GDD、approval、conversation 和 `.agent/planning` 文件只读保留;旧入口 caller 关闭,但不删除旧代码、旧测试或旧数据。
- 影响范围:AGC 做方案入口、Rust/Tauri planning session/Provider adapter、GDD/审批 V2、前端 planning lane、阶段任务与 BDD 验收;做游戏/做素材 DirectProject 不变。 - 影响范围:AGC 做方案入口、Rust/Tauri planning session/Provider adapter、GDD/审批 V2、前端 planning lane、阶段任务与 BDD 验收;做游戏/做素材 DirectProject 不变。
- 验证方式:按 `docs/technical/【技术方案】策划会话RuntimeV2接入与旧链路退役-2026-09-03.md` 的 P0~P5 阶段验收执行;至少覆盖第 8 个问题、上限后 question 抑制、Provider 失败、非法输出、批准/修改/退回、重启恢复、旧会话切换强制失败、迟到 Provider 结果丢弃和当前空能力快照。 - 验证方式:按 `docs/technical/【技术方案】策划会话RuntimeV2接入与旧链路退役-2026-09-03.md` 的 P0~P5 阶段验收执行;至少覆盖第 8 个问题、上限后 question 抑制、Provider 失败、非法输出、批准/修改/退回、重启恢复、旧会话切换强制失败、迟到 Provider 结果丢弃和当前空能力快照。
@@ -7970,3 +7970,15 @@ CI 上 `background_agent_runtime_recovers_stale_running_before_pending_task` 在
- UI 编辑器导出的 `ui/generated-*.js` 是派生本地产物。代码生成只写文件,绝不推进项目 revision、UI State revision、manifest 阶段或 Runtime 验证门;写入失败只返回生成错误,不能把生成文件写入冒充项目 mutation。 - UI 编辑器导出的 `ui/generated-*.js` 是派生本地产物。代码生成只写文件,绝不推进项目 revision、UI State revision、manifest 阶段或 Runtime 验证门;写入失败只返回生成错误,不能把生成文件写入冒充项目 mutation。
- 生成文件名保留可读清洗前缀,并追加 asset ID 的 SHA-256 摘要前缀以避免不同 ID 碰撞;不迁移既有旧路径,调用方需在采用新命名后使用新返回路径。 - 生成文件名保留可读清洗前缀,并追加 asset ID 的 SHA-256 摘要前缀以避免不同 ID 碰撞;不迁移既有旧路径,调用方需在采用新命名后使用新返回路径。
- Radial90 的前端预览与 Rust 导出统一使用角点映射和顺时针起始角规则,顺时针填充从角点前一条边开始,避免两端渲染偏移。 - Radial90 的前端预览与 Rust 导出统一使用角点映射和顺时针起始角规则,顺时针填充从角点前一条边开始,避免两端渲染偏移。
## 2026-09-03 策划会话 Runtime V2 P1 内核落地
- 新增 `PlanningSessionRuntime V2` 内核入口:`start_planning_session_v2``continue_planning_session_v2``hydrate_planning_session_v2`。P1 只负责单 Agent 会话生命周期、Provider 流式/普通调用、消息持久化、回合幂等、单项目单活跃回合、耗时和失败恢复,不接入 GDD 解析、审批或旧 Supervisor。
- V2 会话快照落在 `.agent/planning-v2/session.json`,完整消息落在 `.agent/planning-v2/conversation.jsonl`。同一 `clientTurnId` 已有成功 assistant 记录时直接重放;若只有 error 记录则允许沿用同一用户意图重试,不重复追加用户消息。进程退出后 hydrate 发现 `planning` 会投影为 `provider_failed/RECOVERY_REQUIRED`,不伪造成功或自动重试。
- Provider 调用复用现有 `platform-llm` 的 API-kind、流式解析、超时和重试配置;当前策略快照固定 `mode=gdd``questionLimit=8``tools=[]``skills=[]`。GDD 业务规则留给 P2,生产 UI 接入留给 P3。
## 2026-09-03 策划会话 Runtime V2 P2 产物闭环
- V2 新增 `GddPlanningPolicy`Provider 输出只接受合法 question 或完整 GDD JSONquestion 在 `questionCount < questionLimit` 时保存并展示,第 8 个问题仍可展示,第 8 个之后再次返回 question 时只允许一次内部强制出稿重试,额外 question 不落盘、不进入用户等待态。
- V2 GDD 使用独立 `plan-gdd.v2`,只保留项目身份、版本、游戏内容、决定、原型验证项和指纹,不带旧 Supervisor/Run/delegation 字段。每个版本写入 `.agent/planning-v2/gdd.vN.json`,同步更新 V2 index 和 `game/fast_gdd.md`;旧版本不可覆盖。
- 新增 `decide_planning_artifact_v2``plan-approval.v2`。批准、修改、退回均绑定当前 Session、artifact、version 和 fingerprint;修改/退回必须有意见,修改后 Session 回到 `revision_requested`,下一轮由同一 V2 Session 继续。`answerSource` 缺失或未知值回退,不成为单独阻断项。
@@ -1,7 +1,7 @@
# 策划会话 Runtime V2 接入与旧链路退役方案 # 策划会话 Runtime V2 接入与旧链路退役方案
- 日期:2026-09-03 - 日期:2026-09-03
- 状态:P0 合同冻结已完成,P1 待开工;本文是新生产实现的目标方案与阶段验收合同 - 状态:P0 合同冻结、P1 内核和 P2 产物闭环核心已完成;P3~P5 待实施;本文是新生产实现的目标方案与阶段验收合同
- 适用范围:AGC 桌面 App 的“做方案”入口、策划会话、GDD 产物与审批 - 适用范围:AGC 桌面 App 的“做方案”入口、策划会话、GDD 产物与审批
> 本文只规定新策划 Agent 的生产接入和旧链路退役方式,不修改当前生产代码。现有 `project-supervisor-plan` / `project-planning` 链路在 V2 切换前仍是存量实现;V2 切换时旧链路直接封存,所有未完成旧会话强制失败,旧 Fast GDD 文档之后只作为历史记录依据。 > 本文只规定新策划 Agent 的生产接入和旧链路退役方式,不修改当前生产代码。现有 `project-supervisor-plan` / `project-planning` 链路在 V2 切换前仍是存量实现;V2 切换时旧链路直接封存,所有未完成旧会话强制失败,旧 Fast GDD 文档之后只作为历史记录依据。
@@ -616,6 +616,12 @@ hydrate_planning_session_v2
### P1PlanningSessionRuntime 内核 ### P1PlanningSessionRuntime 内核
状态:实现已落在 AGC Tauri Runtime2026-09-03)。当前仅提供内核闭环,尚未接入 GDD 解析、审批或生产 UI。
已落地的 P1 入口:`start_planning_session_v2``continue_planning_session_v2``hydrate_planning_session_v2`。会话快照和完整消息分别持久化到 `.agent/planning-v2/session.json``.agent/planning-v2/conversation.jsonl`Provider 请求沿用现有 `platform-llm`,按配置执行流式或普通调用,并把流式增量统一投影为 `planning-session-v2-stream` 事件。
当前 P1 的恢复语义是轻量且显式的:进程退出时若快照仍为 `planning`hydrate 将其投影为 `provider_failed/RECOVERY_REQUIRED`,要求用户重新提交当前意图;不会伪造成功或自动制造 GDD。`clientTurnId` 命中已有成功 assistant 记录时直接等值重放;若只有 error 记录,则沿用原用户意图重试且不重复追加用户消息。
目标:在不包含 GDD 业务规则的情况下,跑通单 Agent 会话、流式响应、持久化和恢复。 目标:在不包含 GDD 业务规则的情况下,跑通单 Agent 会话、流式响应、持久化和恢复。
任务: 任务:
@@ -642,6 +648,10 @@ hydrate_planning_session_v2
### P2GddPlanningPolicy 与 V2 产物闭环 ### P2GddPlanningPolicy 与 V2 产物闭环
状态:核心实现已落地(2026-09-03)。当前已支持 question/GDD 解析、最多 8 个有效问题、达到上限后的单次强制出稿、`plan-gdd.v2` 版本文件、`game/fast_gdd.md` 投影和 `plan-approval.v2` 审批记录;审批修改后的下一轮仍由同一 V2 Session 继续。策略校验完成前的流式内容只在回合成功后对外转发,达到上限而被丢弃的 question、非法输出和重试内容不会泄露给调用方。等待审批时不能直接提交新的策划输入。P3 仍需把正式“做方案”入口和现有 UI 切到这些 command。
已落地入口:`decide_planning_artifact_v2``answerSource` 缺失或未知值按当前状态回退为 `user_freeform` / `default`,不作为单独阻断项;GDD 结构、必填业务字段、版本、指纹和当前项目身份仍必须合法。
目标:把新版原型的策划行为落到生产 V2,不把旧 Supervisor 协议带回来。 目标:把新版原型的策划行为落到生产 V2,不把旧 Supervisor 协议带回来。
任务: 任务: