Feat/design agent simple #305

Merged
lhk229 merged 66 commits from feat/design_agent_simple into master 2026-09-09 16:34:50 +08:00
Showing only changes of commit 55377f9e51 - Show all commits
@@ -28,10 +28,6 @@ const SECTION_FILES: &[(&str, &str)] = &[
("supervisorPlaybook", "supervisor/playbook.md"),
("supervisorClaimGate", "supervisor/claim-gate.md"),
("supervisorRepair", "supervisor/repair.md"),
("planCommon", "plan/common.md"),
("planSupervisorIdentity", "plan/supervisor-identity.md"),
("planSupervisorPlaybook", "plan/supervisor-playbook.md"),
("projectPlanningRoleBrief", "roles/project-planning.md"),
(
"providerIsolatedToolContract",
"provider/isolated-tool-contract.md",
@@ -144,14 +140,6 @@ fn valid_manifest() -> Value {
"supervisorClaimGate",
"supervisorRepair"
],
"supervisorPlan": [
"$header",
"planCommon",
"isolatedAgentContract",
"planSupervisorIdentity",
"planSupervisorPlaybook",
"supervisorRepair"
],
"supervisorChat": {
"identity": "supervisorIdentityContract",
"finalReply": "supervisorFinalReplyContract"
@@ -167,12 +155,7 @@ fn valid_manifest() -> Value {
"editorUnavailable": "supervisorVisualWithoutEditor"
}
},
"roleOverlays": [
{
"agentId": "project-planning",
"sections": ["projectPlanningRoleBrief"]
}
],
"roleOverlays": [],
"providerFragments": {
"isolatedToolContract": "providerIsolatedToolContract",
"autonomousRunProfile": "providerAutonomousRunProfile",
@@ -199,21 +182,6 @@ fn valid_manifest() -> Value {
}
]
},
"planning": {
"id": "planning",
"label": "立项策划",
"role": "Project Planning",
"briefPathName": "project-planning.md",
"roles": [
{
"id": "project-planning",
"role": "Project Planning",
"taskId": "project-planning",
"toolId": "agent.runtime.project-planning",
"briefPathName": "project-planning.md"
}
]
},
"groups": [
{
"id": "code",
@@ -622,34 +590,73 @@ fn rejects_unused_registered_and_unregistered_markdown_sections() {
.contains("未登记的 Markdown section"));
}
// 基础 fixture 不携带 overlay(与生产 manifest 一致);本测试自带一份合法 overlay,
// 再逐项破坏它。overlay section 必须先落盘成普通文件——编译器先读完全部 section
// 文件才做语义校验。
fn overlay_fixture() -> Fixture {
let mut fixture = Fixture::new();
fs::create_dir_all(fixture.root().join("roles")).expect("create roles directory");
fs::write(
fixture.root().join("roles/code-director-brief.md"),
"SECTION:codeDirectorRoleBrief\n",
)
.expect("write overlay section");
fixture.manifest["sections"]["codeDirectorRoleBrief"] =
json!("roles/code-director-brief.md");
fixture.manifest["roleOverlays"] = json!([{
"agentId": "code-director",
"sections": ["codeDirectorRoleBrief"]
}]);
fixture.write_manifest();
fixture
}
fn compile_overlay_after(mutator: impl FnOnce(&mut Value)) -> Result<(), String> {
let mut fixture = overlay_fixture();
mutator(&mut fixture.manifest);
fixture.write_manifest();
fixture.compile().map(|_| ())
}
fn assert_overlay_compile_error(mutator: impl FnOnce(&mut Value), expected: &str) {
let error = compile_overlay_after(mutator).expect_err("manifest must fail closed");
assert!(
error.contains(expected),
"expected error containing {expected:?}, got {error:?}"
);
}
#[test]
fn rejects_invalid_role_overlays() {
assert_compile_error(
overlay_fixture()
.compile()
.expect("valid overlay manifest must compile");
assert_overlay_compile_error(
|manifest| manifest["roleOverlays"][0]["agentId"] = json!("unknown-agent"),
"未知 agentId",
);
assert_compile_error(
assert_overlay_compile_error(
|manifest| manifest["roleOverlays"][0]["sections"] = json!([]),
"sections 不能为空",
);
assert_compile_error(
assert_overlay_compile_error(
|manifest| manifest["roleOverlays"][0]["sections"] = json!(["missingSection"]),
"未知 section",
);
assert_compile_error(
assert_overlay_compile_error(
|manifest| {
manifest["roleOverlays"][0]["sections"] = json!(["supervisorClaimGate"]);
},
"Prompt section 跨语义所有者复用:supervisorClaimGate",
);
assert_compile_error(
assert_overlay_compile_error(
|manifest| {
manifest["roleOverlays"][0]["sections"] =
json!(["projectPlanningRoleBrief", "projectPlanningRoleBrief"]);
json!(["codeDirectorRoleBrief", "codeDirectorRoleBrief"]);
},
"重复 section",
);
assert_compile_error(
assert_overlay_compile_error(
|manifest| {
let overlay = manifest["roleOverlays"][0].clone();
manifest["roleOverlays"] = json!([overlay.clone(), overlay]);