Spaces:
Sleeping
Sleeping
databoysu commited on
Commit ·
9882200
1
Parent(s): 100d601
SWE-Gym v1
Browse files- Dockerfile +9 -10
- README.md +53 -17
- __init__.py +3 -2
- client.py +9 -5
- inference.py +11 -7
- models.py +1 -1
- openenv.yaml +1 -1
- openenv_python_debugging_gym.egg-info/PKG-INFO +0 -11
- openenv_python_debugging_gym.egg-info/SOURCES.txt +0 -19
- openenv_python_debugging_gym.egg-info/dependency_links.txt +0 -1
- openenv_python_debugging_gym.egg-info/entry_points.txt +0 -2
- openenv_python_debugging_gym.egg-info/requires.txt +0 -7
- openenv_python_debugging_gym.egg-info/top_level.txt +0 -1
- pyproject.toml +6 -6
- server/Dockerfile +0 -79
- server/__init__.py +3 -3
- server/app.py +5 -5
- server/requirements.txt +0 -7
- server/{my_env_environment.py → swe_gym_environment.py} +2 -2
Dockerfile
CHANGED
|
@@ -23,18 +23,10 @@ RUN if ! command -v uv >/dev/null 2>&1; then \
|
|
| 23 |
fi
|
| 24 |
|
| 25 |
RUN --mount=type=cache,target=/root/.cache/uv \
|
| 26 |
-
|
| 27 |
-
uv sync --frozen --no-install-project --no-editable; \
|
| 28 |
-
else \
|
| 29 |
-
uv sync --no-install-project --no-editable; \
|
| 30 |
-
fi
|
| 31 |
|
| 32 |
RUN --mount=type=cache,target=/root/.cache/uv \
|
| 33 |
-
|
| 34 |
-
uv sync --frozen --no-editable; \
|
| 35 |
-
else \
|
| 36 |
-
uv sync --no-editable; \
|
| 37 |
-
fi
|
| 38 |
|
| 39 |
FROM ${BASE_IMAGE}
|
| 40 |
|
|
@@ -43,10 +35,17 @@ WORKDIR /app
|
|
| 43 |
COPY --from=builder /app/env/.venv /app/.venv
|
| 44 |
COPY --from=builder /app/env /app/env
|
| 45 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 46 |
ENV PATH="/app/.venv/bin:$PATH"
|
| 47 |
ENV PYTHONPATH="/app/env:$PYTHONPATH"
|
| 48 |
|
| 49 |
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
| 50 |
CMD curl -f http://localhost:7860/health || exit 1
|
| 51 |
|
|
|
|
|
|
|
| 52 |
CMD ["sh", "-c", "cd /app/env && uvicorn server.app:app --host 0.0.0.0 --port 7860"]
|
|
|
|
| 23 |
fi
|
| 24 |
|
| 25 |
RUN --mount=type=cache,target=/root/.cache/uv \
|
| 26 |
+
uv sync --no-install-project --no-editable
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
|
| 28 |
RUN --mount=type=cache,target=/root/.cache/uv \
|
| 29 |
+
uv sync --no-editable
|
|
|
|
|
|
|
|
|
|
|
|
|
| 30 |
|
| 31 |
FROM ${BASE_IMAGE}
|
| 32 |
|
|
|
|
| 35 |
COPY --from=builder /app/env/.venv /app/.venv
|
| 36 |
COPY --from=builder /app/env /app/env
|
| 37 |
|
| 38 |
+
# Ported from RL_ENV Dockerfile hardening:
|
| 39 |
+
# run the HF Space as uid 1000 rather than root.
|
| 40 |
+
RUN useradd -m -u 1000 appuser && \
|
| 41 |
+
chown -R appuser:appuser /app
|
| 42 |
+
|
| 43 |
ENV PATH="/app/.venv/bin:$PATH"
|
| 44 |
ENV PYTHONPATH="/app/env:$PYTHONPATH"
|
| 45 |
|
| 46 |
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
| 47 |
CMD curl -f http://localhost:7860/health || exit 1
|
| 48 |
|
| 49 |
+
USER appuser
|
| 50 |
+
|
| 51 |
CMD ["sh", "-c", "cd /app/env && uvicorn server.app:app --host 0.0.0.0 --port 7860"]
|
README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
-
emoji:
|
| 4 |
colorFrom: blue
|
| 5 |
colorTo: cyan
|
| 6 |
sdk: docker
|
|
@@ -10,27 +10,40 @@ base_path: /web
|
|
| 10 |
tags:
|
| 11 |
- openenv
|
| 12 |
- reinforcement-learning
|
| 13 |
-
-
|
| 14 |
---
|
| 15 |
|
| 16 |
-
#
|
| 17 |
|
| 18 |
-
|
| 19 |
-
|
|
|
|
| 20 |
|
| 21 |
-
##
|
| 22 |
|
| 23 |
- Action space:
|
| 24 |
`VIEW_CODE`, `RUN_TESTS`, `REPLACE_LINES`, `UNDO_EDIT`, `RESET_TO_ORIGINAL`, `SUBMIT`
|
| 25 |
-
- Observation includes
|
| 26 |
-
|
| 27 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 28 |
|
| 29 |
## Local Run
|
| 30 |
|
| 31 |
```bash
|
| 32 |
uv sync
|
| 33 |
-
uv run --project . server
|
| 34 |
```
|
| 35 |
|
| 36 |
Server endpoints:
|
|
@@ -38,18 +51,41 @@ Server endpoints:
|
|
| 38 |
- `POST /step`
|
| 39 |
- `GET /health`
|
| 40 |
- `WS /ws`
|
| 41 |
-
- `GET /web`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
|
| 43 |
-
##
|
|
|
|
|
|
|
| 44 |
|
| 45 |
```bash
|
| 46 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
```
|
| 48 |
|
| 49 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
|
| 51 |
-
|
| 52 |
|
| 53 |
```bash
|
| 54 |
-
./pre-val.sh https://<your-space>.hf.space .
|
| 55 |
```
|
|
|
|
| 1 |
---
|
| 2 |
+
title: SWE-Gym - Software Engineer Gym
|
| 3 |
+
emoji: 🧑💻
|
| 4 |
colorFrom: blue
|
| 5 |
colorTo: cyan
|
| 6 |
sdk: docker
|
|
|
|
| 10 |
tags:
|
| 11 |
- openenv
|
| 12 |
- reinforcement-learning
|
| 13 |
+
- software-engineering
|
| 14 |
---
|
| 15 |
|
| 16 |
+
# SWE-Gym - Software Engineer Gym
|
| 17 |
|
| 18 |
+
SWE-Gym is an OpenEnv-compatible RL environment where an agent must debug broken
|
| 19 |
+
Python code by iteratively inspecting source, running tests, editing lines, and
|
| 20 |
+
submitting once all tests pass.
|
| 21 |
|
| 22 |
+
## Core Design
|
| 23 |
|
| 24 |
- Action space:
|
| 25 |
`VIEW_CODE`, `RUN_TESTS`, `REPLACE_LINES`, `UNDO_EDIT`, `RESET_TO_ORIGINAL`, `SUBMIT`
|
| 26 |
+
- Observation includes full code, localized edit context, execution output, syntax status, and per-test outcomes.
|
| 27 |
+
- Dense rewards:
|
| 28 |
+
`RUN_TESTS` bonus, per-test progress bonus, step-cost penalty, invalid-edit penalties, and final clamped score in `[0, 1]`.
|
| 29 |
+
- Curriculum-ready task sampling:
|
| 30 |
+
easy/medium/hard buckets with safe random fallback for evaluator runs.
|
| 31 |
+
|
| 32 |
+
## Environment Files
|
| 33 |
+
|
| 34 |
+
- `models.py`: action/observation schemas
|
| 35 |
+
- `tasks.py`: static curated task registry
|
| 36 |
+
- `sandbox.py`: isolated timed execution
|
| 37 |
+
- `environment.py`: reset/step/reward logic
|
| 38 |
+
- `context.py`: localized code windowing
|
| 39 |
+
- `server/app.py`: FastAPI OpenEnv server entry
|
| 40 |
+
- `inference.py`: baseline OpenAI-client inference script
|
| 41 |
|
| 42 |
## Local Run
|
| 43 |
|
| 44 |
```bash
|
| 45 |
uv sync
|
| 46 |
+
uv run --project . server
|
| 47 |
```
|
| 48 |
|
| 49 |
Server endpoints:
|
|
|
|
| 51 |
- `POST /step`
|
| 52 |
- `GET /health`
|
| 53 |
- `WS /ws`
|
| 54 |
+
- `GET /web`
|
| 55 |
+
|
| 56 |
+
## Inference Script Compliance
|
| 57 |
+
|
| 58 |
+
- Script location/name: `inference.py` at repo root.
|
| 59 |
+
- Uses OpenAI client with:
|
| 60 |
+
`API_BASE_URL`, `MODEL_NAME`, `HF_TOKEN`.
|
| 61 |
+
- Supports local container mode with:
|
| 62 |
+
`LOCAL_IMAGE_NAME`.
|
| 63 |
+
- Emits standardized stdout lines in this order:
|
| 64 |
+
`[START]`, one or more `[STEP]`, then `[END]`.
|
| 65 |
+
- Final score is clamped to `[0, 1]`.
|
| 66 |
|
| 67 |
+
## Docker + Deployment
|
| 68 |
+
|
| 69 |
+
Build locally:
|
| 70 |
|
| 71 |
```bash
|
| 72 |
+
docker build -t swe-gym:test -f Dockerfile .
|
| 73 |
+
```
|
| 74 |
+
|
| 75 |
+
Run locally:
|
| 76 |
+
|
| 77 |
+
```bash
|
| 78 |
+
docker run --rm -p 7860:7860 swe-gym:test
|
| 79 |
```
|
| 80 |
|
| 81 |
+
Deploy to Hugging Face:
|
| 82 |
+
|
| 83 |
+
```bash
|
| 84 |
+
openenv push
|
| 85 |
+
```
|
| 86 |
|
| 87 |
+
Validate before submit:
|
| 88 |
|
| 89 |
```bash
|
| 90 |
+
bash ./pre-val.sh https://<your-space>.hf.space .
|
| 91 |
```
|
__init__.py
CHANGED
|
@@ -4,14 +4,15 @@
|
|
| 4 |
# This source code is licensed under the BSD-style license found in the
|
| 5 |
# LICENSE file in the root directory of this source tree.
|
| 6 |
|
| 7 |
-
"""
|
| 8 |
|
| 9 |
-
from .client import MyEnv
|
| 10 |
from .models import CodeAction, CodeObservation, TestResult
|
| 11 |
|
| 12 |
__all__ = [
|
| 13 |
"CodeAction",
|
| 14 |
"CodeObservation",
|
| 15 |
"TestResult",
|
|
|
|
| 16 |
"MyEnv",
|
| 17 |
]
|
|
|
|
| 4 |
# This source code is licensed under the BSD-style license found in the
|
| 5 |
# LICENSE file in the root directory of this source tree.
|
| 6 |
|
| 7 |
+
"""SWE-Gym OpenEnv package."""
|
| 8 |
|
| 9 |
+
from .client import MyEnv, SWEGymEnv
|
| 10 |
from .models import CodeAction, CodeObservation, TestResult
|
| 11 |
|
| 12 |
__all__ = [
|
| 13 |
"CodeAction",
|
| 14 |
"CodeObservation",
|
| 15 |
"TestResult",
|
| 16 |
+
"SWEGymEnv",
|
| 17 |
"MyEnv",
|
| 18 |
]
|
client.py
CHANGED
|
@@ -4,7 +4,7 @@
|
|
| 4 |
# This source code is licensed under the BSD-style license found in the
|
| 5 |
# LICENSE file in the root directory of this source tree.
|
| 6 |
|
| 7 |
-
"""Client for the
|
| 8 |
|
| 9 |
from typing import Dict
|
| 10 |
|
|
@@ -18,11 +18,11 @@ except ImportError:
|
|
| 18 |
from models import CodeAction, CodeObservation, TestResult
|
| 19 |
|
| 20 |
|
| 21 |
-
class
|
| 22 |
EnvClient[CodeAction, CodeObservation, State]
|
| 23 |
):
|
| 24 |
"""
|
| 25 |
-
Client for the
|
| 26 |
|
| 27 |
This client maintains a persistent WebSocket connection to the environment server,
|
| 28 |
enabling efficient multi-step interactions with lower latency.
|
|
@@ -30,7 +30,7 @@ class MyEnv(
|
|
| 30 |
|
| 31 |
Example:
|
| 32 |
>>> # Connect to a running server
|
| 33 |
-
>>> with
|
| 34 |
... result = client.reset()
|
| 35 |
... print(result.observation.echoed_message)
|
| 36 |
...
|
|
@@ -39,7 +39,7 @@ class MyEnv(
|
|
| 39 |
|
| 40 |
Example with Docker:
|
| 41 |
>>> # Automatically start container and connect
|
| 42 |
-
>>> client =
|
| 43 |
>>> try:
|
| 44 |
... result = client.reset()
|
| 45 |
... result = client.step(MyAction(message="Test"))
|
|
@@ -107,3 +107,7 @@ class MyEnv(
|
|
| 107 |
episode_id=payload.get("episode_id"),
|
| 108 |
step_count=payload.get("step_count", 0),
|
| 109 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
# This source code is licensed under the BSD-style license found in the
|
| 5 |
# LICENSE file in the root directory of this source tree.
|
| 6 |
|
| 7 |
+
"""Client for the SWE-Gym OpenEnv environment."""
|
| 8 |
|
| 9 |
from typing import Dict
|
| 10 |
|
|
|
|
| 18 |
from models import CodeAction, CodeObservation, TestResult
|
| 19 |
|
| 20 |
|
| 21 |
+
class SWEGymEnv(
|
| 22 |
EnvClient[CodeAction, CodeObservation, State]
|
| 23 |
):
|
| 24 |
"""
|
| 25 |
+
Client for the SWE-Gym environment.
|
| 26 |
|
| 27 |
This client maintains a persistent WebSocket connection to the environment server,
|
| 28 |
enabling efficient multi-step interactions with lower latency.
|
|
|
|
| 30 |
|
| 31 |
Example:
|
| 32 |
>>> # Connect to a running server
|
| 33 |
+
>>> with SWEGymEnv(base_url="http://localhost:7860") as client:
|
| 34 |
... result = client.reset()
|
| 35 |
... print(result.observation.echoed_message)
|
| 36 |
...
|
|
|
|
| 39 |
|
| 40 |
Example with Docker:
|
| 41 |
>>> # Automatically start container and connect
|
| 42 |
+
>>> client = SWEGymEnv.from_docker_image("swe-gym:latest")
|
| 43 |
>>> try:
|
| 44 |
... result = client.reset()
|
| 45 |
... result = client.step(MyAction(message="Test"))
|
|
|
|
| 107 |
episode_id=payload.get("episode_id"),
|
| 108 |
step_count=payload.get("step_count", 0),
|
| 109 |
)
|
| 110 |
+
|
| 111 |
+
|
| 112 |
+
# Backward-compatible alias for older code paths.
|
| 113 |
+
MyEnv = SWEGymEnv
|
inference.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
"""
|
| 2 |
-
Inference script for
|
| 3 |
|
| 4 |
Mandatory env vars expected in deployment config:
|
| 5 |
API_BASE_URL
|
|
@@ -23,7 +23,11 @@ from typing import Any
|
|
| 23 |
|
| 24 |
from openai import OpenAI
|
| 25 |
|
| 26 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
|
| 28 |
|
| 29 |
API_BASE_URL = os.getenv("API_BASE_URL", "https://router.huggingface.co/v1")
|
|
@@ -32,8 +36,8 @@ HF_TOKEN = os.getenv("HF_TOKEN", "")
|
|
| 32 |
LOCAL_IMAGE_NAME = os.getenv("LOCAL_IMAGE_NAME", "")
|
| 33 |
|
| 34 |
ENV_BASE_URL = os.getenv("ENV_BASE_URL", "http://localhost:7860")
|
| 35 |
-
TASK_NAME = os.getenv("TASK_NAME", "
|
| 36 |
-
BENCHMARK = os.getenv("BENCHMARK", "
|
| 37 |
MAX_STEPS = int(os.getenv("MAX_STEPS", "50"))
|
| 38 |
SUCCESS_SCORE_THRESHOLD = float(os.getenv("SUCCESS_SCORE_THRESHOLD", "0.99"))
|
| 39 |
|
|
@@ -166,7 +170,7 @@ def _compute_score(step_result: Any, rewards: list[float]) -> float:
|
|
| 166 |
async def main() -> None:
|
| 167 |
client = OpenAI(base_url=API_BASE_URL, api_key=HF_TOKEN)
|
| 168 |
|
| 169 |
-
env:
|
| 170 |
rewards: list[float] = []
|
| 171 |
history: list[str] = []
|
| 172 |
steps_taken = 0
|
|
@@ -176,9 +180,9 @@ async def main() -> None:
|
|
| 176 |
|
| 177 |
try:
|
| 178 |
if LOCAL_IMAGE_NAME:
|
| 179 |
-
env = await
|
| 180 |
else:
|
| 181 |
-
env =
|
| 182 |
|
| 183 |
result = await env.reset()
|
| 184 |
task_name = result.observation.info.get("task_name") or TASK_NAME
|
|
|
|
| 1 |
"""
|
| 2 |
+
Inference script for SWE-Gym - Software Engineer Gym.
|
| 3 |
|
| 4 |
Mandatory env vars expected in deployment config:
|
| 5 |
API_BASE_URL
|
|
|
|
| 23 |
|
| 24 |
from openai import OpenAI
|
| 25 |
|
| 26 |
+
try:
|
| 27 |
+
from swe_gym import CodeAction, SWEGymEnv
|
| 28 |
+
except ImportError:
|
| 29 |
+
from client import SWEGymEnv
|
| 30 |
+
from models import CodeAction
|
| 31 |
|
| 32 |
|
| 33 |
API_BASE_URL = os.getenv("API_BASE_URL", "https://router.huggingface.co/v1")
|
|
|
|
| 36 |
LOCAL_IMAGE_NAME = os.getenv("LOCAL_IMAGE_NAME", "")
|
| 37 |
|
| 38 |
ENV_BASE_URL = os.getenv("ENV_BASE_URL", "http://localhost:7860")
|
| 39 |
+
TASK_NAME = os.getenv("TASK_NAME", "swe_gym")
|
| 40 |
+
BENCHMARK = os.getenv("BENCHMARK", "swe_gym")
|
| 41 |
MAX_STEPS = int(os.getenv("MAX_STEPS", "50"))
|
| 42 |
SUCCESS_SCORE_THRESHOLD = float(os.getenv("SUCCESS_SCORE_THRESHOLD", "0.99"))
|
| 43 |
|
|
|
|
| 170 |
async def main() -> None:
|
| 171 |
client = OpenAI(base_url=API_BASE_URL, api_key=HF_TOKEN)
|
| 172 |
|
| 173 |
+
env: SWEGymEnv | None = None
|
| 174 |
rewards: list[float] = []
|
| 175 |
history: list[str] = []
|
| 176 |
steps_taken = 0
|
|
|
|
| 180 |
|
| 181 |
try:
|
| 182 |
if LOCAL_IMAGE_NAME:
|
| 183 |
+
env = await SWEGymEnv.from_docker_image(LOCAL_IMAGE_NAME)
|
| 184 |
else:
|
| 185 |
+
env = SWEGymEnv(base_url=ENV_BASE_URL)
|
| 186 |
|
| 187 |
result = await env.reset()
|
| 188 |
task_name = result.observation.info.get("task_name") or TASK_NAME
|
models.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
"""Pydantic schema layer for
|
| 2 |
|
| 3 |
from __future__ import annotations
|
| 4 |
|
|
|
|
| 1 |
+
"""Pydantic schema layer for SWE-Gym - Software Engineer Gym."""
|
| 2 |
|
| 3 |
from __future__ import annotations
|
| 4 |
|
openenv.yaml
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
spec_version: 1
|
| 2 |
-
name:
|
| 3 |
type: space
|
| 4 |
runtime: fastapi
|
| 5 |
app: server.app:app
|
|
|
|
| 1 |
spec_version: 1
|
| 2 |
+
name: swe_gym
|
| 3 |
type: space
|
| 4 |
runtime: fastapi
|
| 5 |
app: server.app:app
|
openenv_python_debugging_gym.egg-info/PKG-INFO
DELETED
|
@@ -1,11 +0,0 @@
|
|
| 1 |
-
Metadata-Version: 2.4
|
| 2 |
-
Name: openenv-python-debugging-gym
|
| 3 |
-
Version: 0.1.0
|
| 4 |
-
Summary: Python Debugging Gym environment for OpenEnv
|
| 5 |
-
Requires-Python: >=3.10
|
| 6 |
-
Requires-Dist: openenv-core[core]>=0.2.2
|
| 7 |
-
Requires-Dist: openai>=1.30.0
|
| 8 |
-
Requires-Dist: websockets>=12.0
|
| 9 |
-
Provides-Extra: dev
|
| 10 |
-
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
| 11 |
-
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openenv_python_debugging_gym.egg-info/SOURCES.txt
DELETED
|
@@ -1,19 +0,0 @@
|
|
| 1 |
-
README.md
|
| 2 |
-
pyproject.toml
|
| 3 |
-
./__init__.py
|
| 4 |
-
./client.py
|
| 5 |
-
./context.py
|
| 6 |
-
./environment.py
|
| 7 |
-
./inference.py
|
| 8 |
-
./models.py
|
| 9 |
-
./sandbox.py
|
| 10 |
-
./tasks.py
|
| 11 |
-
openenv_python_debugging_gym.egg-info/PKG-INFO
|
| 12 |
-
openenv_python_debugging_gym.egg-info/SOURCES.txt
|
| 13 |
-
openenv_python_debugging_gym.egg-info/dependency_links.txt
|
| 14 |
-
openenv_python_debugging_gym.egg-info/entry_points.txt
|
| 15 |
-
openenv_python_debugging_gym.egg-info/requires.txt
|
| 16 |
-
openenv_python_debugging_gym.egg-info/top_level.txt
|
| 17 |
-
server/__init__.py
|
| 18 |
-
server/app.py
|
| 19 |
-
server/my_env_environment.py
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openenv_python_debugging_gym.egg-info/dependency_links.txt
DELETED
|
@@ -1 +0,0 @@
|
|
| 1 |
-
|
|
|
|
|
|
openenv_python_debugging_gym.egg-info/entry_points.txt
DELETED
|
@@ -1,2 +0,0 @@
|
|
| 1 |
-
[console_scripts]
|
| 2 |
-
server = my_env.server.app:main
|
|
|
|
|
|
|
|
|
openenv_python_debugging_gym.egg-info/requires.txt
DELETED
|
@@ -1,7 +0,0 @@
|
|
| 1 |
-
openenv-core[core]>=0.2.2
|
| 2 |
-
openai>=1.30.0
|
| 3 |
-
websockets>=12.0
|
| 4 |
-
|
| 5 |
-
[dev]
|
| 6 |
-
pytest>=8.0.0
|
| 7 |
-
pytest-cov>=4.0.0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openenv_python_debugging_gym.egg-info/top_level.txt
DELETED
|
@@ -1 +0,0 @@
|
|
| 1 |
-
my_env
|
|
|
|
|
|
pyproject.toml
CHANGED
|
@@ -9,9 +9,9 @@ requires = ["setuptools>=45", "wheel"]
|
|
| 9 |
build-backend = "setuptools.build_meta"
|
| 10 |
|
| 11 |
[project]
|
| 12 |
-
name = "openenv-
|
| 13 |
version = "0.1.0"
|
| 14 |
-
description = "
|
| 15 |
requires-python = ">=3.10"
|
| 16 |
dependencies = [
|
| 17 |
# Core OpenEnv runtime (provides FastAPI server + HTTP client types)
|
|
@@ -38,10 +38,10 @@ dev = [
|
|
| 38 |
|
| 39 |
[project.scripts]
|
| 40 |
# Server entry point - enables running via: uv run --project . server
|
| 41 |
-
# or: python -m
|
| 42 |
-
server = "
|
| 43 |
|
| 44 |
[tool.setuptools]
|
| 45 |
include-package-data = true
|
| 46 |
-
packages = ["
|
| 47 |
-
package-dir = { "
|
|
|
|
| 9 |
build-backend = "setuptools.build_meta"
|
| 10 |
|
| 11 |
[project]
|
| 12 |
+
name = "openenv-swe-gym"
|
| 13 |
version = "0.1.0"
|
| 14 |
+
description = "SWE-Gym - Software Engineer Gym environment for OpenEnv"
|
| 15 |
requires-python = ">=3.10"
|
| 16 |
dependencies = [
|
| 17 |
# Core OpenEnv runtime (provides FastAPI server + HTTP client types)
|
|
|
|
| 38 |
|
| 39 |
[project.scripts]
|
| 40 |
# Server entry point - enables running via: uv run --project . server
|
| 41 |
+
# or: python -m swe_gym.server.app
|
| 42 |
+
server = "swe_gym.server.app:main"
|
| 43 |
|
| 44 |
[tool.setuptools]
|
| 45 |
include-package-data = true
|
| 46 |
+
packages = ["swe_gym", "swe_gym.server"]
|
| 47 |
+
package-dir = { "swe_gym" = ".", "swe_gym.server" = "server" }
|
server/Dockerfile
DELETED
|
@@ -1,79 +0,0 @@
|
|
| 1 |
-
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
| 2 |
-
# All rights reserved.
|
| 3 |
-
#
|
| 4 |
-
# This source code is licensed under the BSD-style license found in the
|
| 5 |
-
# LICENSE file in the root directory of this source tree.
|
| 6 |
-
|
| 7 |
-
# Multi-stage build using openenv-base
|
| 8 |
-
# This Dockerfile is flexible and works for both:
|
| 9 |
-
# - In-repo environments (with local OpenEnv sources)
|
| 10 |
-
# - Standalone environments (with openenv from PyPI/Git)
|
| 11 |
-
# The build script (openenv build) handles context detection and sets appropriate build args.
|
| 12 |
-
|
| 13 |
-
ARG BASE_IMAGE=ghcr.io/meta-pytorch/openenv-base:latest
|
| 14 |
-
FROM ${BASE_IMAGE} AS builder
|
| 15 |
-
|
| 16 |
-
WORKDIR /app
|
| 17 |
-
|
| 18 |
-
# Ensure git is available (required for installing dependencies from VCS)
|
| 19 |
-
RUN apt-get update && \
|
| 20 |
-
apt-get install -y --no-install-recommends git && \
|
| 21 |
-
rm -rf /var/lib/apt/lists/*
|
| 22 |
-
|
| 23 |
-
# Build argument to control whether we're building standalone or in-repo
|
| 24 |
-
ARG BUILD_MODE=standalone
|
| 25 |
-
|
| 26 |
-
# Copy environment code (always at root of build context)
|
| 27 |
-
COPY . /app/env
|
| 28 |
-
|
| 29 |
-
# For in-repo builds, openenv is already vendored in the build context
|
| 30 |
-
# For standalone builds, openenv will be installed via pyproject.toml
|
| 31 |
-
WORKDIR /app/env
|
| 32 |
-
|
| 33 |
-
# Ensure uv is available (for local builds where base image lacks it)
|
| 34 |
-
RUN if ! command -v uv >/dev/null 2>&1; then \
|
| 35 |
-
curl -LsSf https://astral.sh/uv/install.sh | sh && \
|
| 36 |
-
mv /root/.local/bin/uv /usr/local/bin/uv && \
|
| 37 |
-
mv /root/.local/bin/uvx /usr/local/bin/uvx; \
|
| 38 |
-
fi
|
| 39 |
-
|
| 40 |
-
# Install dependencies using uv sync
|
| 41 |
-
# If uv.lock exists, use it; otherwise resolve on the fly
|
| 42 |
-
RUN --mount=type=cache,target=/root/.cache/uv \
|
| 43 |
-
if [ -f uv.lock ]; then \
|
| 44 |
-
uv sync --frozen --no-install-project --no-editable; \
|
| 45 |
-
else \
|
| 46 |
-
uv sync --no-install-project --no-editable; \
|
| 47 |
-
fi
|
| 48 |
-
|
| 49 |
-
RUN --mount=type=cache,target=/root/.cache/uv \
|
| 50 |
-
if [ -f uv.lock ]; then \
|
| 51 |
-
uv sync --frozen --no-editable; \
|
| 52 |
-
else \
|
| 53 |
-
uv sync --no-editable; \
|
| 54 |
-
fi
|
| 55 |
-
|
| 56 |
-
# Final runtime stage
|
| 57 |
-
FROM ${BASE_IMAGE}
|
| 58 |
-
|
| 59 |
-
WORKDIR /app
|
| 60 |
-
|
| 61 |
-
# Copy the virtual environment from builder
|
| 62 |
-
COPY --from=builder /app/env/.venv /app/.venv
|
| 63 |
-
|
| 64 |
-
# Copy the environment code
|
| 65 |
-
COPY --from=builder /app/env /app/env
|
| 66 |
-
|
| 67 |
-
# Set PATH to use the virtual environment
|
| 68 |
-
ENV PATH="/app/.venv/bin:$PATH"
|
| 69 |
-
|
| 70 |
-
# Set PYTHONPATH so imports work correctly
|
| 71 |
-
ENV PYTHONPATH="/app/env:$PYTHONPATH"
|
| 72 |
-
|
| 73 |
-
# Health check
|
| 74 |
-
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
| 75 |
-
CMD curl -f http://localhost:7860/health || exit 1
|
| 76 |
-
|
| 77 |
-
# Run the FastAPI server
|
| 78 |
-
# The module path is constructed to work with the /app/env structure
|
| 79 |
-
CMD ["sh", "-c", "cd /app/env && uvicorn server.app:app --host 0.0.0.0 --port 7860"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
server/__init__.py
CHANGED
|
@@ -4,8 +4,8 @@
|
|
| 4 |
# This source code is licensed under the BSD-style license found in the
|
| 5 |
# LICENSE file in the root directory of this source tree.
|
| 6 |
|
| 7 |
-
"""
|
| 8 |
|
| 9 |
-
from .
|
| 10 |
|
| 11 |
-
__all__ = ["
|
|
|
|
| 4 |
# This source code is licensed under the BSD-style license found in the
|
| 5 |
# LICENSE file in the root directory of this source tree.
|
| 6 |
|
| 7 |
+
"""SWE-Gym server components."""
|
| 8 |
|
| 9 |
+
from .swe_gym_environment import SWEGymEnvironment
|
| 10 |
|
| 11 |
+
__all__ = ["SWEGymEnvironment"]
|
server/app.py
CHANGED
|
@@ -4,7 +4,7 @@
|
|
| 4 |
# This source code is licensed under the BSD-style license found in the
|
| 5 |
# LICENSE file in the root directory of this source tree.
|
| 6 |
|
| 7 |
-
"""FastAPI entry point for
|
| 8 |
|
| 9 |
try:
|
| 10 |
from openenv.core.env_server.http_server import create_app
|
|
@@ -15,22 +15,22 @@ except Exception as e: # pragma: no cover
|
|
| 15 |
|
| 16 |
try:
|
| 17 |
from ..models import CodeAction, CodeObservation
|
| 18 |
-
from .
|
| 19 |
except ImportError:
|
| 20 |
import sys
|
| 21 |
from pathlib import Path
|
| 22 |
|
| 23 |
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
| 24 |
from models import CodeAction, CodeObservation
|
| 25 |
-
from server.
|
| 26 |
|
| 27 |
|
| 28 |
# Create the app with web interface and README integration
|
| 29 |
app = create_app(
|
| 30 |
-
|
| 31 |
CodeAction,
|
| 32 |
CodeObservation,
|
| 33 |
-
env_name="
|
| 34 |
max_concurrent_envs=1, # increase this number to allow more concurrent WebSocket sessions
|
| 35 |
)
|
| 36 |
|
|
|
|
| 4 |
# This source code is licensed under the BSD-style license found in the
|
| 5 |
# LICENSE file in the root directory of this source tree.
|
| 6 |
|
| 7 |
+
"""FastAPI entry point for SWE-Gym - Software Engineer Gym."""
|
| 8 |
|
| 9 |
try:
|
| 10 |
from openenv.core.env_server.http_server import create_app
|
|
|
|
| 15 |
|
| 16 |
try:
|
| 17 |
from ..models import CodeAction, CodeObservation
|
| 18 |
+
from .swe_gym_environment import SWEGymEnvironment
|
| 19 |
except ImportError:
|
| 20 |
import sys
|
| 21 |
from pathlib import Path
|
| 22 |
|
| 23 |
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
| 24 |
from models import CodeAction, CodeObservation
|
| 25 |
+
from server.swe_gym_environment import SWEGymEnvironment
|
| 26 |
|
| 27 |
|
| 28 |
# Create the app with web interface and README integration
|
| 29 |
app = create_app(
|
| 30 |
+
SWEGymEnvironment,
|
| 31 |
CodeAction,
|
| 32 |
CodeObservation,
|
| 33 |
+
env_name="swe_gym",
|
| 34 |
max_concurrent_envs=1, # increase this number to allow more concurrent WebSocket sessions
|
| 35 |
)
|
| 36 |
|
server/requirements.txt
DELETED
|
@@ -1,7 +0,0 @@
|
|
| 1 |
-
openenv[core]>=0.2.0
|
| 2 |
-
fastapi>=0.115.0
|
| 3 |
-
uvicorn>=0.24.0
|
| 4 |
-
openai>=1.30.0
|
| 5 |
-
websockets>=12.0
|
| 6 |
-
|
| 7 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
server/{my_env_environment.py → swe_gym_environment.py}
RENAMED
|
@@ -4,7 +4,7 @@
|
|
| 4 |
# This source code is licensed under the BSD-style license found in the
|
| 5 |
# LICENSE file in the root directory of this source tree.
|
| 6 |
|
| 7 |
-
"""OpenEnv adapter around the
|
| 8 |
|
| 9 |
from openenv.core.env_server.interfaces import Environment
|
| 10 |
from openenv.core.env_server.types import State
|
|
@@ -17,7 +17,7 @@ except ImportError:
|
|
| 17 |
from models import CodeAction, CodeObservation
|
| 18 |
|
| 19 |
|
| 20 |
-
class
|
| 21 |
"""Environment implementation compatible with OpenEnv's server interface."""
|
| 22 |
|
| 23 |
# Enable concurrent WebSocket sessions.
|
|
|
|
| 4 |
# This source code is licensed under the BSD-style license found in the
|
| 5 |
# LICENSE file in the root directory of this source tree.
|
| 6 |
|
| 7 |
+
"""OpenEnv adapter around the SWE-Gym core environment."""
|
| 8 |
|
| 9 |
from openenv.core.env_server.interfaces import Environment
|
| 10 |
from openenv.core.env_server.types import State
|
|
|
|
| 17 |
from models import CodeAction, CodeObservation
|
| 18 |
|
| 19 |
|
| 20 |
+
class SWEGymEnvironment(Environment):
|
| 21 |
"""Environment implementation compatible with OpenEnv's server interface."""
|
| 22 |
|
| 23 |
# Enable concurrent WebSocket sessions.
|