Spaces:
Build error
Build error
File size: 12,391 Bytes
c8e832f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 | # 2. Deploying an OpenEnv environment
This section covers deploying OpenEnv environments locally, on clusters, and on Hugging Face Spaces.
**Contents:**
- [Local Development with Uvicorn](#local-development-with-uvicorn)
- [Docker Deployment](#docker-deployment)
- [Hugging Face Spaces](#hugging-face-spaces)
- [Best Practices](#best-practices)
## HF Spaces are the infrastructure for OpenEnv environments
Every HF Space provides three things that OpenEnv environments need:
| Component | What it provides | How to access | Used as |
|-----------|------------------|---------------|-----------|
| **Server** | Running environment endpoint | `https://<username>-<space-name>.hf.space` | Agent and Public API |
| **Repository** | Installable Python package | `pip install git+https://huggingface.co/spaces/<username>-<space-name>` | Code and client |
| **Registry** | Docker container image | `docker pull registry.hf.space/<username>-<space-name>:latest` | Deployment |
This means a single Space deployment gives you all the components you need to use an environment in training.
### 1. Server: A running environment endpoint
When you deploy to HF Spaces, your environment runs as a server. The client connects via **WebSocket** (`/ws`) for a persistent session:
```python
from echo_env import EchoEnv, EchoAction
# Connect directly to the running Space (WebSocket under the hood)
# Async (recommended):
async with EchoEnv(base_url="https://openenv-echo-env.hf.space") as client:
result = await client.reset()
result = await client.step(EchoAction(message="Hello"))
# Sync (using .sync() wrapper):
with EchoEnv(base_url="https://openenv-echo-env.hf.space").sync() as client:
result = client.reset()
result = client.step(EchoAction(message="Hello"))
```
**Endpoints available:**
| Endpoint | Protocol | Description |
|----------|----------|-------------|
| `/ws` | **WebSocket** | Persistent session (used by client) |
| `/health` | HTTP GET | Health check |
| `/reset` | HTTP POST | Reset environment (stateless) |
| `/step` | HTTP POST | Execute action (stateless) |
| `/state` | HTTP GET | Get current state |
| `/docs` | HTTP GET | OpenAPI documentation |
| `/web` | HTTP GET | Interactive web UI |
> **Note:** The Python client uses the `/ws` WebSocket endpoint by default. HTTP endpoints are available for debugging or stateless use cases.
**Example: Check if a Space is running**
```bash
curl https://openenv-echo-env.hf.space/health
# {"status": "healthy"}
```
### 2. Repository: Installable Python package
Every Space is a Git repository. OpenEnv environments include a `pyproject.toml`, making them pip-installable directly from the Space URL.
```bash
# Install client package from Space
pip install git+https://huggingface.co/spaces/openenv/echo-env
```
This installs:
- **Client class** (`EchoEnv`) โ Handles HTTP/WebSocket communication
- **Models** (`EchoAction`, `EchoObservation`) โ Typed action and observation classes
- **Utilities** โ Any helper functions the environment provides
**After installation:**
```python
from envs.echo_env import EchoEnv, EchoAction, EchoObservation
# Now you have typed classes for the environment
action = EchoAction(message="Hello")
```
### 3. Registry: Docker container image
Every Docker-based Space has a container registry. You can pull and run the environment locally.
```bash
# Pull the image
docker pull registry.hf.space/openenv-echo-env:latest
# Run locally on port 8001
docker run -d -p 8001:8000 registry.hf.space/openenv-echo-env:latest
```
**Find the registry URL for any Space:**
1. Go to the Space page (e.g., [openenv/echo-env](https://huggingface.co/spaces/openenv/echo-env))
2. Click **โฎ** (three dots) โ **"Run locally"**
3. Copy the `docker run` command
### Choosing an access method
| Method | Use when | Pros | Cons |
|--------|----------|------|------|
| **Server** | Quick testing, low volume | Zero setup | Network latency, rate limits |
| **Repository** | Need typed classes | Type safety, IDE support | Still need a server |
| **Docker** | Local dev, high throughput | Full control, no network | Requires Docker |
**Typical workflow:**
```python
import asyncio
from echo_env import EchoEnv, EchoAction
async def main():
# Development: connect to remote Space
async with EchoEnv(base_url="https://openenv-echo-env.hf.space") as client:
result = await client.reset()
# Production: run locally for speed
# docker run -d -p 8001:8000 registry.hf.space/openenv-echo-env:latest
async with EchoEnv(base_url="http://localhost:8001") as client:
result = await client.reset()
# Or let the client manage Docker for you
client = await EchoEnv.from_env("openenv/echo-env") # Auto-pulls and runs
async with client:
result = await client.reset()
asyncio.run(main())
# For sync usage, use the .sync() wrapper:
with EchoEnv(base_url="http://localhost:8001").sync() as client:
result = client.reset()
```
> **Reference:** [HF Spaces Documentation](https://huggingface.co/docs/hub/spaces) | [Environment Hub Collection](https://huggingface.co/collections/openenv/environment-hub)
## Local Development with Uvicorn
The fastest way to iterate on environment logic is running directly with Uvicorn.
## Clone and run the environment locally
```bash
# Clone from HF Space
git clone https://huggingface.co/spaces/burtenshaw/openenv-benchmark
cd openenv-benchmark
# Install in editable mode
uv sync
# Start server
uv run server
# Run isolated from remote Space
uv run --isolated --project https://huggingface.co/spaces/burtenshaw/openenv-benchmark server
```
## Uvicorn directly in python
```bash
# Full control over uvicorn options
uvicorn benchmark.server.app:app --host "$HOST" --port "$PORT" --workers "$WORKERS"
# With reload for development
uvicorn benchmark.server.app:app --host 0.0.0.0 --port 8000 --reload
# Multi-Worker Mode For better concurrency:
uvicorn benchmark.server.app:app --host 0.0.0.0 --port 8000 --workers 4
```
| Flag | Purpose |
|------|---------|
| `--reload` | Auto-restart on code changes |
| `--workers N` | Run N worker processes |
| `--log-level debug` | Verbose logging |
## Docker Deployment
Docker provides isolation and reproducibility for production use.
### Run the environment locally from the space
```bash
# Run the environment locally from the space
docker run -d -p 8000:8000 registry.hf.space/openenv-echo-env:latest
```
### Build Image
```bash
# Clone from HF Space
git clone https://huggingface.co/spaces/burtenshaw/openenv-benchmark
cd openenv-benchmark
# Using OpenEnv CLI (recommended)
openenv build -t openenv-benchmark:latest
# Or with Docker directly
docker build -t openenv-benchmark:latest -f server/Dockerfile .
```
### Run Container
```bash
# Basic run
docker run -d -p 8000:8000 my-env:latest
# With environment variables
docker run -d -p 8000:8000 \
-e WORKERS=4 \
-e MAX_CONCURRENT_ENVS=100 \
my-env:latest
# Named container for easy management
docker run -d --name my-env -p 8000:8000 my-env:latest
```
### Connect from Python
```python
import asyncio
from echo_env import EchoEnv, EchoAction
async def main():
# Async usage (recommended)
async with EchoEnv(base_url="http://localhost:8000") as client:
result = await client.reset()
result = await client.step(EchoAction(message="Hello"))
print(result.observation)
# From Docker image
client = await EchoEnv.from_docker_image("<local_docker_image>")
async with client:
result = await client.reset()
print(result.observation)
asyncio.run(main())
# Sync usage (using .sync() wrapper)
with EchoEnv(base_url="http://localhost:8000").sync() as client:
result = client.reset()
result = client.step(EchoAction(message="Hello"))
print(result.observation)
```
### Container Lifecycle
| Method | Container | WebSocket | On `close()` |
|--------|-----------|-----------|--------------|
| `from_hub(repo_id)` | Starts | Connects | Stops container |
| `from_hub(repo_id, use_docker=False)` | None (UV) | Connects | Stops UV server |
| `from_docker_image(image)` | Starts | Connects | Stops container |
| `MyEnv(base_url=...)` | None | Connects | Disconnects only |
Find Docker Commands for Any Space
1. Open the Space on HuggingFace Hub
2. Click **โฎ (three dots)** menu
3. Select **"Run locally"**
4. Copy the provided `docker run` command
## Deploy with CLI
```bash
cd my_env
# Deploy to your namespace
openenv push
# Deploy to specific repo
openenv push --repo-id username/my-env
# Deploy as private
openenv push --repo-id username/my-env --private
```
### Space Configuration
The `openenv.yaml` manifest controls Space settings:
```yaml
# openenv.yaml
name: my_env
version: "1.0.0"
description: My custom environment
```
Hardware Options:
| Tier | vCPU | RAM | Cost |
|------|------|-----|------|
| CPU Basic (Free) | 2 | 16GB | Free |
| CPU Upgrade | 8 | 32GB | $0.03/hr |
OpenEnv environments support configuration via environment variables.
| Variable | Default | Description |
|----------|---------|-------------|
| `WORKERS` | 4 | Uvicorn worker processes |
| `PORT` | 8000 | Server port |
| `HOST` | 0.0.0.0 | Bind address |
| `MAX_CONCURRENT_ENVS` | 100 | Max WebSocket sessions |
| `ENABLE_WEB_INTERFACE` | Auto | Enable web UI |
### Environment-Specific Variables
Some environments have custom variables:
**TextArena:**
```bash
TEXTARENA_ENV_ID=Wordle-v0
TEXTARENA_NUM_PLAYERS=1
TEXTARENA_MAX_TURNS=6
```
**Coding Environment:**
```bash
SANDBOX_TIMEOUT=30
MAX_OUTPUT_LENGTH=10000
```
# DEMO: Deploying to Hugging Face Spaces
This demo walks through the full workflow: create an environment, test locally, deploy to HF Spaces, and use it.
## Step 1: Initialize a new environment
```bash
openenv init my_env
cd my_env
```
This creates the standard OpenEnv structure:
```
my_env/
โโโ server/
โ โโโ app.py # FastAPI server
โ โโโ environment.py # Your environment logic
โ โโโ Dockerfile
โโโ models.py # Action/Observation types
โโโ client.py # HTTP client
โโโ openenv.yaml # Manifest
โโโ pyproject.toml
```
## Step 2: Run locally
```bash
# Start the server
uv run server
# Or with uvicorn directly
uvicorn server.app:app --host 0.0.0.0 --port 8000 --reload
```
Test the health endpoint:
```bash
curl http://localhost:8000/health
# {"status": "healthy"}
```
## Step 3: Deploy to HF Spaces
```bash
openenv push --repo-id username/my-env
```
Your environment is now live at:
- Web UI: https://username-my-env.hf.space/web
- API Docs: https://username-my-env.hf.space/docs
- Health: https://username-my-env.hf.space/health
```bash
curl https://openenv-echo-env.hf.space/health
# {"status": "healthy"}
```
## Step 4: install the environment
```bash
uv pip install git+https://huggingface.co/spaces/openenv/echo_env
```
## Step 5: Run locally via Docker (optional)
Pull and run the container from the HF registry, or open the [browser](https://huggingface.co/spaces/openenv/echo_env?docker=true):
```bash
# Pull from HF Spaces registry
docker pull registry.hf.space/openenv-echo-env:latest
# Run locally
docker run -it -p 7860:7860 --platform=linux/amd64 \
registry.hf.space/openenv-echo-env:latest
```
Now connect to your local instance:
```python
import asyncio
from echo_env import EchoEnv, EchoAction
# Async (recommended)
async def main():
async with EchoEnv(base_url="http://localhost:8000") as env:
result = await env.reset()
print(result.observation)
result = await env.step(EchoAction(message="Hello"))
print(result.observation)
asyncio.run(main())
# Sync (using .sync() wrapper)
with EchoEnv(base_url="http://localhost:8000").sync() as env:
result = env.reset()
print(result.observation)
result = env.step(EchoAction(message="Hello"))
print(result.observation)
``` |