From 22edb1dfb1a0f3799f9132091ce1b2a8491ef4a3 Mon Sep 17 00:00:00 2001 From: kdletters Date: Tue, 4 Aug 2026 18:44:53 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=B6=E7=B4=A7Supervisor=20Prompt=E6=89=80?= =?UTF-8?q?=E6=9C=89=E6=9D=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 从planning visual与chat组合推导完整Supervisor专属section集合 拒绝专属section流入公共runtime平台变体专业overlay或Provider fragment 将公共Runtime header改为身份中立并消除Supervisor双重system身份 保留普通专业Agent规划与最终回复身份约束 补齐跨层逃逸负例并同步架构文档 --- .../build_support/runtime_prompt_bundle.rs | 97 ++++++++++++------- .../src-tauri/src/agent/prompt.rs | 4 +- .../provider_request_builders.rs | 7 ++ .../tests/runtime_prompt_bundle_build.rs | 31 ++++-- .../shared-memory/decision-log.md | 2 +- ...案】AI游戏创作智能体App实施计划-2026-06-24.md | 2 +- 6 files changed, 99 insertions(+), 44 deletions(-) diff --git a/apps/ai-game-creator-shell/src-tauri/build_support/runtime_prompt_bundle.rs b/apps/ai-game-creator-shell/src-tauri/build_support/runtime_prompt_bundle.rs index ad57c3354..a22bb438d 100644 --- a/apps/ai-game-creator-shell/src-tauri/build_support/runtime_prompt_bundle.rs +++ b/apps/ai-game-creator-shell/src-tauri/build_support/runtime_prompt_bundle.rs @@ -347,7 +347,7 @@ pub fn compile_manifest(manifest_path: &Path) -> Result Result Result<(), String> { +fn validate_supervisor_section_ownership(manifest: &PromptBundleManifest) -> Result<(), String> { let identity = manifest.compositions.supervisor_chat.identity.as_str(); let final_reply = manifest.compositions.supervisor_chat.final_reply.as_str(); - let reserved = BTreeSet::from([identity, final_reply]); - let reject_reserved = |owner: &str, section: &str| { - if reserved.contains(section) { - Err(format!( - "{owner} 不得复用 Supervisor chat 专属 section:{section}" - )) - } else { - Ok(()) - } - }; - - for section in manifest - .compositions - .runtime - .iter() - .filter(|section| !section.starts_with('$')) - { - reject_reserved("composition runtime", section)?; - } + let chat_reserved = BTreeSet::from([identity, final_reply]); if manifest .compositions .supervisor @@ -438,29 +418,80 @@ fn validate_supervisor_chat_section_ownership( )); } for (owner, section) in [ - ( - "variants.platform.default", - &manifest.variants.platform.default, - ), - ("variants.platform.linux", &manifest.variants.platform.linux), ( "variants.visualContract.editorConfigured", - &manifest.variants.visual_contract.editor_configured, + manifest.variants.visual_contract.editor_configured.as_str(), ), ( "variants.visualContract.editorUnavailable", - &manifest.variants.visual_contract.editor_unavailable, + manifest + .variants + .visual_contract + .editor_unavailable + .as_str(), ), ] { - reject_reserved(owner, section)?; + if chat_reserved.contains(section) { + return Err(format!( + "{owner} 不得复用 Supervisor chat 专属 section:{section}" + )); + } + } + + let mut supervisor_owned = manifest + .compositions + .supervisor + .iter() + .filter(|section| !section.starts_with('$')) + .map(String::as_str) + .collect::>(); + supervisor_owned.extend([ + manifest.variants.visual_contract.editor_configured.as_str(), + manifest + .variants + .visual_contract + .editor_unavailable + .as_str(), + identity, + final_reply, + ]); + let reject_supervisor_owned = |owner: &str, section: &str| { + if supervisor_owned.contains(section) { + Err(format!( + "{owner} 不得复用 Supervisor 专属 section:{section}" + )) + } else { + Ok(()) + } + }; + + for section in manifest + .compositions + .runtime + .iter() + .filter(|section| !section.starts_with('$')) + { + reject_supervisor_owned("composition runtime", section)?; + } + for (owner, section) in [ + ( + "variants.platform.default", + manifest.variants.platform.default.as_str(), + ), + ( + "variants.platform.linux", + manifest.variants.platform.linux.as_str(), + ), + ] { + reject_supervisor_owned(owner, section)?; } for overlay in &manifest.role_overlays { for section in &overlay.sections { - reject_reserved(&format!("role overlay {}", overlay.agent_id), section)?; + reject_supervisor_owned(&format!("role overlay {}", overlay.agent_id), section)?; } } for (owner, _, section) in provider_fragment_entries(&manifest.provider_fragments) { - reject_reserved(owner, section)?; + reject_supervisor_owned(owner, section)?; } Ok(()) } diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/prompt.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/prompt.rs index c8383084d..25baf1c92 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/prompt.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/prompt.rs @@ -641,7 +641,7 @@ pub(crate) fn game_creator_agent_runtime_tool_plan_system_prompt() -> String { fn game_creator_agent_runtime_tool_plan_system_prompt_for_platform(linux: bool) -> String { let tool_catalog = agent_runtime_native_executable_tools().join("、"); let prompt_header = format!( - "你是 Genarrative AI 游戏创作多智能体 Runtime 中的专业 Agent。你必须直接调用当前请求广告的原生函数:复杂任务首次拆解、实际进度变化、steer 调整顺序或最终收束时调用 update_agent_plan,并提交 explanation 与完整 steps;无需更新时不要调用 update_agent_plan。steps 只允许 pending、in_progress、completed 且同时最多一个 in_progress;已完成步骤必须保留且不得回退,所有必要步骤 completed 前不得调用 respond_to_user,Runtime 不会按工具动作下标代替你更新进度。只能请求以下 Runtime 当前注册的原生可执行工具:{tool_catalog}。MCP 工具仅以当前请求提供的动态目录为准。" + "你正在使用 Genarrative AI 游戏创作多智能体 Runtime。你必须直接调用当前请求广告的原生函数:复杂任务首次拆解、实际进度变化、steer 调整顺序或最终收束时调用 update_agent_plan,并提交 explanation 与完整 steps;无需更新时不要调用 update_agent_plan。steps 只允许 pending、in_progress、completed 且同时最多一个 in_progress;已完成步骤必须保留且不得回退,所有必要步骤 completed 前不得调用 respond_to_user,Runtime 不会按工具动作下标代替你更新进度。只能请求以下 Runtime 当前注册的原生可执行工具:{tool_catalog}。MCP 工具仅以当前请求提供的动态目录为准。" ); let isolated_template_ids = GAME_CREATOR_AGENT_GROUP_DEFINITIONS .iter() @@ -1214,6 +1214,8 @@ mod tests { game_creator_agent_runtime_tool_plan_system_prompt_for_agent("code-prototype"); assert_eq!(code_agent_prompt, shared_prompt); + assert!(code_agent_prompt.contains("你正在使用 Genarrative AI 游戏创作多智能体 Runtime")); + assert!(!code_agent_prompt.contains("多智能体 Runtime 中的专业 Agent")); assert!(code_agent_prompt.contains("preview.validate")); assert!(!code_agent_prompt.contains("角色边界:项目文件写入只允许")); } 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 81c2020a1..3b711d32c 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 @@ -595,6 +595,7 @@ mod tests { ); assert!(!supervisor_prompt.contains(supervisor_identity_contract)); assert!(supervisor_system_prompt.contains("总控不能替代已有专业角色")); + assert!(!supervisor_system_prompt.contains("多智能体 Runtime 中的专业 Agent")); assert!(!supervisor_system_prompt.contains("你拥有最终回复权")); assert!(supervisor_prompt.contains(SUPERVISOR_NOTICE)); assert!(!supervisor_prompt.contains("你拥有最终回复权")); @@ -729,6 +730,9 @@ mod tests { &catalog, ) .expect("build ordinary planning request"); + assert!(ordinary_request.messages[0] + .content + .contains("你正在使用 Genarrative AI 游戏创作多智能体 Runtime")); let ordinary_prompt = &ordinary_request.messages[1].content; assert!(!ordinary_prompt.contains(supervisor_identity_contract)); assert!(ordinary_prompt.contains(ORDINARY_NOTICE)); @@ -792,6 +796,9 @@ mod tests { &[], ) .expect("build ordinary final reply request"); + assert!(ordinary_final_request.messages[0] + .content + .contains("多智能体中的一个专业角色 Agent")); assert!(ordinary_final_request.messages[1] .content .contains("请只以这个专业 Agent 的身份行动")); diff --git a/apps/ai-game-creator-shell/src-tauri/tests/runtime_prompt_bundle_build.rs b/apps/ai-game-creator-shell/src-tauri/tests/runtime_prompt_bundle_build.rs index 6b39b9994..91a06c4b4 100644 --- a/apps/ai-game-creator-shell/src-tauri/tests/runtime_prompt_bundle_build.rs +++ b/apps/ai-game-creator-shell/src-tauri/tests/runtime_prompt_bundle_build.rs @@ -463,7 +463,16 @@ fn rejects_unknown_duplicate_and_missing_composition_items() { .expect("runtime composition array") .push(json!("supervisorIdentityContract")); }, - "composition runtime 不得复用 Supervisor chat 专属 section", + "composition runtime 不得复用 Supervisor 专属 section", + ); + assert_compile_error( + |manifest| { + manifest["compositions"]["runtime"] + .as_array_mut() + .expect("runtime composition array") + .push(json!("supervisorPlaybook")); + }, + "composition runtime 不得复用 Supervisor 专属 section:supervisorPlaybook", ); assert_compile_error( |manifest| { @@ -523,9 +532,16 @@ fn rejects_invalid_variant_references() { ); assert_compile_error( |manifest| { - manifest["variants"]["platform"]["default"] = json!("supervisorIdentityContract"); + manifest["variants"]["platform"]["default"] = json!("supervisorVisualWithEditor"); }, - "variants.platform.default 不得复用 Supervisor chat 专属 section", + "variants.platform.default 不得复用 Supervisor 专属 section", + ); + assert_compile_error( + |manifest| { + manifest["variants"]["visualContract"]["editorConfigured"] = + json!("supervisorIdentityContract"); + }, + "variants.visualContract.editorConfigured 不得复用 Supervisor chat 专属 section", ); } @@ -552,10 +568,9 @@ fn rejects_invalid_provider_fragment_registry() { ); assert_compile_error( |manifest| { - manifest["providerFragments"]["delegatedPlaytestRepair"] = - json!("supervisorFinalReplyContract"); + manifest["providerFragments"]["delegatedPlaytestRepair"] = json!("supervisorRepair"); }, - "providerFragments.delegatedPlaytestRepair 不得复用 Supervisor chat 专属 section", + "providerFragments.delegatedPlaytestRepair 不得复用 Supervisor 专属 section", ); assert_compile_error( |manifest| { @@ -614,9 +629,9 @@ fn rejects_invalid_role_overlays() { ); assert_compile_error( |manifest| { - manifest["roleOverlays"][0]["sections"] = json!(["supervisorIdentityContract"]); + manifest["roleOverlays"][0]["sections"] = json!(["supervisorClaimGate"]); }, - "role overlay code-prototype 不得复用 Supervisor chat 专属 section", + "role overlay code-prototype 不得复用 Supervisor 专属 section", ); assert_compile_error( |manifest| { diff --git a/docs/project-memory/shared-memory/decision-log.md b/docs/project-memory/shared-memory/decision-log.md index 972fb8f8a..644afff6d 100644 --- a/docs/project-memory/shared-memory/decision-log.md +++ b/docs/project-memory/shared-memory/decision-log.md @@ -5940,7 +5940,7 @@ - 决策:把 `prompt.rs` 中依赖长自然语言精确匹配的链式 `.replace()` 拆成仓库内版本化 Prompt Bundle;`build.rs` 读取、校验并生成静态 Rust 定义编译进 Tauri 二进制,生产源码不再直接引用 `prompts/runtime` 的单个 Markdown。 - 边界:Supervisor 的角色选择、并行委派、all-join、视觉返工、claim gate 和 repair 自然语言合同,以及 Supervisor / 六组专业 Agent 的编译期静态节点目录进入 Bundle。Bundle 不是完整可执行 graph,也不是生产 Skill;正式 DAG 依赖边、权限、安全门和完成合同继续由 Rust、`shared-contracts` 与校验后的项目协作策略掌控。 -- 一致性:manifest 是 section、组合顺序、平台 / Editor 变体、role overlay、Provider 协作 fragment 和静态节点目录的单一来源;role overlay 只接受 `rootSourceKind` 强类型语义 selector,构建期拒绝未知 kind,运行期再把权威 source 常量映射为生成的 kind,禁止在 manifest 中复制易漂移的 durable source 字符串。isolated / all-join、autonomous 首轮、首批协作修复、delivery 收敛、manifest wait、试玩后续委派,以及 Supervisor interaction / background planning / final-reply 身份合同不得在 Provider 或 `prompt.rs` 源码中复制。Supervisor 共享核心身份与最终回复专属规则拆成两个 section:background planning 的 system composition 必须复用核心身份 section,interaction / final-reply 的 system prompt 按 manifest composition 组合核心身份与最终回复两段,所有 user context 都不重复注入 Supervisor 身份;identity section 不得进入公共 runtime、变体、role overlay 或 Provider fragment,final-reply section 只能进入 `supervisorChat`。构建脚本同时监听 Bundle 每一级目录、manifest 和已登记 section,保证任意嵌套目录新增孤立 Markdown 都会触发增量构建并失败关闭;同时拒绝未知字段、非法 / 重复 / symlink 路径、未知 / 重叠 selector、节点 / alias / 生成标识符冲突,并强制 Supervisor planning composition 复用 chat identity、专业节点 taskId / group / role 与正式 seed DAG 一致。原生工具目录仍从 `agent_runtime_native_executable_tools()` 生成,`mcp.call` 不混入静态原生目录;MCP 工具只从当前请求的动态 catalog 暴露。 +- 一致性:manifest 是 section、组合顺序、平台 / Editor 变体、role overlay、Provider 协作 fragment 和静态节点目录的单一来源;role overlay 只接受 `rootSourceKind` 强类型语义 selector,构建期拒绝未知 kind,运行期再把权威 source 常量映射为生成的 kind,禁止在 manifest 中复制易漂移的 durable source 字符串。isolated / all-join、autonomous 首轮、首批协作修复、delivery 收敛、manifest wait、试玩后续委派,以及 Supervisor interaction / background planning / final-reply 身份合同不得在 Provider 或 `prompt.rs` 源码中复制。公共 runtime system header 保持身份中立;Supervisor 共享核心身份与最终回复专属规则拆成两个 section:background planning 的 system composition 必须复用核心身份 section,interaction / final-reply 的 system prompt 按 manifest composition 组合核心身份与最终回复两段,所有 user context 都不重复注入 Supervisor 身份合同正文。由 planning composition、visual variants 和 `supervisorChat` 推导的全部 Supervisor-owned section 不得进入公共 runtime、platform variant、专业 role overlay 或 Provider fragment;identity 不得冒充 visual variant,final-reply 只能进入 `supervisorChat`。构建脚本同时监听 Bundle 每一级目录、manifest 和已登记 section,保证任意嵌套目录新增孤立 Markdown 都会触发增量构建并失败关闭;同时拒绝未知字段、非法 / 重复 / symlink 路径、未知 / 重叠 selector、节点 / alias / 生成标识符冲突,并强制 Supervisor planning composition 复用 chat identity、专业节点 taskId / group / role 与正式 seed DAG 一致。原生工具目录仍从 `agent_runtime_native_executable_tools()` 生成,`mcp.call` 不混入静态原生目录;MCP 工具只从当前请求的动态 catalog 暴露。 ## 2026-08-03 AI 游戏生成泥点不足使用确定性中断说明 diff --git a/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md b/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md index a03cd46b6..55a072d24 100644 --- a/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md +++ b/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md @@ -78,7 +78,7 @@ V1.11 的受保护仓库控制目录同时包含 `.git / .agent / .agents / .codex / .hermes`;其中 `.agent` 对项目命令隐藏,其余控制目录只读。 -2026-08-04 起,Runtime 的公共工具规划指令、Supervisor 协作编排 playbook、条件 overlay 和编译期静态 Agent 节点目录统一由版本化 Prompt Bundle 驱动,位于 `apps/ai-game-creator-shell/src-tauri/prompts/runtime/`。`manifest.json` 是 section 路径、组合顺序、平台 / Editor 变体、role overlay、Provider 协作 fragment,以及 Supervisor 与六组专业 Agent 静态目录的单一来源;role overlay 只允许 `rootSourceKind` 强类型语义 selector,构建期拒绝未知 kind,运行期把权威 source 常量映射为生成 kind。`build.rs` 同时监听 Bundle 每一级目录、manifest 和已登记 section,保证任意嵌套目录新增孤立 Markdown 都会触发增量构建,并以失败关闭方式校验 schema、引用、路径 / symlink、孤立 Markdown、selector、节点身份、旧 alias 和生成标识符,再生成 `'static + Copy` Rust 定义并编译进发布二进制。生成的 Supervisor planning composition 必须复用 `supervisorChat.identity`,且 identity section 不得进入公共 runtime、变体、role overlay 或 Provider fragment,final-reply section 只能进入 `supervisorChat`;专业节点 taskId / group / role 还必须在构建期与 `shared-contracts::new_game_creation_app_seed_tasks()` 强一致,防止身份合同、静态目录和正式 seed DAG 漂移。Bundle 承载公共指令、隔离 Agent 合同、平台差异、角色选择、并行委派、all-join、视觉返工、claim gate,Supervisor 共享核心身份、interaction / final-reply 专属合同及其组合,以及首批协作、delivery 收敛、manifest wait、试玩后续委派等 repair 自然语言合同;background planning 在 system composition 复用核心身份,所有 user context 都不再重复注入 Supervisor 身份。`agent_runtime_native_executable_tools()` 仍是原生可执行工具的权威源列表,同时供 Prompt 工具目录与 native capability registry 使用,MCP 工具只从当前请求的动态 catalog 暴露。最终 Provider 请求必须通过生成的 section、composition、overlay 与 provider fragment API 构建,禁止恢复直接 `include_str!("prompts/runtime/...")`、在 Provider 或 `prompt.rs` 源码中复制协作 graph 文案,或依赖自然语言精确 `.replace()` 注入工具合同、平台规则或角色规则。Bundle 不是完整可执行 graph:正式 DAG 依赖边、权限、沙箱、委派容量、持久 all-join 状态机、完成门和身份校验仍由 Rust、`shared-contracts` 与经校验的 `.agent/collaboration-policy.json` 强制执行,不允许通过 Skill、外部配置或任意运行时 Prompt 覆盖绕过。 +2026-08-04 起,Runtime 的公共工具规划指令、Supervisor 协作编排 playbook、条件 overlay 和编译期静态 Agent 节点目录统一由版本化 Prompt Bundle 驱动,位于 `apps/ai-game-creator-shell/src-tauri/prompts/runtime/`。`manifest.json` 是 section 路径、组合顺序、平台 / Editor 变体、role overlay、Provider 协作 fragment,以及 Supervisor 与六组专业 Agent 静态目录的单一来源;role overlay 只允许 `rootSourceKind` 强类型语义 selector,构建期拒绝未知 kind,运行期把权威 source 常量映射为生成 kind。`build.rs` 同时监听 Bundle 每一级目录、manifest 和已登记 section,保证任意嵌套目录新增孤立 Markdown 都会触发增量构建,并以失败关闭方式校验 schema、引用、路径 / symlink、孤立 Markdown、selector、节点身份、旧 alias 和生成标识符,再生成 `'static + Copy` Rust 定义并编译进发布二进制。公共 runtime system header 保持身份中立;生成的 Supervisor planning composition 必须复用 `supervisorChat.identity`,由 planning composition、visual variants 和 `supervisorChat` 推导的全部 Supervisor-owned section 不得进入公共 runtime、platform variant、专业 role overlay 或 Provider fragment,identity 不得冒充 visual variant,final-reply 只能进入 `supervisorChat`;专业节点 taskId / group / role 还必须在构建期与 `shared-contracts::new_game_creation_app_seed_tasks()` 强一致,防止身份合同、静态目录和正式 seed DAG 漂移。Bundle 承载公共指令、隔离 Agent 合同、平台差异、角色选择、并行委派、all-join、视觉返工、claim gate,Supervisor 共享核心身份、interaction / final-reply 专属合同及其组合,以及首批协作、delivery 收敛、manifest wait、试玩后续委派等 repair 自然语言合同;background planning 在 system composition 复用核心身份,所有 user context 都不再重复注入 Supervisor 身份合同正文。`agent_runtime_native_executable_tools()` 仍是原生可执行工具的权威源列表,同时供 Prompt 工具目录与 native capability registry 使用,MCP 工具只从当前请求的动态 catalog 暴露。最终 Provider 请求必须通过生成的 section、composition、overlay 与 provider fragment API 构建,禁止恢复直接 `include_str!("prompts/runtime/...")`、在 Provider 或 `prompt.rs` 源码中复制协作 graph 文案,或依赖自然语言精确 `.replace()` 注入工具合同、平台规则或角色规则。Bundle 不是完整可执行 graph:正式 DAG 依赖边、权限、沙箱、委派容量、持久 all-join 状态机、完成门和身份校验仍由 Rust、`shared-contracts` 与经校验的 `.agent/collaboration-policy.json` 强制执行,不允许通过 Skill、外部配置或任意运行时 Prompt 覆盖绕过。 2026-07-12 起,通用开发能力的 Runtime V1.1 增量以 [`【技术方案】AI游戏创作Agent Runtime V1.1-2026-07-12.md`](./【技术方案】AI游戏创作Agent%20Runtime%20V1.1-2026-07-12.md) 为编码级事实源。它补充仓库启动上下文、同一发布二进制独立 Runner、受限本地预览浏览器验证、动态隔离子 Agent 和真实 Provider 全链路验收;本文件中“进程内 tokio task”“首轮不预加载项目内容”和“不创建动态执行实例”的旧口径由 V1.1 明确替代,未涉及能力继续沿用本文件。