fitness-web/app/services/opencode_proxy.py

54 lines
1.5 KiB
Python

import asyncio
import json
import logging
from typing import AsyncGenerator
from app.config import OPENCODE_SERVE_URL
logger = logging.getLogger("opencode_proxy")
class OpenCodeUnavailableError(Exception):
pass
async def query_opencode(
message: str,
session_id: str,
user_context: str = "",
) -> AsyncGenerator[str, None]:
prompt = message
if user_context:
prompt = f"[User context: {user_context}]\n\n{message}"
try:
proc = await asyncio.create_subprocess_exec(
"opencode", "run", "--attach", OPENCODE_SERVE_URL,
"--format", "json",
prompt,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
)
while True:
line = await proc.stdout.readline()
if not line:
break
line = line.decode().strip()
if line:
try:
data = json.loads(line)
content = data.get("content", data.get("text", line))
yield content
except json.JSONDecodeError:
yield line
await proc.wait()
except FileNotFoundError:
logger.error("opencode binary not found in PATH")
raise OpenCodeUnavailableError(
"opencode binary not found. Install opencode or run `opencode serve`."
)
except Exception as e:
logger.error("opencode proxy error: %s", e)
raise OpenCodeUnavailableError(f"AI coach unavailable: {e}")