from typing import Any from fastapi import APIRouter, Depends, HTTPException, Query from pydantic import BaseModel, Field from sqlalchemy.orm import Session from app.auth.api_key import get_api_key_auth from app.database import get_db from app.services.agent_commands import ( command_to_dict, complete_command, get_command_for_host_poll, resolve_host_by_agent_instance_id, ) router = APIRouter(prefix="/agent", tags=["agent"]) class AgentCommandResultBody(BaseModel): status: str = Field(pattern="^(completed|failed)$") stdout: str | None = None stderr: str | None = None class AgentCommandsPollResponse(BaseModel): commands: list[dict[str, Any]] @router.get("/commands", response_model=AgentCommandsPollResponse) def poll_agent_commands( agent_instance_id: str = Query(..., min_length=1), db: Session = Depends(get_db), _api_key: str = Depends(get_api_key_auth), ) -> AgentCommandsPollResponse: host = resolve_host_by_agent_instance_id(db, agent_instance_id) if host is None: raise HTTPException(status_code=404, detail="Unknown agent_instance_id") pending = get_command_for_host_poll(db, host) return AgentCommandsPollResponse( commands=[command_to_dict(c, include_run_as=True) for c in pending] ) @router.post("/commands/{command_uuid}/result") def post_agent_command_result( command_uuid: str, body: AgentCommandResultBody, db: Session = Depends(get_db), _api_key: str = Depends(get_api_key_auth), ) -> dict[str, str]: cmd = complete_command( db, command_uuid, status=body.status, stdout=body.stdout, stderr=body.stderr, ) if cmd is None: raise HTTPException(status_code=404, detail="Command not found") db.commit() return {"status": cmd.status, "command_uuid": cmd.command_uuid}