openenv 0.2.1__tar.gz → 0.2.3__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.
- openenv-0.2.3/MANIFEST.in +2 -0
- {openenv-0.2.1 → openenv-0.2.3}/PKG-INFO +76 -32
- openenv-0.2.1/src/openenv.egg-info/PKG-INFO → openenv-0.2.3/README.md +53 -69
- {openenv-0.2.1 → openenv-0.2.3}/pyproject.toml +65 -2
- openenv-0.2.3/src/openenv/__init__.py +62 -0
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/auto/_discovery.py +2 -2
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/auto/auto_action.py +5 -5
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/auto/auto_env.py +37 -26
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/cli/__main__.py +10 -2
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/cli/_cli_utils.py +17 -14
- openenv-0.2.3/src/openenv/cli/_validation.py +594 -0
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/cli/commands/__init__.py +2 -2
- openenv-0.2.3/src/openenv/cli/commands/fork.py +197 -0
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/cli/commands/init.py +0 -2
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/cli/commands/push.py +198 -21
- openenv-0.2.3/src/openenv/cli/commands/skills.py +200 -0
- openenv-0.2.3/src/openenv/cli/commands/validate.py +198 -0
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/cli/templates/openenv_env/client.py +2 -2
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/cli/templates/openenv_env/models.py +1 -2
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/cli/templates/openenv_env/pyproject.toml +1 -1
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/cli/templates/openenv_env/server/__ENV_NAME___environment.py +4 -1
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/cli/templates/openenv_env/server/app.py +6 -3
- openenv-0.2.3/src/openenv/core/__init__.py +81 -0
- openenv-0.2.3/src/openenv/core/containers/runtime/daytona_provider.py +572 -0
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/core/containers/runtime/providers.py +2 -0
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/core/containers/test_local_docker_provider.py +0 -1
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/core/env_client.py +145 -45
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/core/env_server/__init__.py +62 -33
- openenv-0.2.3/src/openenv/core/env_server/gradio_theme.py +128 -0
- openenv-0.2.3/src/openenv/core/env_server/gradio_ui.py +240 -0
- openenv-0.2.3/src/openenv/core/env_server/http_server.py +1646 -0
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/core/env_server/interfaces.py +106 -3
- openenv-0.2.3/src/openenv/core/env_server/mcp_environment.py +645 -0
- openenv-0.2.3/src/openenv/core/env_server/mcp_types.py +321 -0
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/core/env_server/serialization.py +35 -1
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/core/env_server/types.py +50 -6
- openenv-0.2.3/src/openenv/core/env_server/web_interface.py +697 -0
- openenv-0.2.3/src/openenv/core/evals/__init__.py +18 -0
- openenv-0.2.3/src/openenv/core/evals/base.py +62 -0
- openenv-0.2.3/src/openenv/core/evals/inspect_harness.py +160 -0
- openenv-0.2.3/src/openenv/core/evals/types.py +40 -0
- openenv-0.2.3/src/openenv/core/llm_client.py +506 -0
- openenv-0.2.3/src/openenv/core/mcp_client.py +484 -0
- openenv-0.2.3/src/openenv/core/rubrics/__init__.py +40 -0
- openenv-0.2.3/src/openenv/core/rubrics/base.py +195 -0
- openenv-0.2.3/src/openenv/core/rubrics/containers.py +574 -0
- openenv-0.2.3/src/openenv/core/rubrics/llm_judge.py +118 -0
- openenv-0.2.3/src/openenv/core/rubrics/trajectory.py +203 -0
- openenv-0.2.3/src/openenv/core/sync_client.py +263 -0
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/core/tools/__init__.py +6 -1
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/core/tools/local_python_executor.py +2 -4
- openenv-0.2.3/src/openenv/core/utils.py +59 -0
- openenv-0.2.1/README.md → openenv-0.2.3/src/openenv.egg-info/PKG-INFO +113 -30
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv.egg-info/SOURCES.txt +17 -0
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv.egg-info/requires.txt +25 -1
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv_core/__init__.py +9 -1
- openenv-0.2.1/src/openenv/__init__.py +0 -15
- openenv-0.2.1/src/openenv/cli/_validation.py +0 -161
- openenv-0.2.1/src/openenv/cli/commands/validate.py +0 -108
- openenv-0.2.1/src/openenv/core/__init__.py +0 -22
- openenv-0.2.1/src/openenv/core/env_server/http_server.py +0 -1076
- openenv-0.2.1/src/openenv/core/env_server/mcp_environment.py +0 -386
- openenv-0.2.1/src/openenv/core/env_server/mcp_types.py +0 -166
- openenv-0.2.1/src/openenv/core/env_server/web_interface.py +0 -1658
- openenv-0.2.1/src/openenv/core/mcp_client.py +0 -292
- openenv-0.2.1/src/openenv/core/utils.py +0 -27
- {openenv-0.2.1 → openenv-0.2.3}/LICENSE +0 -0
- {openenv-0.2.1 → openenv-0.2.3}/setup.cfg +0 -0
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/auto/__init__.py +0 -0
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/cli/__init__.py +0 -0
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/cli/commands/build.py +1 -1
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/cli/commands/serve.py +0 -0
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/cli/templates/__init__.py +0 -0
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/cli/templates/openenv_env/README.md +0 -0
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/cli/templates/openenv_env/__init__.py +0 -0
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/cli/templates/openenv_env/openenv.yaml +0 -0
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/cli/templates/openenv_env/server/Dockerfile +0 -0
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/cli/templates/openenv_env/server/__init__.py +0 -0
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/cli/templates/openenv_env/server/requirements.txt +0 -0
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/core/client_types.py +0 -0
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/core/containers/__init__.py +0 -0
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/core/containers/runtime/__init__.py +0 -0
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/core/containers/runtime/uv_provider.py +0 -0
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/core/env_server/base_transforms.py +0 -0
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/core/env_server/exceptions.py +0 -0
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/core/env_server/route_config.py +0 -0
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/core/generic_client.py +0 -0
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv/core/tools/git_server_client.py +0 -0
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv.egg-info/dependency_links.txt +0 -0
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv.egg-info/entry_points.txt +0 -0
- {openenv-0.2.1 → openenv-0.2.3}/src/openenv.egg-info/top_level.txt +0 -0
- {openenv-0.2.1 → openenv-0.2.3}/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
|
+
Version: 0.2.3
|
|
4
4
|
Summary: A unified framework for reinforcement learning environments
|
|
5
5
|
Requires-Python: >=3.10
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -17,7 +17,9 @@ Requires-Dist: openai>=2.7.2
|
|
|
17
17
|
Requires-Dist: tomli>=2.3.0
|
|
18
18
|
Requires-Dist: tomli-w>=1.2.0
|
|
19
19
|
Requires-Dist: websockets>=15.0.1
|
|
20
|
-
Requires-Dist: fastmcp>=
|
|
20
|
+
Requires-Dist: fastmcp>=3.0.0
|
|
21
|
+
Requires-Dist: gradio>=4.0.0
|
|
22
|
+
Requires-Dist: httpx>=0.28.1
|
|
21
23
|
Provides-Extra: core
|
|
22
24
|
Requires-Dist: fastapi>=0.104.0; extra == "core"
|
|
23
25
|
Requires-Dist: pydantic>=2.0.0; extra == "core"
|
|
@@ -32,9 +34,28 @@ Requires-Dist: huggingface_hub>=0.20.0; extra == "cli"
|
|
|
32
34
|
Requires-Dist: openai>=2.7.2; extra == "cli"
|
|
33
35
|
Requires-Dist: tomli>=2.3.0; extra == "cli"
|
|
34
36
|
Requires-Dist: tomli-w>=1.2.0; extra == "cli"
|
|
37
|
+
Provides-Extra: docs
|
|
38
|
+
Requires-Dist: sphinx==7.2.6; extra == "docs"
|
|
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"
|
|
42
|
+
Requires-Dist: sphinx-design==0.6.1; extra == "docs"
|
|
43
|
+
Requires-Dist: sphinxcontrib-mermaid==1.0.0; extra == "docs"
|
|
44
|
+
Requires-Dist: myst-parser; extra == "docs"
|
|
45
|
+
Requires-Dist: sphinxext-opengraph; extra == "docs"
|
|
46
|
+
Requires-Dist: sphinx-sitemap==2.7.1; extra == "docs"
|
|
47
|
+
Requires-Dist: sphinx-gallery>=0.14.0; extra == "docs"
|
|
48
|
+
Requires-Dist: matplotlib; extra == "docs"
|
|
49
|
+
Requires-Dist: nest-asyncio; extra == "docs"
|
|
50
|
+
Requires-Dist: smolagents; extra == "docs"
|
|
35
51
|
Provides-Extra: all
|
|
36
52
|
Requires-Dist: openenv[core]; extra == "all"
|
|
37
53
|
Requires-Dist: openenv[cli]; extra == "all"
|
|
54
|
+
Provides-Extra: daytona
|
|
55
|
+
Requires-Dist: daytona>=0.136.0; extra == "daytona"
|
|
56
|
+
Requires-Dist: pyyaml>=6.0; extra == "daytona"
|
|
57
|
+
Provides-Extra: inspect
|
|
58
|
+
Requires-Dist: inspect-ai>=0.3.0; extra == "inspect"
|
|
38
59
|
Dynamic: license-file
|
|
39
60
|
|
|
40
61
|
# <img width="35" height="35" alt="image" src="https://github.com/user-attachments/assets/2700a971-e5d6-4036-b03f-2f89c9791609" /> OpenEnv: Agentic Execution Environments
|
|
@@ -50,7 +71,7 @@ An e2e framework for creating, deploying and using isolated execution environmen
|
|
|
50
71
|
|
|
51
72
|
**🚀 Featured Example:** Train LLMs to play BlackJack using [torchforge](https://github.com/meta-pytorch/torchforge) (PyTorch's agentic RL framework): [`examples/grpo_blackjack/`](examples/grpo_blackjack/)
|
|
52
73
|
|
|
53
|
-
**🔥
|
|
74
|
+
**🔥 Zero to Hero Tutorial:** End to end tutorial from our [GPU Mode](tutorial/README.md) lecture and other hackathons.
|
|
54
75
|
|
|
55
76
|
## Quick Start
|
|
56
77
|
|
|
@@ -69,22 +90,34 @@ pip install git+https://huggingface.co/spaces/openenv/echo_env
|
|
|
69
90
|
Then use the environment:
|
|
70
91
|
|
|
71
92
|
```python
|
|
93
|
+
import asyncio
|
|
72
94
|
from echo_env import EchoAction, EchoEnv
|
|
73
95
|
|
|
74
|
-
|
|
75
|
-
|
|
96
|
+
async def main():
|
|
97
|
+
# Connect to a running Space (async context manager)
|
|
98
|
+
async with EchoEnv(base_url="https://openenv-echo-env.hf.space") as client:
|
|
99
|
+
# Reset the environment
|
|
100
|
+
result = await client.reset()
|
|
101
|
+
print(result.observation.echoed_message) # "Echo environment ready!"
|
|
76
102
|
|
|
77
|
-
#
|
|
78
|
-
result = client.
|
|
79
|
-
print(result.observation.echoed_message) # "
|
|
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)
|
|
80
107
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
108
|
+
asyncio.run(main())
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**Synchronous usage** is also supported via the `.sync()` wrapper:
|
|
85
112
|
|
|
86
|
-
|
|
87
|
-
|
|
113
|
+
```python
|
|
114
|
+
from echo_env import EchoAction, EchoEnv
|
|
115
|
+
|
|
116
|
+
# Use .sync() for synchronous context manager
|
|
117
|
+
with EchoEnv(base_url="https://openenv-echo-env.hf.space").sync() as client:
|
|
118
|
+
result = client.reset()
|
|
119
|
+
result = client.step(EchoAction(message="Hello, World!"))
|
|
120
|
+
print(result.observation.echoed_message)
|
|
88
121
|
```
|
|
89
122
|
|
|
90
123
|
For a detailed quick start, check out the [docs page](https://meta-pytorch.org/OpenEnv/quickstart/).
|
|
@@ -117,6 +150,10 @@ The OpenEnv CLI (`openenv`) provides commands to initialize new environments and
|
|
|
117
150
|
Below is a list of active and historical RFCs for OpenEnv. RFCs are proposals for major changes or features. Please review and contribute!
|
|
118
151
|
|
|
119
152
|
- [RFC 001: Baseline API and Interface Specifications](https://github.com/meta-pytorch/OpenEnv/pull/26)
|
|
153
|
+
- [RFC 002: Discoverability of environment tools by agents](https://github.com/meta-pytorch/OpenEnv/pull/32)
|
|
154
|
+
- [RFC 003: Add MCP (Model Context Protocol) support](https://github.com/meta-pytorch/OpenEnv/pull/224)
|
|
155
|
+
- [RFC 004: Add delayed rewards support for trajectory-based scoring](https://github.com/meta-pytorch/OpenEnv/pull/337)
|
|
156
|
+
- [RFC 005: Agentic Harness Integration](https://github.com/meta-pytorch/OpenEnv/pull/387)
|
|
120
157
|
|
|
121
158
|
## Architecture
|
|
122
159
|
|
|
@@ -179,6 +216,8 @@ Base class for implementing environment logic:
|
|
|
179
216
|
|
|
180
217
|
#### 3. EnvClient (Client-Side)
|
|
181
218
|
Base class for environment communication:
|
|
219
|
+
- **Async by default**: Use `async with` and `await` for all operations
|
|
220
|
+
- **Sync wrapper**: Call `.sync()` to get a `SyncEnvClient` for synchronous usage
|
|
182
221
|
- Handles WebSocket connections to environment server
|
|
183
222
|
- Contains a utility to spin up a docker container locally for the corresponding environment
|
|
184
223
|
- Type-safe action/observation parsing
|
|
@@ -261,9 +300,21 @@ See [`envs/README.md`](envs/README.md) for a complete guide on building environm
|
|
|
261
300
|
To use an environment:
|
|
262
301
|
1. Install the client: `pip install git+https://huggingface.co/spaces/openenv/echo-env`
|
|
263
302
|
2. Import: `from echo_env import EchoAction, EchoEnv`
|
|
264
|
-
3.
|
|
265
|
-
|
|
266
|
-
|
|
303
|
+
3. Use async (recommended) or sync API:
|
|
304
|
+
|
|
305
|
+
**Async (recommended):**
|
|
306
|
+
```python
|
|
307
|
+
async with EchoEnv(base_url="...") as client:
|
|
308
|
+
result = await client.reset()
|
|
309
|
+
result = await client.step(action)
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
**Sync (via `.sync()` wrapper):**
|
|
313
|
+
```python
|
|
314
|
+
with EchoEnv(base_url="...").sync() as client:
|
|
315
|
+
result = client.reset()
|
|
316
|
+
result = client.step(action)
|
|
317
|
+
```
|
|
267
318
|
|
|
268
319
|
See example scripts in `examples/` directory.
|
|
269
320
|
|
|
@@ -368,22 +419,15 @@ See the [Oumi example](https://github.com/oumi-ai/oumi/blob/main/notebooks/Oumi%
|
|
|
368
419
|
|
|
369
420
|
## Example Environments
|
|
370
421
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
### Coding Environment
|
|
380
|
-
Executes arbitrary Python code in a sandboxed environment. Features:
|
|
381
|
-
- Safe code execution using smolagents
|
|
382
|
-
- Capture stdout, stderr, and exit codes
|
|
383
|
-
- Persistent execution context within episodes
|
|
384
|
-
- Error handling with detailed messages
|
|
422
|
+
| Environment | Description |
|
|
423
|
+
|---|---|
|
|
424
|
+
| [Echo Environment](envs/echo_env/README.md) | Echoes back messages with metadata. Ideal for testing HTTP server infrastructure, learning framework basics, and verifying container deployment. |
|
|
425
|
+
| [Coding Environment](envs/coding_env/README.md) | Sandboxed Python code execution via smolagents. Captures stdout/stderr/exit codes, supports persistent episode context, and provides detailed error handling. |
|
|
426
|
+
| [Chess Environment](envs/chess_env/README.md) | Chess RL environment with configurable opponents and full rules support. |
|
|
427
|
+
| [Atari Environment](envs/atari_env/README.md) | Classic Arcade Learning Environment tasks for RL benchmarking. |
|
|
428
|
+
| [FinRL Environment](envs/finrl_env/README.md) | Financial market simulations for algorithmic trading experiments. |
|
|
385
429
|
|
|
386
|
-
|
|
430
|
+
> Browse the full catalog of community environments at [meta-pytorch.org/OpenEnv/environments](https://meta-pytorch.org/OpenEnv/environments/).
|
|
387
431
|
|
|
388
432
|
## Community Support & Acknowledgments
|
|
389
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!!
|
|
@@ -1,42 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: openenv
|
|
3
|
-
Version: 0.2.1
|
|
4
|
-
Summary: A unified framework for reinforcement learning environments
|
|
5
|
-
Requires-Python: >=3.10
|
|
6
|
-
Description-Content-Type: text/markdown
|
|
7
|
-
License-File: LICENSE
|
|
8
|
-
Requires-Dist: fastapi>=0.104.0
|
|
9
|
-
Requires-Dist: pydantic>=2.0.0
|
|
10
|
-
Requires-Dist: uvicorn>=0.24.0
|
|
11
|
-
Requires-Dist: requests>=2.25.0
|
|
12
|
-
Requires-Dist: typer>=0.9.0
|
|
13
|
-
Requires-Dist: rich>=13.0.0
|
|
14
|
-
Requires-Dist: pyyaml>=6.0
|
|
15
|
-
Requires-Dist: huggingface_hub>=0.20.0
|
|
16
|
-
Requires-Dist: openai>=2.7.2
|
|
17
|
-
Requires-Dist: tomli>=2.3.0
|
|
18
|
-
Requires-Dist: tomli-w>=1.2.0
|
|
19
|
-
Requires-Dist: websockets>=15.0.1
|
|
20
|
-
Requires-Dist: fastmcp>=2.0.0
|
|
21
|
-
Provides-Extra: core
|
|
22
|
-
Requires-Dist: fastapi>=0.104.0; extra == "core"
|
|
23
|
-
Requires-Dist: pydantic>=2.0.0; extra == "core"
|
|
24
|
-
Requires-Dist: uvicorn>=0.24.0; extra == "core"
|
|
25
|
-
Requires-Dist: requests>=2.25.0; extra == "core"
|
|
26
|
-
Requires-Dist: websockets>=15.0.1; extra == "core"
|
|
27
|
-
Provides-Extra: cli
|
|
28
|
-
Requires-Dist: typer>=0.9.0; extra == "cli"
|
|
29
|
-
Requires-Dist: rich>=13.0.0; extra == "cli"
|
|
30
|
-
Requires-Dist: pyyaml>=6.0; extra == "cli"
|
|
31
|
-
Requires-Dist: huggingface_hub>=0.20.0; extra == "cli"
|
|
32
|
-
Requires-Dist: openai>=2.7.2; extra == "cli"
|
|
33
|
-
Requires-Dist: tomli>=2.3.0; extra == "cli"
|
|
34
|
-
Requires-Dist: tomli-w>=1.2.0; extra == "cli"
|
|
35
|
-
Provides-Extra: all
|
|
36
|
-
Requires-Dist: openenv[core]; extra == "all"
|
|
37
|
-
Requires-Dist: openenv[cli]; extra == "all"
|
|
38
|
-
Dynamic: license-file
|
|
39
|
-
|
|
40
1
|
# <img width="35" height="35" alt="image" src="https://github.com/user-attachments/assets/2700a971-e5d6-4036-b03f-2f89c9791609" /> OpenEnv: Agentic Execution Environments
|
|
41
2
|
|
|
42
3
|
An e2e framework for creating, deploying and using isolated execution environments for agentic RL training, built using Gymnasium style simple APIs.
|
|
@@ -50,7 +11,7 @@ An e2e framework for creating, deploying and using isolated execution environmen
|
|
|
50
11
|
|
|
51
12
|
**🚀 Featured Example:** Train LLMs to play BlackJack using [torchforge](https://github.com/meta-pytorch/torchforge) (PyTorch's agentic RL framework): [`examples/grpo_blackjack/`](examples/grpo_blackjack/)
|
|
52
13
|
|
|
53
|
-
**🔥
|
|
14
|
+
**🔥 Zero to Hero Tutorial:** End to end tutorial from our [GPU Mode](tutorial/README.md) lecture and other hackathons.
|
|
54
15
|
|
|
55
16
|
## Quick Start
|
|
56
17
|
|
|
@@ -69,22 +30,34 @@ pip install git+https://huggingface.co/spaces/openenv/echo_env
|
|
|
69
30
|
Then use the environment:
|
|
70
31
|
|
|
71
32
|
```python
|
|
33
|
+
import asyncio
|
|
72
34
|
from echo_env import EchoAction, EchoEnv
|
|
73
35
|
|
|
74
|
-
|
|
75
|
-
|
|
36
|
+
async def main():
|
|
37
|
+
# Connect to a running Space (async context manager)
|
|
38
|
+
async with EchoEnv(base_url="https://openenv-echo-env.hf.space") as client:
|
|
39
|
+
# Reset the environment
|
|
40
|
+
result = await client.reset()
|
|
41
|
+
print(result.observation.echoed_message) # "Echo environment ready!"
|
|
42
|
+
|
|
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)
|
|
76
47
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
print(result.observation.echoed_message) # "Echo environment ready!"
|
|
48
|
+
asyncio.run(main())
|
|
49
|
+
```
|
|
80
50
|
|
|
81
|
-
|
|
82
|
-
result = client.step(EchoAction(message="Hello, World!"))
|
|
83
|
-
print(result.observation.echoed_message) # "Hello, World!"
|
|
84
|
-
print(result.reward) # 1.3 (based on message length)
|
|
51
|
+
**Synchronous usage** is also supported via the `.sync()` wrapper:
|
|
85
52
|
|
|
86
|
-
|
|
87
|
-
|
|
53
|
+
```python
|
|
54
|
+
from echo_env import EchoAction, EchoEnv
|
|
55
|
+
|
|
56
|
+
# Use .sync() for synchronous context manager
|
|
57
|
+
with EchoEnv(base_url="https://openenv-echo-env.hf.space").sync() as client:
|
|
58
|
+
result = client.reset()
|
|
59
|
+
result = client.step(EchoAction(message="Hello, World!"))
|
|
60
|
+
print(result.observation.echoed_message)
|
|
88
61
|
```
|
|
89
62
|
|
|
90
63
|
For a detailed quick start, check out the [docs page](https://meta-pytorch.org/OpenEnv/quickstart/).
|
|
@@ -117,6 +90,10 @@ The OpenEnv CLI (`openenv`) provides commands to initialize new environments and
|
|
|
117
90
|
Below is a list of active and historical RFCs for OpenEnv. RFCs are proposals for major changes or features. Please review and contribute!
|
|
118
91
|
|
|
119
92
|
- [RFC 001: Baseline API and Interface Specifications](https://github.com/meta-pytorch/OpenEnv/pull/26)
|
|
93
|
+
- [RFC 002: Discoverability of environment tools by agents](https://github.com/meta-pytorch/OpenEnv/pull/32)
|
|
94
|
+
- [RFC 003: Add MCP (Model Context Protocol) support](https://github.com/meta-pytorch/OpenEnv/pull/224)
|
|
95
|
+
- [RFC 004: Add delayed rewards support for trajectory-based scoring](https://github.com/meta-pytorch/OpenEnv/pull/337)
|
|
96
|
+
- [RFC 005: Agentic Harness Integration](https://github.com/meta-pytorch/OpenEnv/pull/387)
|
|
120
97
|
|
|
121
98
|
## Architecture
|
|
122
99
|
|
|
@@ -179,6 +156,8 @@ Base class for implementing environment logic:
|
|
|
179
156
|
|
|
180
157
|
#### 3. EnvClient (Client-Side)
|
|
181
158
|
Base class for environment communication:
|
|
159
|
+
- **Async by default**: Use `async with` and `await` for all operations
|
|
160
|
+
- **Sync wrapper**: Call `.sync()` to get a `SyncEnvClient` for synchronous usage
|
|
182
161
|
- Handles WebSocket connections to environment server
|
|
183
162
|
- Contains a utility to spin up a docker container locally for the corresponding environment
|
|
184
163
|
- Type-safe action/observation parsing
|
|
@@ -261,9 +240,21 @@ See [`envs/README.md`](envs/README.md) for a complete guide on building environm
|
|
|
261
240
|
To use an environment:
|
|
262
241
|
1. Install the client: `pip install git+https://huggingface.co/spaces/openenv/echo-env`
|
|
263
242
|
2. Import: `from echo_env import EchoAction, EchoEnv`
|
|
264
|
-
3.
|
|
265
|
-
|
|
266
|
-
|
|
243
|
+
3. Use async (recommended) or sync API:
|
|
244
|
+
|
|
245
|
+
**Async (recommended):**
|
|
246
|
+
```python
|
|
247
|
+
async with EchoEnv(base_url="...") as client:
|
|
248
|
+
result = await client.reset()
|
|
249
|
+
result = await client.step(action)
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
**Sync (via `.sync()` wrapper):**
|
|
253
|
+
```python
|
|
254
|
+
with EchoEnv(base_url="...").sync() as client:
|
|
255
|
+
result = client.reset()
|
|
256
|
+
result = client.step(action)
|
|
257
|
+
```
|
|
267
258
|
|
|
268
259
|
See example scripts in `examples/` directory.
|
|
269
260
|
|
|
@@ -368,22 +359,15 @@ See the [Oumi example](https://github.com/oumi-ai/oumi/blob/main/notebooks/Oumi%
|
|
|
368
359
|
|
|
369
360
|
## Example Environments
|
|
370
361
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
### Coding Environment
|
|
380
|
-
Executes arbitrary Python code in a sandboxed environment. Features:
|
|
381
|
-
- Safe code execution using smolagents
|
|
382
|
-
- Capture stdout, stderr, and exit codes
|
|
383
|
-
- Persistent execution context within episodes
|
|
384
|
-
- Error handling with detailed messages
|
|
362
|
+
| Environment | Description |
|
|
363
|
+
|---|---|
|
|
364
|
+
| [Echo Environment](envs/echo_env/README.md) | Echoes back messages with metadata. Ideal for testing HTTP server infrastructure, learning framework basics, and verifying container deployment. |
|
|
365
|
+
| [Coding Environment](envs/coding_env/README.md) | Sandboxed Python code execution via smolagents. Captures stdout/stderr/exit codes, supports persistent episode context, and provides detailed error handling. |
|
|
366
|
+
| [Chess Environment](envs/chess_env/README.md) | Chess RL environment with configurable opponents and full rules support. |
|
|
367
|
+
| [Atari Environment](envs/atari_env/README.md) | Classic Arcade Learning Environment tasks for RL benchmarking. |
|
|
368
|
+
| [FinRL Environment](envs/finrl_env/README.md) | Financial market simulations for algorithmic trading experiments. |
|
|
385
369
|
|
|
386
|
-
|
|
370
|
+
> Browse the full catalog of community environments at [meta-pytorch.org/OpenEnv/environments](https://meta-pytorch.org/OpenEnv/environments/).
|
|
387
371
|
|
|
388
372
|
## Community Support & Acknowledgments
|
|
389
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!!
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "openenv"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.3"
|
|
8
8
|
description = "A unified framework for reinforcement learning environments"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -26,7 +26,10 @@ dependencies = [
|
|
|
26
26
|
"tomli-w>=1.2.0",
|
|
27
27
|
"websockets>=15.0.1",
|
|
28
28
|
# MCP support
|
|
29
|
-
"fastmcp>=
|
|
29
|
+
"fastmcp>=3.0.0",
|
|
30
|
+
# Web UI dependencies
|
|
31
|
+
"gradio>=4.0.0",
|
|
32
|
+
"httpx>=0.28.1",
|
|
30
33
|
]
|
|
31
34
|
|
|
32
35
|
[project.optional-dependencies]
|
|
@@ -46,10 +49,32 @@ cli = [
|
|
|
46
49
|
"tomli>=2.3.0",
|
|
47
50
|
"tomli-w>=1.2.0",
|
|
48
51
|
]
|
|
52
|
+
docs = [
|
|
53
|
+
"sphinx==7.2.6",
|
|
54
|
+
"pytorch-sphinx-theme2",
|
|
55
|
+
"sphinxcontrib.katex==0.9.10",
|
|
56
|
+
"docutils>=0.18.1,<0.21",
|
|
57
|
+
"sphinx-design==0.6.1",
|
|
58
|
+
"sphinxcontrib-mermaid==1.0.0",
|
|
59
|
+
"myst-parser",
|
|
60
|
+
"sphinxext-opengraph",
|
|
61
|
+
"sphinx-sitemap==2.7.1",
|
|
62
|
+
"sphinx-gallery>=0.14.0",
|
|
63
|
+
"matplotlib",
|
|
64
|
+
"nest-asyncio",
|
|
65
|
+
"smolagents",
|
|
66
|
+
]
|
|
49
67
|
all = [
|
|
50
68
|
"openenv[core]",
|
|
51
69
|
"openenv[cli]",
|
|
52
70
|
]
|
|
71
|
+
daytona = [
|
|
72
|
+
"daytona>=0.136.0",
|
|
73
|
+
"pyyaml>=6.0",
|
|
74
|
+
]
|
|
75
|
+
inspect = [
|
|
76
|
+
"inspect-ai>=0.3.0",
|
|
77
|
+
]
|
|
53
78
|
|
|
54
79
|
[project.scripts]
|
|
55
80
|
openenv = "openenv.cli.__main__:main"
|
|
@@ -61,8 +86,12 @@ include-package-data = true
|
|
|
61
86
|
[tool.setuptools.package-data]
|
|
62
87
|
"openenv.cli" = ["templates/**/*"]
|
|
63
88
|
|
|
89
|
+
[tool.setuptools.exclude-package-data]
|
|
90
|
+
"*" = ["*.pyc", "*.pyo", "__pycache__/*"]
|
|
91
|
+
|
|
64
92
|
[tool.setuptools.packages.find]
|
|
65
93
|
where = ["src"]
|
|
94
|
+
exclude = ["*.__pycache__", "*.__pycache__.*"]
|
|
66
95
|
|
|
67
96
|
[tool.coverage.run]
|
|
68
97
|
omit = [
|
|
@@ -82,8 +111,42 @@ exclude_lines = [
|
|
|
82
111
|
]
|
|
83
112
|
|
|
84
113
|
[tool.pytest.ini_options]
|
|
114
|
+
asyncio_mode = "auto"
|
|
115
|
+
asyncio_default_fixture_loop_scope = "function"
|
|
85
116
|
markers = [
|
|
86
117
|
"docker: Tests that require Docker to be running",
|
|
87
118
|
"network: Tests that require network access (HuggingFace, etc.)",
|
|
88
119
|
"integration: Integration tests with external resources",
|
|
89
120
|
]
|
|
121
|
+
|
|
122
|
+
[dependency-groups]
|
|
123
|
+
dev = [
|
|
124
|
+
"ruff>=0.14.0",
|
|
125
|
+
"usort>=1.1.0",
|
|
126
|
+
"pytest>=7.0",
|
|
127
|
+
"pytest-asyncio>=0.21",
|
|
128
|
+
]
|
|
129
|
+
|
|
130
|
+
[tool.usort]
|
|
131
|
+
# Disable first_party auto-detection so all non-stdlib imports land in
|
|
132
|
+
# the same "third_party" bucket (the default_category). This matches
|
|
133
|
+
# pyfmt's usort behavior inside arc f, which groups openenv.* and env
|
|
134
|
+
# package imports together without blank-line separators.
|
|
135
|
+
first_party_detection = false
|
|
136
|
+
|
|
137
|
+
[tool.ruff]
|
|
138
|
+
line-length = 88
|
|
139
|
+
|
|
140
|
+
[tool.ruff.lint]
|
|
141
|
+
select = ["E", "F", "W"]
|
|
142
|
+
ignore = [
|
|
143
|
+
"E402", # Module level import not at top of file (needed for pytest.importorskip patterns)
|
|
144
|
+
"E501", # Line too long (not enforced previously, would require large refactor)
|
|
145
|
+
]
|
|
146
|
+
|
|
147
|
+
[tool.ruff.lint.per-file-ignores]
|
|
148
|
+
# Context manager variables that are intentionally unused
|
|
149
|
+
"tests/envs/test_websockets.py" = ["F841"]
|
|
150
|
+
"tests/test_cli/test_push.py" = ["F841"]
|
|
151
|
+
# Compatibility shim module
|
|
152
|
+
"src/openenv_core/__init__.py" = ["F401"]
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""Unified OpenEnv package bundling the CLI and core runtime."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from importlib import import_module, metadata
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
"core",
|
|
9
|
+
"cli",
|
|
10
|
+
"AutoEnv",
|
|
11
|
+
"AutoAction",
|
|
12
|
+
"GenericEnvClient",
|
|
13
|
+
"GenericAction",
|
|
14
|
+
"SyncEnvClient",
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _load_package_version() -> str:
|
|
19
|
+
"""Resolve the installed distribution version for the OpenEnv package."""
|
|
20
|
+
for distribution_name in ("openenv", "openenv"):
|
|
21
|
+
try:
|
|
22
|
+
return metadata.version(distribution_name)
|
|
23
|
+
except metadata.PackageNotFoundError:
|
|
24
|
+
continue
|
|
25
|
+
return "0.0.0"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
__version__ = _load_package_version()
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
_LAZY_MODULES = {
|
|
32
|
+
"core": ".core",
|
|
33
|
+
"cli": ".cli",
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
_LAZY_ATTRS = {
|
|
37
|
+
"AutoEnv": (".auto", "AutoEnv"),
|
|
38
|
+
"AutoAction": (".auto", "AutoAction"),
|
|
39
|
+
"GenericEnvClient": (".core", "GenericEnvClient"),
|
|
40
|
+
"GenericAction": (".core", "GenericAction"),
|
|
41
|
+
"SyncEnvClient": (".core", "SyncEnvClient"),
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def __getattr__(name: str):
|
|
46
|
+
if name in _LAZY_MODULES:
|
|
47
|
+
module = import_module(_LAZY_MODULES[name], __name__)
|
|
48
|
+
globals()[name] = module
|
|
49
|
+
return module
|
|
50
|
+
|
|
51
|
+
if name in _LAZY_ATTRS:
|
|
52
|
+
module_path, attr_name = _LAZY_ATTRS[name]
|
|
53
|
+
module = import_module(module_path, __name__)
|
|
54
|
+
value = getattr(module, attr_name)
|
|
55
|
+
globals()[name] = value
|
|
56
|
+
return value
|
|
57
|
+
|
|
58
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def __dir__() -> list[str]:
|
|
62
|
+
return sorted(set(globals().keys()) | set(__all__))
|
|
@@ -24,9 +24,9 @@ import json
|
|
|
24
24
|
import logging
|
|
25
25
|
import re
|
|
26
26
|
import tempfile
|
|
27
|
-
from dataclasses import
|
|
27
|
+
from dataclasses import asdict, dataclass
|
|
28
28
|
from pathlib import Path
|
|
29
|
-
from typing import
|
|
29
|
+
from typing import Any, Dict, Optional, Type
|
|
30
30
|
|
|
31
31
|
import yaml
|
|
32
32
|
|
|
@@ -33,9 +33,9 @@ Example:
|
|
|
33
33
|
from __future__ import annotations
|
|
34
34
|
|
|
35
35
|
import logging
|
|
36
|
-
from typing import
|
|
36
|
+
from typing import Any, Dict, Type
|
|
37
37
|
|
|
38
|
-
from ._discovery import
|
|
38
|
+
from ._discovery import _is_hub_url, get_discovery
|
|
39
39
|
from .auto_env import AutoEnv
|
|
40
40
|
|
|
41
41
|
logger = logging.getLogger(__name__)
|
|
@@ -153,9 +153,9 @@ class AutoAction:
|
|
|
153
153
|
|
|
154
154
|
if not available_envs:
|
|
155
155
|
raise ValueError(
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
156
|
+
"No OpenEnv environments found.\n"
|
|
157
|
+
"Install an environment with: pip install openenv-<env-name>\n"
|
|
158
|
+
"Or specify a HuggingFace Hub repository: AutoAction.from_env('openenv/echo_env')"
|
|
159
159
|
)
|
|
160
160
|
|
|
161
161
|
# Try to suggest similar environment names
|
|
@@ -36,10 +36,13 @@ import os
|
|
|
36
36
|
import shutil
|
|
37
37
|
import subprocess
|
|
38
38
|
import sys
|
|
39
|
+
from typing import Any, Dict, Optional, TYPE_CHECKING
|
|
40
|
+
|
|
39
41
|
import requests
|
|
40
|
-
from
|
|
42
|
+
from openenv.core.utils import run_async_safely
|
|
43
|
+
|
|
44
|
+
from ._discovery import _is_hub_url, get_discovery
|
|
41
45
|
|
|
42
|
-
from ._discovery import get_discovery, _is_hub_url
|
|
43
46
|
|
|
44
47
|
if TYPE_CHECKING:
|
|
45
48
|
from openenv.core.containers.runtime import ContainerProvider
|
|
@@ -590,12 +593,14 @@ class AutoEnv:
|
|
|
590
593
|
f"Space not running at {space_url}, "
|
|
591
594
|
f"using GenericEnvClient with HF Docker registry"
|
|
592
595
|
)
|
|
593
|
-
return
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
596
|
+
return run_async_safely(
|
|
597
|
+
GenericEnvClient.from_env(
|
|
598
|
+
name,
|
|
599
|
+
use_docker=True,
|
|
600
|
+
provider=container_provider,
|
|
601
|
+
env_vars=env_vars or {},
|
|
602
|
+
**kwargs,
|
|
603
|
+
)
|
|
599
604
|
)
|
|
600
605
|
|
|
601
606
|
# For local environments with skip_install, we need docker_image
|
|
@@ -604,12 +609,14 @@ class AutoEnv:
|
|
|
604
609
|
f"Using GenericEnvClient with Docker image {docker_image} "
|
|
605
610
|
f"(skip_install=True)"
|
|
606
611
|
)
|
|
607
|
-
return
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
612
|
+
return run_async_safely(
|
|
613
|
+
GenericEnvClient.from_docker_image(
|
|
614
|
+
image=docker_image,
|
|
615
|
+
provider=container_provider,
|
|
616
|
+
wait_timeout=wait_timeout,
|
|
617
|
+
env_vars=env_vars or {},
|
|
618
|
+
**kwargs,
|
|
619
|
+
)
|
|
613
620
|
)
|
|
614
621
|
else:
|
|
615
622
|
raise ValueError(
|
|
@@ -715,12 +722,14 @@ class AutoEnv:
|
|
|
715
722
|
# Local server not running, auto-start Docker container
|
|
716
723
|
logger.info(f"❌ Server not available at {base_url}")
|
|
717
724
|
logger.info(f"🐳 Auto-starting Docker container: {docker_image}")
|
|
718
|
-
return
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
725
|
+
return run_async_safely(
|
|
726
|
+
client_class.from_docker_image(
|
|
727
|
+
image=docker_image,
|
|
728
|
+
provider=container_provider,
|
|
729
|
+
wait_timeout=wait_timeout,
|
|
730
|
+
env_vars=env_vars or {},
|
|
731
|
+
**kwargs,
|
|
732
|
+
)
|
|
724
733
|
)
|
|
725
734
|
else:
|
|
726
735
|
# Remote server not available, cannot auto-start
|
|
@@ -730,12 +739,14 @@ class AutoEnv:
|
|
|
730
739
|
)
|
|
731
740
|
else:
|
|
732
741
|
# No base_url provided, start new Docker container
|
|
733
|
-
return
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
742
|
+
return run_async_safely(
|
|
743
|
+
client_class.from_docker_image(
|
|
744
|
+
image=docker_image,
|
|
745
|
+
provider=container_provider,
|
|
746
|
+
wait_timeout=wait_timeout,
|
|
747
|
+
env_vars=env_vars or {},
|
|
748
|
+
**kwargs,
|
|
749
|
+
)
|
|
739
750
|
)
|
|
740
751
|
except Exception as e:
|
|
741
752
|
raise ValueError(
|