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
6 changes: 6 additions & 0 deletions docs/ops/distributed-prefill-kv-network.md
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,12 @@ Completed Generator/Critic text is atomically checkpointed with mode `0600` at
`--recover-run <id> --recover-log <path> --auto-continue` reconstructs a
checkpoint from a complete timestamped run and resumes without using any
partial Terminal echo.
Continuous `auto-loop` is enabled by default. After every successful
Generator/Critic turn, the READY state internally queues `/continue`; it does
not wait for Terminal automation. A short boundary window still accepts an
explicit whitelisted command such as `/quit` or `/steer`. Any inference
exception pauses auto-loop and preserves the last complete checkpoint.
`--no-auto-loop` restores manual one-turn-at-a-time operation.
Generator output is always streamed in full to Terminal and passed verbatim to
the Gemma Critic. Sampling, truncation, summarization, independent chunk scores,
and semantic fallback are forbidden. A global Critic score is valid only when
Expand Down
53 changes: 52 additions & 1 deletion scripts/agent_gan_repl.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import json
import os
import re
import select
import signal
import sys
import threading
Expand Down Expand Up @@ -481,9 +482,24 @@ def main() -> int:
default="~/.kakeya/logs/agent_gan_repl.log",
)
parser.add_argument("--auto-continue", action="store_true")
parser.add_argument(
"--no-auto-loop",
action="store_false",
dest="auto_loop",
help="Pause after each successful turn instead of continuing.",
)
parser.set_defaults(auto_loop=True)
parser.add_argument(
"--auto-loop-boundary-wait-s",
type=float,
default=0.5,
help="Boundary window for an explicit command before auto-continue.",
)
args = parser.parse_args()
if args.output_tokens <= 0:
raise SystemExit("output-tokens must be > 0")
if args.auto_loop_boundary_wait_s < 0:
raise SystemExit("auto-loop-boundary-wait-s must be >= 0")
transcript = TimestampedTee(
sys.stdout,
Path(args.log_file).expanduser(),
Expand Down Expand Up @@ -536,12 +552,19 @@ def get_stats():
previous_generator = checkpoint.previous_generator if checkpoint else ""
previous_critic = checkpoint.previous_critic if checkpoint else ""
phase = ReplPhase.READY if checkpoint else ReplPhase.WAITING_FOR_GOAL
pending_input = "/continue" if args.auto_continue and checkpoint else ""
auto_loop_active = bool(args.auto_loop)
pending_input = (
"/continue"
if checkpoint and (args.auto_continue or auto_loop_active)
else ""
)
print(
"Kakeya Agent GAN REPL ready.\n"
"Commands: /new <goal>, /continue, /steer <text>, /quit.\n"
"Raw text is accepted only as the initial goal; inference output can "
"never become implicit steering.\n"
f"Auto-loop is {'enabled' if auto_loop_active else 'disabled'}; "
"successful turns continue automatically and exceptions pause it.\n"
"Each turn runs allens Prefill → Primary hot Generator → "
"allens Prefill → Primary hot Critic.",
flush=True,
Expand All @@ -560,6 +583,19 @@ def get_stats():
raw_input = pending_input
pending_input = ""
print(f"\nprompt> {raw_input}", flush=True)
elif auto_loop_active and phase == ReplPhase.READY:
print("\nprompt> ", end="", flush=True)
readable, _, _ = select.select(
[sys.stdin],
[],
[],
args.auto_loop_boundary_wait_s,
)
if readable:
raw_input = input()
else:
raw_input = "/continue"
print(raw_input, flush=True)
else:
try:
raw_input = input("\nprompt> ")
Expand All @@ -584,8 +620,11 @@ def get_stats():
ReplCheckpoint(research_goal=research_goal),
)
phase = ReplPhase.READY
auto_loop_active = bool(args.auto_loop)
print(f"[goal] reset: {research_goal}", flush=True)
steering = command.payload if command.action == "steer" else ""
if command.action in {"continue", "steer"} and args.auto_loop:
auto_loop_active = True
phase = ReplPhase.RUNNING
run_nonce = uuid.uuid4().hex
telemetry_state["degraded"] = False
Expand Down Expand Up @@ -776,6 +815,12 @@ def get_stats():
),
)
phase = ReplPhase.READY
if auto_loop_active:
print(
"[auto-loop] successful turn complete; "
"/continue queued",
flush=True,
)
except Exception as exc:
if remote_run:
_telemetry_request(
Expand All @@ -791,6 +836,12 @@ def get_stats():
flush=True,
)
phase = ReplPhase.READY
auto_loop_active = False
print(
"[auto-loop-paused] inference exception; checkpoint "
"preserved. Use /continue after remediation.",
flush=True,
)
transcript.log_only("[session-end]")
return 0

Expand Down
15 changes: 15 additions & 0 deletions tests/inference_engine/bridge/test_agent_gan_repl.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,21 @@ def test_command_state_machine_requires_explicit_ready_commands():
raise AssertionError(f"expected rejection for {raw!r} in {phase}")


def test_continuous_auto_loop_is_default_and_exception_pauses():
source = (
Path(__file__).resolve().parents[3]
/ "scripts"
/ "agent_gan_repl.py"
).read_text()
assert 'parser.set_defaults(auto_loop=True)' in source
assert "select.select(" in source
assert 'raw_input = "/continue"' in source
assert '"/continue queued"' in source
assert "auto_loop_active = False" in source
assert "[auto-loop-paused]" in source
assert '"--no-auto-loop"' in source


def test_checkpoint_round_trip_is_private(tmp_path):
path = tmp_path / "state.json"
expected = ReplCheckpoint(
Expand Down
Loading