54 lines
1.5 KiB
Python
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}")
|