The standalone prototype should be the root-level project shape for fengqun while preserving the existing planning documents already at the root. This keeps README, examples, tests, and the Python package directly discoverable without deleting the prior docs. Constraint: User clarified that swarm-minimal is the repository root, but other existing root files must remain. Rejected: Deleting existing root docs | They are part of the fengqun repository context and were explicitly protected. Confidence: high Scope-risk: narrow Directive: Keep secrets in ignored .env only; do not commit live credentials. Tested: python3 -B -m unittest discover -s tests; git diff --check; secret-pattern scan showed only placeholders/test values/task-id false positives. Not-tested: Remote web UI rendering after push.
88 lines
3.3 KiB
Python
88 lines
3.3 KiB
Python
from pathlib import Path
|
|
import json
|
|
import subprocess
|
|
import sys
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
|
|
|
|
SCENARIOS = [
|
|
{
|
|
"id": "B01",
|
|
"name": "single_agnet_failure_isolation",
|
|
"claim": "single Agnet failure does not prevent result convergence",
|
|
"why": "Robustness is a core swarm property: one failed individual should not collapse the group result.",
|
|
"test": "tests.test_swarm_behavior_academic.SwarmBehaviorAcademicTest.test_single_agnet_failure_isolated_by_redundant_convergence",
|
|
},
|
|
{
|
|
"id": "B02",
|
|
"name": "emergent_consensus",
|
|
"claim": "group consensus can beat any single weak local signal",
|
|
"why": "Emergence means global behavior appears from local evidence and shared environment updates.",
|
|
"test": "tests.test_swarm_behavior_academic.SwarmBehaviorAcademicTest.test_emergent_consensus_accumulates_local_evidence",
|
|
},
|
|
{
|
|
"id": "B03",
|
|
"name": "pheromone_stigmergy",
|
|
"claim": "pheromone state biases work selection and records positive feedback",
|
|
"why": "Stigmergy is the indirect coordination mechanism that distinguishes a swarm from a plain chain.",
|
|
"test": "tests.test_swarm_behavior_academic.SwarmBehaviorAcademicTest.test_pheromone_biases_claim_order_and_records_positive_feedback",
|
|
},
|
|
{
|
|
"id": "B04",
|
|
"name": "handoff_continuity",
|
|
"claim": "handoff preserves target agent, active-agent state, and context payload",
|
|
"why": "LangGraph Swarm centers on dynamic control handoff between named specialized agents.",
|
|
"test": "tests.test_swarm_behavior_academic.SwarmBehaviorAcademicTest.test_langgraph_style_handoff_preserves_active_agent_and_payload",
|
|
},
|
|
]
|
|
|
|
|
|
def main() -> None:
|
|
results = []
|
|
for scenario in SCENARIOS:
|
|
command = [sys.executable, "-B", "-m", "unittest", scenario["test"]]
|
|
completed = subprocess.run(
|
|
command,
|
|
cwd=ROOT,
|
|
text=True,
|
|
capture_output=True,
|
|
timeout=120,
|
|
)
|
|
results.append(
|
|
{
|
|
"id": scenario["id"],
|
|
"name": scenario["name"],
|
|
"claim": scenario["claim"],
|
|
"why": scenario["why"],
|
|
"command": " ".join(command),
|
|
"passed": completed.returncode == 0,
|
|
"evidence": summarize_output(completed.stdout, completed.stderr),
|
|
}
|
|
)
|
|
if completed.returncode != 0:
|
|
break
|
|
|
|
report = {
|
|
"standard": "swarm-behavior-academic-v1",
|
|
"status": "PASS" if len(results) == len(SCENARIOS) and all(item["passed"] for item in results) else "FAIL",
|
|
"basis": [
|
|
"Swarm claims: decentralized/self-organizing behavior, stigmergy, robustness, emergence, convergence.",
|
|
"LangGraph Swarm claims: named agents, active-agent routing, and create_handoff_tool-style transfer.",
|
|
],
|
|
"scenarios": results,
|
|
}
|
|
print(json.dumps(report, ensure_ascii=False, indent=2))
|
|
if report["status"] != "PASS":
|
|
raise SystemExit(1)
|
|
|
|
|
|
def summarize_output(stdout: str, stderr: str) -> dict[str, str]:
|
|
combined = "\n".join(part.strip() for part in [stdout, stderr] if part.strip())
|
|
return {"tail": combined[-1000:] if combined else "<no output>"}
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|