Spaces:
Sleeping
Sleeping
File size: 3,141 Bytes
60df783 32951ca 60df783 32951ca ab6a3f1 32951ca 60df783 d860a1c 60df783 32951ca 60df783 32951ca 60df783 32951ca 60df783 32951ca 60df783 8249911 32951ca 8249911 60df783 32951ca 60df783 ab6a3f1 32951ca 60df783 32951ca 60df783 32951ca 60df783 32951ca 60df783 32951ca 60df783 32951ca 60df783 32951ca 60df783 32951ca 60df783 32951ca 60df783 32951ca 60df783 32951ca d860a1c | 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 | """
server.py β FastAPI server exposing the OpenEnv HTTP API.
"""
import os
import traceback
from fastapi import FastAPI, HTTPException, Body
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from pydantic import BaseModel, ValidationError
from typing import Optional
from env_models import TriageAction, StepResult, EnvState, TicketObservation
from env_core import ITSupportEnv
app = FastAPI(
title="IT Support Triage β OpenEnv",
description=(
"An OpenEnv-compliant RL environment for training and evaluating agents "
"on IT helpdesk ticket triage tasks. Includes 3 tasks (easy β medium β hard) "
"with deterministic graders and safety-aware reward functions."
),
version="1.0.0",
)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_methods=["*"],
allow_headers=["*"],
)
env = ITSupportEnv()
class ResetRequest(BaseModel):
task_id: Optional[str] = "task_easy"
class StepRequest(BaseModel):
action: TriageAction
# βββ Endpoints ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
@app.get("/")
def root():
return {
"environment": "it-support-triage",
"version": "1.0.0",
"status": "ok",
"endpoints": {
"POST /reset": "Start episode. Body: {task_id: task_easy|task_medium|task_hard}",
"POST /step": "Submit action. Body: {action: {...}}",
"GET /state": "Current environment state",
"GET /tasks": "List all tasks",
"GET /health": "Health check",
"GET /docs": "Interactive API docs (Swagger UI)",
}
}
@app.get("/health")
def health():
return {"status": "ok", "environment": "it-support-triage", "version": "1.0.0"}
@app.post("/reset", response_model=TicketObservation)
async def reset(request: Optional[ResetRequest] = Body(default=None)):
task_id = (request.task_id if request else None) or "task_easy"
try:
obs = env.reset(task_id)
return obs
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
except Exception as e:
raise HTTPException(status_code=500, detail=traceback.format_exc())
@app.post("/step", response_model=StepResult)
def step(request: StepRequest):
try:
result = env.step(request.action)
return result
except RuntimeError as e:
raise HTTPException(status_code=400, detail=str(e))
except ValidationError as e:
raise HTTPException(status_code=422, detail=str(e))
except Exception as e:
raise HTTPException(status_code=500, detail=traceback.format_exc())
@app.get("/state", response_model=EnvState)
def state():
return env.state()
@app.get("/tasks")
def list_tasks():
return {"tasks": env.list_tasks()}
if __name__ == "__main__":
import uvicorn
port = int(os.environ.get("PORT", 7860))
uvicorn.run("server:app", host="0.0.0.0", port=port, reload=False) |