fix(llm): skip unsupported json_object mode for openrouter stepfun models
This commit is contained in:
@@ -437,6 +437,26 @@ class LLMClient:
|
||||
self.client = AsyncOpenAI(api_key=api_key, base_url=base_url)
|
||||
# [/DEF:LLMClient.__init__:Function]
|
||||
|
||||
# [DEF:LLMClient._supports_json_response_format:Function]
|
||||
# @PURPOSE: Detect whether provider/model is likely compatible with response_format=json_object.
|
||||
# @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
|
||||
return True
|
||||
# [/DEF:LLMClient._supports_json_response_format:Function]
|
||||
|
||||
# [DEF:LLMClient.get_json_completion:Function]
|
||||
# @PURPOSE: Helper to handle LLM calls with JSON mode and fallback parsing.
|
||||
# @PRE: messages is a list of valid message dictionaries.
|
||||
@@ -460,19 +480,34 @@ class LLMClient:
|
||||
with belief_scope("get_json_completion"):
|
||||
response = None
|
||||
try:
|
||||
use_json_mode = self._supports_json_response_format()
|
||||
try:
|
||||
logger.info(f"[get_json_completion] Attempting LLM call with JSON mode for model: {self.default_model}")
|
||||
logger.info(
|
||||
f"[get_json_completion] Attempting LLM call for model: {self.default_model} "
|
||||
f"(json_mode={'on' if use_json_mode else 'off'})"
|
||||
)
|
||||
logger.info(f"[get_json_completion] Base URL being used: {self.base_url}")
|
||||
logger.info(f"[get_json_completion] Number of messages: {len(messages)}")
|
||||
logger.info(f"[get_json_completion] API Key present: {bool(self.api_key and len(self.api_key) > 0)}")
|
||||
|
||||
response = await self.client.chat.completions.create(
|
||||
model=self.default_model,
|
||||
messages=messages,
|
||||
response_format={"type": "json_object"}
|
||||
)
|
||||
|
||||
if use_json_mode:
|
||||
response = await self.client.chat.completions.create(
|
||||
model=self.default_model,
|
||||
messages=messages,
|
||||
response_format={"type": "json_object"}
|
||||
)
|
||||
else:
|
||||
response = await self.client.chat.completions.create(
|
||||
model=self.default_model,
|
||||
messages=messages
|
||||
)
|
||||
except Exception as e:
|
||||
if "JSON mode is not enabled" in str(e) or "400" in str(e):
|
||||
if use_json_mode and (
|
||||
"JSON mode is not enabled" in str(e)
|
||||
or "json_object is not supported" in str(e).lower()
|
||||
or "response_format" in str(e).lower()
|
||||
or "400" in str(e)
|
||||
):
|
||||
logger.warning(f"[get_json_completion] JSON mode failed or not supported: {str(e)}. Falling back to plain text response.")
|
||||
response = await self.client.chat.completions.create(
|
||||
model=self.default_model,
|
||||
|
||||
Reference in New Issue
Block a user