Spaces:
Sleeping
Sleeping
| # 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 API Integration Debugging Environment. | |
| 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 | |
| - GET /tasks: List all tasks with action schema | |
| - POST /grader: Get grader score for current episode | |
| - POST /baseline: Run baseline inference on all tasks | |
| Usage: | |
| uvicorn server.app:app --reload --host 0.0.0.0 --port 8000 | |
| """ | |
| import os | |
| from typing import Dict, Any, Optional | |
| from fastapi import FastAPI | |
| from pydantic import BaseModel | |
| try: | |
| from openenv.core.env_server.http_server import create_app | |
| except Exception as e: | |
| raise ImportError( | |
| "openenv is required. Install with: uv sync" | |
| ) from e | |
| try: | |
| from ..models import ApiDebugAction, ApiDebugObservation | |
| from .api_debug_env_environment import ApiDebugEnvironment | |
| except ImportError: | |
| from models import ApiDebugAction, ApiDebugObservation | |
| from server.api_debug_env_environment import ApiDebugEnvironment | |
| try: | |
| from ..scenarios import get_all_task_ids, get_scenario | |
| except ImportError: | |
| from scenarios import get_all_task_ids, get_scenario | |
| # βββ Create the core OpenEnv app βββββββββββββββββββββββββββββββββββββββββββββ | |
| app = create_app( | |
| ApiDebugEnvironment, | |
| ApiDebugAction, | |
| ApiDebugObservation, | |
| env_name="api_debug_env", | |
| max_concurrent_envs=3, | |
| ) | |
| # βββ Hackathon-required endpoints βββββββββββββββββββββββββββββββββββββββββββββ | |
| # Store environment instances per task for grading | |
| _grading_envs: Dict[str, ApiDebugEnvironment] = {} | |
| class GraderRequest(BaseModel): | |
| task_id: str = "easy" | |
| class BaselineRequest(BaseModel): | |
| api_key: Optional[str] = None | |
| async def list_tasks(): | |
| """Return list of all tasks with action schema.""" | |
| tasks = [] | |
| for task_id in get_all_task_ids(): | |
| scenario = get_scenario(task_id) | |
| tasks.append({ | |
| "task_id": task_id, | |
| "difficulty": scenario.difficulty, | |
| "description": scenario.description, | |
| "max_steps": scenario.max_steps, | |
| "issues_count": len(scenario.issues), | |
| "services": scenario.services, | |
| "action_schema": { | |
| "action_type": { | |
| "type": "string", | |
| "enum": ["inspect_logs", "inspect_config", "inspect_endpoint", "submit_fix"], | |
| }, | |
| "target": { | |
| "type": "string", | |
| "enum": scenario.services, | |
| }, | |
| "fix_payload": { | |
| "type": "object", | |
| "required": False, | |
| }, | |
| }, | |
| }) | |
| return {"tasks": tasks} | |
| async def run_grader(request: GraderRequest): | |
| """Return grader score for a completed episode.""" | |
| task_id = request.task_id | |
| if task_id in _grading_envs: | |
| env = _grading_envs[task_id] | |
| score = env.grade() | |
| return { | |
| "task_id": task_id, | |
| "score": score, | |
| "issues_fixed": len(env._issues_fixed), | |
| "issues_total": len(env._scenario.issues) if env._scenario else 0, | |
| "steps_used": env._state.step_count, | |
| } | |
| return { | |
| "task_id": task_id, | |
| "score": 0.0, | |
| "message": "No completed episode found. Run the environment first.", | |
| } | |
| async def run_baseline(request: BaselineRequest): | |
| """ | |
| Run a simple rule-based baseline agent on all tasks. | |
| Returns baseline scores for each task. | |
| """ | |
| results = {} | |
| for task_id in get_all_task_ids(): | |
| env = ApiDebugEnvironment(task_id=task_id) | |
| obs = env.reset() | |
| # Simple baseline strategy: inspect all logs, then all configs, then submit fixes | |
| for service in obs.available_targets: | |
| if env._done: | |
| break | |
| obs = env.step(ApiDebugAction( | |
| action_type="inspect_logs", | |
| target=service, | |
| )) | |
| for service in obs.available_targets: | |
| if env._done: | |
| break | |
| obs = env.step(ApiDebugAction( | |
| action_type="inspect_config", | |
| target=service, | |
| )) | |
| for service in obs.available_targets: | |
| if env._done: | |
| break | |
| obs = env.step(ApiDebugAction( | |
| action_type="inspect_endpoint", | |
| target=service, | |
| )) | |
| # Store for grading | |
| _grading_envs[task_id] = env | |
| score = env.grade() | |
| results[task_id] = { | |
| "score": score, | |
| "steps_used": env._state.step_count, | |
| "issues_found": len(env._issues_found), | |
| "issues_fixed": len(env._issues_fixed), | |
| "issues_total": len(env._scenario.issues) if env._scenario else 0, | |
| } | |
| return {"baseline_scores": results} | |
| # βββ Entry point ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def main(host: str = "0.0.0.0", port: int = 8000): | |
| """Run the server directly.""" | |
| import argparse | |
| import uvicorn | |
| parser = argparse.ArgumentParser() | |
| parser.add_argument("--host", type=str, default=host) | |
| parser.add_argument("--port", type=int, default=port) | |
| args = parser.parse_args() | |
| uvicorn.run(app, host=args.host, port=args.port) | |
| if __name__ == "__main__": | |
| main() | |