RAHUL-13/bug-report-structuring-env
0
1"""2Bug Report Structuring Environment - FastAPI Server3 4Exposes the environment via HTTP endpoints:5 POST /reset → start new episode6 POST /step → submit structured bug report7 GET /state → get episode metadata8 GET /health → health check9 GET / → landing page10"""11 12import os13import uuid14from contextlib import asynccontextmanager15from typing import Dict16 17from fastapi import FastAPI, HTTPException18from fastapi.responses import HTMLResponse, JSONResponse19 20from models import (21 ResetRequest,22 StepRequest,23 BugReportAction,24 BugReportObservation,25 BugReportState,26)27from environment import BugReportEnvironment28from tasks import get_all_task_ids29 30 31# ─── Session Management ──────────────────────────────────────────32# Each session gets its own environment instance33_sessions: Dict[str, BugReportEnvironment] = {}34_default_session_id = "default"35 36 37def get_or_create_env(session_id: str = None) -> BugReportEnvironment:38 """Get or create an environment for a session."""39 sid = session_id or _default_session_id40 if sid not in _sessions:41 _sessions[sid] = BugReportEnvironment()42 return _sessions[sid]43 44 45# ─── FastAPI App ──────────────────────────────────────────────────46 47@asynccontextmanager48async def lifespan(app: FastAPI):49 """Startup and shutdown events."""50 print("🚀 Bug Report Structuring Environment starting up...")51 print(f"📋 Available tasks: {get_all_task_ids()}")52 yield53 print("👋 Shutting down...")54 _sessions.clear()55 56 57app = FastAPI(58 title="Bug Report Structuring Environment",59 description=(60 "An OpenEnv environment that challenges LLM agents to convert "61 "messy, unstructured bug reports into well-organized structured formats. "62 "Supports 3 difficulty levels: easy, medium, hard."63 ),64 version="1.0.0",65 lifespan=lifespan,66)67 68 69# ─── Endpoints ────────────────────────────────────────────────────70 71@app.get("/", response_class=HTMLResponse)72async def landing_page():73 """Landing page with environment info."""74 return """75 <!DOCTYPE html>76 <html>77 <head>78 <title>Bug Report Structuring Environment</title>79 <style>80 body {81 font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;82 max-width: 800px; margin: 50px auto; padding: 20px;83 background: #0f0f23; color: #e0e0e0;84 }85 h1 { color: #00d4aa; font-size: 2em; }86 h2 { color: #ffd700; margin-top: 30px; }87 .endpoint { background: #1a1a3e; padding: 15px; border-radius: 8px;88 margin: 10px 0; border-left: 4px solid #00d4aa; }89 code { background: #2a2a4e; padding: 2px 8px; border-radius: 4px;90 color: #00d4aa; font-size: 0.95em; }91 .badge { display: inline-block; padding: 3px 10px; border-radius: 4px;92 font-size: 0.8em; font-weight: 600; margin-right: 8px; }93 .get { background: #1e4620; color: #4ade80; }94 .post { background: #1e3a5f; color: #60a5fa; }95 a { color: #00d4aa; }96 .task { background: #1a1a3e; padding: 10px 15px; border-radius: 6px;97 margin: 5px 0; }98 .easy { border-left: 4px solid #4ade80; }99 .medium { border-left: 4px solid #fbbf24; }100 .hard { border-left: 4px solid #ef4444; }101 </style>102 </head>103 <body>104 <h1>🐛 Bug Report Structuring Environment</h1>105 <p>An OpenEnv environment that challenges LLM agents to convert messy,106 unstructured bug reports into well-organized structured formats.</p>107 108 <h2>📋 Tasks</h2>109 <div class="task easy"><strong>Easy</strong> — Single clear bug, all info present but unstructured</div>110 <div class="task medium"><strong>Medium</strong> — Multiple symptoms, some ambiguity, partial info</div>111 <div class="task hard"><strong>Hard</strong> — Multiple distinct bugs, technical details, compound report</div>112 113 <h2>🔌 API Endpoints</h2>114 <div class="endpoint">115 <span class="badge post">POST</span> <code>/reset</code>116 <p>Start a new episode. Body: <code>{"task_id": "easy|medium|hard"}</code></p>117 </div>118 <div class="endpoint">119 <span class="badge post">POST</span> <code>/step</code>120 <p>Submit a structured bug report. Returns score and feedback.</p>121 </div>122 <div class="endpoint">123 <span class="badge get">GET</span> <code>/state</code>124 <p>Get current episode metadata.</p>125 </div>126 <div class="endpoint">127 <span class="badge get">GET</span> <code>/health</code>128 <p>Health check endpoint.</p>129 </div>130 131 <h2>📖 Docs</h2>132 <p>Interactive API docs: <a href="/docs">/docs</a></p>133 134 <h2>📊 Scoring</h2>135 <p>Reports are graded on 7 dimensions (0.0–1.0 each):</p>136 <ul>137 <li><strong>Title</strong> (15%) — Clear, descriptive title</li>138 <li><strong>Steps to Reproduce</strong> (25%) — Complete reproduction steps</li>139 <li><strong>Expected Behavior</strong> (15%) — What should happen</li>140 <li><strong>Actual Behavior</strong> (15%) — What actually happens</li>141 <li><strong>Severity</strong> (15%) — Correct classification</li>142 <li><strong>Environment</strong> (10%) — Platform/version info</li>143 <li><strong>Format</strong> (5%) — Structural completeness</li>144 </ul>145 </body>146 </html>147 """148 149 150@app.get("/health")151async def health_check():152 """Health check — returns 200 OK if the service is running."""153 return {154 "status": "healthy",155 "environment": "bug_report_structuring",156 "version": "1.0.0",157 "tasks": get_all_task_ids(),158 }159 160 161@app.post("/reset", response_model=BugReportObservation)162async def reset_endpoint(request: ResetRequest = None):163 """164 Start a new episode.165 166 Resets the environment with the specified task (or random).167 Returns the messy bug report as the initial observation.168 """169 if request is None:170 request = ResetRequest()171 172 try:173 env = get_or_create_env(request.episode_id)174 observation = env.reset(175 task_id=request.task_id,176 seed=request.seed,177 episode_id=request.episode_id,178 )179 return observation180 except ValueError as e:181 raise HTTPException(status_code=400, detail=str(e))182 except Exception as e:183 raise HTTPException(status_code=500, detail=f"Reset failed: {str(e)}")184 185 186@app.post("/step", response_model=BugReportObservation)187async def step_endpoint(request: StepRequest):188 """189 Submit a structured bug report and receive grading.190 191 The agent sends a structured version of the messy bug report.192 The environment returns a score (0.0-1.0) with detailed feedback.193 """194 try:195 env = get_or_create_env()196 observation = env.step(request.action)197 return observation198 except Exception as e:199 raise HTTPException(status_code=500, detail=f"Step failed: {str(e)}")200 201 202@app.get("/state", response_model=BugReportState)203async def state_endpoint():204 """205 Get current episode state metadata.206 207 Returns episode_id, step_count, task_id, scores, and done status.208 """209 try:210 env = get_or_create_env()211 return env.state212 except Exception as e:213 raise HTTPException(status_code=500, detail=f"State retrieval failed: {str(e)}")214 215 216# ─── Run directly ─────────────────────────────────────────────────217if __name__ == "__main__":218 import uvicorn219 port = int(os.environ.get("PORT", 7860))220 uvicorn.run(app, host="0.0.0.0", port=port)221 