Skip to content

Commit 5f840ae

Browse files
authored
Merge pull request #66 from meta-pytorch/pypi-setup
add openenv-core pypi project and build instructions
2 parents b2a96fb + f63c837 commit 5f840ae

File tree

3 files changed

+297
-0
lines changed

3 files changed

+297
-0
lines changed
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
name: Publish OpenEnv Core to PyPI
2+
3+
on:
4+
release:
5+
types: [published]
6+
# Allow manual trigger for testing
7+
workflow_dispatch:
8+
inputs:
9+
use_test_pypi:
10+
description: 'Publish to Test PyPI instead of PyPI'
11+
required: false
12+
default: 'true'
13+
type: choice
14+
options:
15+
- 'true'
16+
- 'false'
17+
18+
jobs:
19+
build-and-publish:
20+
runs-on: ubuntu-latest
21+
22+
steps:
23+
- name: Checkout code
24+
uses: actions/checkout@v4
25+
26+
- name: Set up Python
27+
uses: actions/setup-python@v5
28+
with:
29+
python-version: '3.11'
30+
31+
- name: Install build dependencies
32+
run: |
33+
python -m pip install --upgrade pip
34+
pip install build twine
35+
36+
- name: Build package
37+
run: |
38+
cd src/core
39+
python -m build
40+
41+
- name: Check package
42+
run: |
43+
cd src/core
44+
twine check dist/*
45+
46+
- name: List package contents
47+
run: |
48+
cd src/core
49+
tar -tzf dist/*.tar.gz | head -20
50+
51+
- name: Publish to Test PyPI
52+
if: github.event_name == 'workflow_dispatch' && github.event.inputs.use_test_pypi == 'true'
53+
env:
54+
TWINE_USERNAME: __token__
55+
TWINE_PASSWORD: ${{ secrets.TEST_PYPI_API_TOKEN }}
56+
run: |
57+
cd src/core
58+
twine upload --repository testpypi dist/*
59+
60+
- name: Publish to PyPI
61+
if: github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.use_test_pypi == 'false')
62+
env:
63+
TWINE_USERNAME: __token__
64+
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
65+
run: |
66+
cd src/core
67+
twine upload dist/*

src/core/README.md

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
# OpenEnv Core
2+
3+
Core components for OpenEnv - a framework for building HTTP-based agentic environments.
4+
5+
## Overview
6+
7+
`openenv-core` provides the foundational building blocks for creating and interacting with containerized environments over HTTP. It enables you to build agent environments that can be deployed as Docker containers and accessed via a simple HTTP API.
8+
9+
## Features
10+
11+
- **HTTPEnvClient**: Generic HTTP client for interacting with remote environments
12+
- **HTTPEnvServer**: FastAPI-based server wrapper for exposing environments over HTTP
13+
- **Container Providers**: Pluggable architecture for running containers (Docker, Kubernetes, etc.)
14+
- **Type System**: Strongly-typed Action/Observation/State interfaces
15+
- **Web Interface**: Optional web UI for interacting with environments
16+
17+
## Installation
18+
19+
```bash
20+
pip install openenv-core
21+
```
22+
23+
For development:
24+
```bash
25+
pip install openenv-core[dev]
26+
```
27+
28+
## Quick Start
29+
30+
### Creating an Environment Client
31+
32+
```python
33+
from openenv_core import HTTPEnvClient, StepResult
34+
from dataclasses import dataclass
35+
36+
@dataclass
37+
class MyAction:
38+
text: str
39+
40+
@dataclass
41+
class MyObservation:
42+
response: str
43+
44+
class MyEnvClient(HTTPEnvClient[MyAction, MyObservation]):
45+
def _step_payload(self, action: MyAction) -> dict:
46+
return {"text": action.text}
47+
48+
def _parse_result(self, payload: dict) -> StepResult[MyObservation]:
49+
obs_data = payload["observation"]
50+
return StepResult(
51+
observation=MyObservation(**obs_data),
52+
reward=payload.get("reward"),
53+
done=payload.get("done", False)
54+
)
55+
56+
def _parse_state(self, payload: dict) -> Any:
57+
return payload
58+
59+
# Use with Docker
60+
env = MyEnvClient.from_docker_image("my-env:latest")
61+
result = env.reset()
62+
step_result = env.step(MyAction(text="hello"))
63+
env.close()
64+
```
65+
66+
### Creating an Environment Server
67+
68+
```python
69+
from openenv_core.env_server import Environment, HTTPEnvServer, create_app
70+
from dataclasses import dataclass
71+
72+
@dataclass
73+
class MyAction:
74+
text: str
75+
76+
@dataclass
77+
class MyObservation:
78+
response: str
79+
reward: float = 0.0
80+
done: bool = False
81+
82+
class MyEnvironment(Environment):
83+
def reset(self) -> MyObservation:
84+
return MyObservation(response="Ready")
85+
86+
def step(self, action: MyAction) -> MyObservation:
87+
return MyObservation(
88+
response=f"Echo: {action.text}",
89+
reward=1.0,
90+
done=False
91+
)
92+
93+
# Create FastAPI app
94+
env = MyEnvironment()
95+
app = create_app(env, MyAction, MyObservation)
96+
97+
# Run with: uvicorn module:app --host 0.0.0.0 --port 8000
98+
```
99+
100+
## Container Providers
101+
102+
OpenEnv Core supports multiple container providers:
103+
104+
### Local Docker Provider
105+
106+
```python
107+
from openenv_core.containers.runtime import LocalDockerProvider
108+
109+
provider = LocalDockerProvider()
110+
base_url = provider.start_container("my-env:latest")
111+
provider.wait_for_ready(base_url)
112+
# Use environment...
113+
provider.stop_container()
114+
```
115+
116+
### Kubernetes Provider (Coming Soon)
117+
118+
```python
119+
from openenv_core.containers.runtime import KubernetesProvider
120+
121+
provider = KubernetesProvider(namespace="envs")
122+
base_url = provider.start_container("my-env:latest")
123+
# Use environment...
124+
provider.stop_container()
125+
```
126+
127+
## Architecture
128+
129+
OpenEnv Core follows a client-server architecture:
130+
131+
```
132+
┌─────────────────┐ HTTP ┌─────────────────┐
133+
│ │◄─────────────────────►│ │
134+
│ HTTPEnvClient │ /reset, /step │ HTTPEnvServer │
135+
│ │ /state, /health │ │
136+
└─────────────────┘ └─────────────────┘
137+
│ │
138+
│ │
139+
▼ ▼
140+
┌─────────────────┐ ┌─────────────────┐
141+
│ Container │ │ Environment │
142+
│ Provider │ │ Implementation │
143+
└─────────────────┘ └─────────────────┘
144+
```
145+
146+
## API Reference
147+
148+
### HTTPEnvClient
149+
150+
Base class for environment clients with these abstract methods:
151+
152+
- `_step_payload(action)`: Convert action to JSON
153+
- `_parse_result(payload)`: Parse response to StepResult
154+
- `_parse_state(payload)`: Parse state response
155+
156+
### HTTPEnvServer
157+
158+
Server wrapper with these methods:
159+
160+
- `register_routes(app)`: Register endpoints on FastAPI app
161+
- `_deserialize_action(data)`: Convert JSON to Action
162+
- `_serialize_observation(obs)`: Convert Observation to JSON
163+
164+
### Environment Interface
165+
166+
Base interface for environment implementations:
167+
168+
- `reset()`: Reset environment and return initial observation
169+
- `step(action)`: Execute action and return observation
170+
- `state`: Property returning current environment state
171+
172+
## License
173+
174+
This project is licensed under the BSD-3-Clause License - see the LICENSE file for details.
175+
176+
## Contributing
177+
178+
Contributions are welcome! Please see the main OpenEnv repository for contribution guidelines.
179+
180+
## Links
181+
182+
- **Homepage**: https://github.com/facebookresearch/OpenEnv
183+
- **Documentation**: https://github.com/facebookresearch/OpenEnv/blob/main/README.md
184+
- **Bug Tracker**: https://github.com/facebookresearch/OpenEnv/issues

src/core/pyproject.toml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
[build-system]
2+
requires = ["setuptools>=45", "wheel"]
3+
build-backend = "setuptools.build_meta"
4+
5+
[project]
6+
name = "openenv-core"
7+
version = "0.1.0"
8+
description = "Core components for OpenEnv - HTTP-based agentic environments"
9+
readme = "README.md"
10+
requires-python = ">=3.8"
11+
license = {text = "BSD-3-Clause"}
12+
authors = [
13+
{name = "Meta Platforms, Inc.", email = "opensource@meta.com"}
14+
]
15+
keywords = ["environment", "agent", "http", "docker", "fastapi"]
16+
17+
dependencies = [
18+
"requests>=2.25.0",
19+
"fastapi>=0.104.0",
20+
"uvicorn>=0.24.0",
21+
]
22+
23+
[project.optional-dependencies]
24+
dev = [
25+
"pytest>=7.0.0",
26+
"black>=23.0.0",
27+
"ruff>=0.1.0",
28+
"mypy>=1.0.0",
29+
]
30+
31+
[project.urls]
32+
Homepage = "https://github.com/facebookresearch/OpenEnv"
33+
Repository = "https://github.com/facebookresearch/OpenEnv"
34+
Documentation = "https://github.com/facebookresearch/OpenEnv/blob/main/README.md"
35+
"Bug Tracker" = "https://github.com/facebookresearch/OpenEnv/issues"
36+
37+
[tool.setuptools]
38+
py-modules = ["openenv_core.__init__", "openenv_core.http_env_client", "openenv_core.types"]
39+
packages = [
40+
"openenv_core",
41+
"openenv_core.containers",
42+
"openenv_core.containers.runtime",
43+
"openenv_core.env_server",
44+
"openenv_core.tools"
45+
]
46+
package-dir = {"openenv_core" = "."}

0 commit comments

Comments
 (0)