"""Thin Python SDK client for the ``/v1`` REST API. Capability: ``platform-sdk``. Uses ``httpx`` directly so the client can talk to any deployed cloud-runtime process over HTTP, or to a FastAPI ``TestClient`` instance in tests. """ from __future__ import annotations from typing import Any import httpx class CloudClient: """A minimal Python wrapper for the platform SDK's ``/v1`` routes.""" def __init__( self, base_url: str, *, http_client: httpx.Client | Any = None, api_prefix: str = "/v1", ) -> None: self._base_url = base_url.rstrip("/") self._api_prefix = api_prefix.rstrip("/") if http_client is None: self._http = httpx.Client(base_url=self._base_url) self._owns_client = True else: self._http = http_client self._owns_client = False def close(self) -> None: if self._owns_client: self._http.close() def __enter__(self) -> "CloudClient": return self def __exit__(self, *exc: object) -> None: self.close() # ------------------------------------------------------------------- tasks def submit_task( self, *, goal: str | None = None, workflow_definition_id: str | None = None, driver_type: str | None = None, capability_tags: list[str] | None = None, ) -> dict[str, Any]: payload: dict[str, Any] = { "goal": goal, "workflow_definition_id": workflow_definition_id, } if driver_type is not None or capability_tags is not None: payload["constraints"] = { "driver_type": driver_type, "capability_tags": list(capability_tags or []), } resp = self._http.post(self._url("/tasks"), json=payload) resp.raise_for_status() return resp.json() def get_task_status(self, task_id: str) -> dict[str, Any]: resp = self._http.get(self._url(f"/tasks/{task_id}")) resp.raise_for_status() return resp.json() # ----------------------------------------------------------------- devices def list_devices(self) -> list[dict[str, Any]]: resp = self._http.get(self._url("/devices")) resp.raise_for_status() return resp.json() def list_hosts(self) -> list[dict[str, Any]]: resp = self._http.get(self._url("/hosts")) resp.raise_for_status() return resp.json() # ----------------------------------------------------------------- plugins def list_plugins(self) -> list[dict[str, Any]]: resp = self._http.get(self._url("/plugins")) resp.raise_for_status() return resp.json() def register_plugin( self, *, name: str, version: str, entry_point_kind: str, target: str, ) -> dict[str, Any]: payload = { "name": name, "version": version, "entry_point_kind": entry_point_kind, "target": target, } resp = self._http.post(self._url("/plugins"), json=payload) resp.raise_for_status() return resp.json() # ------------------------------------------------------------------ helpers def _url(self, path: str) -> str: return f"{self._base_url}{self._api_prefix}{path}"