From 3254fe9f3cb0fd248dc10fbbcafc9d385d6aaef2 Mon Sep 17 00:00:00 2001 From: Alex Clarke Date: Sat, 12 Sep 2026 01:37:13 -0600 Subject: [PATCH] feat: Fixed graph agents with new agent variable passing functionality --- assets/agents/adversary/graph.yaml | 7 ++++++- assets/agents/adversary/scripts/diff_facts.py | 6 ++++-- assets/agents/code-reviewer/graph.yaml | 8 +++++++- assets/agents/code-reviewer/scripts/facts.py | 6 ++++-- assets/agents/finding-verifier/graph.yaml | 11 +++++++++-- assets/agents/review-gauntlet/graph.yaml | 7 ++++++- assets/agents/review-gauntlet/scripts/signals.py | 6 ++++-- 7 files changed, 40 insertions(+), 11 deletions(-) diff --git a/assets/agents/adversary/graph.yaml b/assets/agents/adversary/graph.yaml index 89d2474..9ad6001 100644 --- a/assets/agents/adversary/graph.yaml +++ b/assets/agents/adversary/graph.yaml @@ -33,6 +33,7 @@ settings: timeout: 5400 initial_state: + project_dir_in: '' criteria: [] diff_spec: auto plan_notes: '' @@ -68,6 +69,8 @@ nodes: - `diff_spec`: the git diff basis the caller named — a range, a ref/SHA, "staged", "worktree", or "auto" when unnamed (a caller phrase like "get_diff --base X" means diff_spec = "X"). + - `project_dir_in`: the directory/worktree path the caller named as + holding the code under review; empty string when the caller named none. - `plan_notes`: recorded decisions the plan states ("do X not Y because Z"), verbatim — the holistic pass checks the diff didn't silently override them. - `scope_notes`: what the plan says NOT to touch / explicit boundaries. @@ -98,7 +101,9 @@ nodes: type: string extra_context: type: string - required: [criteria, diff_spec, plan_notes, scope_notes, extra_context] + project_dir_in: + type: string + required: [criteria, diff_spec, plan_notes, scope_notes, extra_context, project_dir_in] max_iterations: 3 max_attempts: 2 next: facts diff --git a/assets/agents/adversary/scripts/diff_facts.py b/assets/agents/adversary/scripts/diff_facts.py index 1b4efb3..85efdb5 100644 --- a/assets/agents/adversary/scripts/diff_facts.py +++ b/assets/agents/adversary/scripts/diff_facts.py @@ -22,7 +22,9 @@ def load_state(): state = load_state() -proj = state.get("project_dir") or "." +proj = os.path.expanduser( + (state.get("project_dir_in") or "").strip() or state.get("project_dir") or "." +) spec = (state.get("diff_spec") or "auto").strip() @@ -33,7 +35,7 @@ def git(*args): return r.stdout -out = {"diff_note": ""} +out = {"diff_note": "", "project_dir": proj} try: if spec in ("auto", ""): text = git("diff", "--cached") diff --git a/assets/agents/code-reviewer/graph.yaml b/assets/agents/code-reviewer/graph.yaml index ea1d834..6f4eb8a 100644 --- a/assets/agents/code-reviewer/graph.yaml +++ b/assets/agents/code-reviewer/graph.yaml @@ -50,6 +50,7 @@ settings: timeout: 10800 initial_state: + project_dir_in: '' diff_spec: auto intent: '' rigor_in: '' @@ -111,6 +112,9 @@ nodes: - `rigor_in`: ONLY when the caller explicitly set a rigor (poc|prototype|production), e.g. via a "Quality bar:" line; else empty string. - `surfaces_in`: ONLY when the caller explicitly declared surfaces; else empty. + - `project_dir_in`: the directory/worktree path the caller named as + holding the code under review (e.g. "in /tmp/pr-review-x", "the repo + at ~/code/foo"); empty string when the caller named none. - `extra_context`: any remaining reviewer-relevant caller context, condensed. prompt: | Extract the review-request facts from this request: @@ -128,9 +132,11 @@ nodes: type: string surfaces_in: type: string + project_dir_in: + type: string extra_context: type: string - required: [diff_spec, intent, rigor_in, surfaces_in, extra_context] + required: [diff_spec, intent, rigor_in, surfaces_in, project_dir_in, extra_context] max_iterations: 3 max_attempts: 2 next: facts diff --git a/assets/agents/code-reviewer/scripts/facts.py b/assets/agents/code-reviewer/scripts/facts.py index f52d2ad..3c51aba 100644 --- a/assets/agents/code-reviewer/scripts/facts.py +++ b/assets/agents/code-reviewer/scripts/facts.py @@ -23,10 +23,12 @@ def load_state(): state = load_state() -proj = state.get("project_dir") or "." +proj = os.path.expanduser( + (state.get("project_dir_in") or "").strip() or state.get("project_dir") or "." +) spec = (state.get("diff_spec") or "auto").strip() notes = [] -out = {} +out = {"project_dir": proj} def git(*args, timeout=60): diff --git a/assets/agents/finding-verifier/graph.yaml b/assets/agents/finding-verifier/graph.yaml index e7fcba3..1adc582 100644 --- a/assets/agents/finding-verifier/graph.yaml +++ b/assets/agents/finding-verifier/graph.yaml @@ -55,8 +55,12 @@ nodes: - `path` and `lines` come from the finding verbatim; if a finding cites multiple locations, emit one entry per location with the same id plus a `-b`, `-c` suffix. + - `project_dir`: the repository directory named in the request (a + "Repository:" or "Project:" line). When none is named, echo the + default shown in the prompt. prompt: | - Extract the findings from this verification request: + Extract the findings from this verification request (default repository + directory when the request names none: {{project_dir}}): {{initial_prompt}} tools: [] @@ -84,7 +88,10 @@ nodes: type: string description: Self-contained statement of what the finding asserts about the code. required: [id, severity, path, lines, claim] - required: [findings_list] + project_dir: + type: string + description: Repository directory named in the request (echo the prompt default when none). + required: [findings_list, project_dir] next: verify_each verify_each: diff --git a/assets/agents/review-gauntlet/graph.yaml b/assets/agents/review-gauntlet/graph.yaml index c62a5f7..54b3e74 100644 --- a/assets/agents/review-gauntlet/graph.yaml +++ b/assets/agents/review-gauntlet/graph.yaml @@ -83,6 +83,9 @@ nodes: range ("main...HEAD", "HEAD~3..HEAD"), a single ref, or the literal "worktree" for uncommitted changes against HEAD. When the caller did not name one, use "worktree". + - `project_dir_in`: the repository directory the caller named as holding + the change (absolute path preferred); empty string when the caller + named none. - `plan_context`: the plan / spec / acceptance-criteria text the implementation must satisfy, verbatim (or a file path the caller pointed at). Empty string when the caller supplied none. @@ -121,7 +124,9 @@ nodes: type: string extra_context: type: string - required: [diff_spec, plan_context, rigor, security_posture, probe_context, forced_lanes, extra_context] + project_dir_in: + type: string + required: [diff_spec, plan_context, rigor, security_posture, probe_context, forced_lanes, extra_context, project_dir_in] max_iterations: 3 max_attempts: 2 next: signals diff --git a/assets/agents/review-gauntlet/scripts/signals.py b/assets/agents/review-gauntlet/scripts/signals.py index f36369f..6ccecb4 100644 --- a/assets/agents/review-gauntlet/scripts/signals.py +++ b/assets/agents/review-gauntlet/scripts/signals.py @@ -21,7 +21,9 @@ def load_state(): state = load_state() -proj = state.get("project_dir") or "." +proj = os.path.expanduser( + (state.get("project_dir_in") or "").strip() or state.get("project_dir") or "." +) spec = (state.get("diff_spec") or "worktree").strip() @@ -34,7 +36,7 @@ def git(*args): return r.stdout -out = {} +out = {"project_dir": proj} try: if spec in ("", "worktree"): names = git("diff", "--name-only", "HEAD")