fix(llm): handle null LLM content and skip retry on null/model errors

When Kilo gateway + Nvidia NeMo :free model returns content: null
for image inputs, get_json_completion crashed with
'the JSON object must be str, bytes or bytearray, not NoneType'
and retried 5 times (unnecessary).

Fixes:
- _should_retry no longer retries RuntimeError with 'null content'
  (retrying won't help — the model genuinely returned null)
- get_json_completion now raises RuntimeError explicitly when
  content is None, with a clear message (instead of json.loads(None))
This commit is contained in:
2026-06-01 10:17:41 +03:00
parent 9b2d96786d
commit 1a7f368324

View File

@@ -953,12 +953,19 @@ class LLMClient:
# @POST Returns a parsed JSON dictionary.
# @SIDE_EFFECT Calls external LLM API.
def _should_retry(exception: Exception) -> bool:
"""Custom retry predicate that excludes authentication errors."""
"""Custom retry predicate that excludes non-recoverable errors."""
# Don't retry on authentication errors
if isinstance(exception, OpenAIAuthenticationError):
return False
# Retry on rate limit errors and other exceptions
return isinstance(exception, (RateLimitError, Exception))
# Don't retry on null content / model errors — retrying won't help
msg = str(exception).lower()
if "null content" in msg or "none" in msg:
return False
# Retry on rate limit errors
if isinstance(exception, RateLimitError):
return True
# For other exceptions, limit retries
return True
@retry(
stop=stop_after_attempt(5),
@@ -1058,6 +1065,10 @@ class LLMClient:
content = response.choices[0].message.content
logger.debug(f"[get_json_completion] Raw content to parse: {content}")
# LLM returned null content — likely content filter or rate limit
if content is None:
raise RuntimeError("LLM returned null content (content filter or rate limit)")
try:
return json.loads(content)
except json.JSONDecodeError: