同步自主首批任务图测试夹具
补齐可信 Supervisor 根任务与三 Leader 首批合同测试数据 更新视觉失败和 Ready 任务调度断言以匹配最新任务图 修复 Provider 重试恢复响应仍使用旧底层 Agent 合同的问题
This commit is contained in:
@@ -1609,6 +1609,24 @@ mod tests {
|
||||
let root = temporary.path().join("project");
|
||||
init_local_game_project_at(&root, "manifest-dag-policy", "测试正式任务图等待")
|
||||
.expect("init manifest DAG policy project");
|
||||
let session_id = resolve_agent_conversation_session_id_at(
|
||||
&root,
|
||||
GAME_CREATOR_PROJECT_SUPERVISOR_AGENT_ID,
|
||||
None,
|
||||
true,
|
||||
)
|
||||
.expect("resolve manifest DAG Supervisor session");
|
||||
append_unique_game_creator_agent_runtime_pending_task(
|
||||
&root,
|
||||
GAME_CREATOR_PROJECT_SUPERVISOR_AGENT_ID,
|
||||
&session_id,
|
||||
"测试正式任务图等待",
|
||||
"manifest-dag-policy-run",
|
||||
AGENT_RUNTIME_SUPERVISOR_CLI_SOURCE,
|
||||
Some(AGENT_RUNTIME_RUN_PROFILE_AUTONOMOUS_GAME_BUILD),
|
||||
None,
|
||||
)
|
||||
.expect("queue trusted autonomous root task");
|
||||
assert!(!autonomous_manifest_dag_in_progress_at(&root).expect("read pending DAG"));
|
||||
|
||||
update_manifest_task_status_at(
|
||||
|
||||
@@ -937,14 +937,16 @@ async fn missing_completed_visual_asset_fails_same_child_without_retry() {
|
||||
"missing visual output must fail the current logical task"
|
||||
);
|
||||
|
||||
assert!(schedule_autonomous_game_build_ready_tasks_at(
|
||||
let scheduled_after_failure = schedule_autonomous_game_build_ready_tasks_at(
|
||||
&root,
|
||||
GAME_CREATOR_PROJECT_SUPERVISOR_AGENT_ID,
|
||||
PARENT_RUN_ID,
|
||||
1,
|
||||
)
|
||||
.expect("repeat scheduling after visual failure")
|
||||
.is_empty());
|
||||
.expect("schedule other ready work after visual failure");
|
||||
assert!(scheduled_after_failure
|
||||
.iter()
|
||||
.all(|scheduled| scheduled.state.agent_id != CHILD_ID));
|
||||
let records = read_all_game_creator_agent_runtime_tasks(&game_creator_agent_runtime_task_path(
|
||||
&root, CHILD_ID,
|
||||
))
|
||||
|
||||
+66
-136
@@ -300,55 +300,36 @@ async fn supervisor_autonomous_durable_batch_rejects_invalid_responsibilities_wi
|
||||
let AgentRuntimeProviderActionBatchPreparation::Ready(valid_batch) = preparation else {
|
||||
panic!("valid autonomous responsibilities must form a ready durable batch");
|
||||
};
|
||||
assert_eq!(valid_batch.actions.len(), 2);
|
||||
assert_eq!(valid_batch.actions.len(), 3);
|
||||
assert!(valid_batch.collaboration_contract.is_some());
|
||||
let valid_batch_id = valid_batch.batch_id.clone();
|
||||
let mut quality_not_read_only = autonomous_initial_responsibility_actions_for_test(
|
||||
"创建或修改 game/index.html,完成可直接试玩的游戏实现并执行静态验证。",
|
||||
&["game/index.html"],
|
||||
"直接修改 game/index.html,修复试玩阻塞并重新验证。",
|
||||
&[],
|
||||
);
|
||||
quality_not_read_only[1].input["acceptanceCriteria"] = serde_json::json!([
|
||||
"直接写入 game/index.html 修复试玩问题",
|
||||
"修改后执行静态验证并交付新 revision"
|
||||
]);
|
||||
let mut design_not_read_only = valid_autonomous_initial_responsibility_actions_for_test();
|
||||
design_not_read_only[0].input["task"] = serde_json::json!("直接修改项目并完成首轮策划实现。");
|
||||
design_not_read_only[0].input["acceptanceCriteria"] = serde_json::json!(["直接修改项目文件"]);
|
||||
let mut design_with_artifacts = valid_autonomous_initial_responsibility_actions_for_test();
|
||||
design_with_artifacts[0].input["expectedArtifacts"] =
|
||||
serde_json::json!(["game/game_design.md"]);
|
||||
let mut art_missing_spec = valid_autonomous_initial_responsibility_actions_for_test();
|
||||
art_missing_spec[1].input["expectedArtifacts"] = serde_json::json!(["assets/art-preview.png"]);
|
||||
let mut code_with_artifacts = valid_autonomous_initial_responsibility_actions_for_test();
|
||||
code_with_artifacts[2].input["expectedArtifacts"] = serde_json::json!(["game/index.html"]);
|
||||
|
||||
let invalid_cases = vec![
|
||||
(
|
||||
"code-missing-game-index",
|
||||
"game/index.html",
|
||||
autonomous_initial_responsibility_actions_for_test(
|
||||
"创建可直接试玩的游戏实现并执行静态验证。",
|
||||
&["game/main.js"],
|
||||
"只读验收 game/index.html 的可玩性;不要修改任何项目文件。",
|
||||
&[],
|
||||
),
|
||||
"design-not-read-only",
|
||||
"design-director",
|
||||
design_not_read_only,
|
||||
),
|
||||
(
|
||||
"code-read-only",
|
||||
"code-prototype",
|
||||
autonomous_initial_responsibility_actions_for_test(
|
||||
"只读检查 game/index.html,不要修改任何项目文件。",
|
||||
&["game/index.html"],
|
||||
"只读验收 game/index.html 的可玩性;不要修改任何项目文件。",
|
||||
&[],
|
||||
),
|
||||
),
|
||||
(
|
||||
"quality-not-read-only",
|
||||
"quality-review",
|
||||
quality_not_read_only,
|
||||
),
|
||||
(
|
||||
"quality-with-artifacts",
|
||||
"design-with-artifacts",
|
||||
"expectedArtifacts",
|
||||
autonomous_initial_responsibility_actions_for_test(
|
||||
"创建或修改 game/index.html,完成可直接试玩的游戏实现并执行静态验证。",
|
||||
&["game/index.html"],
|
||||
"只读验收 game/index.html 的可玩性;不要修改任何项目文件。",
|
||||
&["game/index.html"],
|
||||
),
|
||||
design_with_artifacts,
|
||||
),
|
||||
("art-missing-spec", "assets/art-spec.png", art_missing_spec),
|
||||
(
|
||||
"code-with-artifacts",
|
||||
"expectedArtifacts",
|
||||
code_with_artifacts,
|
||||
),
|
||||
];
|
||||
for (case_name, expected_error, actions) in invalid_cases {
|
||||
@@ -389,12 +370,7 @@ async fn supervisor_autonomous_durable_batch_rejects_invalid_responsibilities_wi
|
||||
rewrite_autonomous_responsibility_batch_actions_for_test(
|
||||
&root,
|
||||
&mut legacy_v2_batch,
|
||||
autonomous_initial_responsibility_actions_for_test(
|
||||
"创建或修改 game/index.html,完成可直接试玩的游戏实现并执行静态验证。",
|
||||
&["game/index.html"],
|
||||
"直接修改 game/index.html,修复试玩阻塞并重新验证。",
|
||||
&[],
|
||||
),
|
||||
valid_autonomous_initial_responsibility_actions_for_test(),
|
||||
);
|
||||
let legacy_v2_schema = "game-creator-provider-action-batch.v2";
|
||||
legacy_v2_batch.schema_version = legacy_v2_schema.to_string();
|
||||
@@ -600,68 +576,37 @@ async fn autonomous_game_build_repairs_supervisor_failed_playtest_stall_into_mut
|
||||
fs::remove_dir_all(root).ok();
|
||||
}
|
||||
|
||||
fn autonomous_initial_responsibility_actions_for_test(
|
||||
code_task: &str,
|
||||
code_artifacts: &[&str],
|
||||
quality_task: &str,
|
||||
quality_artifacts: &[&str],
|
||||
) -> Vec<AgentRuntimeToolAction> {
|
||||
fn valid_autonomous_initial_responsibility_actions_for_test() -> Vec<AgentRuntimeToolAction> {
|
||||
vec![
|
||||
AgentRuntimeToolAction {
|
||||
tool: "agent.delegate".to_string(),
|
||||
reason: Some("委派程序 Agent 形成可玩入口".to_string()),
|
||||
input: serde_json::json!({
|
||||
"agentId": "code-prototype",
|
||||
"task": code_task,
|
||||
"acceptanceCriteria": [
|
||||
"game/index.html 必须形成可直接试玩的完整入口",
|
||||
"程序交付必须完成当前 revision 的静态验证"
|
||||
],
|
||||
"expectedArtifacts": code_artifacts,
|
||||
"repairOfDelegationId": null,
|
||||
"runId": null
|
||||
}),
|
||||
},
|
||||
AgentRuntimeToolAction {
|
||||
tool: "agent.delegate".to_string(),
|
||||
reason: Some("委派质量 Agent 独立只读验收".to_string()),
|
||||
input: serde_json::json!({
|
||||
"agentId": "quality-review",
|
||||
"task": quality_task,
|
||||
"acceptanceCriteria": [
|
||||
"只读核对可玩性、交互闭环和阻塞问题",
|
||||
"返回可追溯的验收结论,不修改项目文件"
|
||||
],
|
||||
"expectedArtifacts": quality_artifacts,
|
||||
"repairOfDelegationId": null,
|
||||
"runId": null
|
||||
}),
|
||||
},
|
||||
autonomous_initial_leader_responsibility_action_for_test("design-director", &[]),
|
||||
autonomous_initial_leader_responsibility_action_for_test(
|
||||
"art-director",
|
||||
&["assets/art-spec.png"],
|
||||
),
|
||||
autonomous_initial_leader_responsibility_action_for_test("code-director", &[]),
|
||||
]
|
||||
}
|
||||
|
||||
fn valid_autonomous_initial_responsibility_actions_for_test() -> Vec<AgentRuntimeToolAction> {
|
||||
autonomous_initial_responsibility_actions_for_test(
|
||||
"创建或修改 game/index.html,完成可直接试玩的游戏实现并执行静态验证。",
|
||||
&["game/index.html"],
|
||||
"只读验收 game/index.html 的可玩性与交互闭环;不要修改任何项目文件。",
|
||||
&[],
|
||||
)
|
||||
}
|
||||
|
||||
fn autonomous_art_director_responsibility_action_for_test(
|
||||
fn autonomous_initial_leader_responsibility_action_for_test(
|
||||
agent_id: &str,
|
||||
expected_artifacts: &[&str],
|
||||
) -> AgentRuntimeToolAction {
|
||||
let read_only = matches!(agent_id, "design-director" | "code-director");
|
||||
AgentRuntimeToolAction {
|
||||
tool: "agent.delegate".to_string(),
|
||||
reason: Some("委派美术总监生成统一视觉规范图".to_string()),
|
||||
reason: Some("建立首批 Leader 专业规划".to_string()),
|
||||
input: serde_json::json!({
|
||||
"agentId": "art-director",
|
||||
"task": "生成项目统一视觉规范图并写入项目资产目录。",
|
||||
"acceptanceCriteria": [
|
||||
"使用画布生成接口产出后续 UI 与图集共用的规范图",
|
||||
"生成结果必须登记为项目本地 icon-spec 资产"
|
||||
],
|
||||
"agentId": agent_id,
|
||||
"task": if read_only {
|
||||
format!("由 {agent_id} 只读完成首轮专业规划,不得修改项目")
|
||||
} else {
|
||||
"生成首轮统一视觉规范图供后续专业 Agent 使用".to_string()
|
||||
},
|
||||
"acceptanceCriteria": if read_only {
|
||||
serde_json::json!(["只读输出专业规划,不得修改项目文件"])
|
||||
} else {
|
||||
serde_json::json!(["生成并登记统一视觉规范图"])
|
||||
},
|
||||
"expectedArtifacts": expected_artifacts,
|
||||
"repairOfDelegationId": null,
|
||||
"runId": null
|
||||
@@ -713,9 +658,7 @@ async fn supervisor_autonomous_initial_art_director_requires_canonical_art_spec_
|
||||
)
|
||||
.expect("start autonomous Supervisor runtime");
|
||||
let mut actions = valid_autonomous_initial_responsibility_actions_for_test();
|
||||
actions.push(autonomous_art_director_responsibility_action_for_test(&[
|
||||
"assets/art-preview.png",
|
||||
]));
|
||||
actions[1].input["expectedArtifacts"] = serde_json::json!(["assets/art-preview.png"]);
|
||||
let plan = supervisor_collaboration_plan_for_test(actions);
|
||||
let revision = read_game_creator_agent_runtime_project_revision(&root)
|
||||
.expect("read art contract project revision");
|
||||
@@ -834,40 +777,21 @@ async fn supervisor_autonomous_initial_responsibilities_reject_invalid_plans_bef
|
||||
)
|
||||
.expect("start autonomous Supervisor runtime");
|
||||
|
||||
let code_missing_game_index = autonomous_initial_responsibility_actions_for_test(
|
||||
"创建可直接试玩的游戏实现并执行静态验证。",
|
||||
&["game/main.js"],
|
||||
"只读验收 game/index.html 的可玩性;不要修改任何项目文件。",
|
||||
&[],
|
||||
);
|
||||
let code_read_only = autonomous_initial_responsibility_actions_for_test(
|
||||
"只读检查 game/index.html,不要修改任何项目文件。",
|
||||
&["game/index.html"],
|
||||
"只读验收 game/index.html 的可玩性;不要修改任何项目文件。",
|
||||
&[],
|
||||
);
|
||||
let mut quality_not_read_only = autonomous_initial_responsibility_actions_for_test(
|
||||
"创建或修改 game/index.html,完成可直接试玩的游戏实现并执行静态验证。",
|
||||
&["game/index.html"],
|
||||
"直接修改 game/index.html,修复试玩阻塞并重新验证。",
|
||||
&[],
|
||||
);
|
||||
quality_not_read_only[1].input["acceptanceCriteria"] = serde_json::json!([
|
||||
"直接写入 game/index.html 修复试玩问题",
|
||||
"修改后执行静态验证并交付新 revision"
|
||||
]);
|
||||
let quality_with_artifacts = autonomous_initial_responsibility_actions_for_test(
|
||||
"创建或修改 game/index.html,完成可直接试玩的游戏实现并执行静态验证。",
|
||||
&["game/index.html"],
|
||||
"只读验收 game/index.html 的可玩性;不要修改任何项目文件。",
|
||||
&["game/index.html"],
|
||||
);
|
||||
let valid = valid_autonomous_initial_responsibility_actions_for_test();
|
||||
let mut missing_design = valid.clone();
|
||||
missing_design.remove(0);
|
||||
let mut design_not_read_only = valid.clone();
|
||||
design_not_read_only[0].input["task"] = serde_json::json!("直接修改项目完成策划实现");
|
||||
design_not_read_only[0].input["acceptanceCriteria"] = serde_json::json!(["直接修改项目文件"]);
|
||||
let mut art_missing_spec = valid.clone();
|
||||
art_missing_spec[1].input["expectedArtifacts"] = serde_json::json!(["assets/art-preview.png"]);
|
||||
let mut code_with_artifacts = valid.clone();
|
||||
code_with_artifacts[2].input["expectedArtifacts"] = serde_json::json!(["game/index.html"]);
|
||||
let responses = [
|
||||
("code-missing-game-index", &code_missing_game_index),
|
||||
("code-read-only", &code_read_only),
|
||||
("quality-not-read-only", &quality_not_read_only),
|
||||
("quality-with-artifacts", &quality_with_artifacts),
|
||||
("missing-design", &missing_design),
|
||||
("design-not-read-only", &design_not_read_only),
|
||||
("art-missing-spec", &art_missing_spec),
|
||||
("code-with-artifacts", &code_with_artifacts),
|
||||
("valid-responsibilities", &valid),
|
||||
]
|
||||
.into_iter()
|
||||
@@ -904,7 +828,13 @@ async fn supervisor_autonomous_initial_responsibilities_reject_invalid_plans_bef
|
||||
.await
|
||||
.expect("repair invalid initial responsibilities")
|
||||
.expect("valid initial responsibility plan");
|
||||
assert_eq!(plan.actions, valid);
|
||||
let mut expected_valid = valid.clone();
|
||||
expected_valid.sort_by(|left, right| {
|
||||
left.input["agentId"]
|
||||
.as_str()
|
||||
.cmp(&right.input["agentId"].as_str())
|
||||
});
|
||||
assert_eq!(plan.actions, expected_valid);
|
||||
assert!(plan.response.is_empty());
|
||||
|
||||
let requests = (0..5)
|
||||
|
||||
@@ -4922,24 +4922,36 @@ async fn provider_transient_retry_autonomous_upstream_400_retries_with_bounded_b
|
||||
.expect("project init");
|
||||
let delegate_function =
|
||||
native_runtime_function_name("agent.delegate").expect("delegate function");
|
||||
let code_arguments = serde_json::json!({
|
||||
"reason": "委派可玩原型实现",
|
||||
let design_arguments = serde_json::json!({
|
||||
"reason": "委派策划 Leader",
|
||||
"input": {
|
||||
"agentId": "code-prototype",
|
||||
"task": "实现可直接试玩的游戏原型",
|
||||
"acceptanceCriteria": ["项目能够启动并完成最小玩法闭环"],
|
||||
"expectedArtifacts": ["game/index.html"],
|
||||
"agentId": "design-director",
|
||||
"task": "只读拆解首轮玩法目标和专业分工,不得修改项目",
|
||||
"acceptanceCriteria": ["只读输出策划规划,不得修改项目文件"],
|
||||
"expectedArtifacts": [],
|
||||
"repairOfDelegationId": null,
|
||||
"runId": null
|
||||
}
|
||||
})
|
||||
.to_string();
|
||||
let quality_arguments = serde_json::json!({
|
||||
"reason": "委派独立质量评审",
|
||||
let art_arguments = serde_json::json!({
|
||||
"reason": "委派美术 Leader",
|
||||
"input": {
|
||||
"agentId": "quality-review",
|
||||
"task": "只读评审可玩性与闯关闭环,不要修改任何项目文件",
|
||||
"acceptanceCriteria": ["只读给出阻塞试玩的问题和验收结论"],
|
||||
"agentId": "art-director",
|
||||
"task": "生成首轮统一视觉规范图供后续专业 Agent 使用",
|
||||
"acceptanceCriteria": ["生成并登记统一视觉规范图"],
|
||||
"expectedArtifacts": ["assets/art-spec.png"],
|
||||
"repairOfDelegationId": null,
|
||||
"runId": null
|
||||
}
|
||||
})
|
||||
.to_string();
|
||||
let code_arguments = serde_json::json!({
|
||||
"reason": "委派程序 Leader",
|
||||
"input": {
|
||||
"agentId": "code-director",
|
||||
"task": "只读拆解首轮程序实现边界,不得修改项目",
|
||||
"acceptanceCriteria": ["只读输出程序规划,不得修改项目文件"],
|
||||
"expectedArtifacts": [],
|
||||
"repairOfDelegationId": null,
|
||||
"runId": null
|
||||
@@ -4947,16 +4959,21 @@ async fn provider_transient_retry_autonomous_upstream_400_retries_with_bounded_b
|
||||
})
|
||||
.to_string();
|
||||
let recovered_response = native_agent_tool_plan_chat_response_with_calls(vec![
|
||||
(
|
||||
"call-autonomous-upstream-400-design",
|
||||
delegate_function.as_str(),
|
||||
design_arguments,
|
||||
),
|
||||
(
|
||||
"call-autonomous-upstream-400-art",
|
||||
delegate_function.as_str(),
|
||||
art_arguments,
|
||||
),
|
||||
(
|
||||
"call-autonomous-upstream-400-code",
|
||||
delegate_function.as_str(),
|
||||
code_arguments,
|
||||
),
|
||||
(
|
||||
"call-autonomous-upstream-400-quality",
|
||||
delegate_function.as_str(),
|
||||
quality_arguments,
|
||||
),
|
||||
]);
|
||||
let (request_notice_sender, request_notice_receiver) = mpsc::channel();
|
||||
let base_url = spawn_mock_llm_upstream_400_then_raw_response(
|
||||
@@ -5042,7 +5059,7 @@ async fn provider_transient_retry_autonomous_upstream_400_retries_with_bounded_b
|
||||
assert!(request_notice_receiver
|
||||
.recv_timeout(Duration::from_millis(100))
|
||||
.is_err());
|
||||
assert_eq!(plan.actions.len(), 2);
|
||||
assert_eq!(plan.actions.len(), 3);
|
||||
assert!(plan
|
||||
.actions
|
||||
.iter()
|
||||
|
||||
@@ -707,7 +707,7 @@ async fn background_agent_runtime_can_schedule_ready_manifest_tasks() {
|
||||
));
|
||||
|
||||
let scheduled =
|
||||
schedule_game_creator_agent_ready_tasks_at(&root, 0).expect("schedule ready tasks");
|
||||
schedule_game_creator_agent_ready_tasks_at(&root, 1).expect("schedule one ready task");
|
||||
assert_eq!(scheduled.len(), 1);
|
||||
assert_eq!(scheduled[0].state.agent_id, "design-director");
|
||||
assert_eq!(scheduled[0].state.source, "agent-ready-task-scheduler");
|
||||
|
||||
Reference in New Issue
Block a user