Spaces:
Sleeping
Sleeping
Upload folder using huggingface_hub
Browse files- core/validation/parser.py +6 -1
- server/app.py +20 -8
core/validation/parser.py
CHANGED
|
@@ -10,12 +10,13 @@ from typing import Optional
|
|
| 10 |
|
| 11 |
@dataclass
|
| 12 |
class ParsedCommand:
|
| 13 |
-
type: str # "cat" | "echo_append" | "sed" | "pipeline_run" | "pipeline_logs" | "pipeline_status" | "unknown"
|
| 14 |
filename: Optional[str] = None
|
| 15 |
content: Optional[str] = None # for echo >>
|
| 16 |
pattern: Optional[str] = None # for sed: old value
|
| 17 |
replacement: Optional[str] = None # for sed: new value
|
| 18 |
stage: Optional[str] = None
|
|
|
|
| 19 |
|
| 20 |
|
| 21 |
def parse_command(command: str) -> ParsedCommand:
|
|
@@ -61,4 +62,8 @@ def parse_command(command: str) -> ParsedCommand:
|
|
| 61 |
if re.fullmatch(r"pipeline\s+status", command):
|
| 62 |
return ParsedCommand(type="pipeline_status")
|
| 63 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 64 |
return ParsedCommand(type="unknown")
|
|
|
|
| 10 |
|
| 11 |
@dataclass
|
| 12 |
class ParsedCommand:
|
| 13 |
+
type: str # "cat" | "echo_append" | "sed" | "pipeline_run" | "pipeline_logs" | "pipeline_status" | "diagnose" | "unknown"
|
| 14 |
filename: Optional[str] = None
|
| 15 |
content: Optional[str] = None # for echo >>
|
| 16 |
pattern: Optional[str] = None # for sed: old value
|
| 17 |
replacement: Optional[str] = None # for sed: new value
|
| 18 |
stage: Optional[str] = None
|
| 19 |
+
diagnosis: Optional[str] = None # for diagnose: agent's theory about the bug
|
| 20 |
|
| 21 |
|
| 22 |
def parse_command(command: str) -> ParsedCommand:
|
|
|
|
| 62 |
if re.fullmatch(r"pipeline\s+status", command):
|
| 63 |
return ParsedCommand(type="pipeline_status")
|
| 64 |
|
| 65 |
+
m = re.match(r'diagnose\s+([\'"])(.*?)\1\s*$', command, re.DOTALL)
|
| 66 |
+
if m:
|
| 67 |
+
return ParsedCommand(type="diagnose", diagnosis=m.group(2))
|
| 68 |
+
|
| 69 |
return ParsedCommand(type="unknown")
|
server/app.py
CHANGED
|
@@ -8,7 +8,7 @@ served via openenv's create_app() infrastructure.
|
|
| 8 |
try:
|
| 9 |
from openenv.core.env_server.http_server import create_app
|
| 10 |
from openenv.core.env_server.interfaces import Environment
|
| 11 |
-
from openenv.core.env_server.types import Action, Observation, State
|
| 12 |
except Exception as e: # pragma: no cover
|
| 13 |
raise ImportError(
|
| 14 |
"openenv is required for the web interface. Install dependencies with '\n uv sync\n'"
|
|
@@ -23,13 +23,11 @@ from .environment import PipelineEnvironment
|
|
| 23 |
|
| 24 |
from fastapi.responses import PlainTextResponse
|
| 25 |
from pathlib import Path
|
|
|
|
| 26 |
|
| 27 |
-
# OpenEnv-compatible action — wraps the agent's raw command string
|
| 28 |
class CiCdDoctorAction(Action):
|
| 29 |
command: str = Field(..., description="Shell-like command the agent issues")
|
| 30 |
|
| 31 |
-
|
| 32 |
-
# OpenEnv-compatible observation — extends base Observation with pipeline fields
|
| 33 |
class CiCdDoctorObservation(Observation):
|
| 34 |
stdout: str = Field(default="", description="Command output / logs seen by agent")
|
| 35 |
exit_code: int = Field(default=0, description="0 = success, 1 = error")
|
|
@@ -77,9 +75,23 @@ class CiCdDoctorEnvironment(Environment):
|
|
| 77 |
def state(self) -> State:
|
| 78 |
return self._state_obj
|
| 79 |
|
| 80 |
-
def
|
| 81 |
-
|
| 82 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 83 |
|
| 84 |
app = create_app(
|
| 85 |
CiCdDoctorEnvironment,
|
|
@@ -91,7 +103,7 @@ app = create_app(
|
|
| 91 |
|
| 92 |
@app.get("/instructions", response_class=PlainTextResponse)
|
| 93 |
def instructions():
|
| 94 |
-
return
|
| 95 |
|
| 96 |
def main():
|
| 97 |
import uvicorn
|
|
|
|
| 8 |
try:
|
| 9 |
from openenv.core.env_server.http_server import create_app
|
| 10 |
from openenv.core.env_server.interfaces import Environment
|
| 11 |
+
from openenv.core.env_server.types import Action, Observation, State, EnvironmentMetadata
|
| 12 |
except Exception as e: # pragma: no cover
|
| 13 |
raise ImportError(
|
| 14 |
"openenv is required for the web interface. Install dependencies with '\n uv sync\n'"
|
|
|
|
| 23 |
|
| 24 |
from fastapi.responses import PlainTextResponse
|
| 25 |
from pathlib import Path
|
| 26 |
+
import os
|
| 27 |
|
|
|
|
| 28 |
class CiCdDoctorAction(Action):
|
| 29 |
command: str = Field(..., description="Shell-like command the agent issues")
|
| 30 |
|
|
|
|
|
|
|
| 31 |
class CiCdDoctorObservation(Observation):
|
| 32 |
stdout: str = Field(default="", description="Command output / logs seen by agent")
|
| 33 |
exit_code: int = Field(default=0, description="0 = success, 1 = error")
|
|
|
|
| 75 |
def state(self) -> State:
|
| 76 |
return self._state_obj
|
| 77 |
|
| 78 |
+
def get_metadata(self) -> EnvironmentMetadata:
|
| 79 |
+
return EnvironmentMetadata(
|
| 80 |
+
name="CI_CD_Doctor",
|
| 81 |
+
description="An interactive environment where agents diagnose and fix broken CI/CD pipelines.",
|
| 82 |
+
version="1.0.0",
|
| 83 |
+
readme_content=_load_readme() or None,
|
| 84 |
+
)
|
| 85 |
+
|
| 86 |
+
_README_DIR = Path(__file__).resolve().parent.parent / "docs"
|
| 87 |
+
_README_PATH = _README_DIR / "README.md"
|
| 88 |
+
|
| 89 |
+
if _README_PATH.exists() and not os.environ.get("ENV_README_PATH"):
|
| 90 |
+
os.environ["ENV_README_PATH"] = str(_README_PATH)
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
def _load_readme() -> str:
|
| 94 |
+
return _README_PATH.read_text() if _README_PATH.exists() else ""
|
| 95 |
|
| 96 |
app = create_app(
|
| 97 |
CiCdDoctorEnvironment,
|
|
|
|
| 103 |
|
| 104 |
@app.get("/instructions", response_class=PlainTextResponse)
|
| 105 |
def instructions():
|
| 106 |
+
return _load_readme()
|
| 107 |
|
| 108 |
def main():
|
| 109 |
import uvicorn
|