from __future__ import annotations import os from typing import Any import httpx class ColonyConfigurationError(RuntimeError): pass class ColonyGatewayError(RuntimeError): pass class ColonyGateway: """HTTP client from the Python root to the internal colony orchestrator.""" def __init__(self, *, base_url: str | None = None, timeout_s: float | None = None) -> None: resolved_base_url = (base_url or os.getenv("COLONY_SERVICE_URL", "")).strip().rstrip("/") if not resolved_base_url: raise ColonyConfigurationError("COLONY_SERVICE_URL is not configured.") self.base_url = resolved_base_url self.timeout = httpx.Timeout(timeout_s or float(os.getenv("COLONY_TIMEOUT_SECONDS", "30"))) async def health(self) -> dict[str, Any]: async with httpx.AsyncClient(timeout=httpx.Timeout(5.0)) as client: response = await client.get(f"{self.base_url}/health") if response.status_code >= 400: raise ColonyGatewayError(f"Colony service health check failed with HTTP {response.status_code}.") return response.json() async def dispatch_mission(self, mission: dict[str, Any]) -> dict[str, Any]: async with httpx.AsyncClient(timeout=self.timeout) as client: response = await client.post(f"{self.base_url}/missions", json=mission) if response.status_code >= 400: raise ColonyGatewayError( f"Colony service rejected mission with HTTP {response.status_code}: {response.text}" ) return response.json() async def mission_status(self, mission_id: str) -> dict[str, Any]: async with httpx.AsyncClient(timeout=self.timeout) as client: response = await client.get(f"{self.base_url}/missions/{mission_id}/status") if response.status_code >= 400: raise ColonyGatewayError( f"Colony service status check failed with HTTP {response.status_code}: {response.text}" ) return response.json()