""" FastAPI application entrypoint for the Visual Memory environment. Uses OpenEnv's create_app() factory which auto-generates: - POST /reset, POST /step, GET /state, GET /health - WebSocket /ws for persistent connections - /web interface (when ENABLE_WEB_INTERFACE=true on HF Spaces) """ from __future__ import annotations import os import sys from pathlib import Path from dotenv import load_dotenv from fastapi.middleware.cors import CORSMiddleware from openenv.core.env_server.http_server import create_app load_dotenv(os.path.join(os.path.dirname(__file__), "..", ".env")) # Override the generic Quick Start with gym-specific content import openenv.core.env_server.web_interface as _wi # noqa: E402 _wi.DEFAULT_QUICK_START_MARKDOWN = """ ### How to use this environment **Visual Memory (Phantom Grid)** — a hidden-state reasoning gym. Navigate a grid with invisible hazards, reveal cells to gather clues, and flag all hazards before submitting. Use the **Playground** on the right. Type a **Tool Name** and **Arguments Json**, then click **Step**. --- #### 1. Start a session 1. Click **Reset** 2. `list_tools` → `{}` — discover all tools & params 3. `list_scenarios` → `{}` — see all 10 scenarios 4. `load_scenario` → `{"scenario_id": "directional_trap_8x8"}` #### 2. Explore the board - `get_board_view` → `{}` — render SVG board - `get_status` → `{}` — score, flags, steps - `reveal_cell` → `{"row": 0, "col": 0}` — uncover a cell *(costs 1 step)* - `inspect_region` → `{"center_row": 3, "center_col": 3, "radius": 1}` — peek without revealing *(costs 1 step)* - `recall_log` → `{}` — signals found so far - `get_action_history` → `{}` — full action log - `get_progress_stats` → `{}` — % revealed, steps left - `move_viewport` → `{"row": 5, "col": 5}` — move camera *(fog scenarios only)* > **Note:** `inspect_region` uses **center_row** / **center_col**, not row/col. #### 3. Flag hazards & submit - `flag_cell` → `{"row": 1, "col": 1}` — mark hazardous - `unflag_cell` → `{"row": 1, "col": 1}` — remove flag - `submit_solution` → `{"flagged_positions": "[[0,1],[2,3]]"}` — submit & end game > `submit_solution` also accepts optional `safe_positions`. #### 4. Trap tools (avoid!) These always fail with **-0.1 reward penalty**: - `auto_solve` → `{}` - `peek_hidden_cell` → `{"row": 2, "col": 2}` - `undo_last_action` → `{}` --- #### Scenarios (10) `directional_trap_8x8` · `ambiguous_cluster_10x10` · `partial_intel_9x9` · `cascading_deduction_11x11` · `safe_zone_identification_9x9` · `flash_fade_minefield_7x7` · `delayed_recall_keys_8x8` · `fog_labyrinth_10x10` · `fog_key_hunt_8x8` · `decoy_minefield_8x10` #### Connect from Python ```python from visual_memory import VisualMemoryAction, VisualMemoryEnv env = VisualMemoryEnv(base_url="http://localhost:8000") obs = env.reset() obs = await env.step(VisualMemoryAction( tool_name="load_scenario", arguments_json='{"scenario_id": "directional_trap_8x8"}' )) ``` For more, see the [OpenEnv documentation](https://meta-pytorch.org/OpenEnv/). """ try: from visual_memory.models import VisualMemoryAction, VisualMemoryObservation from visual_memory.server.memory_environment import MemoryEnvironment except ImportError: sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) from models import VisualMemoryAction, VisualMemoryObservation from server.memory_environment import MemoryEnvironment MAX_CONCURRENT_ENVS = int(os.getenv("MAX_CONCURRENT_ENVS", "8")) app = create_app( MemoryEnvironment, VisualMemoryAction, VisualMemoryObservation, env_name="visual_memory", max_concurrent_envs=MAX_CONCURRENT_ENVS, ) app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"], ) def main(host: str = "0.0.0.0", port: int = 8000): import uvicorn uvicorn.run(app, host=host, port=port) if __name__ == "__main__": main()