fix(agent): content 为空时回退 reasoning_content(修思考模型空响应)
CI / guardrails (push) Successful in 6s
CI / tests (push) Successful in 44s
CI / guardrails (pull_request) Successful in 5s
CI / tests (pull_request) Successful in 39s

qwen3.7-max 思考模型常返回空 message.content、答案在 reasoning_content。原代码只读
content → 拿到 "" → json.loads("") → "Expecting value: line 1 column 1 (char 0)" → 任务失败。
新增 _message_text():content → reasoning_content(attr 或 OpenAI SDK model_extra)回退,
_complete 两个返回点都用它。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
gongzhiyong
2026-06-22 03:39:06 +08:00
co-authored by Claude Opus 4.8
parent c5595cf344
commit c4c2116122
+17 -2
View File
@@ -595,6 +595,21 @@ Return ONLY the JSON, no other text."""
except Exception as exc:
return f"[tool error: {exc}]"
@staticmethod
def _message_text(msg) -> str:
"""Robustly extract the assistant's textual answer. qwen3.7-max (a THINKING model) can return
an empty `content` with the real answer in `reasoning_content`; reading only `content` then
yields "" → `json.loads("")` → "Expecting value: line 1 column 1 (char 0)" → task fails.
Fallback chain: content → reasoning_content (attribute or OpenAI-SDK model_extra)."""
text = (getattr(msg, "content", None) or "").strip()
if text:
return text
rc = getattr(msg, "reasoning_content", None)
if not rc:
extra = getattr(msg, "model_extra", None) or {}
rc = extra.get("reasoning_content") if isinstance(extra, dict) else None
return (rc or "").strip()
async def _complete(self, prompt: str, max_tokens: int) -> str:
"""Call the LLM with optional Jina MCP tools; handles the tool-call loop."""
extra_headers = self._model_attribution_headers()
@@ -620,7 +635,7 @@ Return ONLY the JSON, no other text."""
logger.info("[LLM·第%d轮] 思考/回复:\n%s", round_i + 1, msg.content.strip()[:1200])
if not msg.tool_calls:
return msg.content or ""
return self._message_text(msg)
# Execute each tool call and feed results back
messages.append(msg.model_dump(exclude_unset=True))
@@ -646,7 +661,7 @@ Return ONLY the JSON, no other text."""
extra_headers=extra_headers or None,
)
self._record_openai_usage(response)
return response.choices[0].message.content or ""
return self._message_text(response.choices[0].message)
async def peer_reply(self, *, query: str, capabilities: list[str],
last_summary: Optional[str], max_tokens: Optional[int] = None) -> dict: