# Copyright (c) Meta Platforms, Inc. and affiliates. # All rights reserved. # # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. """ FastAPI application for the My Env Environment. This module creates an HTTP server that exposes the MyEnvironment over HTTP and WebSocket endpoints, compatible with EnvClient. Endpoints: - POST /reset: Reset the environment - POST /step: Execute an action - GET /state: Get current environment state - GET /schema: Get action/observation schemas - WS /ws: WebSocket endpoint for persistent sessions Usage: # Development (with auto-reload): uvicorn server.app:app --reload --host 0.0.0.0 --port 8000 # Production: uvicorn server.app:app --host 0.0.0.0 --port 8000 --workers 4 # Or run directly: python -m server.app """ from openenv.core.env_server import create_fastapi_app from fastapi import HTTPException import uvicorn try: from ..models import MyAction, MyObservation, MyState from .my_env_environment import MyEnvironment, EPISODE_REGISTRY except ImportError: from models import MyAction, MyObservation, MyState from server.my_env_environment import MyEnvironment, EPISODE_REGISTRY # Create the app with web interface and README integration app = create_fastapi_app( MyEnvironment, MyAction, MyObservation, ) # --------------------------------------------------------------------------- # /grade endpoint — appended to the FastAPI app after create_fastapi_app. # Does NOT touch any OpenEnv internals; just reads from EPISODE_REGISTRY. # --------------------------------------------------------------------------- @app.get("/grade", tags=["Grading"], summary="Grade an episode by episode_id") def grade(episode_id: str): """ Compute a normalized grade (0.0 – 1.0) for a given episode. The grade reflects both how many sub-tasks the agent completed (structural score) and how efficiently it used its step budget (efficiency score). Callable at any point during or after the episode. Args: episode_id: The episode_id returned by /reset. Returns: JSON with episode_id, task_type, and grade (float in [0.0, 1.0]). """ env = EPISODE_REGISTRY.get(episode_id) if env is None: raise HTTPException( status_code=404, detail=f"No episode found for episode_id '{episode_id}'. " f"Make sure /reset was called with this episode_id.", ) return { "episode_id": episode_id, "task_type": env.state.task_type, "grade": env.grade(), } def main(): uvicorn.run("server.app:app", host="0.0.0.0", port=7860) if __name__ == "__main__": main()