mirror of
https://github.com/zhayujie/chatgpt-on-wechat.git
synced 2026-06-02 00:57:41 +08:00
fix(mimo): round-trip reasoning_content for thinking-mode providers
This commit is contained in:
@@ -249,24 +249,49 @@ class OpenAICompatibleBot:
|
|||||||
def _convert_messages_to_openai_format(self, messages):
|
def _convert_messages_to_openai_format(self, messages):
|
||||||
"""
|
"""
|
||||||
Convert messages from Claude format to OpenAI format
|
Convert messages from Claude format to OpenAI format
|
||||||
|
|
||||||
Claude uses content blocks with types like 'tool_use', 'tool_result'
|
Claude content blocks (tool_use / tool_result / thinking) → OpenAI
|
||||||
OpenAI uses 'tool_calls' in assistant messages and 'tool' role for results
|
tool_calls / tool role / reasoning_content. Some thinking-mode
|
||||||
|
providers require reasoning_content on assistant messages after a
|
||||||
|
tool_call appears in history; back-fill with empty string when the
|
||||||
|
trace was not captured.
|
||||||
"""
|
"""
|
||||||
if not messages:
|
if not messages:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
# Detect any prior tool-call turn — gates reasoning_content back-fill below.
|
||||||
|
has_tool_call_history = False
|
||||||
|
for msg in messages:
|
||||||
|
if msg.get("role") != "assistant":
|
||||||
|
continue
|
||||||
|
if msg.get("tool_calls"):
|
||||||
|
has_tool_call_history = True
|
||||||
|
break
|
||||||
|
inner = msg.get("content")
|
||||||
|
if isinstance(inner, list) and any(
|
||||||
|
isinstance(b, dict) and b.get("type") == "tool_use" for b in inner
|
||||||
|
):
|
||||||
|
has_tool_call_history = True
|
||||||
|
break
|
||||||
|
|
||||||
openai_messages = []
|
openai_messages = []
|
||||||
|
|
||||||
for msg in messages:
|
for msg in messages:
|
||||||
role = msg.get("role")
|
role = msg.get("role")
|
||||||
content = msg.get("content")
|
content = msg.get("content")
|
||||||
|
|
||||||
# Handle string content (already in correct format)
|
# Handle string content (already in correct format)
|
||||||
if isinstance(content, str):
|
if isinstance(content, str):
|
||||||
openai_messages.append(msg)
|
if (role == "assistant" and has_tool_call_history
|
||||||
|
and isinstance(msg, dict)
|
||||||
|
and "reasoning_content" not in msg):
|
||||||
|
patched = dict(msg)
|
||||||
|
patched["reasoning_content"] = ""
|
||||||
|
openai_messages.append(patched)
|
||||||
|
else:
|
||||||
|
openai_messages.append(msg)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Handle list content (Claude format with content blocks)
|
# Handle list content (Claude format with content blocks)
|
||||||
if isinstance(content, list):
|
if isinstance(content, list):
|
||||||
# Check if this is a tool result message (user role with tool_result blocks)
|
# Check if this is a tool result message (user role with tool_result blocks)
|
||||||
@@ -305,14 +330,17 @@ class OpenAICompatibleBot:
|
|||||||
|
|
||||||
# Check if this is an assistant message with tool_use blocks
|
# Check if this is an assistant message with tool_use blocks
|
||||||
elif role == "assistant":
|
elif role == "assistant":
|
||||||
# Separate text content and tool_use blocks
|
|
||||||
text_parts = []
|
text_parts = []
|
||||||
tool_calls = []
|
tool_calls = []
|
||||||
|
reasoning_parts = []
|
||||||
|
|
||||||
for block in content:
|
for block in content:
|
||||||
if block.get("type") == "text":
|
if not isinstance(block, dict):
|
||||||
|
continue
|
||||||
|
btype = block.get("type")
|
||||||
|
if btype == "text":
|
||||||
text_parts.append(block.get("text", ""))
|
text_parts.append(block.get("text", ""))
|
||||||
elif block.get("type") == "tool_use":
|
elif btype == "tool_use":
|
||||||
tool_id = block.get("id") or ""
|
tool_id = block.get("id") or ""
|
||||||
if not tool_id:
|
if not tool_id:
|
||||||
logger.warning(f"[OpenAICompatible] tool_use missing id for '{block.get('name')}'")
|
logger.warning(f"[OpenAICompatible] tool_use missing id for '{block.get('name')}'")
|
||||||
@@ -324,6 +352,8 @@ class OpenAICompatibleBot:
|
|||||||
"arguments": json.dumps(block.get("input", {}))
|
"arguments": json.dumps(block.get("input", {}))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
elif btype == "thinking":
|
||||||
|
reasoning_parts.append(block.get("thinking", ""))
|
||||||
|
|
||||||
# Build OpenAI format assistant message
|
# Build OpenAI format assistant message
|
||||||
openai_msg = {
|
openai_msg = {
|
||||||
@@ -334,6 +364,13 @@ class OpenAICompatibleBot:
|
|||||||
if tool_calls:
|
if tool_calls:
|
||||||
openai_msg["tool_calls"] = tool_calls
|
openai_msg["tool_calls"] = tool_calls
|
||||||
|
|
||||||
|
# Round-trip reasoning_content; empty string when missing
|
||||||
|
# after a tool-call turn keeps strict providers happy.
|
||||||
|
if reasoning_parts:
|
||||||
|
openai_msg["reasoning_content"] = "\n".join(reasoning_parts)
|
||||||
|
elif has_tool_call_history:
|
||||||
|
openai_msg["reasoning_content"] = ""
|
||||||
|
|
||||||
if msg.get("_gemini_raw_parts"):
|
if msg.get("_gemini_raw_parts"):
|
||||||
openai_msg["_gemini_raw_parts"] = msg["_gemini_raw_parts"]
|
openai_msg["_gemini_raw_parts"] = msg["_gemini_raw_parts"]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user