Add required human review gate to the Agent pipeline #1

Open
woogi wants to merge 28 commits from agent-mode into main
4 changed files with 34 additions and 1 deletions
Showing only changes of commit 8631a26006 - Show all commits
+1 -1
View File
@@ -12,7 +12,7 @@ from typing import Dict, List
def _norm(value) -> str:
return re.sub(r"\s+", " ", str(value or "").strip().lower())
return re.sub(r"\s+", " ", ("" if value is None else str(value)).strip().lower())
def find_disputes(assertions: List[Dict]) -> List[Dict]:
+4
View File
@@ -11,6 +11,7 @@ from backend.agents.code_agent import CodeAgent, build_code_scopes
from backend.agents.completeness import CompletenessAgent, build_sheet_summaries
from backend.agents.conflict_critic import ConflictCriticAgent
from backend.agents.construct_agent import ConstructabilityAgent, build_construct_scopes
from backend.agents.disputes import annotate_clusters
from backend.agents.extractors import (
JurisdictionAgent,
SheetExtractorAgent,
@@ -113,6 +114,9 @@ def run_agent_pipeline(
for artifact in result.artifacts
][:config.CLUSTER_MAX]
object_graph = build_object_graph(clusters)
disputed_count = annotate_clusters(clusters)
if disputed_count:
orchestrator.stage(f"[Link] {disputed_count} clusters carry disputed extracted values")
memory.replace("clusters", clusters)
memory.replace("object_graph", object_graph)
memory.dump("03-link.json")
+2
View File
@@ -54,6 +54,8 @@ def slim_clusters(clusters: List[Dict]) -> List[Dict]:
"location": c.get("location"),
"disciplines": c.get("disciplines"),
"kind": c.get("kind"),
**({"disputed_attributes": c["disputed_attributes"]}
if c.get("disputed_attributes") else {}),
"assertions": [slim_assertion(a) for a in c.get("assertions", [])],
}
for c in clusters
+27
View File
@@ -40,3 +40,30 @@ def test_annotate_clusters_writes_disputed_attributes():
assert annotate_clusters(clusters) == 1
assert clusters[0]["disputed_attributes"][0]["attribute"] == "stud_pack_size"
assert "disputed_attributes" not in clusters[1]
def test_slim_clusters_preserves_disputed_attributes():
from backend.pipeline._serialize import slim_clusters
cluster = {"key": "c1", "assertions": [],
"disputed_attributes": [{"attribute": "a", "values": ["1", "2"],
"assertion_ids": ["x", "y"]}]}
slim = slim_clusters([cluster])[0]
assert slim["disputed_attributes"][0]["values"] == ["1", "2"]
def test_find_disputes_handles_none_and_zero_values():
# None value/attribute -> skipped; numeric 0 is a real value, not blank
assertions = [
{"id": "a1", "attribute": "count", "value": 0},
{"id": "a2", "attribute": "count", "value": 1},
{"id": "a3", "attribute": None, "value": "x"},
{"id": "a4", "attribute": "count", "value": None},
]
disputes = find_disputes(assertions)
assert len(disputes) == 1
assert disputes[0]["values"] == ["0", "1"]
def test_find_disputes_empty_input():
assert find_disputes([]) == []
assert annotate_clusters([]) == 0