From 3e460db94eebcaf035ffbbb51e5803503a9e402a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 13 Jan 2026 02:36:38 +0000 Subject: [PATCH 1/3] Initial plan From 31c3876515de8878e2674392b641546f682a79f5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 13 Jan 2026 02:41:48 +0000 Subject: [PATCH 2/3] Address critical feedback: fix episode ID, pin gym version, add .dockerignore, remove "beefy compute" references Co-authored-by: Darktex <890615+Darktex@users.noreply.github.com> --- .dockerignore | 56 ++++++++++++++++++++++ src/envs/nle_env/README.md | 16 ++++--- src/envs/nle_env/client.py | 10 +--- src/envs/nle_env/models.py | 7 ++- src/envs/nle_env/server/Dockerfile | 4 +- src/envs/nle_env/server/nle_environment.py | 11 ++--- 6 files changed, 77 insertions(+), 27 deletions(-) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000..8d85d01ba0 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,56 @@ +# Git +.git/ +.gitignore +.github/ + +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +*.egg-info/ +dist/ +build/ +*.egg +.pytest_cache/ +.mypy_cache/ +.ruff_cache/ +venv/ +env/ +ENV/ + +# IDEs +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# Documentation (keep README.md as it's explicitly copied) +*.md +!README.md +docs/ + +# CI/CD +.travis.yml +.gitlab-ci.yml + +# OS +.DS_Store +Thumbs.db + +# Test and development files +tests/ +*.test +test_* + +# Environment files +.env +.env.local +*.log + +# Temporary files +tmp/ +temp/ +*.tmp diff --git a/src/envs/nle_env/README.md b/src/envs/nle_env/README.md index 667532fee5..935b2c0306 100644 --- a/src/envs/nle_env/README.md +++ b/src/envs/nle_env/README.md @@ -2,6 +2,10 @@ A reinforcement learning environment based on NetHack 3.6.6, wrapped for the OpenEnv framework. +**Note**: This environment currently uses HTTP-based communication. OpenEnv is transitioning +to WebSocket-based communication for the Gym-like API, so this implementation may need +migration in the future. + ## Overview NetHack is one of the oldest and most challenging roguelike games, featuring: @@ -45,8 +49,7 @@ env.close() ### Building the Docker Image ```bash -# Build from repository root (not from server directory) -cd /Users/sanyambhutani/GH/OpenEnv +# Build from repository root docker build -f src/envs/nle_env/server/Dockerfile -t nle-env:latest . ``` @@ -94,7 +97,7 @@ For a complete action mapping, see [NLE Actions Documentation](https://github.co ## Observation Space -NLE provides rich observations about the game state. With OpenEnv's beefy compute assumption, all observations are included by default: +NLE provides rich observations about the game state. All observations are included by default: ### Core Observations - **glyphs** `(21, 79)`: Symbolic dungeon map representation @@ -245,11 +248,10 @@ env.close() ## Performance Considerations -With **beefy compute** (64+ cores, 256GB+ RAM, 10Gbps network): +Typical performance characteristics: - Observation size: ~140KB per step (all observation types) -- Network overhead: Negligible (<1ms on fast network) - Memory: ~200-500MB per container -- Throughput: 100+ parallel environments easily +- Throughput: 100+ parallel environments on multi-core systems **Optimizations are NOT needed** - just run it simple with JSON serialization! @@ -288,7 +290,7 @@ Common issues: ### Slow Performance -If you experience slowness even with beefy compute: +If you experience slow performance: 1. Check network latency: `ping ` 2. Monitor CPU: NLE is CPU-intensive for dungeon generation 3. Check Docker resources: Ensure containers have sufficient CPU allocation diff --git a/src/envs/nle_env/client.py b/src/envs/nle_env/client.py index dee5c1d167..34eaed2a95 100644 --- a/src/envs/nle_env/client.py +++ b/src/envs/nle_env/client.py @@ -26,10 +26,6 @@ class NLEEnv(HTTPEnvClient[NLEAction, NLEObservation]): This client connects to an NLEEnvironment HTTP server and provides methods to interact with NetHack: reset(), step(), and state access. - With beefy compute, we use simple JSON serialization. The server sends - all observation arrays as nested lists, which we keep as-is or convert - back to numpy arrays as needed. - Example: >>> # Connect to a running server >>> client = NLEEnv(base_url="http://localhost:8000") @@ -72,9 +68,7 @@ def _parse_result(self, payload: Dict) -> StepResult[NLEObservation]: """ Parse server response into StepResult[NLEObservation]. - The server sends all arrays as nested lists. With beefy compute, - we just keep them as lists - no need to convert back to numpy - unless the user specifically needs it. + The server sends all arrays as nested lists for JSON compatibility. Args: payload: JSON response from server @@ -90,7 +84,7 @@ def _parse_result(self, payload: Dict) -> StepResult[NLEObservation]: metadata = obs_data.get("metadata", {}) # Build observation with all the array fields - # Keep them as lists - simple and works great with beefy compute + # Keep them as lists for JSON compatibility observation = NLEObservation( # Core observations glyphs=obs_data.get("glyphs"), diff --git a/src/envs/nle_env/models.py b/src/envs/nle_env/models.py index c362ae28a6..2186dc88a9 100644 --- a/src/envs/nle_env/models.py +++ b/src/envs/nle_env/models.py @@ -45,6 +45,11 @@ class NLEObservation(Observation): Contains a subset of NLE's 14+ observation types. All numpy arrays are serialized as nested lists for JSON compatibility. + Note: All observation fields are optional because NLE supports configurable + observation spaces. The environment can be configured with `observation_keys` + to include only a subset of available observations, allowing flexibility in + balancing information richness with data size. + Observation types (all optional, configured at env creation): - glyphs: (21, 79) - Symbolic dungeon map representation - chars: (21, 79) - ASCII character display @@ -60,8 +65,6 @@ class NLEObservation(Observation): - tty_colors: (24, 80) - Full terminal colors - tty_cursor: (2,) - Terminal cursor position [row, col] - screen_descriptions: (21, 79, 80) - Text descriptions of dungeon - - With beefy compute, we include all observations by default. """ # Core observations (always useful) diff --git a/src/envs/nle_env/server/Dockerfile b/src/envs/nle_env/server/Dockerfile index 8d965a001a..dc862e6293 100644 --- a/src/envs/nle_env/server/Dockerfile +++ b/src/envs/nle_env/server/Dockerfile @@ -33,8 +33,8 @@ RUN pip install --no-cache-dir \ numpy # Install NLE (this will compile NetHack from source) -# Using the stable version from PyPI -RUN pip install --no-cache-dir nle gym +# Pin gym version for reproducibility and API compatibility +RUN pip install --no-cache-dir nle gym==0.26.2 # Copy OpenEnv core COPY src/core/ /app/src/core/ diff --git a/src/envs/nle_env/server/nle_environment.py b/src/envs/nle_env/server/nle_environment.py index 9839b0de10..731707f009 100644 --- a/src/envs/nle_env/server/nle_environment.py +++ b/src/envs/nle_env/server/nle_environment.py @@ -32,9 +32,6 @@ class NLEEnvironment(Environment): This environment wraps NLE's gym interface and provides OpenEnv-compatible reset(), step(), and state access. - With beefy compute, we use simple JSON serialization and include all - observation types by default. No optimization needed - compute handles it. - Example: >>> env = NLEEnvironment() >>> obs = env.reset() @@ -90,7 +87,6 @@ def __init__( self._observation_keys = observation_keys # Create NLE gym environment - # With beefy compute: no ttyrec saving, all observations enabled self.nle_env = NLE( character=character, observation_keys=observation_keys, @@ -101,7 +97,7 @@ def __init__( ) # Episode tracking - self._episode_id: Optional[str] = None + self._episode_id: str = f"nle_init_{int(time.time() * 1000000)}" self._step_count = 0 self._last_reward = 0.0 self._last_done = False @@ -208,8 +204,7 @@ def _convert_observation( """ Convert NLE gym observation to NLEObservation. - With beefy compute, we just convert numpy arrays to lists. - No compression, no optimization - simplicity first. + Converts numpy arrays to lists for JSON serialization. Args: gym_obs: Dictionary from NLE gym env @@ -226,7 +221,7 @@ def _convert_observation( } # Convert each observation type from numpy array to nested list - # This is simple and works perfectly with JSON + beefy compute + # for JSON serialization for key in self._observation_keys: if key in gym_obs: array = gym_obs[key] From d927301ce07c1dd7dd14aae20710364a38f9d31e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 13 Jan 2026 02:44:17 +0000 Subject: [PATCH 3/3] Refactor episode ID generation to reduce duplication and improve readability Co-authored-by: Darktex <890615+Darktex@users.noreply.github.com> --- src/envs/nle_env/server/nle_environment.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/envs/nle_env/server/nle_environment.py b/src/envs/nle_env/server/nle_environment.py index 731707f009..875c35f4f0 100644 --- a/src/envs/nle_env/server/nle_environment.py +++ b/src/envs/nle_env/server/nle_environment.py @@ -97,13 +97,17 @@ def __init__( ) # Episode tracking - self._episode_id: str = f"nle_init_{int(time.time() * 1000000)}" + self._episode_id: str = self._generate_episode_id() self._step_count = 0 self._last_reward = 0.0 self._last_done = False self._end_status = "RUNNING" self._in_normal_game = False + def _generate_episode_id(self) -> str: + """Generate a unique episode ID using timestamp.""" + return f"nle_{int(time.time() * 1_000_000)}" + def reset(self) -> NLEObservation: """ Reset the environment and return initial observation. @@ -122,7 +126,7 @@ def reset(self) -> NLEObservation: gym_obs = reset_result # Old API # Initialize episode tracking - self._episode_id = f"nle_{int(time.time() * 1000000)}" + self._episode_id = self._generate_episode_id() self._step_count = 0 self._last_reward = 0.0 self._last_done = False