import os from fastapi import FastAPI, Request, HTTPException import gradio as gr from client import CiCdDoctorEnv, CiCdDoctorAction from models import PipelineObservation # Optional: your existing Gradio UI try: from app import demo except ImportError: demo = None app = FastAPI( title="CI/CD Doctor", description="Self-healing CI/CD pipeline agent", version="1.0.0", ) _env = None @app.get("/health") async def health(): return {"status": "healthy"} @app.get("/metadata") async def metadata(): return { "name": "CI/CD Doctor", "description": "Fix broken CI/CD pipelines autonomously", "version": "1.0.0", "submission_type": "openenv-v4", } @app.get("/schema") async def schema(): return { "action": CiCdDoctorAction.model_json_schema(), "observation": PipelineObservation.model_json_schema(), "state": {"type": "object"}, } @app.post("/reset") async def reset(request: Request): global _env try: body = await request.json() if await request.body() else {} task = body.get("task", "easy") seed = body.get("seed", 42) base_url = os.getenv("ENV_BASE_URL", "http://localhost:8000") _env = await CiCdDoctorEnv(base_url=base_url) result = await _env.reset(task=task, seed=seed) return result.observation.model_dump() except Exception as e: raise HTTPException(status_code=500, detail=str(e)) @app.post("/step") async def step(request: Request): global _env if _env is None: raise HTTPException(status_code=400, detail="Call /reset first") try: body = await request.json() action = CiCdDoctorAction(**body) result = await _env.step(action) return result.observation.model_dump() except Exception as e: raise HTTPException(status_code=500, detail=str(e)) @app.get("/state") async def state(): global _env if _env is None: return {"status": "uninitialized"} return {"status": "running"} # Mount Gradio UI if available if demo is not None: app = gr.mount_gradio_app(app, demo, path="/") def main(): import uvicorn uvicorn.run(app, host="0.0.0.0", port=8000) if __name__ == "__main__": main()