From 178603e9fd84f8c19f8b7400433001a181395eef Mon Sep 17 00:00:00 2001 From: fluffy314 Date: Mon, 20 Jul 2026 19:50:18 +0800 Subject: [PATCH] fix(autoresearch): scope history to target leaf Prevent prior unrelated proof branches from being reinjected into each Generator turn while preserving complete current-output review by the Critic. Co-authored-by: Cursor --- scripts/agent_gan_repl.py | 41 +++++++++++++++++-- .../bridge/test_agent_gan_repl.py | 32 +++++++++++++++ 2 files changed, 69 insertions(+), 4 deletions(-) diff --git a/scripts/agent_gan_repl.py b/scripts/agent_gan_repl.py index 0293580..38b87f4 100644 --- a/scripts/agent_gan_repl.py +++ b/scripts/agent_gan_repl.py @@ -636,7 +636,17 @@ def build_generator_messages( previous_generator: str = "", previous_critic: str = "", proof_ledger: str = "", + target_obligation_id: str = "", ) -> list[dict[str, str]]: + if target_obligation_id: + previous_generator = extract_obligation_history( + previous_generator, + target_obligation_id, + ) + previous_critic = extract_obligation_history( + previous_critic, + target_obligation_id, + ) feedback = "" if previous_generator or previous_critic: feedback = ( @@ -674,6 +684,22 @@ def build_generator_messages( ] +_OBLIGATION_HISTORY_SECTION = re.compile( + r"^### (?:ISSUE_RESPONSE|ISSUE_VERDICT)\s+(\S+)\s*$" + r"(?P.*?)(?=^### |\Z)", + re.MULTILINE | re.DOTALL, +) + + +def extract_obligation_history(text: str, obligation_id: str) -> str: + sections = [ + match.group(0).strip() + for match in _OBLIGATION_HISTORY_SECTION.finditer(text) + if match.group(1) == obligation_id + ] + return "\n\n".join(sections) + + def build_critic_messages( goal: str, generator_response: str, @@ -1157,12 +1183,19 @@ def get_stats(): try: generator_messages = build_generator_messages( research_goal, - steering=generator_steering, + steering="\n\n".join(filter(None, ( + generator_steering, + critic_issue_injection, + ))), previous_generator=previous_generator, - previous_critic=( - previous_critic + critic_issue_injection - ), + previous_critic=previous_critic, proof_ledger=proof_ledger_text, + target_obligation_id=( + turn_obligations[0].obligation_id + if research_candidate is not None + and len(turn_obligations) == 1 + else "" + ), ) generator_ids = tokenizer.apply_chat_template( generator_messages, diff --git a/tests/inference_engine/bridge/test_agent_gan_repl.py b/tests/inference_engine/bridge/test_agent_gan_repl.py index 1e22890..7e4fffe 100644 --- a/tests/inference_engine/bridge/test_agent_gan_repl.py +++ b/tests/inference_engine/bridge/test_agent_gan_repl.py @@ -19,6 +19,7 @@ _telemetry_request, build_critic_messages, build_generator_messages, + extract_obligation_history, install_signal_protection, is_runtime_artifact_prompt, consume_critic_issue_batch, @@ -292,6 +293,37 @@ def test_interactive_prompts_are_deterministic_for_kv_reuse(): assert "sample, summarize, simplify" in combined +def test_generator_history_is_scoped_to_target_leaf(): + history = """ +### ISSUE_RESPONSE RH-C1 +Correction: unrelated operator branch. + +### ISSUE_VERDICT RH-C1 +Status: UNRESOLVED +Missing lemma: unrelated operator lemma. + +### ISSUE_RESPONSE RH-C2-child +Correction: target convergence branch. + +### ISSUE_VERDICT RH-C2-child +Status: UNRESOLVED +Missing lemma: target compact convergence lemma. +""" + scoped = extract_obligation_history(history, "RH-C2-child") + assert "target convergence branch" in scoped + assert "target compact convergence lemma" in scoped + assert "RH-C1" not in scoped + messages = build_generator_messages( + "prove RH", + previous_generator=history, + previous_critic=history, + target_obligation_id="RH-C2-child", + ) + prompt = messages[-1]["content"] + assert "target convergence branch" in prompt + assert "unrelated operator branch" not in prompt + + def test_runtime_output_cannot_replace_research_goal(): for text in ( "critic> ### Central Claim",