sc-likes-to-code/openenv-customer-support-env
0
1import uvicorn2from fastapi import FastAPI, HTTPException, Query3from contextlib import asynccontextmanager4import traceback5 6from server.your_environment import SupportEnv7from models import Action8 9# ── App lifespan ─────────────────────────────────────────────────────────────10@asynccontextmanager11async def lifespan(app: FastAPI):12 app.state.env = SupportEnv()13 app.state.env.reset("easy")14 yield15 try:16 app.state.env.close()17 except Exception:18 pass19 20 21app = FastAPI(22 title="OpenEnv Customer Support Environment",23 description="Multi-step customer support ticket resolution environment for AI agent evaluation.",24 version="1.0.0",25 lifespan=lifespan,26)27 28VALID_TASKS = {"easy", "medium", "hard"}29 30 31# ── Health check ─────────────────────────────────────────────────────────────32@app.get("/")33@app.get("/health")34def health():35 return {"status": "ok", "message": "OpenEnv Support Environment Running"}36 37 38# ── reset ────────────────────────────────────────────────────────────────────39@app.post("/reset")40def reset(41 task: str = Query(default="easy", description="Task difficulty: easy | medium | hard")42):43 if task not in VALID_TASKS:44 raise HTTPException(45 status_code=400,46 detail=f"Invalid task '{task}'. Must be one of: {sorted(VALID_TASKS)}"47 )48 try:49 obs = app.state.env.reset(task)50 return obs.model_dump()51 except Exception as e:52 raise HTTPException(status_code=500, detail=f"reset() failed: {str(e)}")53 54 55# ── step ─────────────────────────────────────────────────────────────────────56@app.post("/step")57def step(action: dict):58 if app.state.env.state_data is None:59 app.state.env.reset("easy")60 61 try:62 action_obj = Action(**action)63 except Exception as e:64 raise HTTPException(65 status_code=422,66 detail=f"Invalid action payload: {str(e)}"67 )68 69 try:70 obs, reward, done, info = app.state.env.step(action_obj)71 return {72 "observation": obs.model_dump(),73 "reward": reward.score,74 "feedback": reward.feedback,75 "done": done,76 "info": info,77 }78 except Exception as e:79 raise HTTPException(80 status_code=500,81 detail=f"step() failed: {str(e)}\n{traceback.format_exc()}"82 )83 84 85# ── state ────────────────────────────────────────────────────────────────────86@app.get("/state")87def state():88 try:89 return app.state.env.state()90 except Exception as e:91 raise HTTPException(status_code=500, detail=f"state() failed: {str(e)}")92 93 94# ── main ─────────────────────────────────────────────────────────────────────95def main():96 uvicorn.run(97 "server.app:app",98 host="0.0.0.0",99 port=7860,100 reload=False,101 )102 103 104if __name__ == "__main__":105 main()