from typing import Any import httpx from app.core.config import settings from app.core.logging import logger class OpenCodeClient: def __init__(self): self.base_url = f"http://{settings.opencode_host}:{settings.opencode_port}" self._client: httpx.AsyncClient | None = None async def _get_client(self) -> httpx.AsyncClient: if self._client is None: headers = {} if settings.opencode_password: headers["Authorization"] = f"Bearer {settings.opencode_password}" self._client = httpx.AsyncClient( base_url=self.base_url, headers=headers, timeout=300.0, ) return self._client async def close(self): if self._client: await self._client.aclose() self._client = None async def health_check(self) -> dict[str, Any]: client = await self._get_client() resp = await client.get("/global/health") resp.raise_for_status() return resp.json() async def create_session(self, title: str | None = None, parent_id: str | None = None) -> dict[str, Any]: client = await self._get_client() payload = {} if title: payload["title"] = title if parent_id: payload["parentID"] = parent_id resp = await client.post("/session", json=payload) resp.raise_for_status() return resp.json() async def get_session(self, session_id: str) -> dict[str, Any]: client = await self._get_client() resp = await client.get(f"/session/{session_id}") resp.raise_for_status() return resp.json() async def delete_session(self, session_id: str) -> bool: client = await self._get_client() resp = await client.delete(f"/session/{session_id}") resp.raise_for_status() return resp.json() async def send_message(self, session_id: str, text: str) -> dict[str, Any]: client = await self._get_client() payload = { "parts": [{"type": "text", "text": text}] } resp = await client.post(f"/session/{session_id}/message", json=payload) resp.raise_for_status() return resp.json() async def send_message_async(self, session_id: str, text: str) -> None: client = await self._get_client() payload = { "parts": [{"type": "text", "text": text}] } resp = await client.post(f"/session/{session_id}/prompt_async", json=payload) resp.raise_for_status() async def abort_session(self, session_id: str) -> bool: client = await self._get_client() resp = await client.post(f"/session/{session_id}/abort") resp.raise_for_status() return resp.json() async def get_session_status(self) -> dict[str, Any]: client = await self._get_client() resp = await client.get("/session/status") resp.raise_for_status() return resp.json() opencode_client = OpenCodeClient()