From fcc0049ab2e6f9814479b3c39b4671e7577eb248 Mon Sep 17 00:00:00 2001 From: Alex Clarke Date: Tue, 15 Sep 2026 23:09:59 -0600 Subject: [PATCH] feat: further increased budgets for adversary and code reviewer agents --- assets/agents/adversary/graph.yaml | 7 ++++++- assets/agents/adversary/scripts/diff_facts.py | 17 +++++++++++++++++ assets/agents/code-reviewer/graph.yaml | 4 ++-- src/config/request_context.rs | 2 +- 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/assets/agents/adversary/graph.yaml b/assets/agents/adversary/graph.yaml index 18b9446..27537d3 100644 --- a/assets/agents/adversary/graph.yaml +++ b/assets/agents/adversary/graph.yaml @@ -52,6 +52,7 @@ settings: initial_state: project_dir_in: '' + parse_retries: 0 criteria: [] diff_spec: auto plan_notes: '' @@ -88,6 +89,10 @@ nodes: Split compound criteria ("A and B") into separate entries when they are independently verifiable. When the caller supplied NO plan/criteria at all, emit an empty array — downstream fails closed. + An empty array is ONLY correct when the prompt genuinely contains no + plan/criteria section — when the prompt carries one (a "Plan / + acceptance criteria:" or "PLAN —" block), returning zero criteria is + an extraction FAILURE, never a valid result. The caller's explicit enumeration is AUTHORITATIVE: when the caller declares "these N are the (only) criteria" or supplies a numbered criteria list, extract EXACTLY those N — never add entries they did @@ -348,7 +353,7 @@ nodes: observations: type: string required: [extra_complaints, observations] - max_iterations: 30 + max_iterations: 45 max_attempts: 2 state_updates: holistic_failure: '{{output}}' diff --git a/assets/agents/adversary/scripts/diff_facts.py b/assets/agents/adversary/scripts/diff_facts.py index 8019707..e6f5d83 100644 --- a/assets/agents/adversary/scripts/diff_facts.py +++ b/assets/agents/adversary/scripts/diff_facts.py @@ -8,6 +8,7 @@ review proceeds fail-closed rather than crashing. """ import json +import re import os import subprocess @@ -22,6 +23,22 @@ def load_state(): state = load_state() + +# Zero criteria from a prompt that visibly carries a plan is an extraction +# failure (observed non-deterministically live), not a fail-closed no-plan +# run — re-run the parse ONCE before the verdict fails closed on it. +_crit = state.get("criteria") or [] +_prompt = state.get("initial_prompt") or "" +if not _crit and isinstance(_prompt, str) and re.search( + r"acceptance criteria|PLAN\s*—|Plan / acceptance", _prompt, re.I +): + try: + _pr = int(state.get("parse_retries") or 0) + except (TypeError, ValueError): + _pr = 0 + if _pr < 1: + print(json.dumps({"_next": "parse", "parse_retries": _pr + 1})) + raise SystemExit(0) proj = os.path.expanduser( (state.get("project_dir_in") or "").strip() or state.get("project_dir") or "." ) diff --git a/assets/agents/code-reviewer/graph.yaml b/assets/agents/code-reviewer/graph.yaml index 0a2eb5a..7871d6b 100644 --- a/assets/agents/code-reviewer/graph.yaml +++ b/assets/agents/code-reviewer/graph.yaml @@ -147,7 +147,7 @@ nodes: extra_context: type: string required: [diff_spec, intent, rigor_in, surfaces_in, project_dir_in, extra_context] - max_iterations: 3 + max_iterations: 6 max_attempts: 2 state_updates: parse_failure: '{{output}}' @@ -228,7 +228,7 @@ nodes: type: string required: [domain, files] required: [groups] - max_iterations: 3 + max_iterations: 6 max_attempts: 2 state_updates: refine_failure: '{{output}}' diff --git a/src/config/request_context.rs b/src/config/request_context.rs index 345288b..921efa6 100644 --- a/src/config/request_context.rs +++ b/src/config/request_context.rs @@ -11545,7 +11545,7 @@ mod tests { let NodeType::Llm(holistic) = &holistic.node_type else { panic!("holistic must be an llm node"); }; - assert_eq!(holistic.max_iterations, 30); + assert_eq!(holistic.max_iterations, 45); } const BUNDLED_GRAPHS: [&str; 6] = [