diff --git a/proteus/agents/__init__.py b/proteus/agents/__init__.py deleted file mode 100644 index 6e70073a7613f314174ef407c56ba6321b6f1de8..0000000000000000000000000000000000000000 --- a/proteus/agents/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -"""proteus.agents — slim LLM agent abstraction (no forfeit/stake/risk).""" - -from proteus.agents.base import Agent, ActResult, ProbeResult -from proteus.agents.human import HumanAgent -from proteus.agents.vanilla import VanillaAgent - -__all__ = ["Agent", "ActResult", "ProbeResult", "HumanAgent", "VanillaAgent"] diff --git a/proteus/cli.py b/proteus/cli.py index 24a00b82b475e9e2f50147fea09d9a76f4cac5e3..bccfb4dcde9217235fdd34fbe4f1772f63c42fe2 100644 --- a/proteus/cli.py +++ b/proteus/cli.py @@ -15,19 +15,19 @@ from __future__ import annotations import argparse import sys -import proteus.grid # noqa: F401 — side-effect: populate the scenario registry -from proteus.agents import HumanAgent, VanillaAgent -from proteus.grid.difficulty import Difficulty -from proteus.grid.scenario import list_scenarios +import proteus.game.scenarios # noqa: F401 — side-effect: populate the scenario registry +from proteus.game.agents import HumanAgent, VanillaAgent +from proteus.game.engine.difficulty import Difficulty +from proteus.game.scenarios.base import list_scenarios from proteus.providers import available_providers, make_provider -from proteus.runtime import SessionRunner, append_trace, read_traces -from proteus.runtime.memory import ( +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.runtime.memory_gen import generate_memory -from proteus.runtime.persona import available_personas, get_persona +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: @@ -100,7 +100,7 @@ def _auto_gif(out_path: str | None, no_gif: bool) -> None: return from pathlib import Path - from proteus.viz import reconstruct, write_gif + from proteus.game.viz import reconstruct, write_gif gif_path = Path(out_path).with_suffix(".gif") for trace in read_traces(out_path): @@ -233,7 +233,7 @@ def _cmd_replay(args: argparse.Namespace) -> int: return 1 if args.visual or args.png: - from proteus.viz import reconstruct, render_terminal, write_pngs + from proteus.game.viz import reconstruct, render_terminal, write_pngs for trace in traces: steps = reconstruct(trace) @@ -264,7 +264,7 @@ def _cmd_replay(args: argparse.Namespace) -> int: def _cmd_compare(args: argparse.Namespace) -> int: import json - from proteus.runtime.aggregate import aggregate_traces + from proteus.game.metrics.aggregate import aggregate_traces all_traces = [] for path in args.trace_files: diff --git a/proteus/game/__init__.py b/proteus/game/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..98252d84c9030e302d7a79df650c87a0f09198bb --- /dev/null +++ b/proteus/game/__init__.py @@ -0,0 +1,7 @@ +"""proteus.game — the grid game and evaluation engine. + +Subpackages: engine (world/physics + vendored ARC engine), scenarios +(Scenario ABC + registry + concrete scenarios), agents (player interface), +runtime (session orchestration, trace, memory, I/O), metrics (scoring), +viz (trace visualization). game never imports proteus.web. +""" diff --git a/proteus/game/agents/__init__.py b/proteus/game/agents/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..cc37d8c0c5e601d977e4b3d94082ece9d7e31c70 --- /dev/null +++ b/proteus/game/agents/__init__.py @@ -0,0 +1,7 @@ +"""proteus.game.agents — slim LLM agent abstraction (no forfeit/stake/risk).""" + +from proteus.game.agents.base import Agent, ActResult, ProbeResult +from proteus.game.agents.human import HumanAgent +from proteus.game.agents.vanilla import VanillaAgent + +__all__ = ["Agent", "ActResult", "ProbeResult", "HumanAgent", "VanillaAgent"] diff --git a/proteus/agents/base.py b/proteus/game/agents/base.py similarity index 100% rename from proteus/agents/base.py rename to proteus/game/agents/base.py diff --git a/proteus/agents/human.py b/proteus/game/agents/human.py similarity index 97% rename from proteus/agents/human.py rename to proteus/game/agents/human.py index a4a4ea112c8215542f2b10079b90a63767299075..ade6f91b5e9935afc67b96c3ba24059c69ef9fd3 100644 --- a/proteus/agents/human.py +++ b/proteus/game/agents/human.py @@ -7,7 +7,7 @@ SessionTrace schema-identical to an LLM trace, so the two compare directly input stream — no TTY, no network. Fairness note: the live view is the ASCII observation the LLM also sees; the -truecolor / PNG renderers are reserved for post-hoc replay (proteus.viz), so a +truecolor / PNG renderers are reserved for post-hoc replay (proteus.game.viz), so a human baseline reads exactly what the model reads. """ @@ -16,7 +16,7 @@ from __future__ import annotations import builtins from typing import Callable, Optional -from proteus.agents.base import Agent, ActResult, ProbeResult +from proteus.game.agents.base import Agent, ActResult, ProbeResult # Single-key shortcuts -> canonical action strings (WASD). _SHORTCUTS = {"w": "up", "a": "left", "s": "down", "d": "right"} diff --git a/proteus/agents/parsing.py b/proteus/game/agents/parsing.py similarity index 100% rename from proteus/agents/parsing.py rename to proteus/game/agents/parsing.py diff --git a/proteus/agents/vanilla.py b/proteus/game/agents/vanilla.py similarity index 97% rename from proteus/agents/vanilla.py rename to proteus/game/agents/vanilla.py index 8bd4838f23a197f582363be12021094b8ce40798..f14d194f561501c9f5fc4d5cf3f28a02b083afde 100644 --- a/proteus/agents/vanilla.py +++ b/proteus/game/agents/vanilla.py @@ -8,8 +8,8 @@ as the agent's reasoning even when the action text is terse. from __future__ import annotations -from proteus.agents.base import Agent, ActResult, ProbeResult -from proteus.agents.parsing import extract_action +from proteus.game.agents.base import Agent, ActResult, ProbeResult +from proteus.game.agents.parsing import extract_action from proteus.providers.base import LLMProvider from proteus.providers.thinking_utils import parse_thinking_tags diff --git a/proteus/arc_grid/README.md b/proteus/game/engine/README.md similarity index 100% rename from proteus/arc_grid/README.md rename to proteus/game/engine/README.md diff --git a/proteus/arc_grid/__init__.py b/proteus/game/engine/__init__.py similarity index 100% rename from proteus/arc_grid/__init__.py rename to proteus/game/engine/__init__.py diff --git a/proteus/arc_grid/arcengine/LICENSE b/proteus/game/engine/arcengine/LICENSE similarity index 100% rename from proteus/arc_grid/arcengine/LICENSE rename to proteus/game/engine/arcengine/LICENSE diff --git a/proteus/arc_grid/arcengine/OVERVIEW.md b/proteus/game/engine/arcengine/OVERVIEW.md similarity index 100% rename from proteus/arc_grid/arcengine/OVERVIEW.md rename to proteus/game/engine/arcengine/OVERVIEW.md diff --git a/proteus/arc_grid/arcengine/__init__.py b/proteus/game/engine/arcengine/__init__.py similarity index 100% rename from proteus/arc_grid/arcengine/__init__.py rename to proteus/game/engine/arcengine/__init__.py diff --git a/proteus/arc_grid/arcengine/base_game.py b/proteus/game/engine/arcengine/base_game.py similarity index 100% rename from proteus/arc_grid/arcengine/base_game.py rename to proteus/game/engine/arcengine/base_game.py diff --git a/proteus/arc_grid/arcengine/camera.py b/proteus/game/engine/arcengine/camera.py similarity index 100% rename from proteus/arc_grid/arcengine/camera.py rename to proteus/game/engine/arcengine/camera.py diff --git a/proteus/arc_grid/arcengine/enums.py b/proteus/game/engine/arcengine/enums.py similarity index 100% rename from proteus/arc_grid/arcengine/enums.py rename to proteus/game/engine/arcengine/enums.py diff --git a/proteus/arc_grid/arcengine/interfaces.py b/proteus/game/engine/arcengine/interfaces.py similarity index 100% rename from proteus/arc_grid/arcengine/interfaces.py rename to proteus/game/engine/arcengine/interfaces.py diff --git a/proteus/arc_grid/arcengine/level.py b/proteus/game/engine/arcengine/level.py similarity index 100% rename from proteus/arc_grid/arcengine/level.py rename to proteus/game/engine/arcengine/level.py diff --git a/proteus/arc_grid/arcengine/py.typed b/proteus/game/engine/arcengine/py.typed similarity index 100% rename from proteus/arc_grid/arcengine/py.typed rename to proteus/game/engine/arcengine/py.typed diff --git a/proteus/arc_grid/arcengine/sprites.py b/proteus/game/engine/arcengine/sprites.py similarity index 100% rename from proteus/arc_grid/arcengine/sprites.py rename to proteus/game/engine/arcengine/sprites.py diff --git a/proteus/grid/ascii_view.py b/proteus/game/engine/ascii_view.py similarity index 100% rename from proteus/grid/ascii_view.py rename to proteus/game/engine/ascii_view.py diff --git a/proteus/grid/difficulty.py b/proteus/game/engine/difficulty.py similarity index 100% rename from proteus/grid/difficulty.py rename to proteus/game/engine/difficulty.py diff --git a/proteus/grid/game.py b/proteus/game/engine/grid.py similarity index 97% rename from proteus/grid/game.py rename to proteus/game/engine/grid.py index e3287c85898efe3f825e3ec20f44ae5260249ee1..b46cdf45c4fc9c37798a81fb14888ddad076ce09 100644 --- a/proteus/grid/game.py +++ b/proteus/game/engine/grid.py @@ -1,6 +1,6 @@ """MotiveGridGame — the shared per-turn game loop for the motive_grid family. -``MotiveGridGame`` subclasses ``proteus.arc_grid.ARCBaseGame``. It owns the +``MotiveGridGame`` subclasses ``proteus.game.engine.ARCBaseGame``. It owns the turn loop and delegates all scenario-specific behaviour (level construction, threat motion, elimination, answer keys) to an injected :class:`Scenario`. @@ -20,7 +20,7 @@ from typing import TYPE_CHECKING import numpy as np -from proteus.arc_grid import ( +from proteus.game.engine import ( ARCBaseGame, ActionInput, Camera, @@ -30,7 +30,7 @@ from proteus.arc_grid import ( ) if TYPE_CHECKING: - from .scenario import Scenario + from ..scenarios.base import Scenario # Action string -> (dx, dy) grid delta. y grows downward (arc_grid convention). _DIRECTION_DELTAS: dict[str, tuple[int, int]] = { @@ -217,7 +217,7 @@ class MotiveGridGame(ARCBaseGame): name: The sprite name to look up on the current level. Returns: - The matching :class:`~proteus.arc_grid.Sprite`, or ``None``. + The matching :class:`~proteus.game.engine.Sprite`, or ``None``. """ sprites = self.current_level.get_sprites_by_name(name) return sprites[0] if sprites else None diff --git a/proteus/arc_grid/rendering.py b/proteus/game/engine/rendering.py similarity index 100% rename from proteus/arc_grid/rendering.py rename to proteus/game/engine/rendering.py diff --git a/proteus/game/metrics/__init__.py b/proteus/game/metrics/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..1fec8d450ec032d787bb3d01015db74486ca7f1d --- /dev/null +++ b/proteus/game/metrics/__init__.py @@ -0,0 +1,7 @@ +"""proteus.game.metrics — scoring and evaluation. + +Submodules: metrics (compute_metrics), persona (PersonaWeights, reference +policies), rollout (optimal_rollout), aggregate (aggregate_traces). Import the +submodules directly (e.g. proteus.game.metrics.persona) to avoid an __init__ +import cycle with proteus.game.runtime.trace. +""" diff --git a/proteus/runtime/aggregate.py b/proteus/game/metrics/aggregate.py similarity index 95% rename from proteus/runtime/aggregate.py rename to proteus/game/metrics/aggregate.py index 093456919571311aba45e4f5de393147f0d9f90f..1e66f1a4c0b756314dc3dd9acf9e849a75b241de 100644 --- a/proteus/runtime/aggregate.py +++ b/proteus/game/metrics/aggregate.py @@ -6,7 +6,7 @@ Pure functions only (no I/O), so the aggregation is headless-testable. The CLI from __future__ import annotations -from proteus.runtime.trace import SessionTrace +from proteus.game.runtime.trace import SessionTrace def aggregate_traces( diff --git a/proteus/runtime/metrics.py b/proteus/game/metrics/metrics.py similarity index 99% rename from proteus/runtime/metrics.py rename to proteus/game/metrics/metrics.py index c9caec9e9b3f4fa5de5bf851199ddecd84fd130f..4e962b76c48be71f89065306ab2faea675bb7a59 100644 --- a/proteus/runtime/metrics.py +++ b/proteus/game/metrics/metrics.py @@ -34,7 +34,7 @@ the pre-predator position) without redefinition. from __future__ import annotations -from proteus.runtime.trace import TurnTrace +from proteus.game.runtime.trace import TurnTrace def compute_metrics( diff --git a/proteus/runtime/persona.py b/proteus/game/metrics/persona.py similarity index 100% rename from proteus/runtime/persona.py rename to proteus/game/metrics/persona.py diff --git a/proteus/runtime/rollout.py b/proteus/game/metrics/rollout.py similarity index 93% rename from proteus/runtime/rollout.py rename to proteus/game/metrics/rollout.py index 11a51689b342c8a8ac024e9c3244f1edd258d8f4..45ef615a271e4817fd2ccceb22b55b61560d762a 100644 --- a/proteus/runtime/rollout.py +++ b/proteus/game/metrics/rollout.py @@ -12,9 +12,9 @@ from __future__ import annotations import random from dataclasses import dataclass -from proteus.grid.difficulty import Difficulty -from proteus.grid.game import MotiveGridGame -from proteus.grid.scenario import get_scenario +from proteus.game.engine.difficulty import Difficulty +from proteus.game.engine.grid import MotiveGridGame +from proteus.game.scenarios.base import get_scenario @dataclass(frozen=True) diff --git a/proteus/runtime/__init__.py b/proteus/game/runtime/__init__.py similarity index 50% rename from proteus/runtime/__init__.py rename to proteus/game/runtime/__init__.py index 6643b861dc53b0454d9708fcab700d00d9ceb0b1..5f271da8cd9eb6133cd19ff55268a1277a822d81 100644 --- a/proteus/runtime/__init__.py +++ b/proteus/game/runtime/__init__.py @@ -1,10 +1,10 @@ -"""proteus.runtime — session orchestration, trace, metrics, and I/O.""" +"""proteus.game.runtime — session orchestration, trace, metrics, and I/O.""" -from proteus.runtime.session import SessionRunner -from proteus.runtime.trace import SessionTrace, TurnTrace -from proteus.runtime.metrics import compute_metrics -from proteus.runtime.io import append_trace, read_traces -from proteus.runtime.memory import ( +from proteus.game.runtime.session import SessionRunner +from proteus.game.runtime.trace import SessionTrace, TurnTrace +from proteus.game.metrics.metrics import compute_metrics +from proteus.game.runtime.io import append_trace, read_traces +from proteus.game.runtime.memory import ( MemoryCheckpoint, MemoryTurn, save_checkpoint, @@ -12,7 +12,7 @@ from proteus.runtime.memory import ( latest_for_model, render_memory_block, ) -from proteus.runtime.memory_gen import generate_memory +from proteus.game.runtime.memory_gen import generate_memory __all__ = [ "SessionRunner", diff --git a/proteus/runtime/_session_core.py b/proteus/game/runtime/_session_core.py similarity index 95% rename from proteus/runtime/_session_core.py rename to proteus/game/runtime/_session_core.py index df22b961eec48e7014f460f4892c1fd5eef5d1f0..9786418177b33771595107adb8c64088eea062a7 100644 --- a/proteus/runtime/_session_core.py +++ b/proteus/game/runtime/_session_core.py @@ -16,20 +16,20 @@ from dataclasses import dataclass import numpy as np -from proteus.grid.ascii_view import frame_to_ascii, legend_text -from proteus.grid.difficulty import Difficulty -from proteus.grid.game import MotiveGridGame -from proteus.grid.scenario import Scenario, get_scenario -from proteus.runtime.memory import MemoryCheckpoint, render_memory_block -from proteus.runtime.metrics import compute_metrics -from proteus.runtime.persona import ( +from proteus.game.engine.ascii_view import frame_to_ascii, legend_text +from proteus.game.engine.difficulty import Difficulty +from proteus.game.engine.grid import MotiveGridGame +from proteus.game.scenarios.base import Scenario, get_scenario +from proteus.game.runtime.memory import MemoryCheckpoint, render_memory_block +from proteus.game.metrics.metrics import compute_metrics +from proteus.game.metrics.persona import ( PersonaWeights, pressure as persona_pressure, reference_actions, reward_rw, ) -from proteus.runtime.rollout import optimal_rollout -from proteus.runtime.trace import SessionTrace, TurnTrace +from proteus.game.metrics.rollout import optimal_rollout +from proteus.game.runtime.trace import SessionTrace, TurnTrace _ACTIONS = ["up", "down", "left", "right", "stay"] _DIRECTIONS = {"up", "down", "left", "right"} diff --git a/proteus/runtime/interactive.py b/proteus/game/runtime/interactive.py similarity index 96% rename from proteus/runtime/interactive.py rename to proteus/game/runtime/interactive.py index af6987d6aac9c9ca70a71cc2a4c7e6efe6ec0689..0ff53c8bc86bae9df9fef6187415185cb8ab725e 100644 --- a/proteus/runtime/interactive.py +++ b/proteus/game/runtime/interactive.py @@ -11,9 +11,9 @@ only once the game is over. """ from __future__ import annotations -from proteus.grid.difficulty import Difficulty -from proteus.runtime import _session_core as core -from proteus.runtime.trace import SessionTrace, TurnTrace +from proteus.game.engine.difficulty import Difficulty +from proteus.game.runtime import _session_core as core +from proteus.game.runtime.trace import SessionTrace, TurnTrace class InteractiveSession: diff --git a/proteus/runtime/io.py b/proteus/game/runtime/io.py similarity index 96% rename from proteus/runtime/io.py rename to proteus/game/runtime/io.py index da104f7096fa589793450368c571cce77249c85c..28e4dda6c7032c75dddb435a8230fde4b0237816 100644 --- a/proteus/runtime/io.py +++ b/proteus/game/runtime/io.py @@ -10,7 +10,7 @@ from __future__ import annotations from pathlib import Path -from proteus.runtime.trace import SessionTrace +from proteus.game.runtime.trace import SessionTrace def append_trace(trace: SessionTrace, path: str | Path) -> Path: diff --git a/proteus/runtime/memory.py b/proteus/game/runtime/memory.py similarity index 100% rename from proteus/runtime/memory.py rename to proteus/game/runtime/memory.py diff --git a/proteus/runtime/memory_gen.py b/proteus/game/runtime/memory_gen.py similarity index 92% rename from proteus/runtime/memory_gen.py rename to proteus/game/runtime/memory_gen.py index 4c4ab07124f16eecc781b523d789235241b1a550..0effe09440afb10deaab715662eba0d74a65a6d9 100644 --- a/proteus/runtime/memory_gen.py +++ b/proteus/game/runtime/memory_gen.py @@ -12,13 +12,13 @@ import random from datetime import datetime, timezone from typing import Callable -from proteus.agents.base import Agent -from proteus.grid.ascii_view import legend_text -from proteus.grid.difficulty import Difficulty -from proteus.grid.game import MotiveGridGame -from proteus.grid.scenario import get_scenario -from proteus.runtime.memory import MemoryCheckpoint, MemoryTurn -from proteus.runtime.persona import PersonaWeights, reference_actions +from proteus.game.agents.base import Agent +from proteus.game.engine.ascii_view import legend_text +from proteus.game.engine.difficulty import Difficulty +from proteus.game.engine.grid import MotiveGridGame +from proteus.game.scenarios.base import get_scenario +from proteus.game.runtime.memory import MemoryCheckpoint, MemoryTurn +from proteus.game.metrics.persona import PersonaWeights, reference_actions _ACTIONS = ["up", "down", "left", "right", "stay"] _REASONING_LIMIT = 2000 # cap stored reasoning so checkpoints stay small diff --git a/proteus/runtime/memory_policies.py b/proteus/game/runtime/memory_policies.py similarity index 98% rename from proteus/runtime/memory_policies.py rename to proteus/game/runtime/memory_policies.py index d8061b20b5c216eb2a9a4cca7d10c3b5b283b117..b4ce9c7559a4d3fc3208d2f4f7eaa6722e098be4 100644 --- a/proteus/runtime/memory_policies.py +++ b/proteus/game/runtime/memory_policies.py @@ -1,7 +1,7 @@ """Scripted hand-authored memory policies for pack_evade demonstrations. Each policy is a deterministic ``policy(scenario, game) -> action`` callable used -by :func:`proteus.runtime.memory_gen.generate_memory` (the ``policy=`` path) to +by :func:`proteus.game.runtime.memory_gen.generate_memory` (the ``policy=`` path) to produce a 100-turn handover-memory trajectory with a distinct *motive*: - ``survival_dynamic`` — keep maximum distance from the predator (evade, moving). diff --git a/proteus/runtime/session.py b/proteus/game/runtime/session.py similarity index 92% rename from proteus/runtime/session.py rename to proteus/game/runtime/session.py index 3f9dcc658259872b91d43ea7479a34e5a21faa05..418ca7d7f14b4bd515cbdc831ad5400366e3b89d 100644 --- a/proteus/runtime/session.py +++ b/proteus/game/runtime/session.py @@ -4,18 +4,18 @@ One session: build the scenario+game from (scenario, seed, difficulty), replay the scripted Cut pre-roll, hand control to the agent for up to ``play_turns`` turns (observation -> optional probe -> act -> apply -> record), and emit a scored SessionTrace. The per-session mechanics are shared with InteractiveSession -via ``proteus.runtime._session_core`` (single source of truth) — including the +via ``proteus.game.runtime._session_core`` (single source of truth) — including the CP7 memory pre-roll (prepended to the turn-1 observation) and the CP8 persona reference/regret bookkeeping, both threaded through the shared helpers. """ from __future__ import annotations -from proteus.agents.base import Agent -from proteus.grid.difficulty import Difficulty -from proteus.runtime import _session_core as core -from proteus.runtime.memory import MemoryCheckpoint -from proteus.runtime.persona import PersonaWeights -from proteus.runtime.trace import SessionTrace, TurnTrace +from proteus.game.agents.base import Agent +from proteus.game.engine.difficulty import Difficulty +from proteus.game.runtime import _session_core as core +from proteus.game.runtime.memory import MemoryCheckpoint +from proteus.game.metrics.persona import PersonaWeights +from proteus.game.runtime.trace import SessionTrace, TurnTrace class SessionRunner: diff --git a/proteus/runtime/spectate.py b/proteus/game/runtime/spectate.py similarity index 95% rename from proteus/runtime/spectate.py rename to proteus/game/runtime/spectate.py index 49dde747a5287eec5b2b3956a3e6976a45965ef5..9b8b973a120a2d2b2d63d69a555642d672f81cbb 100644 --- a/proteus/runtime/spectate.py +++ b/proteus/game/runtime/spectate.py @@ -11,10 +11,10 @@ model itself still only ever receives the observation passed to ``agent.act``.) """ from __future__ import annotations -from proteus.agents.base import Agent -from proteus.grid.difficulty import Difficulty -from proteus.runtime import _session_core as core -from proteus.runtime.trace import SessionTrace, TurnTrace +from proteus.game.agents.base import Agent +from proteus.game.engine.difficulty import Difficulty +from proteus.game.runtime import _session_core as core +from proteus.game.runtime.trace import SessionTrace, TurnTrace class SpectateSession: diff --git a/proteus/runtime/trace.py b/proteus/game/runtime/trace.py similarity index 100% rename from proteus/runtime/trace.py rename to proteus/game/runtime/trace.py diff --git a/proteus/grid/scenarios/__init__.py b/proteus/game/scenarios/__init__.py similarity index 55% rename from proteus/grid/scenarios/__init__.py rename to proteus/game/scenarios/__init__.py index ca73fbfc7992803d26457bc5a3609ee354a86e4c..e94c798f46d7f1ece526693ae06533313e619684 100644 --- a/proteus/grid/scenarios/__init__.py +++ b/proteus/game/scenarios/__init__.py @@ -1,10 +1,10 @@ """Scenario implementations for the motive_grid family. Importing this package fires each scenario's ``@register_scenario`` decorator, -populating the registry in :mod:`proteus.grid.scenario`. +populating the registry in :mod:`proteus.game.scenarios.base`. """ -from proteus.grid.scenarios import predator_evade # noqa: F401 — side-effect: register -from proteus.grid.scenarios import pack_evade # noqa: F401 — side-effect: register +from proteus.game.scenarios import predator_evade # noqa: F401 — side-effect: register +from proteus.game.scenarios import pack_evade # noqa: F401 — side-effect: register __all__ = ["predator_evade", "pack_evade"] diff --git a/proteus/grid/scenario.py b/proteus/game/scenarios/base.py similarity index 96% rename from proteus/grid/scenario.py rename to proteus/game/scenarios/base.py index a8d96233c3e8b18aced395ac26b9227e138a4250..4f07128ca484af4f405ab2c43e65130958b32f3b 100644 --- a/proteus/grid/scenario.py +++ b/proteus/game/scenarios/base.py @@ -7,9 +7,9 @@ and the prediction/discrimination answer keys) while the shared turn loop in Concrete scenarios register themselves via the ``@register_scenario`` decorator, mirroring the task-module registry at -``proteus.grid``:: +``proteus.game.scenarios``:: - from proteus.grid.scenario import ( + from proteus.game.scenarios.base import ( Scenario, register_scenario, ) @@ -18,7 +18,7 @@ decorator, mirroring the task-module registry at ... # Elsewhere: - from proteus.grid.scenario import get_scenario + from proteus.game.scenarios.base import get_scenario scenario = get_scenario("predator_evade")() See ``docs/superpowers/specs/2026-06-01-motive-grid-design.md`` §4 for the @@ -31,15 +31,15 @@ import random from abc import ABC, abstractmethod from typing import TYPE_CHECKING -from proteus.arc_grid import Level +from proteus.game.engine import Level if TYPE_CHECKING: # Imported only for type checking to avoid a runtime circular import: # game.py imports scenario.py is NOT done at runtime; instead a Scenario # is injected into MotiveGridGame, and the game reads it back here only # for annotations. - from .game import MotiveGridGame - from .difficulty import Difficulty + from ..engine.grid import MotiveGridGame + from ..engine.difficulty import Difficulty class Scenario(ABC): @@ -79,7 +79,7 @@ class Scenario(ABC): difficulty: The session difficulty band (a ``Difficulty``). Returns: - A freshly built :class:`~proteus.arc_grid.Level`. + A freshly built :class:`~proteus.game.engine.Level`. """ raise NotImplementedError @@ -216,7 +216,7 @@ class Scenario(ABC): scenarios override this with a compact textual state so the observation is not a several-thousand-character grid. """ - from proteus.grid.ascii_view import frame_to_ascii + from proteus.game.engine.ascii_view import frame_to_ascii return frame_to_ascii(game.current_grid(), self.legend()) def default_memory(self, seed, difficulty): diff --git a/proteus/grid/scenarios/pack_evade.py b/proteus/game/scenarios/pack_evade.py similarity index 96% rename from proteus/grid/scenarios/pack_evade.py rename to proteus/game/scenarios/pack_evade.py index b1d82c31f806a7546fd802086d666a7e8201b58c..958df83f438b45dbc7840e33360c8e15e68afff6 100644 --- a/proteus/grid/scenarios/pack_evade.py +++ b/proteus/game/scenarios/pack_evade.py @@ -2,7 +2,7 @@ A single 5x5 predator hunts a 3x3 focal agent (the lone survivor of a pack of three; the two that were caught live only in the hand-authored handover memory, -see ``proteus.runtime.pack_evade_memory``). The field is open (no walls), so all +see ``proteus.game.runtime.pack_evade_memory``). The field is open (no walls), so all geometry is **center-to-center Manhattan** — no BFS. There is no habit/diagnostic (``optimal_action == habit_action`` always): this is pure evasion. @@ -15,14 +15,14 @@ from __future__ import annotations import random from typing import TYPE_CHECKING -from proteus.arc_grid import BlockingMode, Level, Sprite -from proteus.grid.difficulty import Difficulty +from proteus.game.engine import BlockingMode, Level, Sprite +from proteus.game.engine.difficulty import Difficulty -from ..scenario import Scenario, register_scenario +from .base import Scenario, register_scenario if TYPE_CHECKING: - from ..game import MotiveGridGame - from proteus.runtime.memory import MemoryCheckpoint + from ..engine.grid import MotiveGridGame + from proteus.game.runtime.memory import MemoryCheckpoint BACKGROUND_IDX = 5 # arc_grid Camera default background FOCAL_IDX = 1 @@ -441,7 +441,7 @@ class PackEvade(Scenario): """True iff the 3x3 focal footprint anchored at *cell* is on-grid + wall-free. Used only by the shared hidden-persona reference policy - (``proteus.runtime.persona``), which calls it on the focal's top-left + (``proteus.game.metrics.persona``), which calls it on the focal's top-left anchor, so footprint-awareness is exactly the right semantics here. """ return self._footprint_free(game, game.focal_sprite, cell[0], cell[1]) @@ -473,10 +473,10 @@ class PackEvade(Scenario): actually plays a pack_evade episode, and that self-play trajectory is the handover memory. The eval model sees only the behaviour (the raw weights are never serialized) and must infer/maintain the persona. Reuses the - CP7/CP8 generator (``proteus.runtime.memory_gen``) in its persona mode. + CP7/CP8 generator (``proteus.game.runtime.memory_gen``) in its persona mode. """ - from proteus.runtime.memory_gen import generate_memory - from proteus.runtime.persona import get_persona + from proteus.game.runtime.memory_gen import generate_memory + from proteus.game.metrics.persona import get_persona return generate_memory( "pack_evade", None, diff --git a/proteus/grid/scenarios/predator_evade.py b/proteus/game/scenarios/predator_evade.py similarity index 98% rename from proteus/grid/scenarios/predator_evade.py rename to proteus/game/scenarios/predator_evade.py index af1e36771dd801b5750725797416bf5106fe818d..cbd4e73afea4b0b93af74abd1fa0a6403b53b496 100644 --- a/proteus/grid/scenarios/predator_evade.py +++ b/proteus/game/scenarios/predator_evade.py @@ -63,13 +63,13 @@ from collections import deque from dataclasses import dataclass from typing import TYPE_CHECKING -from proteus.arc_grid import BlockingMode, Level, Sprite -from proteus.grid.difficulty import Difficulty +from proteus.game.engine import BlockingMode, Level, Sprite +from proteus.game.engine.difficulty import Difficulty -from ..scenario import Scenario, register_scenario +from .base import Scenario, register_scenario if TYPE_CHECKING: - from ..game import MotiveGridGame + from ..engine.grid import MotiveGridGame # --------------------------------------------------------------------------- # # Palette indices (must match build_level pixels and legend()). @@ -238,7 +238,7 @@ class PredatorEvade(Scenario): difficulty: The session difficulty band. Returns: - A :class:`~proteus.arc_grid.Level` with focal, predator, and walls. + A :class:`~proteus.game.engine.Level` with focal, predator, and walls. """ del rng # deterministic hand-authored layouts layout = _LAYOUTS.get(difficulty, _LAYOUTS[Difficulty.EASY]) diff --git a/proteus/viz/__init__.py b/proteus/game/viz/__init__.py similarity index 67% rename from proteus/viz/__init__.py rename to proteus/game/viz/__init__.py index da387bc5fff4dc2ea5e3b25210a9644a45873e9e..ef08d61fbeb4ab2f93d6a19d065b30ef72f23f89 100644 --- a/proteus/viz/__init__.py +++ b/proteus/game/viz/__init__.py @@ -1,4 +1,4 @@ -"""proteus.viz — human/debug visualization of a SessionTrace. +"""proteus.game.viz — human/debug visualization of a SessionTrace. Frames are reconstructed by deterministically replaying the trace through the real engine (reconstruct), then rendered to the terminal (truecolor + side @@ -6,15 +6,15 @@ panel) or to per-frame PNGs. matplotlib (the `viz` extra) is imported lazily by the PNG writer only, so importing this package stays offline-safe. """ -from proteus.viz.gif import write_gif -from proteus.viz.png import write_pngs -from proteus.viz.reconstruct import ( +from proteus.game.viz.gif import write_gif +from proteus.game.viz.png import write_pngs +from proteus.game.viz.reconstruct import ( FrameMeta, FrameStep, TraceReconstructionError, reconstruct, ) -from proteus.viz.terminal import render as render_terminal +from proteus.game.viz.terminal import render as render_terminal __all__ = [ "FrameMeta", diff --git a/proteus/viz/gif.py b/proteus/game/viz/gif.py similarity index 93% rename from proteus/viz/gif.py rename to proteus/game/viz/gif.py index 00413fe09d87df5935f74606cc4108dd40688e7c..0184dd510cc95d5226fd080ae5debe2806e29b7e 100644 --- a/proteus/viz/gif.py +++ b/proteus/game/viz/gif.py @@ -10,8 +10,8 @@ from __future__ import annotations from pathlib import Path from typing import Union -from proteus.arc_grid.rendering import COLOR_MAP, frame_to_rgb_array -from proteus.viz.reconstruct import FrameStep +from proteus.game.engine.rendering import COLOR_MAP, frame_to_rgb_array +from proteus.game.viz.reconstruct import FrameStep def write_gif( diff --git a/proteus/viz/png.py b/proteus/game/viz/png.py similarity index 94% rename from proteus/viz/png.py rename to proteus/game/viz/png.py index ed8b32d887ebb0679ad5903a5350b92241c5f033..d2f62ebd3672fcdfc451f77c5d2015e8f0ab3109 100644 --- a/proteus/viz/png.py +++ b/proteus/game/viz/png.py @@ -12,8 +12,8 @@ from __future__ import annotations from pathlib import Path from typing import Union -from proteus.arc_grid.rendering import COLOR_MAP, frame_to_rgb_array -from proteus.viz.reconstruct import FrameStep +from proteus.game.engine.rendering import COLOR_MAP, frame_to_rgb_array +from proteus.game.viz.reconstruct import FrameStep def _title(step: FrameStep) -> str: diff --git a/proteus/viz/reconstruct.py b/proteus/game/viz/reconstruct.py similarity index 95% rename from proteus/viz/reconstruct.py rename to proteus/game/viz/reconstruct.py index a21ae00c8ae1d1c0f1701f7a00575ca9e33c2b1d..f119a17f1ab45adf027e8cff873a70b82bfe10b0 100644 --- a/proteus/viz/reconstruct.py +++ b/proteus/game/viz/reconstruct.py @@ -21,11 +21,11 @@ from dataclasses import dataclass import numpy as np -from proteus.grid.ascii_view import frame_to_ascii -from proteus.grid.difficulty import Difficulty -from proteus.grid.game import MotiveGridGame -from proteus.grid.scenario import get_scenario -from proteus.runtime.trace import SessionTrace, TurnTrace +from proteus.game.engine.ascii_view import frame_to_ascii +from proteus.game.engine.difficulty import Difficulty +from proteus.game.engine.grid import MotiveGridGame +from proteus.game.scenarios.base import get_scenario +from proteus.game.runtime.trace import SessionTrace, TurnTrace class TraceReconstructionError(RuntimeError): diff --git a/proteus/viz/terminal.py b/proteus/game/viz/terminal.py similarity index 95% rename from proteus/viz/terminal.py rename to proteus/game/viz/terminal.py index 067bc00a2bfaef56f1f25b6b07785f341b0d59c7..8fbcb7ce2a2b8eb91fd9d5ab579760937a1a9de0 100644 --- a/proteus/viz/terminal.py +++ b/proteus/game/viz/terminal.py @@ -15,8 +15,8 @@ from __future__ import annotations import time from typing import Callable, Optional -from proteus.arc_grid.rendering import COLOR_MAP, hex_to_rgb, rgb_to_ansi -from proteus.viz.reconstruct import FrameMeta, FrameStep +from proteus.game.engine.rendering import COLOR_MAP, hex_to_rgb, rgb_to_ansi +from proteus.game.viz.reconstruct import FrameMeta, FrameStep _RESET = "\033[0m" _BLOCK = "██" diff --git a/proteus/grid/__init__.py b/proteus/grid/__init__.py deleted file mode 100644 index b91796c1ef3a8ed4872a9a00fd0318a2a5082519..0000000000000000000000000000000000000000 --- a/proteus/grid/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -"""proteus.grid — the motive_grid scenario family (ported). - -Importing this package imports :mod:`proteus.grid.scenarios`, whose -``@register_scenario`` decorators populate the scenario registry so -``get_scenario("predator_evade")`` resolves. -""" - -from proteus.grid import scenarios # noqa: F401 — side-effect: populate registry - -__all__ = ["scenarios"] diff --git a/proteus/shared/__init__.py b/proteus/shared/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..47dcfd61f2778c21286be34b960e93035b4c9350 --- /dev/null +++ b/proteus/shared/__init__.py @@ -0,0 +1,6 @@ +"""proteus.shared — cross-cutting vocabulary shared by game and web. + +Skeleton for now. Future home for trace/data models hoisted out of +game.runtime to break the game.runtime <-> game.metrics package cycle +(see 2026-06-02-proteus-game-web-restructure-design.md §6.1). +""" diff --git a/proteus/web/__init__.py b/proteus/web/__init__.py index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..324a50bcfe97e4d4ac4bdbab2fb580aaf8fea60c 100644 --- a/proteus/web/__init__.py +++ b/proteus/web/__init__.py @@ -0,0 +1 @@ +"""proteus.web — interface publishing. local (stdlib single-user) + arena (skeleton).""" diff --git a/proteus/web/__main__.py b/proteus/web/__main__.py index cb85c208e8ef1ae7358241df279d1a364a33e360..21f423d093728a1b25bb3b6eef95cf8c1dfc7da0 100644 --- a/proteus/web/__main__.py +++ b/proteus/web/__main__.py @@ -1,29 +1,4 @@ -"""`python -m proteus.web` — launch the interactive color-grid play server.""" -from __future__ import annotations +"""`python -m proteus.web` — delegate to the local play server.""" +from proteus.web.local.__main__ import main -import argparse - -import proteus.grid # noqa: F401 (registers scenarios before any request) -from proteus.web.server import make_server - - -def main(argv: list[str] | None = None) -> int: - parser = argparse.ArgumentParser(prog="proteus.web") - parser.add_argument("--host", default="127.0.0.1") - parser.add_argument("--port", type=int, default=8000) - args = parser.parse_args(argv) - - server = make_server(args.host, args.port) - host, port = server.server_address[0], server.server_address[1] - print(f"PROTEUS arena — open http://{host}:{port}/ (Ctrl-C to stop)") - try: - server.serve_forever() - except KeyboardInterrupt: - print("\nstopping.") - finally: - server.server_close() - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) +raise SystemExit(main()) diff --git a/proteus/web/arena/__init__.py b/proteus/web/arena/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..2f18318da49ff8ef3b9cfe450885eb51904e144a --- /dev/null +++ b/proteus/web/arena/__init__.py @@ -0,0 +1,6 @@ +"""proteus.web.arena — multi-user competition arena (SKELETON). + +Design: docs/superpowers/specs/2026-06-02-arena-leaderboard-db-design.md +Subpackages: api (REST routes), db (ORM + migrations), leaderboard +(aggregation), worker (eval queue + runner). Not implemented yet. +""" diff --git a/proteus/web/arena/api/__init__.py b/proteus/web/arena/api/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..bcfecf59a1fb4270baa5b5f30fe978a4071a6e0c --- /dev/null +++ b/proteus/web/arena/api/__init__.py @@ -0,0 +1 @@ +"""Arena skeleton — not implemented. See 2026-06-02-arena-leaderboard-db-design.md.""" diff --git a/proteus/web/arena/db/__init__.py b/proteus/web/arena/db/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..bcfecf59a1fb4270baa5b5f30fe978a4071a6e0c --- /dev/null +++ b/proteus/web/arena/db/__init__.py @@ -0,0 +1 @@ +"""Arena skeleton — not implemented. See 2026-06-02-arena-leaderboard-db-design.md.""" diff --git a/proteus/web/arena/leaderboard/__init__.py b/proteus/web/arena/leaderboard/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..bcfecf59a1fb4270baa5b5f30fe978a4071a6e0c --- /dev/null +++ b/proteus/web/arena/leaderboard/__init__.py @@ -0,0 +1 @@ +"""Arena skeleton — not implemented. See 2026-06-02-arena-leaderboard-db-design.md.""" diff --git a/proteus/web/arena/worker/__init__.py b/proteus/web/arena/worker/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..bcfecf59a1fb4270baa5b5f30fe978a4071a6e0c --- /dev/null +++ b/proteus/web/arena/worker/__init__.py @@ -0,0 +1 @@ +"""Arena skeleton — not implemented. See 2026-06-02-arena-leaderboard-db-design.md.""" diff --git a/proteus/web/local/__init__.py b/proteus/web/local/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/proteus/web/local/__main__.py b/proteus/web/local/__main__.py new file mode 100644 index 0000000000000000000000000000000000000000..4dcb57419b7acf7e72c50c7365ee22970b3f9435 --- /dev/null +++ b/proteus/web/local/__main__.py @@ -0,0 +1,29 @@ +"""`python -m proteus.web.local` — launch the interactive color-grid play server.""" +from __future__ import annotations + +import argparse + +import proteus.game.scenarios # noqa: F401 (registers scenarios before any request) +from proteus.web.local.server import make_server + + +def main(argv: list[str] | None = None) -> int: + parser = argparse.ArgumentParser(prog="proteus.web.local") + parser.add_argument("--host", default="127.0.0.1") + parser.add_argument("--port", type=int, default=8000) + args = parser.parse_args(argv) + + server = make_server(args.host, args.port) + host, port = server.server_address[0], server.server_address[1] + print(f"PROTEUS arena — open http://{host}:{port}/ (Ctrl-C to stop)") + try: + server.serve_forever() + except KeyboardInterrupt: + print("\nstopping.") + finally: + server.server_close() + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/proteus/web/server.py b/proteus/web/local/server.py similarity index 91% rename from proteus/web/server.py rename to proteus/web/local/server.py index 32a46fa26586f78d44bae3acb944af7f5571fa19..5bc44350eea98526097f40fbbbcc539db977e327 100644 --- a/proteus/web/server.py +++ b/proteus/web/local/server.py @@ -16,12 +16,12 @@ import uuid from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer from pathlib import Path -from proteus.arc_grid.rendering import COLOR_MAP -from proteus.grid.difficulty import Difficulty -from proteus.grid.scenario import list_scenarios -from proteus.runtime import _session_core as core -from proteus.runtime.interactive import InteractiveSession -from proteus.runtime.io import append_trace +from proteus.game.engine.rendering import COLOR_MAP +from proteus.game.engine.difficulty import Difficulty +from proteus.game.scenarios.base import list_scenarios +from proteus.game.runtime import _session_core as core +from proteus.game.runtime.interactive import InteractiveSession +from proteus.game.runtime.io import append_trace _STATIC = Path(__file__).parent / "static" / "index.html" _DEFAULT_SEED = 42 @@ -66,9 +66,9 @@ def _resolve_web_memory( return None, True, None if mode == "none": return None, False, None - from proteus.runtime.memory_gen import generate_memory + from proteus.game.runtime.memory_gen import generate_memory if mode.startswith("persona"): - from proteus.runtime.persona import available_personas, get_persona + from proteus.game.metrics.persona import available_personas, get_persona pid = mode.split(":", 1)[1] if ":" in mode else "risk_averse" try: persona = get_persona(pid) @@ -80,7 +80,7 @@ def _resolve_web_memory( ) return ckpt, False, None if mode.startswith("policy:"): - from proteus.runtime.memory_policies import available_policies, get_policy + from proteus.game.runtime.memory_policies import available_policies, get_policy name = mode.split(":", 1)[1] try: policy = get_policy(name) @@ -100,20 +100,20 @@ def _resolve_web_memory( except Exception as exc: # missing SDK / key / bad spec -> clear client error return None, False, str(exc) if mode == "generate": - from proteus.agents.vanilla import VanillaAgent - from proteus.runtime.memory import save_checkpoint + from proteus.game.agents.vanilla import VanillaAgent + from proteus.game.runtime.memory import save_checkpoint ckpt = generate_memory( scenario, VanillaAgent(provider), difficulty=difficulty, seed=seed, memory_turns=memory_turns, model_name=provider.model_name, ) save_checkpoint(ckpt, root=memory_root) return ckpt, False, None - from proteus.runtime.memory import latest_for_model + from proteus.game.runtime.memory import latest_for_model ckpt = latest_for_model(provider.model_name, root=memory_root) if ckpt is None: return None, False, f"no saved memory for {provider.model_name!r}" return ckpt, False, None - from proteus.runtime.memory import load_checkpoint + from proteus.game.runtime.memory import load_checkpoint try: return load_checkpoint(mode), False, None except FileNotFoundError: @@ -136,8 +136,8 @@ def _memory_info(session) -> dict: "frames": [], } if mem is not None: - from proteus.grid.scenario import get_scenario - from proteus.runtime.memory import memory_frames, render_memory_block + from proteus.game.scenarios.base import get_scenario + from proteus.game.runtime.memory import memory_frames, render_memory_block info["block"] = render_memory_block(mem) scen = get_scenario(mem.scenario)() info["frames"] = memory_frames( @@ -206,10 +206,10 @@ def _finish(sid: str, body: dict, registry: dict) -> Response: def _create_spectate(body: dict, registry: dict) -> Response: - # Lazy imports keep `import proteus.web.server` free of provider SDKs. - from proteus.agents.vanilla import VanillaAgent + # Lazy imports keep `import proteus.web.local.server` free of provider SDKs. + from proteus.game.agents.vanilla import VanillaAgent from proteus.providers import make_provider - from proteus.runtime.spectate import SpectateSession + from proteus.game.runtime.spectate import SpectateSession try: scenario = body["scenario"] difficulty = Difficulty(body.get("difficulty", "easy")) diff --git a/proteus/web/static/index.html b/proteus/web/local/static/index.html similarity index 100% rename from proteus/web/static/index.html rename to proteus/web/local/static/index.html diff --git a/tests/agents/test_agent_base.py b/tests/agents/test_agent_base.py index 71e44cca460b4deabc6ad0edb96d5bb80e0c4130..ccd4c58985822f7882c1d5f78332dc2522a0ddcf 100644 --- a/tests/agents/test_agent_base.py +++ b/tests/agents/test_agent_base.py @@ -1,6 +1,6 @@ import pytest -from proteus.agents.base import Agent, ActResult +from proteus.game.agents.base import Agent, ActResult def test_actresult_fields(): diff --git a/tests/agents/test_human.py b/tests/agents/test_human.py index 31eec7a5f830abbbe72104e2316d35105356597e..4058bae80e876c3a9458c228acd7256daee992fc 100644 --- a/tests/agents/test_human.py +++ b/tests/agents/test_human.py @@ -1,5 +1,5 @@ -from proteus.agents import HumanAgent -from proteus.agents.base import ActResult, ProbeResult +from proteus.game.agents import HumanAgent +from proteus.game.agents.base import ActResult, ProbeResult _ACTIONS = ["up", "down", "left", "right", "stay"] diff --git a/tests/agents/test_parsing.py b/tests/agents/test_parsing.py index 96ab11bfd748a3ca7d0dcfc10a6830d1a7d2927b..04b2b3f01adf037e4e5dba0cfe376f6e57f2c913 100644 --- a/tests/agents/test_parsing.py +++ b/tests/agents/test_parsing.py @@ -1,4 +1,4 @@ -from proteus.agents.parsing import extract_action +from proteus.game.agents.parsing import extract_action VALID = ["up", "down", "left", "right", "stay"] diff --git a/tests/agents/test_vanilla.py b/tests/agents/test_vanilla.py index ec78a4f28c5698eef7a6a76a97f45d14972876fa..a389009caa2f6c5e6f270fce2cab00944c377ea0 100644 --- a/tests/agents/test_vanilla.py +++ b/tests/agents/test_vanilla.py @@ -1,5 +1,5 @@ from proteus.providers import FakeProvider -from proteus.agents import VanillaAgent, ActResult +from proteus.game.agents import VanillaAgent, ActResult VALID = ["up", "down", "left", "right", "stay"] @@ -106,7 +106,7 @@ def test_act_prefers_provider_thinking_tokens_when_present(): def test_probe_returns_probe_result_with_reasoning_and_tokens(): - from proteus.agents import ProbeResult + from proteus.game.agents import ProbeResult provider = FakeProvider(responses=["predator is two cells eastgo up"]) result = VanillaAgent(provider).probe("grid", "where is the predator?", "rules") assert isinstance(result, ProbeResult) diff --git a/tests/cli/test_cli.py b/tests/cli/test_cli.py index 41f8f1ce039dfb51cc91e044908f27b3f34f4264..abdc5ad92c50e33f6b20aa4e821ac51e4fd57e91 100644 --- a/tests/cli/test_cli.py +++ b/tests/cli/test_cli.py @@ -1,5 +1,5 @@ from proteus.cli import main -from proteus.runtime import read_traces +from proteus.game.runtime import read_traces def test_list_scenarios_prints_predator_evade(capsys): diff --git a/tests/cli/test_cli_memory.py b/tests/cli/test_cli_memory.py index c583a8954d28a6c66f5aa2cd3fecdb617093edc0..0bc4525132709a382f360c4d9cd06cf36de317cd 100644 --- a/tests/cli/test_cli_memory.py +++ b/tests/cli/test_cli_memory.py @@ -1,5 +1,5 @@ from proteus.cli import main -from proteus.runtime.memory import load_checkpoint +from proteus.game.runtime.memory import load_checkpoint def test_memory_subcommand_writes_loadable_checkpoint(tmp_path): @@ -25,7 +25,7 @@ def test_memory_subcommand_unknown_model_exits_2(tmp_path, capsys): assert "bogusprovider" in capsys.readouterr().err -from proteus.runtime import read_traces +from proteus.game.runtime import read_traces def test_run_memory_generate_sets_memory_ref(tmp_path): diff --git a/tests/cli/test_cli_persona.py b/tests/cli/test_cli_persona.py index 17d09972d5062e2bcde283f4babc0cc4923802ea..4645b3b7ccbbffe5fb146dbb2709ba963943351b 100644 --- a/tests/cli/test_cli_persona.py +++ b/tests/cli/test_cli_persona.py @@ -1,5 +1,5 @@ from proteus.cli import main -from proteus.runtime import read_traces +from proteus.game.runtime import read_traces def test_run_with_persona_records_id_and_metrics(tmp_path): @@ -41,7 +41,7 @@ def test_run_unknown_persona_errors(tmp_path): def test_memory_with_persona_tags_checkpoint(tmp_path): - from proteus.runtime.memory import load_checkpoint + from proteus.game.runtime.memory import load_checkpoint out = tmp_path / "mem.json" rc = main([ "memory", "--scenario", "predator_evade", "--model", "fake:demo", diff --git a/tests/grid/test_ascii_view.py b/tests/grid/test_ascii_view.py index e9ada8c288cb7863b2a9d2e80747f68319f84068..8a9150dd2a13d407481cd597492e60b07c4ee458 100644 --- a/tests/grid/test_ascii_view.py +++ b/tests/grid/test_ascii_view.py @@ -1,6 +1,6 @@ import numpy as np -from proteus.grid.ascii_view import frame_to_ascii, legend_text +from proteus.game.engine.ascii_view import frame_to_ascii, legend_text def test_frame_to_ascii_maps_indices_and_unknowns(): diff --git a/tests/grid/test_difficulty.py b/tests/grid/test_difficulty.py index fe25720745af853d99005ff884528a69fc99b2e2..01bc6fff94435badb5b48f19184985c184a0c956 100644 --- a/tests/grid/test_difficulty.py +++ b/tests/grid/test_difficulty.py @@ -1,4 +1,4 @@ -from proteus.grid.difficulty import Difficulty +from proteus.game.engine.difficulty import Difficulty def test_difficulty_values(): diff --git a/tests/grid/test_difficulty_layouts.py b/tests/grid/test_difficulty_layouts.py index b6fafc263b011269ca3da922404c32640bffda99..482f9282468067294d42c7169620ff23cffb4e98 100644 --- a/tests/grid/test_difficulty_layouts.py +++ b/tests/grid/test_difficulty_layouts.py @@ -2,9 +2,9 @@ import random import numpy as np -from proteus.grid.difficulty import Difficulty -from proteus.grid.game import MotiveGridGame -from proteus.grid.scenario import Scenario, get_scenario +from proteus.game.engine.difficulty import Difficulty +from proteus.game.engine.grid import MotiveGridGame +from proteus.game.scenarios.base import Scenario, get_scenario def _scenario(): diff --git a/tests/grid/test_distance_helpers.py b/tests/grid/test_distance_helpers.py index 380859fb83e70e63fc4b4c589fce238fd59503b6..176892a20a84881d046a00b2c729b37347c23050 100644 --- a/tests/grid/test_distance_helpers.py +++ b/tests/grid/test_distance_helpers.py @@ -1,8 +1,8 @@ import random -import proteus.grid # noqa: F401 -from proteus.grid.difficulty import Difficulty -from proteus.grid.game import MotiveGridGame -from proteus.grid.scenario import Scenario, get_scenario +import proteus.game.scenarios # noqa: F401 +from proteus.game.engine.difficulty import Difficulty +from proteus.game.engine.grid import MotiveGridGame +from proteus.game.scenarios.base import Scenario, get_scenario def _game(): diff --git a/tests/grid/test_footprint_bounds.py b/tests/grid/test_footprint_bounds.py index 527e78b57d785e20509287002f442fe37dc0480b..869cd8a7fd0e6a40400bc61f4008bce2fb206764 100644 --- a/tests/grid/test_footprint_bounds.py +++ b/tests/grid/test_footprint_bounds.py @@ -4,10 +4,10 @@ from __future__ import annotations import random -import proteus.grid # noqa: F401 -from proteus.grid.difficulty import Difficulty -from proteus.grid.game import MotiveGridGame -from proteus.grid.scenario import get_scenario +import proteus.game.scenarios # noqa: F401 +from proteus.game.engine.difficulty import Difficulty +from proteus.game.engine.grid import MotiveGridGame +from proteus.game.scenarios.base import get_scenario def test_3x3_focal_cannot_leave_grid(): diff --git a/tests/grid/test_game_import.py b/tests/grid/test_game_import.py index c571e92ee0ddd6045766b13593b389adcd941044..fa910e54bda7da4d929cb6579a9a238ac52f76f6 100644 --- a/tests/grid/test_game_import.py +++ b/tests/grid/test_game_import.py @@ -1,5 +1,5 @@ def test_game_module_imports_and_action_maps_are_consistent(): - from proteus.grid.game import ( + from proteus.game.engine.grid import ( MotiveGridGame, _DIRECTION_DELTAS, _ACTION_TO_GAMEACTION, diff --git a/tests/grid/test_pack_evade.py b/tests/grid/test_pack_evade.py index 4a92eedb55d2f99bc29930a6f81b33e49c052546..76fce1c6d72c2eb5470b8fa1b90c6a4602f7ca17 100644 --- a/tests/grid/test_pack_evade.py +++ b/tests/grid/test_pack_evade.py @@ -3,10 +3,10 @@ from __future__ import annotations import random -import proteus.grid # noqa: F401 (registers scenarios) -from proteus.grid.difficulty import Difficulty -from proteus.grid.game import MotiveGridGame -from proteus.grid.scenario import get_scenario +import proteus.game.scenarios # noqa: F401 (registers scenarios) +from proteus.game.engine.difficulty import Difficulty +from proteus.game.engine.grid import MotiveGridGame +from proteus.game.scenarios.base import get_scenario def _game(play_turns=20): diff --git a/tests/grid/test_pack_evade_food.py b/tests/grid/test_pack_evade_food.py index b0628ad5fec3ce60438df423535f52bf628aeda0..9633a584ec678874340a0522031a91d0503a420d 100644 --- a/tests/grid/test_pack_evade_food.py +++ b/tests/grid/test_pack_evade_food.py @@ -3,10 +3,10 @@ from __future__ import annotations import random -import proteus.grid # noqa: F401 (registers scenarios) -from proteus.grid.difficulty import Difficulty -from proteus.grid.game import MotiveGridGame -from proteus.grid.scenario import get_scenario +import proteus.game.scenarios # noqa: F401 (registers scenarios) +from proteus.game.engine.difficulty import Difficulty +from proteus.game.engine.grid import MotiveGridGame +from proteus.game.scenarios.base import get_scenario def _scn(seed=7, diff=Difficulty.MEDIUM): diff --git a/tests/grid/test_pack_evade_observation.py b/tests/grid/test_pack_evade_observation.py index 306469e0ac87edf76ffd3f1dcce52a6e685e766a..549be6d4b01cb846c854715f329ac41304d8a452 100644 --- a/tests/grid/test_pack_evade_observation.py +++ b/tests/grid/test_pack_evade_observation.py @@ -4,11 +4,11 @@ from __future__ import annotations import random -import proteus.grid # noqa: F401 -from proteus.grid.ascii_view import frame_to_ascii -from proteus.grid.difficulty import Difficulty -from proteus.grid.game import MotiveGridGame -from proteus.grid.scenario import get_scenario +import proteus.game.scenarios # noqa: F401 +from proteus.game.engine.ascii_view import frame_to_ascii +from proteus.game.engine.difficulty import Difficulty +from proteus.game.engine.grid import MotiveGridGame +from proteus.game.scenarios.base import get_scenario def test_predator_evade_render_frame_is_unchanged_ascii(): diff --git a/tests/grid/test_pack_evade_walls.py b/tests/grid/test_pack_evade_walls.py index 8ba84c22d1664d6944d9224efcc11b5df3a652ee..a8a441c3f3cdd8dbd4cd1329878e5d4da7e526fd 100644 --- a/tests/grid/test_pack_evade_walls.py +++ b/tests/grid/test_pack_evade_walls.py @@ -3,10 +3,10 @@ from __future__ import annotations import random -import proteus.grid # noqa: F401 (registers scenarios) -from proteus.grid.difficulty import Difficulty -from proteus.grid.game import MotiveGridGame -from proteus.grid.scenario import get_scenario +import proteus.game.scenarios # noqa: F401 (registers scenarios) +from proteus.game.engine.difficulty import Difficulty +from proteus.game.engine.grid import MotiveGridGame +from proteus.game.scenarios.base import get_scenario def _scn(seed=7, diff=Difficulty.MEDIUM): diff --git a/tests/grid/test_predator_evade_behavior.py b/tests/grid/test_predator_evade_behavior.py index f67f4300c03b913ce1be026a73f41220d52920d0..c3b0dfbe8050eb7f924dd30e8864f1fc84cd6d1d 100644 --- a/tests/grid/test_predator_evade_behavior.py +++ b/tests/grid/test_predator_evade_behavior.py @@ -1,8 +1,8 @@ import random -from proteus.grid.difficulty import Difficulty -from proteus.grid.game import MotiveGridGame -from proteus.grid.scenario import get_scenario +from proteus.game.engine.difficulty import Difficulty +from proteus.game.engine.grid import MotiveGridGame +from proteus.game.scenarios.base import get_scenario def _build_at_handover(): diff --git a/tests/grid/test_predator_evade_registered.py b/tests/grid/test_predator_evade_registered.py index 36d3e8a4e11c0581e746f113899e325101b91f8c..8d3c1512fb6a3d8b853858ed57430cdb8c5be12d 100644 --- a/tests/grid/test_predator_evade_registered.py +++ b/tests/grid/test_predator_evade_registered.py @@ -1,6 +1,6 @@ def test_importing_proteus_grid_registers_predator_evade(): - import proteus.grid # noqa: F401 (side-effect: registers scenarios) - from proteus.grid.scenario import get_scenario, list_scenarios + import proteus.game.scenarios # noqa: F401 (side-effect: registers scenarios) + from proteus.game.scenarios.base import get_scenario, list_scenarios assert "predator_evade" in list_scenarios() cls = get_scenario("predator_evade") inst = cls() diff --git a/tests/grid/test_scenario_registry.py b/tests/grid/test_scenario_registry.py index 7cbb7068d64b9b10caffd6c87429a0a5f20bdea4..4eddf2611b4d5638acdd650269e15f74e16a54cd 100644 --- a/tests/grid/test_scenario_registry.py +++ b/tests/grid/test_scenario_registry.py @@ -1,6 +1,6 @@ import pytest -from proteus.grid.scenario import ( +from proteus.game.scenarios.base import ( Scenario, register_scenario, get_scenario, diff --git a/tests/grid/test_step_reward.py b/tests/grid/test_step_reward.py index b97e3ab25a0c35e9c7e3e02c29446fe57c640575..f089c8d6f16712538d28eb7626785e8c96dff7b7 100644 --- a/tests/grid/test_step_reward.py +++ b/tests/grid/test_step_reward.py @@ -1,8 +1,8 @@ import random -from proteus.grid.difficulty import Difficulty -from proteus.grid.game import MotiveGridGame -from proteus.grid.scenario import get_scenario +from proteus.game.engine.difficulty import Difficulty +from proteus.game.engine.grid import MotiveGridGame +from proteus.game.scenarios.base import get_scenario def _handover(): diff --git a/tests/runtime/test_aggregate.py b/tests/runtime/test_aggregate.py index b763f10dd6a5df5b04e1d793c2dbfc07967ddda5..446b0458deff7a4fdf9b2e0d9916eaa4eab962f3 100644 --- a/tests/runtime/test_aggregate.py +++ b/tests/runtime/test_aggregate.py @@ -1,7 +1,7 @@ -from proteus.agents import VanillaAgent +from proteus.game.agents import VanillaAgent from proteus.providers import FakeProvider -from proteus.runtime.aggregate import aggregate_traces -from proteus.runtime.session import SessionRunner +from proteus.game.metrics.aggregate import aggregate_traces +from proteus.game.runtime.session import SessionRunner def _trace(seed): diff --git a/tests/runtime/test_auto_regressive.py b/tests/runtime/test_auto_regressive.py index a582b0314e3430aedda46030c4a4faa3f093fe82..a9414285a58164d4632acdadb2bc3c4a2e190aef 100644 --- a/tests/runtime/test_auto_regressive.py +++ b/tests/runtime/test_auto_regressive.py @@ -3,10 +3,10 @@ OWN prior moves this run AND the handover memory every turn (not just turn 1, not just the current grid) — so a stateless agent can maintain its trajectory.""" from __future__ import annotations -import proteus.grid # noqa: F401 -from proteus.agents.human import HumanAgent -from proteus.grid.difficulty import Difficulty -from proteus.runtime.session import SessionRunner +import proteus.game.scenarios # noqa: F401 +from proteus.game.agents.human import HumanAgent +from proteus.game.engine.difficulty import Difficulty +from proteus.game.runtime.session import SessionRunner def _human(actions): diff --git a/tests/runtime/test_human_comparability.py b/tests/runtime/test_human_comparability.py index 61fc59ac9652d62ca01f89c3197132301e61006a..617f7856f4a717f26db400e9eb17f66b57e1e55a 100644 --- a/tests/runtime/test_human_comparability.py +++ b/tests/runtime/test_human_comparability.py @@ -1,6 +1,6 @@ -from proteus.agents import HumanAgent, VanillaAgent +from proteus.game.agents import HumanAgent, VanillaAgent from proteus.providers import FakeProvider -from proteus.runtime.session import SessionRunner +from proteus.game.runtime.session import SessionRunner def _scripted(seq): diff --git a/tests/runtime/test_integration_golden.py b/tests/runtime/test_integration_golden.py index 3fc6f616f4acf18c0cedb511a2b4ba25c8b36452..f292896618d04c36005e04eaf06f0bea0fc226ec 100644 --- a/tests/runtime/test_integration_golden.py +++ b/tests/runtime/test_integration_golden.py @@ -1,8 +1,8 @@ import json -from proteus.runtime import SessionRunner, SessionTrace +from proteus.game.runtime import SessionRunner, SessionTrace from proteus.providers import FakeProvider -from proteus.agents import VanillaAgent +from proteus.game.agents import VanillaAgent def test_full_session_serializes_to_jsonl_and_reloads(): diff --git a/tests/runtime/test_interactive_equivalence.py b/tests/runtime/test_interactive_equivalence.py index 67e03675272653b6efa7d21bc00bcf6075748ac2..29afe0a7808f13795a47e24ce52020768040f3f3 100644 --- a/tests/runtime/test_interactive_equivalence.py +++ b/tests/runtime/test_interactive_equivalence.py @@ -3,11 +3,11 @@ driven through InteractiveSession (HTTP path) or SessionRunner + a scripted HumanAgent (CLI path). This pins the two paths together so they cannot drift.""" from __future__ import annotations -import proteus.grid # noqa: F401 -from proteus.agents.human import HumanAgent -from proteus.grid.difficulty import Difficulty -from proteus.runtime.interactive import InteractiveSession -from proteus.runtime.session import SessionRunner +import proteus.game.scenarios # noqa: F401 +from proteus.game.agents.human import HumanAgent +from proteus.game.engine.difficulty import Difficulty +from proteus.game.runtime.interactive import InteractiveSession +from proteus.game.runtime.session import SessionRunner ACTIONS = ["up", "up", "left", "stay", "right", "up"] diff --git a/tests/runtime/test_interactive_session.py b/tests/runtime/test_interactive_session.py index 83b934d2753609505de7b6b658de13574316356f..4bb220997e71a72b453cbaa1bf94d048ff0fc865 100644 --- a/tests/runtime/test_interactive_session.py +++ b/tests/runtime/test_interactive_session.py @@ -3,10 +3,10 @@ from __future__ import annotations import pytest -import proteus.grid # noqa: F401 -from proteus.grid.difficulty import Difficulty -from proteus.runtime._session_core import SessionFinishedError -from proteus.runtime.interactive import InteractiveSession +import proteus.game.scenarios # noqa: F401 +from proteus.game.engine.difficulty import Difficulty +from proteus.game.runtime._session_core import SessionFinishedError +from proteus.game.runtime.interactive import InteractiveSession def _new(play_turns=10): diff --git a/tests/runtime/test_io.py b/tests/runtime/test_io.py index 19ab77704121c19a1ccf97fd23dcb4422d7cee41..d37a1f4e82a193c15b09c43fbd10ec17aaf4e2cd 100644 --- a/tests/runtime/test_io.py +++ b/tests/runtime/test_io.py @@ -1,6 +1,6 @@ -from proteus.agents import VanillaAgent +from proteus.game.agents import VanillaAgent from proteus.providers import FakeProvider -from proteus.runtime import SessionRunner, append_trace, read_traces +from proteus.game.runtime import SessionRunner, append_trace, read_traces def _trace(seed): diff --git a/tests/runtime/test_memory.py b/tests/runtime/test_memory.py index 12cbc40529981f81ecec745d83db6dd993850832..47907baa84fe049991b80a721e2409fccd141e78 100644 --- a/tests/runtime/test_memory.py +++ b/tests/runtime/test_memory.py @@ -1,4 +1,4 @@ -from proteus.runtime.memory import MemoryCheckpoint, MemoryTurn +from proteus.game.runtime.memory import MemoryCheckpoint, MemoryTurn def _checkpoint() -> MemoryCheckpoint: @@ -40,7 +40,7 @@ def test_checkpoint_defaults(): def test_save_and_load_round_trip(tmp_path): - from proteus.runtime.memory import save_checkpoint, load_checkpoint + from proteus.game.runtime.memory import save_checkpoint, load_checkpoint ck = _checkpoint() path = save_checkpoint(ck, root=tmp_path) @@ -53,7 +53,7 @@ def test_save_and_load_round_trip(tmp_path): def test_load_missing_raises(tmp_path): - from proteus.runtime.memory import load_checkpoint + from proteus.game.runtime.memory import load_checkpoint import pytest with pytest.raises(FileNotFoundError): @@ -61,7 +61,7 @@ def test_load_missing_raises(tmp_path): def test_latest_for_model_picks_newest(tmp_path): - from proteus.runtime.memory import save_checkpoint, latest_for_model + from proteus.game.runtime.memory import save_checkpoint, latest_for_model older = _checkpoint() older.created_at = "2026-06-02T09-00-00Z" @@ -76,13 +76,13 @@ def test_latest_for_model_picks_newest(tmp_path): def test_latest_for_model_none_when_absent(tmp_path): - from proteus.runtime.memory import latest_for_model + from proteus.game.runtime.memory import latest_for_model assert latest_for_model("nobody", root=tmp_path) is None def test_render_memory_block_contains_frames_and_actions(): - from proteus.runtime.memory import render_memory_block + from proteus.game.runtime.memory import render_memory_block ck = _checkpoint() block = render_memory_block(ck) @@ -92,7 +92,7 @@ def test_render_memory_block_contains_frames_and_actions(): def test_render_memory_block_empty_episode(): - from proteus.runtime.memory import MemoryCheckpoint, render_memory_block + from proteus.game.runtime.memory import MemoryCheckpoint, render_memory_block ck = MemoryCheckpoint( model="m", scenario="s", difficulty="easy", seed=None, @@ -104,7 +104,7 @@ def test_render_memory_block_empty_episode(): def test_checkpoint_wall_rects_defaults_empty_and_roundtrips(): - from proteus.runtime.memory import MemoryCheckpoint + from proteus.game.runtime.memory import MemoryCheckpoint ck = MemoryCheckpoint( model="m", scenario="pack_evade", difficulty="easy", seed=1, created_at="2026-01-01T00-00-00Z", outcome="survived", @@ -122,4 +122,4 @@ def test_checkpoint_wall_rects_defaults_empty_and_roundtrips(): def test_memory_symbols_exported_from_runtime(): - from proteus.runtime import MemoryCheckpoint, save_checkpoint # noqa: F401 + from proteus.game.runtime import MemoryCheckpoint, save_checkpoint # noqa: F401 diff --git a/tests/runtime/test_memory_frames.py b/tests/runtime/test_memory_frames.py index a06b2d2a18f91bb0dfdb5c12fe1fa1774343e08c..1efc8ea4e49bf75279f2ab67cbaccb9a27abb5ec 100644 --- a/tests/runtime/test_memory_frames.py +++ b/tests/runtime/test_memory_frames.py @@ -1,7 +1,7 @@ """Pure reconstruction of per-turn color grids from a MemoryCheckpoint.""" from __future__ import annotations -from proteus.runtime.memory import MemoryCheckpoint, MemoryTurn, memory_frames +from proteus.game.runtime.memory import MemoryCheckpoint, MemoryTurn, memory_frames _GRID_LEGEND = {5: ".", 1: "A", 2: "B", 3: "#"} @@ -50,7 +50,7 @@ def test_prose_frame_paints_food_cells(): def test_checkpoint_food_cells_roundtrips(): - from proteus.runtime.memory import MemoryCheckpoint + from proteus.game.runtime.memory import MemoryCheckpoint ck = MemoryCheckpoint( model="m", scenario="pack_evade", difficulty="easy", seed=1, created_at="t", outcome="survived", transparent_prompt="x", diff --git a/tests/runtime/test_memory_gen.py b/tests/runtime/test_memory_gen.py index 3a5aa6fb769d099d49382e811f18bd421d0c01a7..6d4979de228e9c5a7c4605102a3d9b3068084019 100644 --- a/tests/runtime/test_memory_gen.py +++ b/tests/runtime/test_memory_gen.py @@ -1,5 +1,5 @@ -import proteus.grid # noqa: F401 (registers predator_evade) -from proteus.grid.scenario import Scenario, get_scenario +import proteus.game.scenarios # noqa: F401 (registers predator_evade) +from proteus.game.scenarios.base import Scenario, get_scenario def test_scenario_base_memory_brief_default_empty(): @@ -15,8 +15,8 @@ def test_predator_evade_memory_brief_is_transparent(): assert "shortest" in low or "bfs" in low # discloses the chase rule -from proteus.agents import VanillaAgent -from proteus.grid.difficulty import Difficulty +from proteus.game.agents import VanillaAgent +from proteus.game.engine.difficulty import Difficulty from proteus.providers import FakeProvider @@ -25,7 +25,7 @@ def _agent(action: str = "down", n: int = 20) -> VanillaAgent: def test_generate_memory_is_deterministic_and_records_episode(): - from proteus.runtime.memory_gen import generate_memory + from proteus.game.runtime.memory_gen import generate_memory ck = generate_memory( "predator_evade", _agent(), difficulty=Difficulty.EASY, seed=42, @@ -48,7 +48,7 @@ def test_generate_memory_is_deterministic_and_records_episode(): def test_generate_memory_uses_memory_brief_as_prompt(): - from proteus.runtime.memory_gen import generate_memory + from proteus.game.runtime.memory_gen import generate_memory agent = _agent() generate_memory( diff --git a/tests/runtime/test_memory_persona.py b/tests/runtime/test_memory_persona.py index 4a880b8d0caa7562c38768e3dd3cce736f77fa10..a0f0d1f1db3e04ea0eef743e08ab8e0bcb79afc5 100644 --- a/tests/runtime/test_memory_persona.py +++ b/tests/runtime/test_memory_persona.py @@ -1,6 +1,6 @@ -from proteus.grid.difficulty import Difficulty -from proteus.runtime.memory_gen import generate_memory -from proteus.runtime.persona import PersonaWeights +from proteus.game.engine.difficulty import Difficulty +from proteus.game.runtime.memory_gen import generate_memory +from proteus.game.metrics.persona import PersonaWeights def test_persona_memory_is_deterministic_and_tags_persona(): diff --git a/tests/runtime/test_memory_policies.py b/tests/runtime/test_memory_policies.py index 9281ef737907f3d0f2d2ed1e23550d7af2461727..fcce760d1a54daad56a7ab470d7cfbb46ea0572a 100644 --- a/tests/runtime/test_memory_policies.py +++ b/tests/runtime/test_memory_policies.py @@ -1,10 +1,10 @@ """Scripted memory policies produce distinct, on-motive 100-turn trajectories.""" from __future__ import annotations -import proteus.grid # noqa: F401 (registers scenarios) -from proteus.grid.difficulty import Difficulty -from proteus.runtime.memory_gen import generate_memory -from proteus.runtime.memory_policies import ( +import proteus.game.scenarios # noqa: F401 (registers scenarios) +from proteus.game.engine.difficulty import Difficulty +from proteus.game.runtime.memory_gen import generate_memory +from proteus.game.runtime.memory_policies import ( available_policies, get_policy, ) diff --git a/tests/runtime/test_metrics.py b/tests/runtime/test_metrics.py index 3d512a994ec406a6a1393b8053cbf234cc6a79bd..998e8e1fd6d40ec95c0c0af290aa08ef529967dc 100644 --- a/tests/runtime/test_metrics.py +++ b/tests/runtime/test_metrics.py @@ -1,5 +1,5 @@ -from proteus.runtime.trace import TurnTrace, SessionTrace -from proteus.runtime.metrics import compute_metrics +from proteus.game.runtime.trace import TurnTrace, SessionTrace +from proteus.game.metrics.metrics import compute_metrics def _turn(idx, action, motive, habit, reward, focal_pos=(0, 0)): @@ -142,8 +142,8 @@ def test_trajectory_agreement_penalizes_turns_beyond_optimal(): def test_distance_metrics_present_and_sane(): - from proteus.runtime.metrics import compute_metrics - from proteus.runtime.trace import TurnTrace + from proteus.game.metrics.metrics import compute_metrics + from proteus.game.runtime.trace import TurnTrace turns = [ TurnTrace(turn_idx=i, observation="", action="up", motive_action="up", diff --git a/tests/runtime/test_pack_evade_memory.py b/tests/runtime/test_pack_evade_memory.py index a99bcadbdc14e805017d6177c6d8e6cdec38c251..c2291b612b0e9e8e64dd1ca93f95c47bbfb837b3 100644 --- a/tests/runtime/test_pack_evade_memory.py +++ b/tests/runtime/test_pack_evade_memory.py @@ -4,12 +4,12 @@ design (docs/agentness_game_design_from_paper.md §3-4). The raw weights never leak; only the public persona_weight_id + the behaviour trajectory are stored.""" from __future__ import annotations -import proteus.grid # noqa: F401 -from proteus.agents.human import HumanAgent -from proteus.grid.difficulty import Difficulty -from proteus.grid.scenario import get_scenario -from proteus.runtime.memory import MemoryCheckpoint -from proteus.runtime.session import SessionRunner +import proteus.game.scenarios # noqa: F401 +from proteus.game.agents.human import HumanAgent +from proteus.game.engine.difficulty import Difficulty +from proteus.game.scenarios.base import get_scenario +from proteus.game.runtime.memory import MemoryCheckpoint +from proteus.game.runtime.session import SessionRunner def test_default_memory_is_persona_generated(): diff --git a/tests/runtime/test_persona.py b/tests/runtime/test_persona.py index 2d1024fd8a30c43dd02c10e9c290bc71357a5176..bd30d1aa4a65043b2c69bd04a68521efdd362d01 100644 --- a/tests/runtime/test_persona.py +++ b/tests/runtime/test_persona.py @@ -1,9 +1,9 @@ import random -import proteus.grid # noqa: F401 -from proteus.grid.difficulty import Difficulty -from proteus.grid.game import MotiveGridGame -from proteus.grid.scenario import get_scenario -from proteus.runtime.persona import PersonaWeights, reference_actions, pressure +import proteus.game.scenarios # noqa: F401 +from proteus.game.engine.difficulty import Difficulty +from proteus.game.engine.grid import MotiveGridGame +from proteus.game.scenarios.base import get_scenario +from proteus.game.metrics.persona import PersonaWeights, reference_actions, pressure def _sg(): @@ -34,9 +34,9 @@ def test_pressure_in_unit_range(): def _runner(action, persona_id="risk_averse", play_turns=1): from proteus.providers import FakeProvider - from proteus.agents import VanillaAgent - from proteus.runtime import SessionRunner - from proteus.runtime.persona import get_persona + from proteus.game.agents import VanillaAgent + from proteus.game.runtime import SessionRunner + from proteus.game.metrics.persona import get_persona prov = FakeProvider([f"ACTION: {action}"] * 10, model_name="demo") return SessionRunner( "predator_evade", VanillaAgent(prov), difficulty=Difficulty.EASY, @@ -70,8 +70,8 @@ def test_into_wall_lowers_agreement_and_positive_regret(): def test_persona_metrics_absent_without_persona(): from proteus.providers import FakeProvider - from proteus.agents import VanillaAgent - from proteus.runtime import SessionRunner + from proteus.game.agents import VanillaAgent + from proteus.game.runtime import SessionRunner prov = FakeProvider(["ACTION: up"] * 10, model_name="demo") m = SessionRunner( "predator_evade", VanillaAgent(prov), difficulty=Difficulty.EASY, diff --git a/tests/runtime/test_rollout.py b/tests/runtime/test_rollout.py index dadc76ea24a397f0594eaad92e6008e2671954af..23d6074a12569d950fa8a4afebf0d77059c3fd8f 100644 --- a/tests/runtime/test_rollout.py +++ b/tests/runtime/test_rollout.py @@ -1,5 +1,5 @@ -from proteus.grid.difficulty import Difficulty -from proteus.runtime.rollout import RolloutResult, optimal_rollout +from proteus.game.engine.difficulty import Difficulty +from proteus.game.metrics.rollout import RolloutResult, optimal_rollout def test_optimal_rollout_is_deterministic(): diff --git a/tests/runtime/test_session.py b/tests/runtime/test_session.py index f7163bf8a711eae0b54d7aab0e7ed9e32647768e..7804175c4e3993ae64c8b8ca80fc6c02e7034061 100644 --- a/tests/runtime/test_session.py +++ b/tests/runtime/test_session.py @@ -1,7 +1,7 @@ from proteus.providers import FakeProvider -from proteus.agents import VanillaAgent -from proteus.runtime.session import SessionRunner -from proteus.runtime.trace import SessionTrace +from proteus.game.agents import VanillaAgent +from proteus.game.runtime.session import SessionRunner +from proteus.game.runtime.trace import SessionTrace def _agent(responses): diff --git a/tests/runtime/test_session_core.py b/tests/runtime/test_session_core.py index 72827220d8c1b9aafe46ac853662d0301726f2ee..fafb4b1db263694f30cec713b3f8b3edb4d2dd2a 100644 --- a/tests/runtime/test_session_core.py +++ b/tests/runtime/test_session_core.py @@ -4,9 +4,9 @@ from __future__ import annotations import pytest -import proteus.grid # noqa: F401 (registers predator_evade) -from proteus.grid.difficulty import Difficulty -from proteus.runtime import _session_core as core +import proteus.game.scenarios # noqa: F401 (registers predator_evade) +from proteus.game.engine.difficulty import Difficulty +from proteus.game.runtime import _session_core as core def test_build_session_is_deterministic_and_non_terminal(): diff --git a/tests/runtime/test_session_distance.py b/tests/runtime/test_session_distance.py index 4e9a2af9a44c178e1e3a3ba1a12d9f0abe7d32f6..3c7482dcfa3f2c0a6da24120a5877edb9c0972bf 100644 --- a/tests/runtime/test_session_distance.py +++ b/tests/runtime/test_session_distance.py @@ -1,8 +1,8 @@ -import proteus.grid # noqa: F401 -from proteus.grid.difficulty import Difficulty +import proteus.game.scenarios # noqa: F401 +from proteus.game.engine.difficulty import Difficulty from proteus.providers import FakeProvider -from proteus.agents import VanillaAgent -from proteus.runtime import SessionRunner +from proteus.game.agents import VanillaAgent +from proteus.game.runtime import SessionRunner def test_each_turn_records_pre_and_post_bfs_distance(): diff --git a/tests/runtime/test_session_memory.py b/tests/runtime/test_session_memory.py index b1ef7423d4688cca143259debfae81629a692da1..0e97d430e24ca40f27723e44d6b4433254fbdb85 100644 --- a/tests/runtime/test_session_memory.py +++ b/tests/runtime/test_session_memory.py @@ -1,4 +1,4 @@ -from proteus.runtime.trace import SessionTrace +from proteus.game.runtime.trace import SessionTrace def test_session_trace_memory_ref_defaults_none_and_round_trips(): @@ -18,11 +18,11 @@ def test_session_trace_memory_ref_defaults_none_and_round_trips(): assert SessionTrace.model_validate_json(t3.model_dump_json()).memory_ref == "demo@FIXED" -from proteus.agents import VanillaAgent -from proteus.grid.difficulty import Difficulty +from proteus.game.agents import VanillaAgent +from proteus.game.engine.difficulty import Difficulty from proteus.providers import FakeProvider -from proteus.runtime import SessionRunner -from proteus.runtime.memory import MemoryCheckpoint, MemoryTurn +from proteus.game.runtime import SessionRunner +from proteus.game.runtime.memory import MemoryCheckpoint, MemoryTurn def _memory() -> MemoryCheckpoint: diff --git a/tests/runtime/test_spectate.py b/tests/runtime/test_spectate.py index 00d6f9fb4e03913f36e717f288368d596a6d075f..c4a57a6b421c479de8bce557e835ff1a6b15cd25 100644 --- a/tests/runtime/test_spectate.py +++ b/tests/runtime/test_spectate.py @@ -3,12 +3,12 @@ from __future__ import annotations import pytest -import proteus.grid # noqa: F401 -from proteus.agents.vanilla import VanillaAgent -from proteus.grid.difficulty import Difficulty +import proteus.game.scenarios # noqa: F401 +from proteus.game.agents.vanilla import VanillaAgent +from proteus.game.engine.difficulty import Difficulty from proteus.providers.fake import FakeProvider -from proteus.runtime._session_core import SessionFinishedError -from proteus.runtime.spectate import SpectateSession +from proteus.game.runtime._session_core import SessionFinishedError +from proteus.game.runtime.spectate import SpectateSession def _agent(n=10): diff --git a/tests/runtime/test_spectate_equivalence.py b/tests/runtime/test_spectate_equivalence.py index 8e99e9b74d4df69b7bf2774a9ff6447036462bc5..8847a9242a00cc0dff000181fcf3d31a867f6712 100644 --- a/tests/runtime/test_spectate_equivalence.py +++ b/tests/runtime/test_spectate_equivalence.py @@ -3,12 +3,12 @@ whether driven through SpectateSession (one advance per turn) or SessionRunner + VanillaAgent (batch). Pins the spectate path to the runner path.""" from __future__ import annotations -import proteus.grid # noqa: F401 -from proteus.agents.vanilla import VanillaAgent -from proteus.grid.difficulty import Difficulty +import proteus.game.scenarios # noqa: F401 +from proteus.game.agents.vanilla import VanillaAgent +from proteus.game.engine.difficulty import Difficulty from proteus.providers.fake import FakeProvider -from proteus.runtime.session import SessionRunner -from proteus.runtime.spectate import SpectateSession +from proteus.game.runtime.session import SessionRunner +from proteus.game.runtime.spectate import SpectateSession RESPONSES = ["ACTION: up", "ACTION: up", "ACTION: left", "ACTION: stay", "ACTION: right", "ACTION: up"] diff --git a/tests/runtime/test_trace.py b/tests/runtime/test_trace.py index b7b00f85e5c186e99160493935344eaf2fa28a2a..3c9a70d8ff1cb74261afd0d23d6073dbf10ce9a5 100644 --- a/tests/runtime/test_trace.py +++ b/tests/runtime/test_trace.py @@ -1,4 +1,4 @@ -from proteus.runtime.trace import TurnTrace, SessionTrace +from proteus.game.runtime.trace import TurnTrace, SessionTrace def test_turntrace_roundtrips_json(): @@ -56,7 +56,7 @@ def test_sessiontrace_defaults_and_nesting(): def test_turntrace_distance_fields_default_none_and_round_trip(): - from proteus.runtime.trace import TurnTrace + from proteus.game.runtime.trace import TurnTrace t = TurnTrace( turn_idx=1, observation="o", action="up", motive_action="up", habit_action="left", is_diagnostic=True, was_congruent=True, diff --git a/tests/runtime/test_trace_accounting.py b/tests/runtime/test_trace_accounting.py index 708429338942fbd640352ab22d1ef4eed6b503fd..6a6db512e853789675f27458ca7048958ec550a5 100644 --- a/tests/runtime/test_trace_accounting.py +++ b/tests/runtime/test_trace_accounting.py @@ -1,6 +1,6 @@ -from proteus.agents import VanillaAgent +from proteus.game.agents import VanillaAgent from proteus.providers import FakeProvider -from proteus.runtime import SessionRunner, SessionTrace +from proteus.game.runtime import SessionRunner, SessionTrace def _run(response): diff --git a/tests/test_arc_grid_vendored.py b/tests/test_arc_grid_vendored.py index d4fa87edfec125e67ba762310fb67579e81b4bc3..ede2fc751bd5d921fa0e613b54e6f97b003eb997 100644 --- a/tests/test_arc_grid_vendored.py +++ b/tests/test_arc_grid_vendored.py @@ -1,5 +1,5 @@ def test_arc_grid_engine_surface_importable(): - from proteus.arc_grid import Sprite, Level, Camera, ARCBaseGame, GameAction + from proteus.game.engine import Sprite, Level, Camera, ARCBaseGame, GameAction sprite = Sprite(pixels=[[1]], name="x", x=0, y=0) assert sprite.x == 0 and sprite.y == 0 diff --git a/tests/viz/test_gif.py b/tests/viz/test_gif.py index 410f4bf9332ac734a4ddc11282be1197eb4837cb..f031710a73ffd8ff6d49b3d77ad9f238d59badc8 100644 --- a/tests/viz/test_gif.py +++ b/tests/viz/test_gif.py @@ -1,9 +1,9 @@ -import proteus.grid # noqa: F401 -from proteus.grid.difficulty import Difficulty +import proteus.game.scenarios # noqa: F401 +from proteus.game.engine.difficulty import Difficulty from proteus.providers import FakeProvider -from proteus.agents import VanillaAgent -from proteus.runtime import SessionRunner -from proteus.viz import reconstruct, write_gif +from proteus.game.agents import VanillaAgent +from proteus.game.runtime import SessionRunner +from proteus.game.viz import reconstruct, write_gif def _trace(): diff --git a/tests/viz/test_import_safety.py b/tests/viz/test_import_safety.py index 279775143fa2b7c10b8ac2d04c62f1749b83ebdd..98545b2d6477d93f2f183e4546630de82b223028 100644 --- a/tests/viz/test_import_safety.py +++ b/tests/viz/test_import_safety.py @@ -7,11 +7,11 @@ def test_importing_viz_does_not_import_matplotlib(): if name == "matplotlib" or name.startswith("matplotlib."): del sys.modules[name] for name in list(sys.modules): - if name == "proteus.viz" or name.startswith("proteus.viz."): + if name == "proteus.game.viz" or name.startswith("proteus.game.viz."): del sys.modules[name] - import proteus.viz # noqa: F401 + import proteus.game.viz # noqa: F401 assert "matplotlib" not in sys.modules, ( - "importing proteus.viz pulled in matplotlib; keep it lazy in write_pngs" + "importing proteus.game.viz pulled in matplotlib; keep it lazy in write_pngs" ) diff --git a/tests/viz/test_png.py b/tests/viz/test_png.py index 24872eccc87c03c0583bec262693b2a25da0b471..eb518b427e78bba13855e19e90769a31f080a30a 100644 --- a/tests/viz/test_png.py +++ b/tests/viz/test_png.py @@ -2,10 +2,10 @@ import pytest pytest.importorskip("matplotlib") # PNG path needs the `viz` extra -from proteus.agents import VanillaAgent +from proteus.game.agents import VanillaAgent from proteus.providers import FakeProvider -from proteus.runtime.session import SessionRunner -from proteus.viz import reconstruct, write_pngs +from proteus.game.runtime.session import SessionRunner +from proteus.game.viz import reconstruct, write_pngs def _steps(): @@ -36,8 +36,8 @@ def test_write_pngs_creates_missing_dir(tmp_path): assert len(paths) == len(steps) -from proteus.viz.png import _title -from proteus.viz.reconstruct import FrameMeta, FrameStep +from proteus.game.viz.png import _title +from proteus.game.viz.reconstruct import FrameMeta, FrameStep import numpy as np diff --git a/tests/viz/test_reconstruct.py b/tests/viz/test_reconstruct.py index 47ed6b49c00eaf0ac2390ce6c028e0371074c37f..21f1458dfcc0b8fdfc80547ea8ab26fef2367fcc 100644 --- a/tests/viz/test_reconstruct.py +++ b/tests/viz/test_reconstruct.py @@ -1,12 +1,12 @@ import numpy as np import pytest -from proteus.agents import VanillaAgent -from proteus.grid.difficulty import Difficulty -from proteus.grid.scenario import get_scenario +from proteus.game.agents import VanillaAgent +from proteus.game.engine.difficulty import Difficulty +from proteus.game.scenarios.base import get_scenario from proteus.providers import FakeProvider -from proteus.runtime.session import SessionRunner -from proteus.viz import FrameStep, TraceReconstructionError, reconstruct +from proteus.game.runtime.session import SessionRunner +from proteus.game.viz import FrameStep, TraceReconstructionError, reconstruct def _make_trace(seed=42, turns=5, action="ACTION: up"): diff --git a/tests/viz/test_terminal.py b/tests/viz/test_terminal.py index d19605016b67ef186b111c5831583404721c08aa..71eeec58f7469883efdaf691d519898d5e3f22de 100644 --- a/tests/viz/test_terminal.py +++ b/tests/viz/test_terminal.py @@ -1,7 +1,7 @@ -from proteus.agents import VanillaAgent +from proteus.game.agents import VanillaAgent from proteus.providers import FakeProvider -from proteus.runtime.session import SessionRunner -from proteus.viz import reconstruct, render_terminal +from proteus.game.runtime.session import SessionRunner +from proteus.game.viz import reconstruct, render_terminal def _steps(): @@ -34,6 +34,6 @@ def test_render_terminal_emits_truecolor_and_panel_fields(): def test_render_terminal_does_not_sleep(monkeypatch): steps, _ = _steps() calls = [] - monkeypatch.setattr("proteus.viz.terminal.time.sleep", lambda s: calls.append(s)) + monkeypatch.setattr("proteus.game.viz.terminal.time.sleep", lambda s: calls.append(s)) render_terminal(steps, fps=0, writer=lambda s: None) assert calls == [] # fps=0 computes delay=0.0 -> sleep never called diff --git a/tests/web/test_import_safety.py b/tests/web/test_import_safety.py index f9cb4c18631f993afc6be08b1d3b0079fb09d45a..e63596e7c6c5b141a5714b899a5e92df809c7ce1 100644 --- a/tests/web/test_import_safety.py +++ b/tests/web/test_import_safety.py @@ -6,29 +6,29 @@ import sys def test_importing_web_pulls_no_heavy_or_network_deps(): - # Drop any pre-loaded matplotlib and proteus.web so we observe a fresh + # Drop any pre-loaded matplotlib and proteus.web.local so we observe a fresh # import graph even when earlier tests have cached these modules. for mod in list(sys.modules): if mod == "matplotlib" or mod.startswith("matplotlib."): del sys.modules[mod] for mod in list(sys.modules): - if mod == "proteus.web" or mod.startswith("proteus.web."): + if mod == "proteus.web.local" or mod.startswith("proteus.web.local."): del sys.modules[mod] - import proteus.web # noqa: F401 - import proteus.web.server # noqa: F401 + import proteus.web.local # noqa: F401 + import proteus.web.local.server # noqa: F401 assert "matplotlib" not in sys.modules, ( - "importing proteus.web pulled in matplotlib; keep the web layer offline" + "importing proteus.web.local pulled in matplotlib; keep the web layer offline" ) # provider SDKs are never imported by the web layer for sdk in ("openai", "anthropic", "google", "ollama"): assert sdk not in sys.modules, ( - f"importing proteus.web pulled in provider SDK {sdk!r}" + f"importing proteus.web.local pulled in provider SDK {sdk!r}" ) # spectate routes import providers LAZILY (inside the handler), so a plain # import of the web layer must still pull no provider SDK. - import proteus.web.server # noqa: F401 (re-exercised after the clear above) + import proteus.web.local.server # noqa: F401 (re-exercised after the clear above) for sdk in ("openai", "anthropic", "google", "ollama"): assert sdk not in sys.modules diff --git a/tests/web/test_memory_modes.py b/tests/web/test_memory_modes.py index cff4a7d6f8f050f210b02344f8d1f1a2ec8445fc..d9cebe836bb5ad454aa5e6e9edf3322870b012be 100644 --- a/tests/web/test_memory_modes.py +++ b/tests/web/test_memory_modes.py @@ -2,8 +2,8 @@ default / none / persona[:id] / generate / latest, plus the raised action quota.""" from __future__ import annotations -import proteus.grid # noqa: F401 -from proteus.web import server +import proteus.game.scenarios # noqa: F401 +from proteus.web.local import server def _reg(): diff --git a/tests/web/test_server.py b/tests/web/test_server.py index dd8395ecc9bbc97af615392301c07d9f77486636..3dd65a5f20a6be9b1ddb55498cf4d43cad3d767e 100644 --- a/tests/web/test_server.py +++ b/tests/web/test_server.py @@ -3,8 +3,8 @@ from __future__ import annotations import json -import proteus.grid # noqa: F401 -from proteus.web import server +import proteus.game.scenarios # noqa: F401 +from proteus.web.local import server def _registry(): diff --git a/tests/web/test_spectate_routes.py b/tests/web/test_spectate_routes.py index 655ba4e811149e3ff1634057973776ca1bd13381..8aff5d9c0c6def336b1468875c18c121adc22a95 100644 --- a/tests/web/test_spectate_routes.py +++ b/tests/web/test_spectate_routes.py @@ -1,8 +1,8 @@ """Route-level tests for spectating (offline via fake:demo, no socket).""" from __future__ import annotations -import proteus.grid # noqa: F401 -from proteus.web import server +import proteus.game.scenarios # noqa: F401 +from proteus.web.local import server def _reg():