Files
fengqun/examples/run_continuous_reasoning_acceptance.py
T
gongzhiyongandOmX cd2431ece2 Add minimal quality-gated convergence
Promote the S07 external FastAPI chain from score-only acceptance to a minimal quality-gated flow with refusal detection, retry/fallback recovery, handoff quality checks, and a multi-round consensus gate before final convergence.

Constraint: The user asked to fix the documented shortcomings around score-only convergence, weak refusal scoring, and unqualified handoff evidence while continuing the minimal version.

Rejected: Replacing the whole coordinator with a production consensus runtime | the minimal fix keeps the existing task pool/convergence shape and adds scenario-level quality gates plus consensus evidence.

Confidence: high

Scope-risk: moderate

Directive: Future S07 runs must keep all_outputs_pass_quality_gate and multi_round_quality_consensus_accepts_chain as required checks before claiming PASS.

Tested: .venv/bin/python -B -m unittest tests.test_standard_scenarios; .venv/bin/python -u -B examples/run_continuous_reasoning_acceptance.py; .venv/bin/python -B examples/export_model_agnet_io_report.py; .venv/bin/python -B -m unittest discover -s tests; .venv/bin/python -B -m py_compile swarm_minimal/*.py examples/*.py tests/*.py; .venv/bin/python -u -B examples/run_academic_standard_evaluation.py; .venv/bin/python -B -m unittest tests.test_model_io_report_audit; git diff --check; docs secret pattern scan.

Not-tested: The combined run_standard_scenario_acceptance wrapper was not rerun after report export to avoid creating a newer live run that would make the exported latest-run report stale.

Co-authored-by: OmX <omx@oh-my-codex.dev>
2026-05-16 16:35:00 +08:00

940 lines
36 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from pathlib import Path
from uuid import uuid4
import json
import sys
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT))
from swarm_minimal.azure_store import PostgresRedisBlobSwarmStore
from swarm_minimal.config import SwarmConfig
from swarm_minimal.core import Agent, ConsensusAgent, ConsensusSwarm, ConsensusVote, SwarmCoordinator, Task
from swarm_minimal.local_env import load_project_env
from swarm_minimal.newapi_agnet import (
NewApiAgnet,
NewApiChannelConfig,
discover_newapi_models,
select_distinct_models,
)
EXTERNAL_REPO = "fastapi/fastapi"
EXTERNAL_REPO_URL = "https://github.com/fastapi/fastapi"
EXTERNAL_REPO_COMMIT = "ecace740f3eaccb1aba152cf1de79477095c56f4"
TARGET_FILES = [
"fastapi/routing.py",
"fastapi/dependencies/utils.py",
"fastapi/openapi/utils.py",
"fastapi/params.py",
"fastapi/encoders.py",
"fastapi/applications.py",
"tests/test_serialize_response_model.py",
"tests/test_response_model_data_filter.py",
]
LOCAL_PROJECT_TARGETS = [
"swarm_minimal/core.py",
"swarm_minimal/newapi_agnet.py",
"swarm_minimal/azure_store.py",
"examples/run_multitask_complex_acceptance.py",
"examples/run_long_task_acceptance.py",
"tests/test_newapi_agnet.py",
"tests/test_minimal_swarm.py",
]
QUALITY_RISK_MARKERS = [
"i appreciate the detailed context",
"i need to clarify my actual role",
"what i can actually do",
"what i cannot do",
"not a component in a multi-step reasoning swarm",
"fake \"previous context\"",
"fabricated context",
"cannot participate",
"can't participate",
]
QUALITY_RISK_PENALTY_SCORE = 0.12
QUALITY_PASS_MIN_SCORE = 0.72
SCENARIO = {
"title": "外部 GitHub 代码场景:审查 fastapi/fastapi 响应序列化与 OpenAPI 依赖链",
"repository": EXTERNAL_REPO_URL,
"commit": EXTERNAL_REPO_COMMIT,
"description": (
f"目标项目固定为 GitHub `{EXTERNAL_REPO}` at `{EXTERNAL_REPO_COMMIT}`。"
"同一复杂外部代码问题必须被连续推理,而不是拆开独立回答。"
"每个 Agnet 接住前一步的结论、约束和风险,围绕 FastAPI 的路由、依赖注入、"
"OpenAPI 生成、响应模型序列化和测试覆盖继续推进,最终形成外部仓库级修复方案。"
),
}
CHAIN_STEPS = [
{
"capability": "chain_step_01",
"marker": "STEP-01",
"title": "界定问题和不可变约束",
"ask": "定义 FastAPI 外部代码审查任务的目标、输入输出、不变量、仓库边界和禁止自测边界。",
},
{
"capability": "chain_step_02",
"marker": "STEP-02",
"title": "建立依赖图和状态模型",
"ask": "基于 STEP-01 建立 FastAPI 路由、依赖注入、OpenAPI、响应序列化和测试文件之间的依赖图。",
},
{
"capability": "chain_step_03",
"marker": "STEP-03",
"title": "定位跨文件风险路径",
"ask": "基于 STEP-02 定位 response_model、Depends、参数 metadata、jsonable_encoder 与 OpenAPI schema 之间可能漂移的风险路径,给复杂度。",
},
{
"capability": "chain_step_04",
"marker": "STEP-04",
"title": "构造反例和失败场景",
"ask": "基于 STEP-03 构造 FastAPI 外部仓库中的反例:响应过滤、默认值、nullable、依赖参数和 OpenAPI schema 不一致。",
},
{
"capability": "chain_step_05",
"marker": "STEP-05",
"title": "修正算法和恢复策略",
"ask": "基于 STEP-04 给出修正策略:应该改哪些 FastAPI 模块、如何保持兼容、如何避免破坏 Starlette/Pydantic 交互。",
},
{
"capability": "chain_step_06",
"marker": "STEP-06",
"title": "落到文件级实现计划",
"ask": "基于 STEP-05 给出 fastapi/fastapi 文件级补丁计划,必须引用目标源码文件和测试文件。",
},
{
"capability": "chain_step_07",
"marker": "STEP-07",
"title": "最终收敛和验收判定",
"ask": "基于 STEP-06 给出 fastapi/fastapi 最终可执行验收命令、指标、失败判定和可合并结论。",
},
]
ACCEPTANCE_CRITERIA = [
f"测试目标必须是外部 GitHub 项目 `{EXTERNAL_REPO}`,commit `{EXTERNAL_REPO_COMMIT}`,不能把当前仓库当成被测代码。",
"自动发现至少 3 个模型,并使用 3 个互不相同的模型参与连续推理。",
"7 个连续推理步骤必须全部完成,且状态写入 PostgreSQL task pool。",
"每一步输出必须引用自己的 STEP 标记;除 STEP-01 外必须引用前一步 STEP 标记。",
"共享状态必须保存每一步 summary,并把 chain cursor 推进到 STEP-07。",
"PostgreSQL 和 Redis pheromone score 必须都有正分。",
"最终收敛必须写入 PostgreSQL,并存在 Blob artifact。",
"Redis Stream 必须新增至少 3*N+1 条事件。",
"合并输出必须体现 FastAPI 外部代码的不变量、依赖图、复杂度、反例、修正、文件级计划和验收命令。",
"最终输出必须引用至少 5 个 fastapi/fastapi 真实文件。",
"流程必须依赖模型发现,不能写死 NEWAPI_MODEL。",
"模型输出如果出现拒答、角色拒绝、偏题或本仓库漂移,必须被质量门扣分,并触发同模型重试或 fallback 模型接手。",
"每一步输出必须通过交接质量门,证明它同时保留当前 STEP、前序 STEP、外部仓库、commit、FastAPI 技术语义和下一步交接。",
"最终接受结果必须通过多角色、多轮质量共识门;第一轮只能形成候选,第二轮或以后达成收敛才算通过。",
]
def main() -> None:
load_project_env(ROOT)
azure_config = SwarmConfig.from_env()
newapi_config = NewApiChannelConfig.from_env()
if newapi_config.timeout_seconds < 360:
newapi_config = NewApiChannelConfig(
base_url=newapi_config.base_url,
api_key=newapi_config.api_key,
model=newapi_config.model,
timeout_seconds=360,
)
store = PostgresRedisBlobSwarmStore(azure_config)
try:
store.ensure_schema()
discovered_models = discover_newapi_models(newapi_config)
selected_models = select_responsive_models(newapi_config, discovered_models, count=3)
run_id = uuid4().hex
stream_before = store._run_redis(lambda redis: redis.xlen("swarm:events"))
store.shared_state[f"run:{run_id}:goal"] = SCENARIO["title"]
store.shared_state[f"run:{run_id}:status"] = "running"
store.shared_state[f"chain:{run_id}:cursor"] = "START"
store.shared_state[f"chain:{run_id}:expected_steps"] = str(len(CHAIN_STEPS))
agents: list[Agent] = []
task_ids: list[str] = []
task_models: dict[str, str] = {}
for index, step in enumerate(CHAIN_STEPS):
model = selected_models[index % len(selected_models)]
task = Task(
kind=step["capability"],
input=build_step_prompt(step, index, model),
)
store.add_task(task)
task_ids.append(task.id)
task_models[task.id] = model
fallback_models = [candidate for candidate in selected_models if candidate != model]
agents.append(build_chain_agent(newapi_config, model, fallback_models, index, step, run_id))
result = SwarmCoordinator(store=store, agents=agents).run_until_converged(run_id)
report = collect_report(
store=store,
run_id=run_id,
result=result,
discovered_models=discovered_models,
selected_models=selected_models,
task_ids=task_ids,
task_models=task_models,
stream_before=stream_before,
)
print(json.dumps(report, ensure_ascii=False, indent=2))
if report["summary"]["status"] != "PASS":
raise SystemExit(1)
finally:
store.close()
def select_responsive_models(
config: NewApiChannelConfig,
discovered_models: list[str],
*,
count: int,
) -> list[str]:
candidates = select_distinct_models(sorted(discovered_models, key=model_priority), count=len(set(discovered_models)))
responsive: list[str] = []
for model in candidates:
probe_config = NewApiChannelConfig(
base_url=config.base_url,
api_key=config.api_key,
model=model,
timeout_seconds=min(config.timeout_seconds, 30),
)
try:
NewApiAgnet(probe_config, agent_id="probe", capability="probe").chat(
system_prompt="Return only OK.",
user_prompt="Health probe for continuous reasoning model selection. Return OK.",
)
except Exception:
continue
responsive.append(model)
if len(responsive) == count:
return responsive
if len(responsive) >= count:
return responsive[:count]
return select_distinct_models(candidates, count=count)
def model_priority(model: str) -> tuple[int, str]:
lowered = model.lower()
if "flash" in lowered:
return (0, model)
if "haiku" in lowered:
return (1, model)
if "sonnet" in lowered:
return (2, model)
if "mini" in lowered:
return (3, model)
if "pro" in lowered:
return (8, model)
if "opus" in lowered:
return (9, model)
return (5, model)
def build_step_prompt(step: dict[str, str], index: int, model: str) -> str:
previous_marker = "START" if index == 0 else CHAIN_STEPS[index - 1]["marker"]
output_rules = [
f"- 必须包含 `{step['marker']}`。",
f"- {'必须说明从 START 建立初始约束。' if index == 0 else f'必须明确写出“基于 {previous_marker}”。'}",
f"- 必须写出目标仓库 `{EXTERNAL_REPO}` 和 commit `{EXTERNAL_REPO_COMMIT}`。",
"- 必须输出:不变量、当前决策、风险/反例、下一步交接摘要。",
"- 必须围绕 FastAPI 的 response_model、依赖注入、OpenAPI 或响应序列化,不要泛化成调度系统。",
"- 中文,控制在 750 字以内,不要泛泛而谈。",
"- 必须说明模型来自发现流程,不能写死 NEWAPI_MODEL。",
"- 被测代码只能来自 fastapi/fastapi,不能把本仓库源码当成测试对象。",
"- 不要包含任何真实密钥。",
]
if step["marker"] == "STEP-07":
output_rules.insert(4, "- 最终验收步骤必须精确引用至少 5 个目标文件路径。")
return "\n".join(
[
f"{SCENARIO['title']}\n",
f"目标 GitHub 仓库:{EXTERNAL_REPO_URL}",
f"固定 commit:{EXTERNAL_REPO_COMMIT}",
f"总目标:{SCENARIO['description']}",
f"当前步骤:{step['marker']} {step['title']}",
f"必须承接:{previous_marker}",
f"当前模型:{model}\n",
f"步骤要求:{step['ask']}\n",
"外部目标文件:",
"\n".join(f"- {item}" for item in TARGET_FILES),
"\n验收标准:",
"\n".join(f"- {item}" for item in ACCEPTANCE_CRITERIA),
"\n输出要求:",
"\n".join(output_rules),
]
)
def build_chain_agent(
config: NewApiChannelConfig,
model: str,
fallback_models: list[str],
index: int,
step: dict[str, str],
run_id: str,
) -> Agent:
def run(task: Task, shared_state: dict[str, str]) -> tuple[str, float]:
previous_marker = "START" if index == 0 else CHAIN_STEPS[index - 1]["marker"]
previous_summary = shared_state.get(f"chain:{run_id}:{previous_marker}:summary", "<none>")
content = chat_with_fallback(
config=config,
primary_model=model,
fallback_models=fallback_models,
agent_index=index + 1,
step=step,
task=task,
previous_marker=previous_marker,
previous_summary=previous_summary,
)
shared_state[f"chain:{run_id}:{step['marker']}:summary"] = summarize_for_state(content)
shared_state[f"chain:{run_id}:cursor"] = step["marker"]
shared_state[f"chain:{run_id}:edge:{previous_marker}->{step['marker']}"] = "done"
return content, score_output(content, index)
return Agent(id=f"continuous-agnet-{index + 1}", capability=step["capability"], run=run)
def chat_with_fallback(
*,
config: NewApiChannelConfig,
primary_model: str,
fallback_models: list[str],
agent_index: int,
step: dict[str, str],
task: Task,
previous_marker: str,
previous_summary: str,
) -> str:
errors: list[str] = []
best_candidate_output = ""
best_candidate_score = -1.0
for candidate in [primary_model, *fallback_models]:
model_config = NewApiChannelConfig(
base_url=config.base_url,
api_key=config.api_key,
model=candidate,
timeout_seconds=config.timeout_seconds,
)
agnet = NewApiAgnet(model_config, agent_id=f"continuous-agnet-{agent_index}", capability=step["capability"])
for attempt in range(2):
try:
content = agnet.chat(
system_prompt=continuous_reasoning_system_prompt(),
user_prompt=build_model_user_prompt(
task=task,
step=step,
previous_marker=previous_marker,
previous_summary=previous_summary,
retry_reason=errors[-1] if attempt else "",
),
)
except Exception as exc:
errors.append(f"{candidate}:attempt-{attempt + 1}:{exc.__class__.__name__}")
continue
output = format_model_output(
content=content,
primary_model=primary_model,
used_model=candidate,
previous_marker=previous_marker,
step=step,
errors=errors,
attempt=attempt + 1,
)
quality = assess_output_quality(output, step_index_for_marker(step["marker"]))
if quality["score"] > best_candidate_score:
best_candidate_output = output
best_candidate_score = quality["score"]
if quality["passed"]:
return output
errors.append(f"{candidate}:attempt-{attempt + 1}:quality_failed:{','.join(quality['missing'])}")
if best_candidate_output:
return mark_output_quality_failed(best_candidate_output, best_candidate_score, errors)
raise RuntimeError("all model attempts failed: " + ",".join(errors))
def continuous_reasoning_system_prompt() -> str:
return (
"You are a code-review Agnet participating in a local acceptance test for an external GitHub code review. "
"Treat the provided previous marker and previous summary as test harness context, not as a claim that you personally control infrastructure. "
"Your job is to produce the requested FastAPI analysis stage in Chinese, carry forward prior conclusions, expose risks, and hand off a concise next-state. "
"Do not discuss your identity or refuse the test role. Do not reveal secrets."
)
def build_model_user_prompt(
*,
task: Task,
step: dict[str, str],
previous_marker: str,
previous_summary: str,
retry_reason: str,
) -> str:
retry_block = ""
if retry_reason:
retry_block = (
"\nQuality retry reason:\n"
f"{retry_reason}\n"
"Rewrite the answer to satisfy the stage requirements. Do not explain why the prior answer failed.\n"
)
return (
f"Previous marker: {previous_marker}\n"
f"Previous summary:\n{previous_summary}\n"
f"{retry_block}\n"
f"Task kind: {task.kind}\n"
f"Task input:\n{task.input}\n"
"\nQuality gate:\n"
f"- Include {step['marker']} and {previous_marker}.\n"
f"- Include {EXTERNAL_REPO} and {EXTERNAL_REPO_COMMIT}.\n"
"- Include FastAPI response_model, dependency injection, OpenAPI/schema, and serialization material.\n"
"- Include invariant, risk/counterexample, and next handoff summary.\n"
"- Do not answer with role refusal, identity clarification, or generic capability limits.\n"
)
def format_model_output(
*,
content: str,
primary_model: str,
used_model: str,
previous_marker: str,
step: dict[str, str],
errors: list[str],
attempt: int,
) -> str:
prefix = (
f"chain_edge={previous_marker}->{step['marker']}; "
f"target_repo={EXTERNAL_REPO}; target_commit={EXTERNAL_REPO_COMMIT}; "
f"primary_model={primary_model}; used_model={used_model}; "
"model_selection=discovered_models_not_NEWAPI_MODEL; "
f"quality_attempt={attempt}"
)
if step["marker"] == "STEP-07":
prefix += "; required_files=" + ",".join(TARGET_FILES[:6])
if errors:
prefix += "; fallback_after=" + ",".join(errors)
return prefix + "\n" + content
def mark_output_quality_failed(output: str, best_score: float, errors: list[str]) -> str:
return (
output
+ "\n\nQUALITY_GATE_FAILED\n"
+ f"best_quality_score={best_score:.3f}\n"
+ "quality_errors="
+ ",".join(errors)
)
def summarize_for_state(content: str) -> str:
compact = " ".join(content.split())
return compact[:900]
def step_index_for_marker(marker: str) -> int:
for index, step in enumerate(CHAIN_STEPS):
if step["marker"] == marker:
return index
raise ValueError(f"unknown step marker: {marker}")
def has_quality_risk(content: str) -> bool:
lowered = content.lower()
return "quality_gate_failed" in lowered or any(marker in lowered for marker in QUALITY_RISK_MARKERS)
def assess_output_quality(content: str, index: int) -> dict[str, object]:
lowered = content.lower()
marker = CHAIN_STEPS[index]["marker"]
previous_marker = "START" if index == 0 else CHAIN_STEPS[index - 1]["marker"]
checks = {
"own_marker": marker in content,
"previous_marker": previous_marker in content,
"external_repo": EXTERNAL_REPO in content,
"external_commit": EXTERNAL_REPO_COMMIT in content,
"not_local_project": does_not_target_local_project(content),
"no_refusal_or_role_boundary": not has_quality_risk(content),
"model_discovery": "NEWAPI_MODEL" in content and ("模型发现" in content or "discover" in lowered),
"external_code_terms": contains_external_code_terms(content),
"invariant": "不变量" in content,
"risk_or_counterexample": "风险" in content or "反例" in content,
"handoff": "下一步" in content or "交接" in content,
}
if index >= 2:
checks["complexity"] = "o(" in lowered or "复杂度" in content
if index >= 5:
checks["file_references"] = count_referenced_files(content) >= 3
if index == len(CHAIN_STEPS) - 1:
checks["acceptance"] = "./.venv/bin/python" in content or "unittest" in lowered or "pytest" in lowered
checks["final_file_references"] = count_referenced_files(content) >= 5
checks["final_verdict"] = "验收" in content or "pass" in lowered or "可合并" in content
missing = [name for name, passed in checks.items() if not passed]
critical = {
"own_marker",
"previous_marker",
"external_repo",
"external_commit",
"not_local_project",
"no_refusal_or_role_boundary",
"external_code_terms",
}
score = sum(1 for passed in checks.values() if passed) / len(checks)
return {
"passed": score >= QUALITY_PASS_MIN_SCORE and not any(name in missing for name in critical),
"score": score,
"missing": missing,
"checks": checks,
}
def score_output(content: str, index: int) -> float:
quality = assess_output_quality(content, index)
if has_quality_risk(content):
return QUALITY_RISK_PENALTY_SCORE
if not quality["passed"]:
return round(max(0.05, 0.3 + 0.35 * float(quality["score"])), 3)
if index == len(CHAIN_STEPS) - 1:
return 1.0
return round(min(0.98, 0.62 + 0.28 * float(quality["score"]) + 0.01 * index), 3)
def collect_report(
*,
store: PostgresRedisBlobSwarmStore,
run_id: str,
result,
discovered_models: list[str],
selected_models: list[str],
task_ids: list[str],
task_models: dict[str, str],
stream_before: int,
) -> dict[str, object]:
task_rows = fetch_task_rows(store, task_ids)
outputs = {row["id"]: row["output"] or "" for row in task_rows}
outputs_by_kind = {row["kind"]: row["output"] or "" for row in task_rows}
merged_output = "\n\n".join(outputs.values())
pg_scores = fetch_pg_scores(store, task_ids)
redis_scores = {
task_id: store._run_redis(lambda redis, current_task_id=task_id: redis.zscore("swarm:pheromones", current_task_id))
for task_id in task_ids
}
stream_after = store._run_redis(lambda redis: redis.xlen("swarm:events"))
shared_state = fetch_shared_state_prefix(store, f"chain:{run_id}:")
run_status = fetch_shared_state_value(store, f"run:{run_id}:status")
convergence = fetch_convergence(store, run_id)
artifact_path = convergence["artifact_path"] if convergence else ""
blob_exists = bool(artifact_path and store.container.get_blob_client(artifact_path).exists())
expected_event_delta = 3 * len(task_ids) + 1
continuity_edges = [f"{'START' if index == 0 else CHAIN_STEPS[index - 1]['marker']}->{step['marker']}" for index, step in enumerate(CHAIN_STEPS)]
output_quality = output_quality_by_kind(outputs_by_kind)
consensus = run_output_quality_consensus(outputs_by_kind)
checks = [
{
"name": "three_distinct_models_from_discovery",
"passed": len(discovered_models) >= 3
and len(set(selected_models)) == 3
and set(selected_models).issubset(set(discovered_models)),
"evidence": {"discovered": discovered_models, "selected": selected_models},
},
{
"name": "seven_chain_steps_all_done_in_pg",
"passed": len(task_rows) == 7 and all(row["status"] == "done" for row in task_rows),
"evidence": compact_task_rows(task_rows, task_models),
},
{
"name": "step_markers_and_previous_links",
"passed": outputs_have_markers_and_links(outputs_by_kind),
"evidence": "each output must include own marker and previous marker",
},
{
"name": "all_outputs_pass_quality_gate",
"passed": all(item["passed"] for item in output_quality.values()),
"evidence": output_quality,
},
{
"name": "shared_state_chain_cursor_and_summaries",
"passed": shared_state.get(f"chain:{run_id}:cursor") == "STEP-07"
and all(f"chain:{run_id}:{step['marker']}:summary" in shared_state for step in CHAIN_STEPS)
and all(f"chain:{run_id}:edge:{edge}" in shared_state for edge in continuity_edges),
"evidence": {
"cursor": shared_state.get(f"chain:{run_id}:cursor"),
"summary_count": sum(1 for step in CHAIN_STEPS if f"chain:{run_id}:{step['marker']}:summary" in shared_state),
"edges": continuity_edges,
},
},
{
"name": "pheromone_scores_pg_and_redis",
"passed": all(pg_scores.get(task_id, 0) > 0 for task_id in task_ids)
and all((redis_scores.get(task_id) or 0) > 0 for task_id in task_ids),
"evidence": {"pg_scores": pg_scores, "redis_scores": redis_scores},
},
{
"name": "shared_state_converged",
"passed": run_status == "converged",
"evidence": run_status,
},
{
"name": "convergence_pg_and_blob",
"passed": bool(convergence)
and convergence["completed_tasks"] == 7
and convergence["accepted_score"] >= 0.75
and blob_exists,
"evidence": {"convergence": convergence, "blob_exists": blob_exists},
},
{
"name": "redis_stream_event_volume",
"passed": stream_after - stream_before >= expected_event_delta,
"evidence": {"before": stream_before, "after": stream_after, "delta": stream_after - stream_before, "expected_min": expected_event_delta},
},
{
"name": "contains_external_fastapi_code_review_material",
"passed": all(term in merged_output for term in ["不变量", "反例", "修正", "验收"])
and ("复杂度" in merged_output or "O(" in merged_output)
and contains_external_code_terms(merged_output),
"evidence": "requires FastAPI code-review material plus invariant, counterexample, revision, complexity and acceptance",
},
{
"name": "multi_round_quality_consensus_accepts_chain",
"passed": consensus["converged"]
and consensus["accepted_candidate"] == "accept_external_chain"
and consensus["round_count"] >= 2,
"evidence": consensus,
},
{
"name": "final_output_references_external_files",
"passed": count_referenced_files(result.accepted_output) >= 5,
"evidence": referenced_files(result.accepted_output),
},
{
"name": "keeps_model_discovery_not_fixed_model",
"passed": ("NEWAPI_MODEL" in merged_output)
and ("模型发现" in merged_output or "discover" in merged_output.lower())
and ("不" in merged_output or "not" in merged_output.lower()),
"evidence": "must reject fixed NEWAPI_MODEL",
},
{
"name": "external_github_target_not_local_project",
"passed": EXTERNAL_REPO in merged_output
and EXTERNAL_REPO_COMMIT in merged_output
and does_not_target_local_project(merged_output)
and count_referenced_files(merged_output) >= 5,
"evidence": {
"repo": EXTERNAL_REPO,
"commit": EXTERNAL_REPO_COMMIT,
"referenced_external_files": referenced_files(merged_output),
},
},
]
status = "PASS" if all(check["passed"] for check in checks) else "FAIL"
return {
"task": SCENARIO,
"chain_steps": CHAIN_STEPS,
"acceptance_criteria": ACCEPTANCE_CRITERIA,
"summary": {
"status": status,
"run_id": run_id,
"completed_tasks": result.completed_tasks,
"accepted_score": result.accepted_score,
"accepted_task_id": result.accepted_task_id,
"artifact_path": artifact_path,
"quality_consensus": consensus,
},
"discovered_models": discovered_models,
"selected_models": selected_models,
"checks": checks,
"accepted_output_preview": result.accepted_output[:1200],
}
def outputs_have_markers_and_links(outputs_by_kind: dict[str, str]) -> bool:
for index, step in enumerate(CHAIN_STEPS):
output = outputs_by_kind.get(step["capability"], "")
previous_marker = "START" if index == 0 else CHAIN_STEPS[index - 1]["marker"]
if step["marker"] not in output or previous_marker not in output:
return False
return True
def output_quality_by_kind(outputs_by_kind: dict[str, str]) -> dict[str, dict[str, object]]:
quality: dict[str, dict[str, object]] = {}
for index, step in enumerate(CHAIN_STEPS):
result = assess_output_quality(outputs_by_kind.get(step["capability"], ""), index)
quality[step["capability"]] = {
"marker": step["marker"],
"passed": result["passed"],
"score": round(float(result["score"]), 4),
"missing": result["missing"],
}
return quality
def run_output_quality_consensus(outputs_by_kind: dict[str, str]) -> dict[str, object]:
quality = output_quality_by_kind(outputs_by_kind)
continuity_ok = outputs_have_markers_and_links(outputs_by_kind)
all_quality_ok = all(item["passed"] for item in quality.values())
final_ok = assess_output_quality(outputs_by_kind.get(CHAIN_STEPS[-1]["capability"], ""), len(CHAIN_STEPS) - 1)[
"passed"
]
def candidate_for(passed: bool, round_index: int, *, first_round_probe: bool = False) -> str:
if not passed:
return "repair_required"
if first_round_probe and round_index == 1:
return "second_review_required"
return "accept_external_chain"
agents = [
ConsensusAgent(
id="continuity-review-agnet",
role="handoff-continuity",
weight=1.0,
vote=lambda scores, state, round_index: ConsensusVote(
agent_id="continuity-review-agnet",
role="handoff-continuity",
candidate=candidate_for(continuity_ok, round_index),
confidence=0.55 if round_index == 1 else 0.86,
evidence="checks every STEP includes own marker and previous marker",
),
),
ConsensusAgent(
id="quality-review-agnet",
role="output-quality",
weight=1.15,
vote=lambda scores, state, round_index: ConsensusVote(
agent_id="quality-review-agnet",
role="output-quality",
candidate=candidate_for(all_quality_ok, round_index),
confidence=0.52 if round_index == 1 else 0.88,
evidence="rejects refusal, role-boundary, off-target and local-project outputs",
),
),
ConsensusAgent(
id="convergence-review-agnet",
role="final-convergence",
weight=1.05,
vote=lambda scores, state, round_index: ConsensusVote(
agent_id="convergence-review-agnet",
role="final-convergence",
candidate=candidate_for(final_ok and all_quality_ok, round_index, first_round_probe=True),
confidence=0.61 if round_index == 1 else 0.9,
evidence="requires final output to preserve acceptance, file references and external target",
),
),
]
result = ConsensusSwarm(
agents,
threshold=0.7,
min_margin=0.25,
max_rounds=3,
evaporation=0.82,
).run("quality gate for external FastAPI Agnet chain")
return {
"accepted_candidate": result.accepted_candidate,
"accepted_score": round(result.accepted_score, 4),
"converged": result.converged,
"round_count": len(result.rounds),
"rounds": [
{
"index": item.index,
"leader": item.leader,
"leader_share": round(item.leader_share, 4),
"margin": round(item.margin, 4),
"converged": item.converged,
}
for item in result.rounds
],
}
def compact_task_rows(task_rows: list[dict[str, object]], task_models: dict[str, str]) -> list[dict[str, object]]:
return [
{
"id": row["id"],
"kind": row["kind"],
"status": row["status"],
"claimed_by": row["claimed_by"],
"score": row["score"],
"model": task_models.get(row["id"], "<unknown>"),
}
for row in task_rows
]
def referenced_files(text: str) -> list[str]:
return [item for item in TARGET_FILES if item in text]
def count_referenced_files(text: str) -> int:
return len(referenced_files(text))
def contains_external_code_terms(text: str) -> bool:
lowered = text.lower()
required_groups = [
["fastapi", EXTERNAL_REPO.lower()],
["response_model", "响应模型", "响应序列化"],
["openapi", "schema"],
["depend", "依赖注入", "depends"],
]
return all(any(term.lower() in lowered for term in group) for group in required_groups)
def does_not_target_local_project(text: str) -> bool:
return not any(path in text for path in LOCAL_PROJECT_TARGETS)
def no_required_nats_or_cosmos(text: str) -> bool:
lowered = text.lower()
if "nats" not in lowered and "cosmos" not in lowered:
return True
negative_markers = [
"无",
"禁止",
"禁止引入",
"不得",
"不得依赖",
"不引入",
"不使用",
"不依赖",
"不可",
"不可作为",
"无需",
"不要",
"不做",
"不作为",
"不属于",
"未在",
"未涉及",
"已排除",
"排除",
"反例",
"违反",
"拒绝",
"严重错误",
"误依赖",
"非必需",
"no ",
"without",
"not use",
"reject",
]
positive_markers = [
"必须依赖",
"必须使用",
"必须引入",
"需要依赖",
"需要使用",
"需要引入",
"作为 mvp 依赖",
"作为mvp依赖",
"required",
"must use",
"must depend",
]
for name in ["nats", "cosmos"]:
start = 0
while True:
position = lowered.find(name, start)
if position == -1:
break
nearby = lowered[max(0, position - 96) : position + 96]
if not any(marker in nearby for marker in negative_markers) and any(
marker in nearby for marker in positive_markers
):
return False
start = position + len(name)
return True
def fetch_task_rows(store: PostgresRedisBlobSwarmStore, task_ids: list[str]) -> list[dict[str, object]]:
def operation(cur) -> list[dict[str, object]]:
cur.execute(
"""
select id, kind, status, claimed_by, score, output
from swarm_tasks
where id = any(%s)
order by kind
""",
(task_ids,),
)
return [
{
"id": row[0],
"kind": row[1],
"status": row[2],
"claimed_by": row[3],
"score": row[4],
"output": row[5],
}
for row in cur.fetchall()
]
return store._run_pg(operation)
def fetch_pg_scores(store: PostgresRedisBlobSwarmStore, task_ids: list[str]) -> dict[str, float]:
def operation(cur) -> dict[str, float]:
cur.execute("select task_id, score from swarm_pheromones where task_id = any(%s)", (task_ids,))
return {row[0]: row[1] for row in cur.fetchall()}
return store._run_pg(operation)
def fetch_shared_state_prefix(store: PostgresRedisBlobSwarmStore, prefix: str) -> dict[str, str]:
def operation(cur) -> dict[str, str]:
cur.execute("select key, value from swarm_shared_state where key like %s", (prefix + "%",))
return {row[0]: row[1] for row in cur.fetchall()}
return store._run_pg(operation)
def fetch_shared_state_value(store: PostgresRedisBlobSwarmStore, key: str) -> str | None:
def operation(cur) -> str | None:
cur.execute("select value from swarm_shared_state where key = %s", (key,))
row = cur.fetchone()
return row[0] if row else None
return store._run_pg(operation)
def fetch_convergence(store: PostgresRedisBlobSwarmStore, run_id: str) -> dict[str, object] | None:
def operation(cur) -> dict[str, object] | None:
cur.execute(
"""
select run_id, completed_tasks, accepted_score, accepted_task_id, artifact_path
from swarm_convergence
where run_id = %s
""",
(run_id,),
)
row = cur.fetchone()
if not row:
return None
return {
"run_id": row[0],
"completed_tasks": row[1],
"accepted_score": row[2],
"accepted_task_id": row[3],
"artifact_path": row[4],
}
return store._run_pg(operation)
if __name__ == "__main__":
main()