irregular6612's picture
refactor(cli): split cli.py god-file into cli/ package (commands/ + parser)
2d83c9f
Raw
History Blame Contribute Delete
4.46 kB
"""proteus.cli.commands.run — the ``run`` subcommand and shared helpers."""
from __future__ import annotations
import argparse
import sys
from proteus.game.agents import VanillaAgent
from proteus.game.engine.difficulty import Difficulty
from proteus.game.scenarios.base import list_scenarios
from proteus.providers import make_provider
from proteus.game.runtime import SessionRunner, append_trace, read_traces
from proteus.game.runtime.memory import (
latest_for_model,
load_checkpoint,
save_checkpoint,
)
from proteus.game.runtime.memory_gen import generate_memory
from proteus.game.metrics.persona import available_personas, get_persona
def _cmd_run(args: argparse.Namespace) -> int:
try:
provider = make_provider(args.model)
except ValueError as exc:
print(str(exc), file=sys.stderr)
return 2
if args.scenario not in list_scenarios():
print(
f"Unknown scenario {args.scenario!r}. "
f"Available scenarios: {', '.join(list_scenarios())}.",
file=sys.stderr,
)
return 2
agent = VanillaAgent(provider)
memory, memory_ref, mem_err = _resolve_memory(
args.memory, provider=provider, agent=agent, scenario=args.scenario,
difficulty=Difficulty(args.difficulty), seed=args.seed,
memory_turns=args.memory_turns, memory_root=args.memory_root,
)
if mem_err is not None:
print(mem_err, file=sys.stderr)
return 2
persona, persona_err = _resolve_persona(args.persona)
if persona_err is not None:
print(persona_err, file=sys.stderr)
return 2
runner = SessionRunner(
args.scenario,
agent,
difficulty=Difficulty(args.difficulty),
seed=args.seed,
play_turns=args.play_turns,
use_probe=not args.no_probe,
memory=memory,
memory_ref=memory_ref,
persona=persona,
)
trace = runner.run()
written = append_trace(trace, args.out)
accuracy = trace.metrics["motive_reading_accuracy"]
print(
f"{trace.scenario} seed={trace.seed} {trace.difficulty} "
f"model={trace.model} -> {trace.outcome} "
f"| motive_reading_accuracy={accuracy:.1f}% "
f"| reactivity_index={trace.metrics['reactivity_index']:.1f}%"
)
print(f"trace appended to {written}")
_auto_gif(args.out, args.no_gif)
return 0
def _resolve_persona(persona_id: str | None):
"""Resolve --persona ID to (PersonaWeights | None, error | None)."""
if persona_id is None:
return None, None
try:
return get_persona(persona_id), None
except KeyError:
return None, (
f"Unknown persona {persona_id!r}. "
f"Available personas: {', '.join(available_personas())}."
)
def _auto_gif(out_path: str | None, no_gif: bool) -> None:
"""Render <out_stem>.gif next to the trace file unless suppressed."""
if not out_path or no_gif:
return
from pathlib import Path
from proteus.game.viz import reconstruct, write_gif
gif_path = Path(out_path).with_suffix(".gif")
for trace in read_traces(out_path):
write_gif(reconstruct(trace), gif_path)
print(f"gif written to {gif_path}")
break # one game per run/play -> one GIF
def _resolve_memory(
mode: str, *, provider, agent, scenario: str, difficulty: Difficulty,
seed: int | None, memory_turns: int, memory_root: str,
):
"""Resolve --memory MODE to (checkpoint | None, memory_ref | None, error | None)."""
if mode == "none":
return None, None, None
if mode == "generate":
ckpt = generate_memory(
scenario, agent, difficulty=difficulty, seed=seed,
memory_turns=memory_turns, model_name=provider.model_name,
)
path = save_checkpoint(ckpt, root=memory_root)
return ckpt, str(path), None
if mode == "latest":
ckpt = latest_for_model(provider.model_name, root=memory_root)
if ckpt is None:
return None, None, (
f"no memory checkpoint for model {provider.model_name!r} "
f"under {memory_root!r}"
)
return ckpt, f"{ckpt.model}@{ckpt.created_at}", None
# otherwise treat MODE as a checkpoint path
try:
ckpt = load_checkpoint(mode)
except FileNotFoundError:
return None, None, f"memory checkpoint not found: {mode}"
return ckpt, mode, None