Files
langgraph/libs/cli/langgraph_cli/host_backend.py
T

80 lines
2.5 KiB
Python

"""HTTP client for LangGraph host backend deployments."""
from __future__ import annotations
import json
import urllib.error
import urllib.request
from typing import Any
import click
class HostBackendError(click.ClickException):
"""Raised when the host backend returns an error response."""
class HostBackendClient:
"""Minimal JSON HTTP client for the host backend deployment service."""
def __init__(self, base_url: str, api_key: str):
if not base_url:
raise click.UsageError("Host backend URL is required")
base_url = base_url.rstrip("/")
self._base_url = base_url
self._api_key = api_key
def _request(
self, method: str, path: str, payload: dict[str, Any] | None = None
) -> Any:
url = f"{self._base_url}{path}"
data: bytes | None
if payload is not None:
data = json.dumps(payload).encode("utf-8")
else:
data = None
headers = {
"Content-Type": "application/json",
"X-Api-Key": self._api_key,
"Accept": "application/json",
}
req = urllib.request.Request(url, data=data, headers=headers, method=method)
try:
with urllib.request.urlopen(req) as resp: # noqa: S310
body = resp.read()
except urllib.error.HTTPError as err:
detail = err.read().decode("utf-8", errors="ignore")
message = detail or err.reason
raise HostBackendError(
f"{method} {path} failed with status {err.code}: {message}"
) from None
except urllib.error.URLError as err:
raise HostBackendError(str(err.reason)) from None
if not body:
return None
try:
return json.loads(body)
except json.JSONDecodeError as err:
raise HostBackendError(
f"Failed to decode response from {path}: {err.msg}"
) from None
def create_deployment(self, payload: dict[str, Any]) -> dict[str, Any]:
return self._request("POST", "/v2/deployments", payload)
def request_push_token(self, deployment_id: str) -> dict[str, Any]:
return self._request(
"POST",
f"/v2/deployments/{deployment_id}/push-token",
)
def update_deployment_image(
self, deployment_id: str, image_uri: str
) -> dict[str, Any]:
return self._request(
"PATCH",
f"/v2/deployments/{deployment_id}",
{"source_revision_config": {"image_uri": image_uri}},
)