fix(translate): handle invalid LLM JSON responses
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
# Only capath-based ssl.create_default_context() works with OpenSSL 3.x intermediates.
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import ssl
|
||||
from typing import Any
|
||||
|
||||
@@ -115,7 +116,12 @@ def sanitize_url(url: str) -> str:
|
||||
# @BRIEF Call OpenAI-compatible API asynchronously with rate-limit handling and structured output fallback.
|
||||
# @PRE Valid API endpoint, key, model, and prompt.
|
||||
# @POST Returns (response text, finish_reason).
|
||||
# @RAISES ValueError when the provider returns an invalid JSON response body.
|
||||
# @SIDE_EFFECT Async HTTP POST to LLM API with optional retry on 429.
|
||||
# @RATIONALE Normalize malformed successful HTTP bodies into a stable provider error so
|
||||
# preview and execution callers do not leak raw JSONDecodeError details.
|
||||
# @REJECTED Letting response.json() propagate raw decode failures was rejected — it
|
||||
# obscures the upstream failure and prevents callers from classifying the provider error.
|
||||
# @REJECTED Keeping sync requests.post — would block async event loop during LLM calls.
|
||||
# Per-request httpx.AsyncClient — loses connection pooling.
|
||||
async def call_openai_compatible(
|
||||
@@ -177,7 +183,20 @@ async def call_openai_compatible(
|
||||
extra={"src": "SharedLlmHttpClient"},
|
||||
)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
try:
|
||||
data = response.json()
|
||||
except (json.JSONDecodeError, ValueError) as exc:
|
||||
logger.explore(
|
||||
"LLM provider returned an invalid JSON response",
|
||||
extra={
|
||||
"src": "SharedLlmHttpClient",
|
||||
"status_code": response.status_code,
|
||||
"content_type": response.headers.get("content-type"),
|
||||
"response_preview": (response_text or "")[:2000],
|
||||
},
|
||||
error=f"{type(exc).__name__}: {exc}",
|
||||
)
|
||||
raise ValueError("LLM provider returned an invalid JSON response") from exc
|
||||
|
||||
choices = data.get("choices", [])
|
||||
if not choices:
|
||||
|
||||
Reference in New Issue
Block a user