openenv 0.2.3__tar.gz → 0.3.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. {openenv-0.2.3/src/openenv.egg-info → openenv-0.3.1}/PKG-INFO +35 -22
  2. {openenv-0.2.3 → openenv-0.3.1}/README.md +30 -17
  3. {openenv-0.2.3 → openenv-0.3.1}/pyproject.toml +5 -5
  4. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/__init__.py +1 -1
  5. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/auto/_discovery.py +2 -2
  6. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/cli/__main__.py +14 -1
  7. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/cli/_validation.py +81 -9
  8. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/cli/commands/build.py +16 -7
  9. openenv-0.3.1/src/openenv/cli/commands/collect.py +443 -0
  10. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/cli/commands/push.py +211 -26
  11. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/cli/commands/skills.py +12 -5
  12. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/cli/templates/openenv_env/server/app.py +1 -1
  13. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/core/env_server/http_server.py +50 -6
  14. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/core/env_server/interfaces.py +2 -0
  15. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/core/env_server/web_interface.py +39 -6
  16. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/core/evals/inspect_harness.py +13 -1
  17. openenv-0.3.1/src/openenv/core/harness/__init__.py +723 -0
  18. openenv-0.3.1/src/openenv/core/harness/collect.py +586 -0
  19. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/core/llm_client.py +32 -8
  20. {openenv-0.2.3 → openenv-0.3.1/src/openenv.egg-info}/PKG-INFO +35 -22
  21. {openenv-0.2.3 → openenv-0.3.1}/src/openenv.egg-info/SOURCES.txt +3 -1
  22. {openenv-0.2.3 → openenv-0.3.1}/src/openenv.egg-info/requires.txt +4 -4
  23. {openenv-0.2.3 → openenv-0.3.1}/LICENSE +0 -0
  24. {openenv-0.2.3 → openenv-0.3.1}/MANIFEST.in +0 -0
  25. {openenv-0.2.3 → openenv-0.3.1}/setup.cfg +0 -0
  26. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/auto/__init__.py +0 -0
  27. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/auto/auto_action.py +0 -0
  28. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/auto/auto_env.py +0 -0
  29. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/cli/__init__.py +0 -0
  30. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/cli/_cli_utils.py +0 -0
  31. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/cli/commands/__init__.py +0 -0
  32. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/cli/commands/fork.py +0 -0
  33. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/cli/commands/init.py +0 -0
  34. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/cli/commands/serve.py +0 -0
  35. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/cli/commands/validate.py +0 -0
  36. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/cli/templates/__init__.py +0 -0
  37. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/cli/templates/openenv_env/README.md +0 -0
  38. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/cli/templates/openenv_env/__init__.py +0 -0
  39. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/cli/templates/openenv_env/client.py +0 -0
  40. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/cli/templates/openenv_env/models.py +0 -0
  41. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/cli/templates/openenv_env/openenv.yaml +0 -0
  42. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/cli/templates/openenv_env/pyproject.toml +0 -0
  43. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/cli/templates/openenv_env/server/Dockerfile +0 -0
  44. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/cli/templates/openenv_env/server/__ENV_NAME___environment.py +0 -0
  45. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/cli/templates/openenv_env/server/__init__.py +0 -0
  46. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/cli/templates/openenv_env/server/requirements.txt +0 -0
  47. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/core/__init__.py +0 -0
  48. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/core/client_types.py +0 -0
  49. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/core/containers/__init__.py +0 -0
  50. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/core/containers/runtime/__init__.py +0 -0
  51. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/core/containers/runtime/daytona_provider.py +0 -0
  52. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/core/containers/runtime/providers.py +0 -0
  53. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/core/containers/runtime/uv_provider.py +0 -0
  54. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/core/containers/test_local_docker_provider.py +0 -0
  55. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/core/env_client.py +0 -0
  56. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/core/env_server/__init__.py +0 -0
  57. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/core/env_server/base_transforms.py +0 -0
  58. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/core/env_server/exceptions.py +0 -0
  59. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/core/env_server/gradio_theme.py +0 -0
  60. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/core/env_server/gradio_ui.py +0 -0
  61. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/core/env_server/mcp_environment.py +0 -0
  62. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/core/env_server/mcp_types.py +0 -0
  63. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/core/env_server/route_config.py +0 -0
  64. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/core/env_server/serialization.py +0 -0
  65. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/core/env_server/types.py +0 -0
  66. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/core/evals/__init__.py +0 -0
  67. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/core/evals/base.py +0 -0
  68. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/core/evals/types.py +0 -0
  69. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/core/generic_client.py +0 -0
  70. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/core/mcp_client.py +0 -0
  71. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/core/rubrics/__init__.py +0 -0
  72. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/core/rubrics/base.py +0 -0
  73. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/core/rubrics/containers.py +0 -0
  74. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/core/rubrics/llm_judge.py +0 -0
  75. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/core/rubrics/trajectory.py +0 -0
  76. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/core/sync_client.py +0 -0
  77. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/core/tools/__init__.py +0 -0
  78. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/core/tools/git_server_client.py +0 -0
  79. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/core/tools/local_python_executor.py +0 -0
  80. {openenv-0.2.3 → openenv-0.3.1}/src/openenv/core/utils.py +0 -0
  81. {openenv-0.2.3 → openenv-0.3.1}/src/openenv.egg-info/dependency_links.txt +0 -0
  82. {openenv-0.2.3 → openenv-0.3.1}/src/openenv.egg-info/entry_points.txt +0 -0
  83. {openenv-0.2.3 → openenv-0.3.1}/src/openenv.egg-info/top_level.txt +0 -0
  84. {openenv-0.2.3 → openenv-0.3.1}/src/openenv_core/__init__.py +0 -0
  85. {openenv-0.2.3 → openenv-0.3.1}/tests/test_line_endings.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openenv
3
- Version: 0.2.3
3
+ Version: 0.3.1
4
4
  Summary: A unified framework for reinforcement learning environments
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
@@ -37,13 +37,13 @@ Requires-Dist: tomli-w>=1.2.0; extra == "cli"
37
37
  Provides-Extra: docs
38
38
  Requires-Dist: sphinx==7.2.6; extra == "docs"
39
39
  Requires-Dist: pytorch-sphinx-theme2; extra == "docs"
40
- Requires-Dist: sphinxcontrib.katex==0.9.10; extra == "docs"
41
- Requires-Dist: docutils<0.21,>=0.18.1; extra == "docs"
40
+ Requires-Dist: sphinxcontrib.katex==0.9.11; extra == "docs"
41
+ Requires-Dist: docutils<0.23,>=0.18.1; extra == "docs"
42
42
  Requires-Dist: sphinx-design==0.6.1; extra == "docs"
43
- Requires-Dist: sphinxcontrib-mermaid==1.0.0; extra == "docs"
43
+ Requires-Dist: sphinxcontrib-mermaid==2.0.2; extra == "docs"
44
44
  Requires-Dist: myst-parser; extra == "docs"
45
45
  Requires-Dist: sphinxext-opengraph; extra == "docs"
46
- Requires-Dist: sphinx-sitemap==2.7.1; extra == "docs"
46
+ Requires-Dist: sphinx-sitemap==2.9.0; extra == "docs"
47
47
  Requires-Dist: sphinx-gallery>=0.14.0; extra == "docs"
48
48
  Requires-Dist: matplotlib; extra == "docs"
49
49
  Requires-Dist: nest-asyncio; extra == "docs"
@@ -75,7 +75,7 @@ An e2e framework for creating, deploying and using isolated execution environmen
75
75
 
76
76
  ## Quick Start
77
77
 
78
- Install the OpenEnv core package:
78
+ Install the OpenEnv package:
79
79
 
80
80
  ```bash
81
81
  pip install openenv
@@ -91,7 +91,7 @@ Then use the environment:
91
91
 
92
92
  ```python
93
93
  import asyncio
94
- from echo_env import EchoAction, EchoEnv
94
+ from echo_env import CallToolAction, EchoEnv
95
95
 
96
96
  async def main():
97
97
  # Connect to a running Space (async context manager)
@@ -101,9 +101,14 @@ async def main():
101
101
  print(result.observation.echoed_message) # "Echo environment ready!"
102
102
 
103
103
  # Send messages
104
- result = await client.step(EchoAction(message="Hello, World!"))
105
- print(result.observation.echoed_message) # "Hello, World!"
106
- print(result.reward) # 1.3 (based on message length)
104
+ result = await client.step(
105
+ CallToolAction(
106
+ tool_name="echo_message",
107
+ arguments={"message": "Hello, World!"},
108
+ )
109
+ )
110
+ print(result.observation.result) # "Hello, World!"
111
+ print(result.reward)
107
112
 
108
113
  asyncio.run(main())
109
114
  ```
@@ -111,16 +116,21 @@ asyncio.run(main())
111
116
  **Synchronous usage** is also supported via the `.sync()` wrapper:
112
117
 
113
118
  ```python
114
- from echo_env import EchoAction, EchoEnv
119
+ from echo_env import CallToolAction, EchoEnv
115
120
 
116
121
  # Use .sync() for synchronous context manager
117
122
  with EchoEnv(base_url="https://openenv-echo-env.hf.space").sync() as client:
118
123
  result = client.reset()
119
- result = client.step(EchoAction(message="Hello, World!"))
120
- print(result.observation.echoed_message)
124
+ result = client.step(
125
+ CallToolAction(
126
+ tool_name="echo_message",
127
+ arguments={"message": "Hello, World!"},
128
+ )
129
+ )
130
+ print(result.observation.result)
121
131
  ```
122
132
 
123
- For a detailed quick start, check out the [docs page](https://meta-pytorch.org/OpenEnv/quickstart/).
133
+ For a detailed quick start, check out the [docs page](https://meta-pytorch.org/OpenEnv/auto_getting_started/index.html).
124
134
 
125
135
  ## OpenEnv on partner platforms:
126
136
 
@@ -138,12 +148,15 @@ In addition to making it easier for researchers and RL framework writers, we als
138
148
 
139
149
  The OpenEnv CLI (`openenv`) provides commands to initialize new environments and deploy them to Hugging Face Spaces.
140
150
 
151
+ OpenEnv is openly governed by a technical committee that includes Hugging Face, Unsloth, Reflection, and Meta PyTorch. The committee coordinates project direction, major technical decisions, RFCs, and release planning through the public issue tracker, pull requests, and RFC process.
152
+
141
153
  > ⚠️ **Early Development Warning** OpenEnv is currently in an experimental
142
154
  > stage. You should expect bugs, incomplete features, and APIs that may change
143
- > in future versions. The project welcomes bugfixes, but to make sure things are
144
- > well coordinated you should discuss any significant change before starting the
145
- > work. It's recommended that you signal your intention to contribute in the
146
- > issue tracker, either by filing a new issue or by claiming an existing one.
155
+ > in future versions. The project welcomes bugfixes, but significant changes
156
+ > should be discussed before implementation so the technical committee and
157
+ > community can coordinate scope, compatibility, and release timing. It's
158
+ > recommended that you signal your intention to contribute in the issue tracker,
159
+ > either by filing a new issue or by claiming an existing one.
147
160
 
148
161
  ### RFCs
149
162
 
@@ -299,7 +312,7 @@ See [`envs/README.md`](envs/README.md) for a complete guide on building environm
299
312
 
300
313
  To use an environment:
301
314
  1. Install the client: `pip install git+https://huggingface.co/spaces/openenv/echo-env`
302
- 2. Import: `from echo_env import EchoAction, EchoEnv`
315
+ 2. Import: `from echo_env import CallToolAction, EchoEnv`
303
316
  3. Use async (recommended) or sync API:
304
317
 
305
318
  **Async (recommended):**
@@ -427,12 +440,12 @@ See the [Oumi example](https://github.com/oumi-ai/oumi/blob/main/notebooks/Oumi%
427
440
  | [Atari Environment](envs/atari_env/README.md) | Classic Arcade Learning Environment tasks for RL benchmarking. |
428
441
  | [FinRL Environment](envs/finrl_env/README.md) | Financial market simulations for algorithmic trading experiments. |
429
442
 
430
- > Browse the full catalog of community environments at [meta-pytorch.org/OpenEnv/environments](https://meta-pytorch.org/OpenEnv/environments/).
443
+ > Browse the full catalog of community environments at [meta-pytorch.org/OpenEnv/environments](https://meta-pytorch.org/OpenEnv/environments.html).
431
444
 
432
445
  ## Community Support & Acknowledgments
433
- This is an open and community-centric project. If you would like to add your name here, please put up a pull request and tag @jspisak for review. Ty!!
446
+ This is an open and community-centric project, governed in public by a technical committee that includes Hugging Face, Unsloth, Reflection, and Meta PyTorch. If you would like to add your project or organization here, please open a pull request for maintainer review.
434
447
 
435
- Supporters include: Meta-PyTorch, Hugging Face, [Scaler AI Labs](https://scalerailabs.com), [Patronus AI](https://patronus.ai), [Surge AI](https://surgehq.ai), [LastMile AI](https://www.lastmileai.dev), Unsloth AI, Reflection AI, vLLM, SkyRL (UC-Berkeley), LightningAI, Axolotl AI, Stanford Scaling Intelligence Lab, Mithril, [OpenMined](https://openmined.org/), [Fleet AI](https://fleetai.com), [Halluminate](https://halluminate.ai/), [Turing](https://www.turing.com/), [Scale AI](https://scale.com/) ..
448
+ Supporters include: Meta-PyTorch, Hugging Face, [Scaler AI Labs](https://scalerailabs.com), [Patronus AI](https://patronus.ai), [Surge AI](https://surgehq.ai), [LastMile AI](https://www.lastmileai.dev), Unsloth, Reflection, vLLM, SkyRL (UC-Berkeley), LightningAI, Axolotl AI, Stanford Scaling Intelligence Lab, Mithril, [OpenMined](https://openmined.org/), [Fleet AI](https://fleetai.com), [Halluminate](https://halluminate.ai/), [Turing](https://www.turing.com/), [Scale AI](https://scale.com/), [Scorecard](https://www.scorecard.io/) ..
436
449
 
437
450
  And we'd also like to acknowledge the team at Farama Foundation as the OpenEnv API was heavily inspired by the work you all have done on Gymnasium. Cheers!
438
451
 
@@ -15,7 +15,7 @@ An e2e framework for creating, deploying and using isolated execution environmen
15
15
 
16
16
  ## Quick Start
17
17
 
18
- Install the OpenEnv core package:
18
+ Install the OpenEnv package:
19
19
 
20
20
  ```bash
21
21
  pip install openenv
@@ -31,7 +31,7 @@ Then use the environment:
31
31
 
32
32
  ```python
33
33
  import asyncio
34
- from echo_env import EchoAction, EchoEnv
34
+ from echo_env import CallToolAction, EchoEnv
35
35
 
36
36
  async def main():
37
37
  # Connect to a running Space (async context manager)
@@ -41,9 +41,14 @@ async def main():
41
41
  print(result.observation.echoed_message) # "Echo environment ready!"
42
42
 
43
43
  # Send messages
44
- result = await client.step(EchoAction(message="Hello, World!"))
45
- print(result.observation.echoed_message) # "Hello, World!"
46
- print(result.reward) # 1.3 (based on message length)
44
+ result = await client.step(
45
+ CallToolAction(
46
+ tool_name="echo_message",
47
+ arguments={"message": "Hello, World!"},
48
+ )
49
+ )
50
+ print(result.observation.result) # "Hello, World!"
51
+ print(result.reward)
47
52
 
48
53
  asyncio.run(main())
49
54
  ```
@@ -51,16 +56,21 @@ asyncio.run(main())
51
56
  **Synchronous usage** is also supported via the `.sync()` wrapper:
52
57
 
53
58
  ```python
54
- from echo_env import EchoAction, EchoEnv
59
+ from echo_env import CallToolAction, EchoEnv
55
60
 
56
61
  # Use .sync() for synchronous context manager
57
62
  with EchoEnv(base_url="https://openenv-echo-env.hf.space").sync() as client:
58
63
  result = client.reset()
59
- result = client.step(EchoAction(message="Hello, World!"))
60
- print(result.observation.echoed_message)
64
+ result = client.step(
65
+ CallToolAction(
66
+ tool_name="echo_message",
67
+ arguments={"message": "Hello, World!"},
68
+ )
69
+ )
70
+ print(result.observation.result)
61
71
  ```
62
72
 
63
- For a detailed quick start, check out the [docs page](https://meta-pytorch.org/OpenEnv/quickstart/).
73
+ For a detailed quick start, check out the [docs page](https://meta-pytorch.org/OpenEnv/auto_getting_started/index.html).
64
74
 
65
75
  ## OpenEnv on partner platforms:
66
76
 
@@ -78,12 +88,15 @@ In addition to making it easier for researchers and RL framework writers, we als
78
88
 
79
89
  The OpenEnv CLI (`openenv`) provides commands to initialize new environments and deploy them to Hugging Face Spaces.
80
90
 
91
+ OpenEnv is openly governed by a technical committee that includes Hugging Face, Unsloth, Reflection, and Meta PyTorch. The committee coordinates project direction, major technical decisions, RFCs, and release planning through the public issue tracker, pull requests, and RFC process.
92
+
81
93
  > ⚠️ **Early Development Warning** OpenEnv is currently in an experimental
82
94
  > stage. You should expect bugs, incomplete features, and APIs that may change
83
- > in future versions. The project welcomes bugfixes, but to make sure things are
84
- > well coordinated you should discuss any significant change before starting the
85
- > work. It's recommended that you signal your intention to contribute in the
86
- > issue tracker, either by filing a new issue or by claiming an existing one.
95
+ > in future versions. The project welcomes bugfixes, but significant changes
96
+ > should be discussed before implementation so the technical committee and
97
+ > community can coordinate scope, compatibility, and release timing. It's
98
+ > recommended that you signal your intention to contribute in the issue tracker,
99
+ > either by filing a new issue or by claiming an existing one.
87
100
 
88
101
  ### RFCs
89
102
 
@@ -239,7 +252,7 @@ See [`envs/README.md`](envs/README.md) for a complete guide on building environm
239
252
 
240
253
  To use an environment:
241
254
  1. Install the client: `pip install git+https://huggingface.co/spaces/openenv/echo-env`
242
- 2. Import: `from echo_env import EchoAction, EchoEnv`
255
+ 2. Import: `from echo_env import CallToolAction, EchoEnv`
243
256
  3. Use async (recommended) or sync API:
244
257
 
245
258
  **Async (recommended):**
@@ -367,12 +380,12 @@ See the [Oumi example](https://github.com/oumi-ai/oumi/blob/main/notebooks/Oumi%
367
380
  | [Atari Environment](envs/atari_env/README.md) | Classic Arcade Learning Environment tasks for RL benchmarking. |
368
381
  | [FinRL Environment](envs/finrl_env/README.md) | Financial market simulations for algorithmic trading experiments. |
369
382
 
370
- > Browse the full catalog of community environments at [meta-pytorch.org/OpenEnv/environments](https://meta-pytorch.org/OpenEnv/environments/).
383
+ > Browse the full catalog of community environments at [meta-pytorch.org/OpenEnv/environments](https://meta-pytorch.org/OpenEnv/environments.html).
371
384
 
372
385
  ## Community Support & Acknowledgments
373
- This is an open and community-centric project. If you would like to add your name here, please put up a pull request and tag @jspisak for review. Ty!!
386
+ This is an open and community-centric project, governed in public by a technical committee that includes Hugging Face, Unsloth, Reflection, and Meta PyTorch. If you would like to add your project or organization here, please open a pull request for maintainer review.
374
387
 
375
- Supporters include: Meta-PyTorch, Hugging Face, [Scaler AI Labs](https://scalerailabs.com), [Patronus AI](https://patronus.ai), [Surge AI](https://surgehq.ai), [LastMile AI](https://www.lastmileai.dev), Unsloth AI, Reflection AI, vLLM, SkyRL (UC-Berkeley), LightningAI, Axolotl AI, Stanford Scaling Intelligence Lab, Mithril, [OpenMined](https://openmined.org/), [Fleet AI](https://fleetai.com), [Halluminate](https://halluminate.ai/), [Turing](https://www.turing.com/), [Scale AI](https://scale.com/) ..
388
+ Supporters include: Meta-PyTorch, Hugging Face, [Scaler AI Labs](https://scalerailabs.com), [Patronus AI](https://patronus.ai), [Surge AI](https://surgehq.ai), [LastMile AI](https://www.lastmileai.dev), Unsloth, Reflection, vLLM, SkyRL (UC-Berkeley), LightningAI, Axolotl AI, Stanford Scaling Intelligence Lab, Mithril, [OpenMined](https://openmined.org/), [Fleet AI](https://fleetai.com), [Halluminate](https://halluminate.ai/), [Turing](https://www.turing.com/), [Scale AI](https://scale.com/), [Scorecard](https://www.scorecard.io/) ..
376
389
 
377
390
  And we'd also like to acknowledge the team at Farama Foundation as the OpenEnv API was heavily inspired by the work you all have done on Gymnasium. Cheers!
378
391
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "openenv"
7
- version = "0.2.3"
7
+ version = "0.3.1"
8
8
  description = "A unified framework for reinforcement learning environments"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -52,13 +52,13 @@ cli = [
52
52
  docs = [
53
53
  "sphinx==7.2.6",
54
54
  "pytorch-sphinx-theme2",
55
- "sphinxcontrib.katex==0.9.10",
56
- "docutils>=0.18.1,<0.21",
55
+ "sphinxcontrib.katex==0.9.11",
56
+ "docutils>=0.18.1,<0.23",
57
57
  "sphinx-design==0.6.1",
58
- "sphinxcontrib-mermaid==1.0.0",
58
+ "sphinxcontrib-mermaid==2.0.2",
59
59
  "myst-parser",
60
60
  "sphinxext-opengraph",
61
- "sphinx-sitemap==2.7.1",
61
+ "sphinx-sitemap==2.9.0",
62
62
  "sphinx-gallery>=0.14.0",
63
63
  "matplotlib",
64
64
  "nest-asyncio",
@@ -17,7 +17,7 @@ __all__ = [
17
17
 
18
18
  def _load_package_version() -> str:
19
19
  """Resolve the installed distribution version for the OpenEnv package."""
20
- for distribution_name in ("openenv", "openenv"):
20
+ for distribution_name in ("openenv", "openenv-core"):
21
21
  try:
22
22
  return metadata.version(distribution_name)
23
23
  except metadata.PackageNotFoundError:
@@ -369,14 +369,14 @@ class EnvironmentDiscovery:
369
369
  logger.warning(f"Failed to get installed packages: {e}")
370
370
  return environments
371
371
 
372
- # Filter for openenv-* packages (exclude openenv)
372
+ # Filter for openenv-* environment packages; ignore the legacy core wheel.
373
373
  for dist in distributions:
374
374
  package_name = dist.metadata["Name"]
375
375
 
376
376
  if not package_name.startswith("openenv-"):
377
377
  continue
378
378
 
379
- if package_name == "openenv":
379
+ if package_name == "openenv-core":
380
380
  continue
381
381
 
382
382
  # Get module name (e.g., "openenv-echo_env" → "echo_env")
@@ -14,7 +14,16 @@ following the Hugging Face CLI pattern.
14
14
  import sys
15
15
 
16
16
  import typer
17
- from openenv.cli.commands import build, fork, init, push, serve, skills, validate
17
+ from openenv.cli.commands import (
18
+ build,
19
+ collect,
20
+ fork,
21
+ init,
22
+ push,
23
+ serve,
24
+ skills,
25
+ validate,
26
+ )
18
27
 
19
28
  # Create the main CLI app
20
29
  app = typer.Typer(
@@ -47,6 +56,10 @@ app.add_typer(
47
56
  name="skills",
48
57
  help="Manage OpenEnv skills for AI assistants",
49
58
  )
59
+ app.command(
60
+ name="collect",
61
+ help="Collect rollouts from a deployed OpenEnv environment",
62
+ )(collect.collect)
50
63
 
51
64
 
52
65
  # Entry point for setuptools
@@ -11,6 +11,8 @@ This module provides functions to check if environments are properly
11
11
  configured for multi-mode deployment (Docker, direct Python, notebooks, clusters).
12
12
  """
13
13
 
14
+ import ast
15
+ import re
14
16
  from pathlib import Path
15
17
  from typing import Any
16
18
  from urllib.parse import urlparse
@@ -426,6 +428,79 @@ def validate_running_environment(
426
428
  return report
427
429
 
428
430
 
431
+ def _has_main_guard_call(app_content: str) -> bool:
432
+ """Return True when the module calls main() under a __main__ guard."""
433
+ try:
434
+ tree = ast.parse(app_content)
435
+ except SyntaxError:
436
+ return (
437
+ "__name__" in app_content
438
+ and "__main__" in app_content
439
+ and "main(" in app_content
440
+ )
441
+
442
+ for node in ast.iter_child_nodes(tree):
443
+ if not isinstance(node, ast.If):
444
+ continue
445
+
446
+ test = node.test
447
+ if not (
448
+ isinstance(test, ast.Compare)
449
+ and isinstance(test.left, ast.Name)
450
+ and test.left.id == "__name__"
451
+ and len(test.ops) == 1
452
+ and isinstance(test.ops[0], ast.Eq)
453
+ and len(test.comparators) == 1
454
+ and isinstance(test.comparators[0], ast.Constant)
455
+ and test.comparators[0].value == "__main__"
456
+ ):
457
+ continue
458
+
459
+ for guarded_node in node.body:
460
+ for candidate in ast.walk(guarded_node):
461
+ if isinstance(candidate, ast.Call):
462
+ func = candidate.func
463
+ if isinstance(func, ast.Name) and func.id == "main":
464
+ return True
465
+
466
+ return False
467
+
468
+
469
+ _OPENENV_RUNTIME_DEP_RE = re.compile(r"^openenv(?:\s*(?:$|[<>=!~@;])|\[)")
470
+ _LEGACY_OPENENV_CORE_DEP_RE = re.compile(r"^openenv-core(?:\s*(?:$|[<>=!~@;])|\[)")
471
+ _OPENENV_DOCKER_INSTALL_RE = re.compile(
472
+ r"(?<![a-z0-9_.-])openenv(?:\s*(?:$|[<>=!~@;])|\[)"
473
+ )
474
+
475
+
476
+ def _dockerfile_installs_openenv_runtime(env_path: Path) -> bool:
477
+ """Return True when a Docker deployment installs OpenEnv outside pyproject."""
478
+ for dockerfile_path in (
479
+ env_path / "server" / "Dockerfile",
480
+ env_path / "Dockerfile",
481
+ ):
482
+ if not dockerfile_path.exists():
483
+ continue
484
+
485
+ try:
486
+ dockerfile = dockerfile_path.read_text(encoding="utf-8")
487
+ except OSError:
488
+ continue
489
+
490
+ for line in dockerfile.splitlines():
491
+ stripped = line.strip().lower()
492
+ if not stripped or stripped.startswith("#"):
493
+ continue
494
+ if _OPENENV_DOCKER_INSTALL_RE.search(stripped):
495
+ return True
496
+ if "openenv-core" in stripped:
497
+ return True
498
+ if "git+https://github.com/meta-pytorch/openenv" in stripped:
499
+ return True
500
+
501
+ return False
502
+
503
+
429
504
  def validate_multi_mode_deployment(env_path: Path) -> tuple[bool, list[str]]:
430
505
  """
431
506
  Validate that an environment is ready for multi-mode deployment.
@@ -475,15 +550,12 @@ def validate_multi_mode_deployment(env_path: Path) -> tuple[bool, list[str]]:
475
550
 
476
551
  # Check required dependencies
477
552
  deps = [dep.lower() for dep in pyproject.get("project", {}).get("dependencies", [])]
478
- has_openenv = any(
479
- dep.startswith("openenv") and not dep.startswith("openenv") for dep in deps
480
- )
481
- has_legacy_core = any(dep.startswith("openenv") for dep in deps)
553
+ has_openenv = any(_OPENENV_RUNTIME_DEP_RE.match(dep) for dep in deps)
554
+ has_legacy_core = any(_LEGACY_OPENENV_CORE_DEP_RE.match(dep) for dep in deps)
555
+ has_dockerfile_core = _dockerfile_installs_openenv_runtime(env_path)
482
556
 
483
- if not (has_openenv or has_legacy_core):
484
- issues.append(
485
- "Missing required dependency: openenv>=0.2.0 (or openenv>=0.2.0)"
486
- )
557
+ if not (has_openenv or has_legacy_core or has_dockerfile_core):
558
+ issues.append("Missing required dependency: openenv>=0.2.0")
487
559
 
488
560
  # Check server/app.py exists
489
561
  server_app = env_path / "server" / "app.py"
@@ -496,7 +568,7 @@ def validate_multi_mode_deployment(env_path: Path) -> tuple[bool, list[str]]:
496
568
  issues.append("server/app.py missing main() function")
497
569
 
498
570
  # Check if main() is callable
499
- if "__name__" not in app_content or "main()" not in app_content:
571
+ if not _has_main_guard_call(app_content):
500
572
  issues.append(
501
573
  "server/app.py main() function not callable (missing if __name__ == '__main__')"
502
574
  )
@@ -8,6 +8,7 @@
8
8
 
9
9
  from __future__ import annotations
10
10
 
11
+ import re
11
12
  import shutil
12
13
  import subprocess
13
14
  import sys
@@ -21,6 +22,18 @@ from .._cli_utils import console
21
22
 
22
23
  app = typer.Typer(help="Build Docker images for OpenEnv environments")
23
24
 
25
+ _OPENENV_RUNTIME_DEP_RE = re.compile(r"^openenv(?:\s*(?:$|[<>=!~@;])|\[)")
26
+
27
+
28
+ def _is_openenv_runtime_dependency(dep: str) -> bool:
29
+ """Return True for the OpenEnv runtime distribution, not openenv-* envs."""
30
+ normalized = dep.strip().lower()
31
+ return (
32
+ _OPENENV_RUNTIME_DEP_RE.match(normalized) is not None
33
+ or normalized.startswith("openenv-core")
34
+ or normalized.startswith("openenv_core")
35
+ )
36
+
24
37
 
25
38
  def _detect_build_context(env_path: Path) -> tuple[str, Path, Path | None]:
26
39
  """
@@ -156,19 +169,15 @@ def _prepare_inrepo_build(env_path: Path, repo_root: Path, temp_dir: Path) -> Pa
156
169
  pyproject = tomli.load(f)
157
170
  deps = pyproject.get("project", {}).get("dependencies", [])
158
171
 
159
- # Replace openenv/openenv with local reference
172
+ # Replace OpenEnv package references with local source.
160
173
  new_deps = []
161
174
  for dep in deps:
162
- if (
163
- dep.startswith("openenv")
164
- or dep.startswith("openenv_core")
165
- or dep.startswith("openenv")
166
- ):
175
+ if _is_openenv_runtime_dependency(dep):
167
176
  # Skip - we'll use local core
168
177
  continue
169
178
  new_deps.append(dep)
170
179
 
171
- # Write back with local core reference
180
+ # Write back with local OpenEnv reference
172
181
  pyproject["project"]["dependencies"] = new_deps + [
173
182
  "openenv @ file:///app/env/openenv"
174
183
  ]