Spaces:
Running
Running
| """ | |
| app.py β FastAPI server for EnterpriseOps Arena. | |
| Exposes the OpenEnv-compatible endpoints: | |
| POST /reset β reset environment, return primary observation | |
| POST /step β execute one step, return observation + reward + done | |
| POST /step_multi β multi-agent step (all agents at once) | |
| GET /state β full world state snapshot | |
| GET /observations β per-agent observations | |
| POST /scenario β switch scenario for next reset (curriculum) | |
| GET /health β liveness check | |
| """ | |
| from __future__ import annotations | |
| from typing import Any, Optional | |
| from fastapi import FastAPI, HTTPException | |
| from pydantic import BaseModel | |
| import gradio as gr | |
| # ββ Flat HuggingFace Space layout: all files are in /app βββββββββββββββββββ | |
| from environment import EnterpriseEnvironment | |
| from models import EnterpriseAction, EnterpriseObservation | |
| from gradio_app import demo | |
| # --------------------------------------------------------------------------- | |
| # Pydantic request/response models for FastAPI serialisation | |
| # --------------------------------------------------------------------------- | |
| class ResetRequest(BaseModel): | |
| scenario: Optional[str] = None | |
| seed: Optional[int] = None | |
| use_trained_model: bool = False | |
| class ActionRequest(BaseModel): | |
| agent_id: str | |
| tool_call: Optional[str] = None | |
| tool_params: dict[str, Any] = {} | |
| message_to: Optional[str] = None | |
| message_content: Optional[str] = None | |
| reasoning: Optional[str] = None | |
| use_trained_model: bool = False | |
| class MultiActionRequest(BaseModel): | |
| actions: dict[str, ActionRequest] | |
| class ScenarioRequest(BaseModel): | |
| scenario_name: str | |
| class StepResponse(BaseModel): | |
| observation: dict[str, Any] | |
| reward: float | |
| done: bool | |
| info: dict[str, Any] = {} | |
| # --------------------------------------------------------------------------- | |
| # Application | |
| # --------------------------------------------------------------------------- | |
| app = FastAPI( | |
| title="EnterpriseOps Arena", | |
| description="Multi-agent RL environment β OpenEnv server", | |
| version="1.0.0", | |
| ) | |
| env = EnterpriseEnvironment() | |
| # --------------------------------------------------------------------------- | |
| # Endpoints | |
| # --------------------------------------------------------------------------- | |
| def health() -> dict[str, str]: | |
| """Liveness probe.""" | |
| return {"status": "ok", "environment": "EnterpriseOps Arena"} | |
| def reset(req: ResetRequest) -> dict[str, Any]: | |
| """Reset the environment and return the primary observation.""" | |
| obs = env.reset( | |
| scenario=req.scenario, | |
| seed=req.seed, | |
| use_trained_model=req.use_trained_model, | |
| ) | |
| return { | |
| "observation": obs.to_dict(), | |
| "it_agent_status": env.it_agent_status(), | |
| } | |
| def step(req: ActionRequest) -> StepResponse: | |
| """Execute a single-agent step.""" | |
| action = EnterpriseAction( | |
| agent_id=req.agent_id, | |
| tool_call=req.tool_call, | |
| tool_params=req.tool_params, | |
| message_to=req.message_to, | |
| message_content=req.message_content, | |
| reasoning=req.reasoning, | |
| ) | |
| result = env.step(action, use_trained_model=req.use_trained_model) | |
| return StepResponse( | |
| observation=result["observation"].to_dict(), | |
| reward=result["reward"], | |
| done=result["done"], | |
| info=result.get("info", {}), | |
| ) | |
| def step_multi(req: MultiActionRequest) -> dict[str, Any]: | |
| """Execute a multi-agent step (all agents in one call).""" | |
| actions: dict[str, EnterpriseAction] = {} | |
| for aid, a in req.actions.items(): | |
| actions[aid] = EnterpriseAction( | |
| agent_id=aid, | |
| tool_call=a.tool_call, | |
| tool_params=a.tool_params, | |
| message_to=a.message_to, | |
| message_content=a.message_content, | |
| reasoning=a.reasoning, | |
| ) | |
| result = env.step_multi(actions) | |
| obs_dicts: dict[str, Any] = {} | |
| for aid, obs in result.get("observations", {}).items(): | |
| obs_dicts[aid] = obs.to_dict() if hasattr(obs, "to_dict") else obs | |
| return { | |
| "observations": obs_dicts, | |
| "reward": result["reward"], | |
| "done": result["done"], | |
| "info": result.get("info", {}), | |
| } | |
| def get_state() -> dict[str, Any]: | |
| """Return the full world state snapshot.""" | |
| return env.state | |
| def get_observations() -> dict[str, Any]: | |
| """Return per-agent observations from the last step.""" | |
| all_obs = env.get_all_observations() | |
| return {aid: obs.to_dict() for aid, obs in all_obs.items()} | |
| def set_scenario(req: ScenarioRequest) -> dict[str, str]: | |
| """Switch scenario for the next reset() call (curriculum support).""" | |
| env.set_scenario(req.scenario_name) | |
| return {"status": "ok", "scenario": req.scenario_name} | |
| # Mount Gradio AFTER all API routes are defined | |
| app = gr.mount_gradio_app(app, demo, path="/") | |