Spaces:
Running
Running
| """ | |
| Agent Control Routes - REST API for agent-to-agent Atom OS control. | |
| Allows any agent (OpenClaw, Claude, custom) to programmatically control Atom OS: | |
| - Start Atom as background service | |
| - Stop Atom service | |
| - Check status | |
| - Execute commands | |
| Usage: | |
| import requests | |
| # Start Atom | |
| response = requests.post("http://localhost:8000/api/agent/start", | |
| json={"port": 8000}) | |
| # Check status | |
| response = requests.get("http://localhost:8000/api/agent/status") | |
| # Stop Atom | |
| response = requests.post("http://localhost:8000/api/agent/stop") | |
| """ | |
| from fastapi import APIRouter, Depends, HTTPException | |
| from pydantic import BaseModel, Field | |
| from typing import Optional, List, Dict, Any | |
| from sqlalchemy.orm import Session | |
| # Import daemon manager | |
| import sys | |
| from pathlib import Path | |
| sys.path.insert(0, str(Path(__file__).parent.parent)) | |
| from cli.daemon import DaemonManager | |
| # Import authentication and authorization | |
| from core.admin_endpoints import get_super_admin | |
| from core.models import User, DelegationChain | |
| from core.database import get_db | |
| router = APIRouter(prefix="/api/agent", tags=["agent-control"]) | |
| # Request/Response Models | |
| class StartAgentRequest(BaseModel): | |
| """Request model for starting Atom OS service.""" | |
| port: int = Field(default=8000, ge=1, le=65535, description="Port for web server") | |
| host: str = Field(default="0.0.0.0", description="Host to bind to") | |
| workers: int = Field(default=1, ge=1, le=16, description="Number of worker processes") | |
| host_mount: bool = Field(default=False, description="Enable host filesystem mount") | |
| dev: bool = Field(default=False, description="Enable development mode") | |
| class StartAgentResponse(BaseModel): | |
| """Response model for start endpoint.""" | |
| success: bool | |
| pid: Optional[int] = None | |
| status: str | |
| dashboard_url: Optional[str] = None | |
| message: str | |
| error: Optional[str] = None | |
| class StopAgentResponse(BaseModel): | |
| """Response model for stop endpoint.""" | |
| success: bool | |
| status: str | |
| message: str | |
| error: Optional[str] = None | |
| class RestartAgentResponse(BaseModel): | |
| """Response model for restart endpoint.""" | |
| success: bool | |
| pid: Optional[int] = None | |
| status: str | |
| dashboard_url: Optional[str] = None | |
| was_running: bool | |
| message: str | |
| error: Optional[str] = None | |
| class AgentStatusResponse(BaseModel): | |
| """Response model for status endpoint.""" | |
| success: bool | |
| status: dict | |
| message: Optional[str] = None | |
| class ExecuteCommandRequest(BaseModel): | |
| """Request model for execute endpoint.""" | |
| command: str = Field(..., description="Atom command to execute") | |
| timeout: int = Field(default=30, ge=1, le=300, description="Timeout in seconds") | |
| class ExecuteCommandResponse(BaseModel): | |
| """Response model for execute endpoint.""" | |
| success: bool | |
| result: Optional[str] = None | |
| error: Optional[str] = None | |
| note: Optional[str] = None | |
| # API Endpoints | |
| async def start_atom( | |
| request: StartAgentRequest, | |
| current_user: User = Depends(get_super_admin) | |
| ): | |
| """Start Atom OS as background service (super_admin only). | |
| **SECURITY**: Requires super_admin authentication to prevent unauthorized | |
| daemon control. Use this endpoint only from trusted sources. | |
| Called by external agents (Claude, OpenClaw, custom agents) to | |
| programmatically start Atom as a background service. | |
| **Example:** | |
| ```python | |
| import requests | |
| response = requests.post( | |
| "http://localhost:8000/api/agent/start", | |
| json={"port": 8000, "host": "0.0.0.0"} | |
| ) | |
| print(response.json()) | |
| ``` | |
| **Returns:** | |
| - success: True if started successfully | |
| - pid: Process ID of daemon | |
| - status: "started" | |
| - dashboard_url: URL to web dashboard | |
| - message: Success message | |
| **Raises:** | |
| - 400: If Atom is already running | |
| - 500: If daemon fails to start | |
| """ | |
| try: | |
| if DaemonManager.is_running(): | |
| current_pid = DaemonManager.get_pid() | |
| raise HTTPException( | |
| status_code=400, | |
| detail=f"Atom OS is already running (PID: {current_pid})" | |
| ) | |
| pid = DaemonManager.start_daemon( | |
| port=request.port, | |
| host=request.host, | |
| workers=request.workers, | |
| host_mount=request.host_mount, | |
| dev=request.dev | |
| ) | |
| return StartAgentResponse( | |
| success=True, | |
| pid=pid, | |
| status="started", | |
| dashboard_url=f"http://{request.host}:{request.port}", | |
| message="Atom OS started successfully" | |
| ) | |
| except RuntimeError as e: | |
| raise HTTPException(status_code=500, detail=str(e)) | |
| except IOError as e: | |
| raise HTTPException(status_code=500, detail=str(e)) | |
| async def stop_atom(current_user: User = Depends(get_super_admin)): | |
| """Stop Atom OS background service (super_admin only). | |
| **SECURITY**: Requires super_admin authentication to prevent unauthorized | |
| daemon control. | |
| Gracefully shuts down Atom daemon service. | |
| **Example:** | |
| ```python | |
| import requests | |
| response = requests.post("http://localhost:8000/api/agent/stop") | |
| print(response.json()) | |
| ``` | |
| **Returns:** | |
| - success: True if stopped | |
| - status: "stopped" | |
| - message: Success message | |
| **Raises:** | |
| - 400: If Atom is not running | |
| - 500: If stop fails | |
| """ | |
| try: | |
| if not DaemonManager.is_running(): | |
| raise HTTPException( | |
| status_code=400, | |
| detail="Atom OS is not running" | |
| ) | |
| DaemonManager.stop_daemon() | |
| return StopAgentResponse( | |
| success=True, | |
| status="stopped", | |
| message="Atom OS stopped successfully" | |
| ) | |
| except HTTPException: | |
| raise | |
| except Exception as e: | |
| raise HTTPException(status_code=500, detail=str(e)) | |
| async def restart_atom( | |
| request: StartAgentRequest, | |
| current_user: User = Depends(get_super_admin) | |
| ): | |
| """Restart Atom OS background service (super_admin only). | |
| **SECURITY**: Requires super_admin authentication to prevent unauthorized | |
| daemon control. | |
| Stops Atom if running, then starts again with new configuration. | |
| **Example:** | |
| ```python | |
| import requests | |
| response = requests.post( | |
| "http://localhost:8000/api/agent/restart", | |
| json={"port": 8000} | |
| ) | |
| print(response.json()) | |
| ``` | |
| **Returns:** | |
| - success: True if restarted | |
| - pid: New process ID | |
| - status: "restarted" | |
| - dashboard_url: URL to web dashboard | |
| - was_running: Whether Atom was running before restart | |
| - message: Success message | |
| **Raises:** | |
| - 500: If restart fails | |
| """ | |
| try: | |
| was_running = DaemonManager.is_running() | |
| if was_running: | |
| DaemonManager.stop_daemon() | |
| # Wait for clean shutdown | |
| import time | |
| time.sleep(2) | |
| pid = DaemonManager.start_daemon( | |
| port=request.port, | |
| host=request.host, | |
| workers=request.workers, | |
| host_mount=request.host_mount, | |
| dev=request.dev | |
| ) | |
| return RestartAgentResponse( | |
| success=True, | |
| pid=pid, | |
| status="restarted", | |
| dashboard_url=f"http://{request.host}:{request.port}", | |
| was_running=was_running, | |
| message="Atom OS restarted successfully" | |
| ) | |
| except Exception as e: | |
| raise HTTPException(status_code=500, detail=str(e)) | |
| async def get_status(): | |
| """Get Atom OS status and running info. | |
| Returns current status, PID, uptime, memory usage, and CPU. | |
| **Example:** | |
| ```python | |
| import requests | |
| response = requests.get("http://localhost:8000/api/agent/status") | |
| print(response.json()) | |
| ``` | |
| **Returns:** | |
| - success: True | |
| - status: Dict with running status, pid, uptime_seconds, memory_mb, cpu_percent | |
| **Example Response:** | |
| ```json | |
| { | |
| "success": true, | |
| "status": { | |
| "running": true, | |
| "pid": 12345, | |
| "uptime_seconds": 3600, | |
| "memory_mb": 256.5, | |
| "cpu_percent": 5.2, | |
| "status": "running" | |
| } | |
| } | |
| ``` | |
| """ | |
| try: | |
| status_info = DaemonManager.get_status() | |
| return AgentStatusResponse( | |
| success=True, | |
| status=status_info | |
| ) | |
| except Exception as e: | |
| raise HTTPException(status_code=500, detail=str(e)) | |
| async def execute_atom_command( | |
| request: ExecuteCommandRequest, | |
| current_user: User = Depends(get_super_admin) | |
| ): | |
| """Execute single Atom command and return result (super_admin only). | |
| **SECURITY**: Requires super_admin authentication to prevent unauthorized | |
| command execution. This endpoint executes arbitrary Atom commands. | |
| Useful for one-off tasks from other agents. Starts Atom temporarily, | |
| executes command, and shuts down. | |
| **Note:** Command routing not yet fully implemented. | |
| Use POST /api/agent/start to run Atom as service instead. | |
| **Example:** | |
| ```python | |
| import requests | |
| response = requests.post( | |
| "http://localhost:8000/api/agent/execute", | |
| json={"command": "agent.chat('Hello, create a report')"} | |
| ) | |
| print(response.json()) | |
| ``` | |
| **Returns:** | |
| - success: True | |
| - result: Command execution result (when implemented) | |
| - note: Implementation status message | |
| **Note:** | |
| This endpoint is currently a placeholder. Use daemon mode for | |
| full Atom functionality: | |
| ```bash | |
| # Start as service | |
| atom-os daemon | |
| # Or via API | |
| curl -X POST http://localhost:8000/api/agent/start | |
| ``` | |
| """ | |
| return ExecuteCommandResponse( | |
| success=True, | |
| result="Command execution not yet implemented", | |
| note="Use POST /api/agent/start to run Atom as service instead" | |
| ) | |
| async def analyze_chain_bottlenecks( | |
| chain_id: str, | |
| db: Session = Depends(get_db), | |
| # For Upstream, we restrict this to admins as it reveals internal telemetry | |
| current_user: User = Depends(get_super_admin) | |
| ): | |
| """ | |
| Perform diagnostic analysis to identify bottlenecks in the delegation chain. | |
| RESTRICTED: Super Admin only. | |
| """ | |
| # 1. Verify chain existence | |
| chain = db.query(DelegationChain).filter(DelegationChain.id == chain_id).first() | |
| if not chain: | |
| raise HTTPException( | |
| status_code=404, | |
| detail="Delegation chain not found" | |
| ) | |
| # 2. Run analysis | |
| from analytics.fleet_optimization_service import FleetOptimizationService | |
| service = FleetOptimizationService(db) | |
| report = service.analyze_bottlenecks(chain_id) | |
| return { | |
| "chain_id": chain_id, | |
| "report": report, | |
| "summary": { | |
| "total_issues": len(report), | |
| "critical_issues": len([r for r in report if r["severity"] == "critical"]), | |
| "warnings": len([r for r in report if r["severity"] == "warning"]) | |
| } | |
| } | |
| async def get_fleet_health_summary( | |
| db: Session = Depends(get_db), | |
| current_user: User = Depends(get_super_admin) | |
| ): | |
| """ | |
| Get fleet-wide health metrics for the supervisor dashboard. | |
| RESTRICTED: Super Admin only. | |
| """ | |
| from analytics.fleet_optimization_service import FleetOptimizationService | |
| service = FleetOptimizationService(db) | |
| # Scoped to the current admin's tenant if applicable | |
| tenant_id = getattr(current_user, "tenant_id", None) | |
| return service.get_fleet_health_summary(tenant_id) | |