From 4376354aecbcdd3dd348baca94ed5a2020670de3 Mon Sep 17 00:00:00 2001 From: busya Date: Mon, 1 Jun 2026 08:27:14 +0300 Subject: [PATCH] fix(llm): disable json_object mode for :free models on any gateway The _supports_json_response_format check only looked for 'openrouter.ai' in base_url, missing the Kilo gateway ('api.kilo.ai'). Free-tier models routed through ANY gateway (Nvidia NeMo :free via OpenRouter OR Kilo) reject json_object response format, causing the LLM to return content: null. Error: 'the JSON object must be str, bytes or bytearray, not NoneType' Fix: check model name for ':free' and 'stepfun/' directly, regardless of gateway. This covers OpenRouter, Kilo, and any future gateway. --- backend/src/plugins/llm_analysis/service.py | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/backend/src/plugins/llm_analysis/service.py b/backend/src/plugins/llm_analysis/service.py index 5c4ca40a..70bebe54 100644 --- a/backend/src/plugins/llm_analysis/service.py +++ b/backend/src/plugins/llm_analysis/service.py @@ -935,18 +935,15 @@ class LLMClient: # @PRE Client initialized with base_url and default_model. # @POST Returns False for known-incompatible combinations to avoid avoidable 400 errors. def _supports_json_response_format(self) -> bool: - base = (self.base_url or "").lower() model = (self.default_model or "").lower() - # OpenRouter routes to many upstream providers; some models reject json_object mode. - if "openrouter.ai" in base: - incompatible_tokens = ( - "stepfun/", - "step-", - ":free", - ) - if any(token in model for token in incompatible_tokens): - return False + # Free-tier models from ANY gateway often reject json_object mode + # (Nvidia NeMo free via OpenRouter or Kilo, stepfun free, etc.) + if ":free" in model: + return False + # stepfun models (even non-free) don't support json_object mode + if "stepfun/" in model or model.startswith("step-"): + return False return True # endregion LLMClient._supports_json_response_format