From 655aa0e2f619ebd061b3b7962be55984eef7ebb5 Mon Sep 17 00:00:00 2001 From: AIGameCreator App Date: Sat, 25 Jul 2026 20:08:21 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=BA=AF=E9=9D=99=E6=80=81?= =?UTF-8?q?=E7=BE=8E=E6=9C=AF=E4=BA=A7=E7=89=A9=E9=AA=8C=E8=AF=81=E5=90=88?= =?UTF-8?q?=E5=90=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增无 package.json 的 art-asset-plan 回归场景 约束自主验证仅走静态 smoke 与浏览器验收链路 记录当前错误暴露 project.verify 的失败证据 --- .../planning_strategy/autonomous_build.rs | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) diff --git a/apps/ai-game-creator-shell/src-tauri/src/tests/runtime_actions/planning_strategy/autonomous_build.rs b/apps/ai-game-creator-shell/src-tauri/src/tests/runtime_actions/planning_strategy/autonomous_build.rs index c35c4fabc..e7423d118 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/tests/runtime_actions/planning_strategy/autonomous_build.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/tests/runtime_actions/planning_strategy/autonomous_build.rs @@ -2919,3 +2919,134 @@ async fn autonomous_game_build_verified_revision_forces_response_only_delivery() fs::remove_dir_all(root).ok(); } + +#[tokio::test] +async fn autonomous_static_art_asset_verification_does_not_require_node_project() { + let root = unique_project_path(); + init_local_game_project_at( + &root, + "project-autonomous-static-art-verification", + "自主构建纯静态美术验证测试", + ) + .expect("project init"); + assert!( + !root.join("package.json").exists(), + "static HTML fixture must not gain a Node project manifest" + ); + fs::write( + root.join("assets/manifest.art.json"), + br#"{"assets":[{"path":"assets/art-spritesheet.png","kind":"art-spritesheet"}]}"#, + ) + .expect("write static art manifest"); + register_canvas_visual_asset_fixture(&root, "assets/art-spritesheet.png", "art-spritesheet"); + + let child_run_id = "autonomous-static-art-verification-child"; + let task = "为纯静态 HTML 游戏生成并登记 assets/manifest.art.json 与 assets/art-spritesheet.png;项目不使用 Node 或 npm。"; + let response_arguments = serde_json::json!({ + "response": "美术清单和精灵图已经生成,可以交付。" + }) + .to_string(); + let smoke_arguments = serde_json::json!({ + "reason": "使用静态 smoke 验证当前纯静态项目 revision", + "input": {"commandId": "game.static_smoke"} + }) + .to_string(); + let (sender, receiver) = mpsc::channel(); + let base_url = spawn_mock_llm_raw_responses_with_capture( + vec![ + native_agent_tool_plan_chat_response( + "call-autonomous-static-art-response", + AGENT_RUNTIME_RESPOND_FUNCTION_NAME, + response_arguments, + ), + native_agent_tool_plan_chat_response( + "call-autonomous-static-art-smoke", + &native_runtime_function_name("command.run_limited") + .expect("limited command function"), + smoke_arguments, + ), + ], + Some(sender), + ); + let _config_guard = write_test_local_config(format!( + r#"{{ + "agentLlm": {{ + "art-asset-plan": {{ + "apiKey": "autonomous-static-art-verification-key", + "baseUrl": {base_url:?}, + "model": "autonomous-static-art-verification-model", + "apiKind": "openai_chat", + "maxRetries": 0 + }} + }} +}}"# + )); + let runtime = bind_autonomous_specialist_runtime_for_test( + &root, + "autonomous-static-art-verification-parent", + "art-asset-plan", + child_run_id, + task, + ); + prepare_agent_runtime_project_mutation_locked( + &root, + "art-asset-plan", + child_run_id, + "canvas.asset_generate", + ) + .expect("record generated art mutation"); + let observations = vec![AgentRuntimeToolObservation { + tool: "canvas.asset_generate".to_string(), + status: "ok".to_string(), + summary: "已生成 assets/manifest.art.json 与 assets/art-spritesheet.png".to_string(), + detail: None, + }]; + + let plan = request_game_creator_agent_background_tool_plan_for_test( + &root, + "art-asset-plan", + &runtime.session_id, + child_run_id, + task, + &observations, + 2, + 0, + ) + .await + .expect("repair static art delivery into static verification") + .expect("static smoke verification plan"); + assert!(plan.response.is_empty()); + assert_eq!(plan.actions.len(), 1); + assert_eq!(plan.actions[0].tool, "command.run_limited"); + assert_eq!(plan.actions[0].input["commandId"], "game.static_smoke"); + + receiver + .recv_timeout(Duration::from_secs(2)) + .expect("initial static art response request"); + let repair_request = receiver + .recv_timeout(Duration::from_secs(2)) + .expect("static art verification-only repair request"); + let repair_function_names = captured_native_function_names_for_test(&repair_request); + assert_eq!( + repair_function_names, + BTreeSet::from([ + native_runtime_function_name("command.run_limited").expect("static smoke function") + ]), + "pure static asset delivery must not expose package.json-backed project.verify" + ); + let repair_request_json = mock_http_request_json(&repair_request); + let repair_instruction = repair_request_json["messages"] + .as_array() + .and_then(|messages| messages.last()) + .and_then(|message| message.get("content")) + .and_then(serde_json::Value::as_str) + .expect("static art repair instruction"); + assert!(repair_instruction.contains("game.static_smoke")); + assert!(repair_instruction.contains("preview.validate")); + assert!(!repair_instruction.contains("project.verify")); + assert!(!repair_instruction.contains("package.json")); + assert!(!repair_instruction.contains("Node")); + assert!(receiver.recv_timeout(Duration::from_millis(200)).is_err()); + + fs::remove_dir_all(root).ok(); +}