Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion autoresearch/prefill/prepare.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def evaluate(report: dict, candidate) -> dict:
),
"recursive_protocol": (
critic.get("critic_protocol")
== "recursive_proof_decomposition_v2"
== "goal_anchored_recursive_gan_v3"
),
"no_fallback": int(delta.get("fallbacks", 0)) == 0,
"no_job_failure": int(delta.get("remote_job_failures", 0)) == 0,
Expand Down
2 changes: 1 addition & 1 deletion autoresearch/prefill/program.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Minimize `metric_cold_critic_prefill_s`. Lower is better.
- Every compute segment must remain at or below 300 seconds.
- Critic must receive the complete Generator response.
- `critic_omitted_tokens` must equal zero.
- Protocol must be `recursive_proof_decomposition_v2`.
- Protocol must be `goal_anchored_recursive_gan_v3`.
- Snapshot mode must remain `final_only`.
- No fallback, local Primary Prefill, failed remote job, sampling, summary, or
semantic simplification is allowed.
Expand Down
9 changes: 8 additions & 1 deletion docs/ops/distributed-prefill-kv-network.md
Original file line number Diff line number Diff line change
Expand Up @@ -349,13 +349,20 @@ and semantic fallback are forbidden. A global Critic score is valid only when
`critic_omitted_tokens=0`. Long Prefill operations emit a heartbeat every 30
seconds; on the 16GB allens worker, full-context Critic Prefill may take 15–25
minutes.
The Critic uses `recursive_proof_decomposition_v2`: numeric scores and blanket
The interactive Critic uses `goal_anchored_recursive_gan_v3`: numeric scores and blanket
approval are forbidden. It ignores prizes, money, prestige, style, and other
proof-irrelevant facts. It attacks the central stopping claim, recursively
decomposes it into proof obligations, records arguments/counterarguments and
dependencies for every node, and loops until every leaf is either explicitly
derived or a precisely stated open lemma. It then reports the smallest
unresolved frontier and next adversarial step.
The first substantive REPL input becomes an immutable research goal. `/continue`
feeds the complete previous Generator and Critic outputs into the next
Generator turn; `/new <goal>` is the only way to switch topics. Inputs beginning
with `generator>`, `critic>`, `prompt>`, `[metrics]`, `[allens]`, errors, or
tracebacks are rejected so Terminal output cannot contaminate the research
objective. Every Critic turn emits an explicit `Goal Alignment` decision and
restores the anchored proof frontier when drift is detected.
The worker reserves estimated final-snapshot capacity before model compute,
prevents adaptive shrink from consuming active reservations, then atomically
publishes and leases the final snapshot before adding optional intermediate
Expand Down
9 changes: 7 additions & 2 deletions scripts/agent_gan_inference_demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,19 @@ def _output_metadata(text: str) -> dict:
}


def build_critic_context(tokenizer, text: str) -> tuple[str, dict]:
def build_critic_context(
tokenizer,
text: str,
*,
protocol: str = "recursive_proof_decomposition_v2",
) -> tuple[str, dict]:
full_ids = tokenizer.encode(text, add_special_tokens=False)
return text, {
"generator_full_tokens": len(full_ids),
"critic_context_tokens": len(full_ids),
"critic_omitted_tokens": 0,
"review_scope": "full",
"critic_protocol": "recursive_proof_decomposition_v2",
"critic_protocol": protocol,
}


Expand Down
102 changes: 95 additions & 7 deletions scripts/agent_gan_repl.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import argparse
import hashlib
import json
import re
import signal
import threading
import time
Expand Down Expand Up @@ -46,7 +47,37 @@ def _telemetry_request(url: str, **kwargs):
return None


def build_generator_messages(prompt: str) -> list[dict[str, str]]:
_RUNTIME_ARTIFACT = re.compile(
r"^\s*(?:generator>|critic>|prompt>|\[(?:metrics|allens|error|"
r"telemetry-warning|protected|supervisor)\]|Traceback\b)",
re.IGNORECASE,
)


def is_runtime_artifact_prompt(text: str) -> bool:
lines = [line for line in text.splitlines() if line.strip()]
return bool(lines) and bool(_RUNTIME_ARTIFACT.match(lines[0]))


def build_generator_messages(
goal: str,
*,
steering: str = "",
previous_generator: str = "",
previous_critic: str = "",
) -> list[dict[str, str]]:
feedback = ""
if previous_generator or previous_critic:
feedback = (
"\n\nComplete previous Generator response:\n"
f"{previous_generator}\n\nComplete previous Critic correction:\n"
f"{previous_critic}\n\nApply the Critic's Next Adversarial Step "
"while remaining anchored to the immutable goal."
)
steering_text = (
f"\n\nCurrent human steering (subordinate to the goal):\n{steering}"
if steering else ""
)
return [
{
"role": "system",
Expand All @@ -59,14 +90,21 @@ def build_generator_messages(prompt: str) -> list[dict[str, str]]:
"Distinguish unknown from impossible."
),
},
{"role": "user", "content": prompt},
{
"role": "user",
"content": (
f"IMMUTABLE RESEARCH GOAL:\n{goal}"
f"{feedback}{steering_text}"
),
},
]


def build_critic_messages(
prompt: str,
goal: str,
generator_response: str,
*,
steering: str = "",
stop_reason: str,
complete: bool,
) -> list[dict[str, str]]:
Expand Down Expand Up @@ -94,12 +132,17 @@ def build_critic_messages(
"Leaf Obligation Ledger; Smallest Unresolved Frontier; Next "
"Adversarial Step. Do not sample, summarize, simplify, or use a "
"fallback review."
" Begin with `Goal Alignment: ALIGNED` or `Goal Alignment: "
"DRIFTED`. If drifted, discard the off-topic branch and restore "
"the proof-obligation frontier for the immutable goal."
),
},
{
"role": "user",
"content": (
f"Task:\n{prompt}\n\nComplete response:\n{generator_response}\n\n"
f"IMMUTABLE RESEARCH GOAL:\n{goal}\n\n"
f"Current steering:\n{steering or '(none)'}\n\n"
f"Complete response:\n{generator_response}\n\n"
f"Completion: {stop_reason}; complete={complete}"
),
},
Expand Down Expand Up @@ -257,11 +300,16 @@ def get_stats():
return stats

print(
"Kakeya Agent GAN REPL ready. Type a prompt; /quit exits.\n"
"Kakeya Agent GAN REPL ready. First prompt sets the immutable goal.\n"
"Use /continue to apply Critic feedback, /new <goal> to reset, "
"and /quit to exit.\n"
"Each turn runs allens Prefill → Primary hot Generator → "
"allens Prefill → Primary hot Critic.",
flush=True,
)
research_goal = ""
previous_generator = ""
previous_critic = ""
with Client(args.address) as client:
while True:
try:
Expand All @@ -274,6 +322,33 @@ def get_stats():
if prompt.lower() in {"/quit", "/exit"}:
print("[bye]")
break
if prompt.lower().startswith("/new"):
new_goal = prompt[4:].strip()
research_goal = new_goal
previous_generator = ""
previous_critic = ""
if not research_goal:
print("[goal] cleared; enter a new research goal", flush=True)
continue
prompt = research_goal
print(f"[goal] reset: {research_goal}", flush=True)
elif prompt.lower() == "/continue":
if not research_goal:
print("[goal-error] no active research goal", flush=True)
continue
prompt = ""
elif is_runtime_artifact_prompt(prompt):
print(
"[input-rejected] runtime output cannot become a research "
"prompt; use /continue or /new <goal>",
flush=True,
)
continue
elif not research_goal:
research_goal = prompt
print(f"[goal] anchored: {research_goal}", flush=True)
prompt = ""
steering = prompt
run_nonce = uuid.uuid4().hex
telemetry_state["degraded"] = False
run = _telemetry_request(
Expand All @@ -288,13 +363,22 @@ def get_stats():
"agents": ["generator", "critic"],
"rounds": 1,
"output_tokens": args.output_tokens,
"goal_anchor": hashlib.sha256(
research_goal.encode(),
).hexdigest(),
"feedback_applied": bool(previous_critic),
},
},
)
remote_run = run is not None
run_id = run["id"] if remote_run else f"local_{run_nonce[:16]}"
try:
generator_messages = build_generator_messages(prompt)
generator_messages = build_generator_messages(
research_goal,
steering=steering,
previous_generator=previous_generator,
previous_critic=previous_critic,
)
generator_ids = tokenizer.apply_chat_template(
generator_messages,
add_generation_prompt=True,
Expand Down Expand Up @@ -348,6 +432,7 @@ def get_stats():
critic_context, context_metrics = build_critic_context(
tokenizer,
generator_text,
protocol="goal_anchored_recursive_gan_v3",
)
if (
critic_context != generator_text
Expand All @@ -356,8 +441,9 @@ def get_stats():
):
raise RuntimeError("Critic full-context invariant violated")
critic_messages = build_critic_messages(
prompt,
research_goal,
critic_context,
steering=steering,
stop_reason=generator_actual["stop_reason"],
complete=generator_actual["complete"],
)
Expand Down Expand Up @@ -400,6 +486,8 @@ def get_stats():
)
if not critic_stage["ok"] and not telemetry_state["degraded"]:
raise _gate_failure("Critic", critic_warm, critic_actual)
previous_generator = generator_text
previous_critic = critic_text
completed = None
if remote_run:
completed = _telemetry_request(
Expand Down
2 changes: 1 addition & 1 deletion tests/inference_engine/bench/test_prefill_autoresearch.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def _report(**overrides):
"generator_full_tokens": 900,
"critic_context_tokens": 900,
"critic_omitted_tokens": 0,
"critic_protocol": "recursive_proof_decomposition_v2",
"critic_protocol": "goal_anchored_recursive_gan_v3",
"delta": {"fallbacks": 0, "remote_job_failures": 0},
}
stage.update(overrides)
Expand Down
32 changes: 28 additions & 4 deletions tests/inference_engine/bridge/test_agent_gan_repl.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
build_critic_messages,
build_generator_messages,
install_signal_protection,
is_runtime_artifact_prompt,
)


Expand Down Expand Up @@ -149,13 +150,13 @@ def test_stage_includes_full_context_metrics():
"critic_context_tokens": 100,
"critic_omitted_tokens": 0,
"review_scope": "full",
"critic_protocol": "recursive_proof_decomposition_v2",
"critic_protocol": "goal_anchored_recursive_gan_v3",
},
)
assert stage["critic_context_tokens"] == 100
assert stage["critic_omitted_tokens"] == 0
assert stage["review_scope"] == "full"
assert stage["critic_protocol"] == "recursive_proof_decomposition_v2"
assert stage["critic_protocol"] == "goal_anchored_recursive_gan_v3"


def test_telemetry_timeout_warns_without_stopping_inference(
Expand Down Expand Up @@ -185,24 +186,35 @@ def test_gate_failure_exposes_reuse_counters():


def test_interactive_prompts_are_deterministic_for_kv_reuse():
generator_a = build_generator_messages("prove RH")
generator_b = build_generator_messages("prove RH")
kwargs = {
"steering": "continue the zero-free-region branch",
"previous_generator": "previous complete argument",
"previous_critic": "previous complete correction",
}
generator_a = build_generator_messages("prove RH", **kwargs)
generator_b = build_generator_messages("prove RH", **kwargs)
critic_a = build_critic_messages(
"prove RH",
"complete generator response",
steering=kwargs["steering"],
stop_reason="eos",
complete=True,
)
critic_b = build_critic_messages(
"prove RH",
"complete generator response",
steering=kwargs["steering"],
stop_reason="eos",
complete=True,
)
assert generator_a == generator_b
assert critic_a == critic_b
combined = repr(generator_a + critic_a)
assert "Internal run" not in combined
assert "IMMUTABLE RESEARCH GOAL" in combined
assert "previous complete correction" in combined
assert "Goal Alignment: ALIGNED" in combined
assert "Goal Alignment: DRIFTED" in combined
assert "open problem" in combined
assert "recursive adversarial proof analyst" in combined
assert "Never output a numeric score" in combined
Expand All @@ -212,3 +224,15 @@ def test_interactive_prompts_are_deterministic_for_kv_reuse():
assert "Ignore prizes, money, prestige" in combined
assert "smallest unresolved frontier" in combined
assert "sample, summarize, simplify" in combined


def test_runtime_output_cannot_replace_research_goal():
for text in (
"critic> ### Central Claim",
"[metrics] KV hit=100%",
"[allens] Critic Prefill: 30s",
"prompt> ",
"Traceback (most recent call last):",
):
assert is_runtime_artifact_prompt(text)
assert not is_runtime_artifact_prompt("证明黎曼猜想")
Loading