Turn the remaining minimal-boundary items into executable behavior: locked autonomous claim scaling for 3/5/7 agents, multi-candidate fusion, and challenge-revise-revote consensus. Constraint: The user asked to implement code directly, complete testing and acceptance, and explain the test standards rather than only updating the comparison document. Rejected: Leaving SW-AQS-16, candidate fusion, and questioning consensus as documentation-only future work | each now has deterministic code paths and S09 acceptance evidence. Confidence: high Scope-risk: moderate Directive: Future claims about full production readiness must still distinguish this local deterministic S09 acceptance from real runtime/Kubernetes scaling and Manager/Agnet platform integration. Tested: .venv/bin/python -B -m py_compile swarm_minimal/*.py examples/*.py tests/*.py; .venv/bin/python -B -m unittest tests.test_standard_scenarios; .venv/bin/python -B -m unittest discover -s tests; .venv/bin/python -u -B examples/run_next_boundary_acceptance.py; .venv/bin/python -u -B examples/run_academic_standard_evaluation.py; .venv/bin/python -u -B examples/run_standard_scenario_acceptance.py; .venv/bin/python -B examples/export_model_agnet_io_report.py; .venv/bin/python -B -m unittest tests.test_model_io_report_audit; docs secret pattern scan; git diff --check. Not-tested: Real Kubernetes/worker runtime 3/5/7 scaling, Redis Stream consumer-driven replanning, and Manager/Agnet approval integration remain outside this local minimal acceptance. Co-authored-by: OmX <omx@oh-my-codex.dev>
178 lines
6.3 KiB
Python
178 lines
6.3 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
from pathlib import Path
|
|
import sys
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
sys.path.insert(0, str(ROOT))
|
|
|
|
from swarm_minimal.core import ( # noqa: E402
|
|
Agent,
|
|
CandidateOutput,
|
|
ConsensusVote,
|
|
InMemorySwarmStore,
|
|
QuestioningAgent,
|
|
QuestioningConsensusSwarm,
|
|
SwarmCoordinator,
|
|
Task,
|
|
TaskStatus,
|
|
fuse_candidate_outputs,
|
|
)
|
|
|
|
|
|
def main() -> None:
|
|
checks = [
|
|
scaled_autonomous_claim_acceptance(),
|
|
candidate_fusion_acceptance(),
|
|
questioning_consensus_acceptance(),
|
|
]
|
|
report = {
|
|
"standard": "next-boundary-minimal-acceptance-v1",
|
|
"status": "PASS" if all(check["passed"] for check in checks) else "FAIL",
|
|
"scope": {
|
|
"sw_aqs_16": "3/5/7 Agent autonomous claim and scale stress",
|
|
"candidate_fusion": "merge multiple valid candidates instead of selecting one winner only",
|
|
"questioning_consensus": "challenge, revise, and re-vote before final acceptance",
|
|
},
|
|
"checks": checks,
|
|
}
|
|
print(json.dumps(report, ensure_ascii=False, indent=2))
|
|
if report["status"] != "PASS":
|
|
raise SystemExit(1)
|
|
|
|
|
|
def scaled_autonomous_claim_acceptance() -> dict[str, object]:
|
|
cases = []
|
|
for agent_count in (3, 5, 7):
|
|
store = InMemorySwarmStore()
|
|
run_id = f"s09-scaled-claim-{agent_count}"
|
|
task_count = agent_count * 2
|
|
store.shared_state[f"run:{run_id}:goal"] = "scaled autonomous claim"
|
|
store.shared_state[f"run:{run_id}:status"] = "running"
|
|
for index in range(task_count):
|
|
store.add_task(Task(kind="stress", input=f"claim target {index}"))
|
|
|
|
agents = [
|
|
Agent(
|
|
id=f"claim-agent-{index}",
|
|
capability="stress",
|
|
run=lambda task, shared_state, index=index: (
|
|
f"agent={index}; task={task.input}; autonomous_claim=ok",
|
|
0.7 + index / 100,
|
|
),
|
|
)
|
|
for index in range(agent_count)
|
|
]
|
|
report = SwarmCoordinator(store=store, agents=agents).run_autonomous_until_converged(run_id)
|
|
claimed_agents = {event.agent_id for event in report.claim_events}
|
|
case = {
|
|
"agent_count": agent_count,
|
|
"task_count": task_count,
|
|
"completed_tasks": report.completed_tasks,
|
|
"failed_tasks": report.failed_tasks,
|
|
"duplicate_claims": list(report.duplicate_claims),
|
|
"participating_agents": len(claimed_agents),
|
|
"converged": report.converged,
|
|
"passed": (
|
|
report.converged
|
|
and report.completed_tasks == task_count
|
|
and report.failed_tasks == 0
|
|
and report.duplicate_claims == ()
|
|
and len(claimed_agents) == agent_count
|
|
and all(task.status == TaskStatus.DONE for task in store.tasks.values())
|
|
),
|
|
}
|
|
cases.append(case)
|
|
|
|
return {
|
|
"name": "sw_aqs_16_scaled_autonomous_claim_3_5_7",
|
|
"passed": all(case["passed"] for case in cases),
|
|
"evidence": cases,
|
|
}
|
|
|
|
|
|
def candidate_fusion_acceptance() -> dict[str, object]:
|
|
fused = fuse_candidate_outputs(
|
|
[
|
|
CandidateOutput("quality", "保留质量门\n保留 fallback 补救", 0.91, "quality"),
|
|
CandidateOutput("coverage", "保留 fallback 补救\n加入候选融合输出", 0.86, "coverage"),
|
|
CandidateOutput("noise", "低分噪声", 0.2, "below-threshold"),
|
|
],
|
|
min_score=0.5,
|
|
)
|
|
expected_terms = ["保留质量门", "保留 fallback 补救", "加入候选融合输出"]
|
|
passed = (
|
|
fused.source_candidate_ids == ("quality", "coverage")
|
|
and all(term in fused.text for term in expected_terms)
|
|
and "低分噪声" not in fused.text
|
|
)
|
|
return {
|
|
"name": "candidate_fusion_output",
|
|
"passed": passed,
|
|
"evidence": {
|
|
"source_candidate_ids": list(fused.source_candidate_ids),
|
|
"score": fused.score,
|
|
"contains": expected_terms,
|
|
"evidence": fused.evidence,
|
|
},
|
|
}
|
|
|
|
|
|
def questioning_consensus_acceptance() -> dict[str, object]:
|
|
result = QuestioningConsensusSwarm(
|
|
[
|
|
make_questioning_agent("critic", "反驳", "revise_again"),
|
|
make_questioning_agent("repairer", "修正", "revise_again"),
|
|
make_questioning_agent("verifier", "验收", "approve_fused_candidate"),
|
|
],
|
|
threshold=0.7,
|
|
min_margin=0.2,
|
|
max_rounds=3,
|
|
evaporation=0.85,
|
|
).run("questioning consensus", "初始候选:质量门后的最高分输出")
|
|
|
|
passed = (
|
|
result.converged
|
|
and result.accepted_candidate == "approve_fused_candidate"
|
|
and len(result.rounds) >= 2
|
|
and not result.rounds[0].consensus_round.converged
|
|
and result.rounds[-1].consensus_round.converged
|
|
and all(item.challenges for item in result.rounds)
|
|
and all(item.revisions for item in result.rounds)
|
|
)
|
|
return {
|
|
"name": "question_revise_revote_consensus",
|
|
"passed": passed,
|
|
"evidence": {
|
|
"accepted_candidate": result.accepted_candidate,
|
|
"round_count": len(result.rounds),
|
|
"first_round_converged": result.rounds[0].consensus_round.converged,
|
|
"last_round_converged": result.rounds[-1].consensus_round.converged,
|
|
},
|
|
}
|
|
|
|
|
|
def make_questioning_agent(agent_id: str, role: str, first_vote: str) -> QuestioningAgent:
|
|
return QuestioningAgent(
|
|
id=agent_id,
|
|
role=role,
|
|
weight=1.0,
|
|
challenge=lambda candidate, state, round_index, role=role: f"{role} 质询 round={round_index}: 需要补充证据",
|
|
revise=lambda candidate, challenges, state, round_index, role=role: (
|
|
f"{candidate}\n{role} 修正 round={round_index}: 已回应 {len(challenges)} 个质询"
|
|
),
|
|
vote=lambda candidate, state, round_index, agent_id=agent_id, role=role, first_vote=first_vote: ConsensusVote(
|
|
agent_id=agent_id,
|
|
role=role,
|
|
candidate=first_vote if round_index == 1 else "approve_fused_candidate",
|
|
confidence=0.55 if round_index == 1 else 0.78,
|
|
evidence=f"{role} 已检查反驳、修正和再投票",
|
|
),
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|