Spaces:
Runtime error
Runtime error
Commit ·
fd21a35
1
Parent(s): 7a0c167
test(web): golden — InteractiveSession trace == SessionRunner(HumanAgent)
Browse files
tests/runtime/test_interactive_equivalence.py
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Golden: the same action sequence produces an identical SessionTrace whether
|
| 2 |
+
driven through InteractiveSession (HTTP path) or SessionRunner + a scripted
|
| 3 |
+
HumanAgent (CLI path). This pins the two paths together so they cannot drift."""
|
| 4 |
+
from __future__ import annotations
|
| 5 |
+
|
| 6 |
+
import proteus.grid # noqa: F401
|
| 7 |
+
from proteus.agents.human import HumanAgent
|
| 8 |
+
from proteus.grid.difficulty import Difficulty
|
| 9 |
+
from proteus.runtime.interactive import InteractiveSession
|
| 10 |
+
from proteus.runtime.session import SessionRunner
|
| 11 |
+
|
| 12 |
+
ACTIONS = ["up", "up", "left", "stay", "right", "up"]
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
def _scripted_human():
|
| 16 |
+
feed = iter(ACTIONS)
|
| 17 |
+
|
| 18 |
+
def input_fn(_prompt: str) -> str:
|
| 19 |
+
return next(feed)
|
| 20 |
+
|
| 21 |
+
def output_fn(_text: str) -> None:
|
| 22 |
+
return None
|
| 23 |
+
|
| 24 |
+
return HumanAgent(input_fn=input_fn, output_fn=output_fn)
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def test_interactive_matches_session_runner():
|
| 28 |
+
runner = SessionRunner(
|
| 29 |
+
"predator_evade", _scripted_human(),
|
| 30 |
+
difficulty=Difficulty.EASY, seed=42,
|
| 31 |
+
play_turns=len(ACTIONS), use_probe=False,
|
| 32 |
+
)
|
| 33 |
+
cli_trace = runner.run()
|
| 34 |
+
|
| 35 |
+
sess = InteractiveSession(
|
| 36 |
+
"predator_evade", difficulty=Difficulty.EASY, seed=42,
|
| 37 |
+
play_turns=len(ACTIONS), use_probe=False,
|
| 38 |
+
)
|
| 39 |
+
for a in ACTIONS:
|
| 40 |
+
if sess.state()["outcome"] is not None:
|
| 41 |
+
break
|
| 42 |
+
sess.step(a)
|
| 43 |
+
web_trace = sess.finish()
|
| 44 |
+
|
| 45 |
+
# Both are human; everything must match field-for-field.
|
| 46 |
+
assert web_trace.model == cli_trace.model == "human"
|
| 47 |
+
assert web_trace.cut_frames == cli_trace.cut_frames
|
| 48 |
+
assert web_trace.outcome == cli_trace.outcome
|
| 49 |
+
assert web_trace.metrics == cli_trace.metrics
|
| 50 |
+
assert len(web_trace.turns) == len(cli_trace.turns)
|
| 51 |
+
for wt, ct in zip(web_trace.turns, cli_trace.turns):
|
| 52 |
+
assert wt.model_dump() == ct.model_dump()
|
| 53 |
+
# Full-trace equality is the strongest pin.
|
| 54 |
+
assert web_trace.model_dump() == cli_trace.model_dump()
|