diff --git a/relay/relay.py b/relay/relay.py index 3c90a44..b2d212b 100644 --- a/relay/relay.py +++ b/relay/relay.py @@ -7,7 +7,7 @@ AGENT_URL = os.getenv("AGENT_URL", "http://ai-agent:8080") OPENAI_MODEL = os.getenv("OPENAI_MODEL", "gpt-4o-mini") def _read_api_key(): - # Prefer file from Docker secret if present + # Prefer Docker secret if available path = os.getenv("OPENAI_API_KEY_FILE", "/run/secrets/openai_api_key") if os.path.exists(path): return open(path, "r").read().strip() @@ -18,7 +18,7 @@ SYSTEM_PROMPT = ( "with fields: action (scale|restart_service), params (dict). No prose. Examples: " '{"action":"scale","params":{"service":"weblabs_php","replicas":3}} ' 'or {"action":"restart_service","params":{"service":"weblabs_php"}}. ' - "Only produce valid JSON. If unclear, choose the safest no-op." + "Only produce valid JSON." ) class ChatIn(BaseModel): @@ -36,14 +36,16 @@ async def chat(inp: ChatIn): if not api_key: raise HTTPException(500, "Missing OPENAI_API_KEY (env or secret).") - # Call OpenAI Responses API - url = "https://api.openai.com/v1/responses" + url = "https://api.openai.com/v1/chat/completions" headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"} body = { "model": OPENAI_MODEL, - "input": f"{SYSTEM_PROMPT}\nUSER: {inp.prompt}", - "max_output_tokens": 300, - "temperature": 0.1 + "response_format": {"type": "json_object"}, + "temperature": 0.1, + "messages": [ + {"role": "system", "content": SYSTEM_PROMPT}, + {"role": "user", "content": inp.prompt}, + ], } async with httpx.AsyncClient(timeout=30) as client: @@ -51,22 +53,12 @@ async def chat(inp: ChatIn): if r.status_code >= 400: raise HTTPException(502, f"OpenAI error: {r.text}") data = r.json() - # Responses API returns output in 'output_text' (or tool messages). Try common fields. - content = data.get("output_text") or data.get("content") or "" - if isinstance(content, list): - # Some responses return a list of content parts; take text from first text part - for part in content: - if part.get("type") in ("output_text", "text") and part.get("text"): - content = part["text"] - break - if not isinstance(content, str): - content = str(content) - # Parse JSON from the model output try: + content = data["choices"][0]["message"]["content"] cmd = json.loads(content) except Exception as e: - raise HTTPException(500, f"Failed to parse model JSON: {e}; content={content[:200]}") + raise HTTPException(500, f"Failed to parse model JSON: {e}; raw={str(data)[:300]}") # Forward to the agent async with httpx.AsyncClient(timeout=15) as client: