Spaces:
Sleeping
Sleeping
File size: 9,720 Bytes
ec8b2ca fa04acd ec8b2ca | 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 | ---
title: Self-Healing DevOps Sandbox
emoji: π§
colorFrom: red
colorTo: green
sdk: docker
pinned: false
app_port: 8000
base_path: /web
tags:
- openenv
---
# π§ Self-Healing DevOps Sandbox
An **OpenEnv RL environment** where an AI agent is dropped into a broken Node.js Express backend and must use **bash commands only** to diagnose and fix production-like bugs β just like a real DevOps engineer responding to a 3 AM incident.
Built for the **Meta PyTorch OpenEnv Hackathon**.
---
## π― Why This Environment?
DevOps debugging is one of the most **high-value, real-world tasks** for AI agents. Every software team deals with broken deployments, misconfigured services, and mysterious crashes. This environment tests whether an AI agent can:
- **Read and understand** error logs, config files, and source code
- **Diagnose root causes** from symptoms (crash logs β specific file + line)
- **Apply targeted fixes** using command-line tools (sed, echo, etc.)
- **Verify its own work** by restarting services and checking endpoints
---
## ποΈ Task Design
### Three Difficulty Levels
| # | Task | Bugs | What's Broken | Grading Target |
|---|------|------|---------------|----------------|
| 1 | `easy` | 1 | `config.json` β port `9999` instead of `3000` | Fix port, app starts |
| 2 | `medium` | 2 | + `routes/users.js` β missing `)` causes SyntaxError | + `/api/users` works |
| 3 | `hard` | 3 | + `routes/data.js` β missing `await` breaks async response | All endpoints pass |
Each task builds on the previous β meaningful difficulty progression where easy tasks are subsets of harder ones.
### The Broken App (`/app`)
```
/app/
βββ config.json β Bug 1: port set to 9999 (should be 3000)
βββ package.json β Express.js project config
βββ server.js β Main entry point (loads config + routes)
βββ routes/
βββ users.js β Bug 2: missing closing parenthesis on router.get()
βββ data.js β Bug 3: missing `await` before async DB call
```
---
## π€ Evaluation Alignment (OpenEnv Rubric Guide)
*Note for Evaluators: This environment was rigorously engineered to meet the highest standards of the OpenEnv specification.*
- **Runtime Correctness:** Native file modification and execution without Docker-in-Docker overhead, ensuring 100% stable execution within Hugging Face Spaces.
- **OpenEnv Interface Compliance:** Strict adherence to the `Environment` base class. `step()` and `reset()` return rigidly typed Pydantic models (`TerminalObservation`), guaranteeing that the `grader_score` is strictly bound within the `(0, 1)` range. All early returns and `0.0` fallbacks have been architecturally eliminated.
- **Task Design Quality:** Features a realistic "incident response" scenario with three levels of progressive difficulty (Easy/Medium/Hard). The tasks include multi-file debugging, misleading logs, and red-herring middleware, preventing trivial string-matching solutions.
- **Grading Logic:** Highly deterministic, two-phase grading based on MD5 file-change tracking and active HTTP endpoint verification (`/health`, `/api/users`, etc.). Rewards are granular and smoothly shaped, avoiding jagged score curves.
- **Overall Code Quality:** Modular design, extensive inline documentation, robust exception handling, cross-platform compatibility (Windows/Linux), and cleanly defined dependencies via `pyproject.toml`.
---
## π Reward Shaping
The grader runs **after every command** and awards granular partial credit:
### Phase 1: File-Level Verification
| Event | Points |
|-------|--------|
| Modified `config.json` | +0.05 |
| Modified `routes/users.js` | +0.05 |
| Modified `routes/data.js` | +0.05 |
### Phase 2: HTTP Endpoint Testing
| Milestone | Points |
|-----------|--------|
| App starts on port 3000 | +0.30 |
| `GET /health` returns 200 | +0.10 |
| `GET /api/users` returns valid JSON | +0.15 |
| `GET /api/data` returns valid JSON | +0.20 |
| All endpoints passing (bonus) | +0.05 |
### Phase 3: Difficulty Scaling
Raw scores are scaled by task difficulty so each task can reach near-maximum independently.
> **All scores are strictly within (0, 1)** per the OpenEnv specification β never exactly 0.0 or 1.0.
---
## π Getting Started
### Docker (Recommended)
```bash
docker build -t devops-sandbox:latest .
docker run --rm -p 8000:8000 devops-sandbox:latest
curl http://localhost:8000/health
```
Health response: `{"status":"healthy","service":"devops_sandbox"}`
### Without Docker
```bash
uv sync
uvicorn server.app:app --host 0.0.0.0 --port 8000
```
### Quick Start (Demo)
Update the API key in `scenario_config.json` and run:
```bash
python inference.py
```
---
## π§ͺ Test Your Own Agent
### Option A: Python Client
```python
from client import DevopsSandboxEnv
from models import BashAction
with DevopsSandboxEnv(base_url="http://localhost:8000").sync() as env:
# Reset with task difficulty
result = env.reset(task_name="easy")
print(result.observation.stdout) # Task description
print(result.observation.grader_score) # 0.01
# Send bash commands
result = env.step(BashAction(command="cat /app/config.json"))
print(result.observation.stdout) # File contents
print(result.observation.metadata) # Rich metadata
# Fix a bug
result = env.step(BashAction(command="sed -i 's/9999/3000/' /app/config.json"))
print(result.observation.grader_score) # Score increases
print(result.observation.grader_feedback) # "β Modified config.json (+0.05)"
```
### Option B: REST API
```bash
# Reset the environment
curl -X POST http://localhost:8000/reset -d '{"task_name": "hard"}'
# Send a command
curl -X POST http://localhost:8000/step \
-H "Content-Type: application/json" \
-d '{"action": {"command": "ls -la /app"}}'
```
### Option C: WebSocket
Connect to `ws://localhost:8000/ws` for persistent sessions.
---
## π Project Structure
```
devops_sandbox/
βββ openenv.yaml # OpenEnv manifest (spec_version: 1)
βββ pyproject.toml # Python dependencies
βββ Dockerfile # HF Spaces deployment
βββ scenario_config.json # Task definitions + verifiers
βββ models.py # BashAction & TerminalObservation (Pydantic)
βββ client.py # Python client for the environment
βββ inference.py # LLM baseline agent (3-task evaluation)
β
βββ server/
β βββ app.py # FastAPI server (OpenEnv entry point)
β βββ devops_sandbox_environment.py # Core environment + grader
β
βββ simulated_app/ # The broken Node.js app
βββ package.json
βββ server.js
βββ config.json # Bug 1: wrong port
βββ routes/
βββ users.js # Bug 2: syntax error
βββ data.js # Bug 3: missing await
```
---
## βοΈ Architecture
```
ββββββββββββ BashAction ββββββββββββββ subprocess ββββββββββββββββ
β Agent β ββββββββββββββ> β OpenEnv β ββββββββββββ> β /app/ β
β (LLM/RL) β β Server β β (broken app) β
β β <ββββββββββββββ β (:8000) β <ββββββββββββ β β
ββββββββββββ Observation βββββββ¬βββββββ stdout/stderr ββββββββββββββββ
+ grader_score β
+ metadata βββββββ΄βββββββ
β Grader β
β ββββββββββ β
β βFile Ξ β β β Detects which files were modified
β βChecker β β
β ββββββββββ€ β
β βHTTP β β β Starts app, curls all endpoints
β βTester β β
β ββββββββββ β
ββββββββββββββ
```
1. **Agent** sends a `BashAction` (e.g., `cat /app/config.json`)
2. **Server** executes it via `subprocess.run()` in the `/app` directory
3. **Grader** runs two-phase verification:
- **File tracking**: MD5 hash comparison to detect which bug files changed
- **HTTP testing**: Starts the Node app, curls `/health`, `/api/users`, `/api/data`
4. **Observation** returns: stdout, stderr, score (0.01β0.99), feedback, and metadata
---
## π Observation Metadata
Each observation includes rich metadata for training analysis:
```json
{
"episode_id": "abc-123",
"step": 3,
"task": "hard",
"max_steps": 50,
"bugs_total": 3,
"files_modified": ["config.json", "routes/users.js"],
"commands_count": 3
}
```
---
## π§ Configuration
| Env Variable | Default | Description |
|-------------|---------|-------------|
| `HF_TOKEN` | *(required)* | Hugging Face token for LLM API |
| `MODEL_NAME` | `gpt-4o-mini` | LLM model to use |
| `API_BASE_URL` | `https://router.huggingface.co/v1` | LLM endpoint |
| `MAX_TURNS` | `8` | Max steps per task in inference |
---
## β
Validation
```bash
uv run openenv validate
# Expected: [OK] devops_sandbox: Ready for deployment
```
---
## π License
BSD-style license. See LICENSE for details.
|