把本仓从「Master 分解→派发→单评审」重构为去中心化自组织蜂群,并设为唯一行为
(本仓即 swarm 运行时,模式选择在仓外,无 ENABLE_swarm 开关)。依据:heicodeDocs 弱中心
定义 + 蜂群文章(stigmergy)+ OpenAI Swarm(handoff)。
流程(全部无条件生效):
- 播种 build_seed_task_specs(不主控分解)→ 自选 swarm_dispatch(能力+τ+负载+预算,唯一派发)
→ 自主分解 task_proposal(autonomous_tasks)→ 竞争/接管 task_bid/yield/takeover(task_competition)
→ 同伴交叉评审 ≥2 评审者(cross_review,取代单 critic)→ 收敛 ConvergenceReport+termination_reason
(convergence)→ 守卫 guard.diagnose(检测无法运作并列原因)。
删除:planner 主控分解、贪心/ACO/scored 派发与 scored_matchmake、单 critic 评审环、
全部 ENABLE_* swarm 构建开关。master_agent.synthesize 作为汇总工具保留。
测试:test-workflow-e2e 改写为真实 swarm 全流程;test-merge-smoke 改为 seeder/cross-review;
新增 test-swarm-{seed,dispatch,autonomous,competition,cross-review,convergence,guard} + 模块单测;
CI 同步。本地 18 套全绿。
影响范围:agent_swarm(orchestrator + 新模块 + 测试 + docs + CI)。不改 Manager↔Swarm 事件契约
(新事件均为运行时内部状态/遥测,不进 HM 注册表);不影响 Client/计费/密钥/审计/发布链路。
无新增长期开关。
诚实边界:不动 benchmark 验收(G_E 仍需真实 run,#13);convergence 暂为解释性(不强制覆盖
run.status);前端可见状态为跨端(#18);「去中心化是否更优」未证(需 Group C)。
#6 的 DoD(Path B 决策 + 定位文档)本 PR 已满足并实现 Path B → 关闭 #6。
#7/#8/#11/#12 的运行时机制已落地(事件 + e2e),但其 DoD 含前端可见状态(跨端 #18)与
多 Agent 回放,故以 Refs 链接、不自动关闭,留维护者在前端/验收就绪后关闭。
Closes #6
Refs #7
Refs #8
Refs #11
Refs #12
Refs #18
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
52 lines
1.9 KiB
Python
52 lines
1.9 KiB
Python
"""Unit test for the decentralized-rework seeder (build_seed_task_specs, #6 Path B / P2).
|
|
|
|
The seeder turns an objective into ONE seed task with NO up-front Master decomposition. This tests
|
|
the pure function; wiring it as the swarm-only task-creation path (deleting the planner fallback)
|
|
happens at P-cutover once agent-driven decomposition (#7) exists — see
|
|
docs/swarm/decentralized-rework-plan.md. No flag, no Redis, no model.
|
|
|
|
Run from agent_swarm_v6:
|
|
python scripts/test-swarm-seed.py
|
|
"""
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
|
|
|
from orchestrator.main import build_seed_task_specs
|
|
|
|
failures = []
|
|
|
|
|
|
def check(name, cond):
|
|
print(("PASS" if cond else "FAIL"), "-", name)
|
|
if not cond:
|
|
failures.append(name)
|
|
|
|
|
|
class _StubRun:
|
|
"""Minimal stand-in: build_seed_task_specs only reads run.objective."""
|
|
objective = "Build a CSV parser with tests and docs"
|
|
|
|
|
|
specs = build_seed_task_specs(_StubRun(), body={}, base_specs=[])
|
|
|
|
check("seeds exactly ONE task", len(specs) == 1)
|
|
seed = specs[0] if specs else {}
|
|
check("source = 'seed'", seed.get("source") == "seed")
|
|
check("carries the objective", "CSV parser" in (seed.get("description") or ""))
|
|
check("no required capabilities (any agent may self-select)", seed.get("required_capabilities") == [])
|
|
check("workflow_mode = swarm", seed.get("workflow_mode") == "swarm")
|
|
check("context marks is_seed + objective",
|
|
(seed.get("context") or {}).get("is_seed") is True and (seed.get("context") or {}).get("objective"))
|
|
check("no depends_on (it's the root seed)", seed.get("depends_on") == [])
|
|
# The seeder is a PURE spec builder — it must not itself decompose / call any planner.
|
|
check("seeder does not pre-decompose (single root task only)",
|
|
len(specs) == 1 and seed.get("root_task_id") == "seed")
|
|
|
|
print()
|
|
if failures:
|
|
print(f"{len(failures)} seeder (P2) check(s) FAILED: {failures}")
|
|
sys.exit(1)
|
|
print("all swarm seeder (P2) unit checks passed")
|