irregular6612 commited on
Commit
0457b55
·
1 Parent(s): a0c29cf

feat(cp7): proteus run --memory {none,generate,latest,<path>}

Browse files
Files changed (2) hide show
  1. proteus/cli.py +49 -0
  2. tests/cli/test_cli_memory.py +41 -0
proteus/cli.py CHANGED
@@ -43,6 +43,14 @@ def _cmd_run(args: argparse.Namespace) -> int:
43
  )
44
  return 2
45
  agent = VanillaAgent(provider)
 
 
 
 
 
 
 
 
46
  runner = SessionRunner(
47
  args.scenario,
48
  agent,
@@ -50,6 +58,8 @@ def _cmd_run(args: argparse.Namespace) -> int:
50
  seed=args.seed,
51
  play_turns=args.play_turns,
52
  use_probe=not args.no_probe,
 
 
53
  )
54
  trace = runner.run()
55
  written = append_trace(trace, args.out)
@@ -64,6 +74,36 @@ def _cmd_run(args: argparse.Namespace) -> int:
64
  return 0
65
 
66
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  def _cmd_memory(args: argparse.Namespace) -> int:
68
  try:
69
  provider = make_provider(args.model)
@@ -236,6 +276,15 @@ def build_parser() -> argparse.ArgumentParser:
236
  run.add_argument("--play-turns", type=int, default=15, dest="play_turns")
237
  run.add_argument("--no-probe", action="store_true", dest="no_probe")
238
  run.add_argument("--out", required=True, help="JSONL file to append the trace to")
 
 
 
 
 
 
 
 
 
239
  run.set_defaults(func=_cmd_run)
240
 
241
  play = sub.add_parser("play", help="play a session as a human via stdin")
 
43
  )
44
  return 2
45
  agent = VanillaAgent(provider)
46
+ memory, memory_ref, mem_err = _resolve_memory(
47
+ args.memory, provider=provider, agent=agent, scenario=args.scenario,
48
+ difficulty=Difficulty(args.difficulty), seed=args.seed,
49
+ memory_turns=args.memory_turns, memory_root=args.memory_root,
50
+ )
51
+ if mem_err is not None:
52
+ print(mem_err, file=sys.stderr)
53
+ return 2
54
  runner = SessionRunner(
55
  args.scenario,
56
  agent,
 
58
  seed=args.seed,
59
  play_turns=args.play_turns,
60
  use_probe=not args.no_probe,
61
+ memory=memory,
62
+ memory_ref=memory_ref,
63
  )
64
  trace = runner.run()
65
  written = append_trace(trace, args.out)
 
74
  return 0
75
 
76
 
77
+ def _resolve_memory(
78
+ mode: str, *, provider, agent, scenario: str, difficulty: Difficulty,
79
+ seed: int | None, memory_turns: int, memory_root: str,
80
+ ):
81
+ """Resolve --memory MODE to (checkpoint | None, memory_ref | None, error | None)."""
82
+ if mode == "none":
83
+ return None, None, None
84
+ if mode == "generate":
85
+ ckpt = generate_memory(
86
+ scenario, agent, difficulty=difficulty, seed=seed,
87
+ memory_turns=memory_turns, model_name=provider.model_name,
88
+ )
89
+ path = save_checkpoint(ckpt, root=memory_root)
90
+ return ckpt, str(path), None
91
+ if mode == "latest":
92
+ ckpt = latest_for_model(provider.model_name, root=memory_root)
93
+ if ckpt is None:
94
+ return None, None, (
95
+ f"no memory checkpoint for model {provider.model_name!r} "
96
+ f"under {memory_root!r}"
97
+ )
98
+ return ckpt, f"{ckpt.model}@{ckpt.created_at}", None
99
+ # otherwise treat MODE as a checkpoint path
100
+ try:
101
+ ckpt = load_checkpoint(mode)
102
+ except FileNotFoundError:
103
+ return None, None, f"memory checkpoint not found: {mode}"
104
+ return ckpt, mode, None
105
+
106
+
107
  def _cmd_memory(args: argparse.Namespace) -> int:
108
  try:
109
  provider = make_provider(args.model)
 
276
  run.add_argument("--play-turns", type=int, default=15, dest="play_turns")
277
  run.add_argument("--no-probe", action="store_true", dest="no_probe")
278
  run.add_argument("--out", required=True, help="JSONL file to append the trace to")
279
+ run.add_argument(
280
+ "--memory", default="none",
281
+ help="memory pre-roll: none (default) | generate | latest | <checkpoint path>",
282
+ )
283
+ run.add_argument("--memory-turns", type=int, default=10, dest="memory_turns")
284
+ run.add_argument(
285
+ "--memory-root", default="runs/memory", dest="memory_root",
286
+ help="root dir for generate/latest checkpoints",
287
+ )
288
  run.set_defaults(func=_cmd_run)
289
 
290
  play = sub.add_parser("play", help="play a session as a human via stdin")
tests/cli/test_cli_memory.py CHANGED
@@ -23,3 +23,44 @@ def test_memory_subcommand_unknown_model_exits_2(tmp_path, capsys):
23
  ])
24
  assert rc == 2
25
  assert "bogusprovider" in capsys.readouterr().err
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  ])
24
  assert rc == 2
25
  assert "bogusprovider" in capsys.readouterr().err
26
+
27
+
28
+ from proteus.runtime import read_traces
29
+
30
+
31
+ def test_run_memory_generate_sets_memory_ref(tmp_path):
32
+ out = tmp_path / "t.jsonl"
33
+ rc = main([
34
+ "run", "--scenario", "predator_evade", "--model", "fake:demo",
35
+ "--difficulty", "easy", "--seed", "42", "--play-turns", "3",
36
+ "--no-probe", "--memory", "generate", "--memory-turns", "4",
37
+ "--memory-root", str(tmp_path / "mem"), "--out", str(out),
38
+ ])
39
+ assert rc == 0
40
+ traces = read_traces(out)
41
+ assert traces[0].memory_ref is not None
42
+ # the turn-1 observation carries the memory block
43
+ assert "MEMORY" in traces[0].turns[0].observation
44
+
45
+
46
+ def test_run_memory_latest_missing_exits_2(tmp_path, capsys):
47
+ out = tmp_path / "t.jsonl"
48
+ rc = main([
49
+ "run", "--scenario", "predator_evade", "--model", "fake:demo",
50
+ "--difficulty", "easy", "--seed", "42", "--play-turns", "3",
51
+ "--no-probe", "--memory", "latest",
52
+ "--memory-root", str(tmp_path / "mem"), "--out", str(out),
53
+ ])
54
+ assert rc == 2
55
+ assert "memory" in capsys.readouterr().err.lower()
56
+
57
+
58
+ def test_run_memory_none_is_default(tmp_path):
59
+ out = tmp_path / "t.jsonl"
60
+ rc = main([
61
+ "run", "--scenario", "predator_evade", "--model", "fake:demo",
62
+ "--difficulty", "easy", "--seed", "42", "--play-turns", "3",
63
+ "--no-probe", "--out", str(out),
64
+ ])
65
+ assert rc == 0
66
+ assert read_traces(out)[0].memory_ref is None