diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/direct_tool_bridge.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/direct_tool_bridge.rs index ee87f122e..19790ef61 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/direct_tool_bridge.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/direct_tool_bridge.rs @@ -3407,7 +3407,7 @@ async fn start_tool_bridge_for_source( } #[cfg(test)] -pub(in crate::agent) struct DirectExecutionTestFixture { +pub(crate) struct DirectExecutionTestFixture { execution: Option, _host: tempfile::TempDir, } @@ -3426,7 +3426,7 @@ impl Drop for DirectExecutionTestFixture { } #[cfg(test)] -pub(in crate::agent) async fn direct_execution_fixture( +pub(crate) async fn direct_execution_fixture( root: &Path, turn: &str, ) -> DirectExecutionTestFixture { diff --git a/apps/ai-game-creator-shell/src-tauri/src/tests/project.rs b/apps/ai-game-creator-shell/src-tauri/src/tests/project.rs index 2aaf472c3..6e9abb9e8 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/tests/project.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/tests/project.rs @@ -1649,6 +1649,7 @@ async fn direct_image_generation_notifies_after_manifest_commit() { }, ) .expect("allow generation"); + let execution = direct_execution_fixture(&root, "direct-image-refresh-turn").await; let listener = TcpListener::bind((std::net::Ipv4Addr::LOCALHOST, 0)).expect("bind event receiver"); let sink = acquire_game_creator_manifest_invalidation_event_sink_test_guard(); @@ -1691,6 +1692,12 @@ async fn direct_image_generation_notifies_after_manifest_commit() { .await .expect("read rejected result"); assert_eq!(rejected["isError"], true); + assert!( + rejected["content"][0]["text"] + .as_str() + .is_some_and(|message| message.contains("prompt")), + "{rejected}" + ); assert_eq!( read_manifest_invalidation_relay_payload_with_deadline(&listener) .expect_err("rejected generation must not emit a commit") @@ -1698,6 +1705,7 @@ async fn direct_image_generation_notifies_after_manifest_commit() { io::ErrorKind::TimedOut ); drop(bridge); + drop(execution); fs::remove_dir_all(root).ok(); fs::remove_dir_all(config_dir).ok(); } diff --git a/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md b/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md index 8dada4d86..f2f41c0c2 100644 --- a/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md +++ b/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md @@ -60,6 +60,7 @@ - 正式 GUI 和 CLI 的共同 Direct 回合入口建立宿主控制状态,绑定 canonical 项目路径、稳定 clientTurnId 和原始用户输入摘要;宿主私有目录保存权威账本并独占该回合,项目 `.agent` 仅允许保存展示副本。配置或项目侧文件被改写、工具切换、Provider 重试和进程重启不得刷新同一回合的预算。 - Direct 回合集成测试也按生产入口计算原始用户输入的 SHA-256 十六进制摘要(64 字符),不能用请求名称替代。用户回显过滤回归继续覆盖实时消息去重、回合起止身份关联及历史落盘过滤。 +- 直接启动 Direct 工具桥的图片生成通知测试,须复用真实宿主执行会话与已登记交付合同夹具,再发起工具请求;继续验证资源提交后发出 manifest 失效通知,以及空提示词被参数校验拒绝且不发通知,不绕过执行许可门禁。 - 普通聊天与读取不要求交付合同。首次修改、代码执行或付费扩项之前,模型通过结构化工具登记本轮必需范围与验收项;合同非空、有界且只冻结一次。模型只能声明要求,不能提交“通过”作为证据。后续扩项留到新的用户回合。 - 明确新 Web 创建由宿主可信脚手架凭证及尚未交付的宿主记录判定,CLI 同样据此判定,不从提示文本猜测;这种回合即使模型没有调用工具或没有登记合同,也不得按普通聊天宣布交付。已有项目只有未激活合同且从未产生副作用时才允许直接聊天结束。 - 验收项为明确类型的产物、构建/测试命令、双端视觉或指定固定场景的双端玩法。可信新 Web 游戏由宿主补充构建、双端视觉和玩法底线,不能由模型声明“已有项目”降低。已有项目按冻结的变更范围选择层级;平台美术只在用户目标要求时成为必需项。