deer-flow/backend/tests/test_patched_mimo.py
AochenShen99 44677c5eb4
feat(provider) Add patched MiMo reasoning content support (#3298)
* Add patched MiMo reasoning content support

* Clarify MiMo patched model coverage

* Remove unused MiMo payload index

* Address MiMo review nits
2026-05-28 18:24:32 +08:00

170 lines
5.2 KiB
Python

"""Tests for deerflow.models.patched_mimo.PatchedChatMiMo."""
from __future__ import annotations
from unittest.mock import MagicMock, patch
from langchain_core.messages import AIMessage, AIMessageChunk, HumanMessage
def _make_model(**kwargs):
from deerflow.models.patched_mimo import PatchedChatMiMo
return PatchedChatMiMo(
model="mimo-v2.5-pro",
api_key="test-key",
base_url="https://api.xiaomimimo.com/v1",
**kwargs,
)
def test_is_lc_serializable_returns_true():
from deerflow.models.patched_mimo import PatchedChatMiMo
assert PatchedChatMiMo.is_lc_serializable() is True
def test_lc_secrets_contains_mimo_api_key_mapping():
model = _make_model()
assert model.lc_secrets["api_key"] == "MIMO_API_KEY"
assert model.lc_secrets["openai_api_key"] == "MIMO_API_KEY"
def test_reasoning_content_injected_into_assistant_tool_call_message():
model = _make_model()
human = HumanMessage(content="Check Beijing weather.")
ai = AIMessage(
content="",
additional_kwargs={"reasoning_content": "I need to call the weather tool."},
)
payload_message = {
"role": "assistant",
"content": "",
"tool_calls": [
{
"id": "call_weather",
"type": "function",
"function": {"name": "get_weather", "arguments": '{"location":"Beijing"}'},
}
],
}
base_payload = {
"messages": [
{"role": "user", "content": "Check Beijing weather."},
payload_message,
]
}
with patch.object(type(model).__bases__[0], "_get_request_payload", return_value=base_payload):
with patch.object(model, "_convert_input") as mock_convert:
mock_convert.return_value = MagicMock(to_messages=lambda: [human, ai])
payload = model._get_request_payload([human, ai])
assert payload["messages"][1]["reasoning_content"] == "I need to call the weather tool."
def test_reasoning_content_is_noop_when_missing():
model = _make_model()
human = HumanMessage(content="hello")
ai = AIMessage(content="hi", additional_kwargs={})
base_payload = {
"messages": [
{"role": "user", "content": "hello"},
{"role": "assistant", "content": "hi"},
]
}
with patch.object(type(model).__bases__[0], "_get_request_payload", return_value=base_payload):
with patch.object(model, "_convert_input") as mock_convert:
mock_convert.return_value = MagicMock(to_messages=lambda: [human, ai])
payload = model._get_request_payload([human, ai])
assert "reasoning_content" not in payload["messages"][1]
def test_create_chat_result_maps_message_reasoning_content():
model = _make_model()
response = {
"choices": [
{
"message": {
"role": "assistant",
"content": "The weather is sunny.",
"reasoning_content": "The tool returned sunny weather, so answer directly.",
"tool_calls": None,
},
"finish_reason": "stop",
}
],
"model": "mimo-v2.5-pro",
}
result = model._create_chat_result(response)
message = result.generations[0].message
assert message.content == "The weather is sunny."
assert message.additional_kwargs["reasoning_content"] == "The tool returned sunny weather, so answer directly."
def test_create_chat_result_reads_reasoning_content_from_message_attribute():
model = _make_model()
class FakeMessage:
reasoning_content = "Reasoning stored on the SDK message object."
class FakeChoice:
message = FakeMessage()
class FakeResponse:
choices = [FakeChoice()]
def model_dump(self, **kwargs):
return {
"choices": [
{
"message": {
"role": "assistant",
"content": "Answer.",
},
"finish_reason": "stop",
}
],
"model": "mimo-v2.5-pro",
}
result = model._create_chat_result(FakeResponse())
assert result.generations[0].message.additional_kwargs["reasoning_content"] == "Reasoning stored on the SDK message object."
def test_convert_chunk_to_generation_chunk_preserves_reasoning_deltas():
model = _make_model()
first = model._convert_chunk_to_generation_chunk(
{"choices": [{"delta": {"role": "assistant", "reasoning_content": "I need "}}]},
AIMessageChunk,
{},
)
second = model._convert_chunk_to_generation_chunk(
{"choices": [{"delta": {"reasoning_content": "a tool."}}]},
AIMessageChunk,
{},
)
answer = model._convert_chunk_to_generation_chunk(
{"choices": [{"delta": {"content": "Done."}, "finish_reason": "stop"}], "model": "mimo-v2.5-pro"},
AIMessageChunk,
{},
)
assert first is not None
assert second is not None
assert answer is not None
combined = first.message + second.message + answer.message
assert combined.additional_kwargs["reasoning_content"] == "I need a tool."
assert combined.content == "Done."