import logging
import pytest
from openjiuwen_deepsearch.config.config import LLMConfig
from openjiuwen_deepsearch.llm import llm_wrapper
from openjiuwen_deepsearch.llm import llm_request_adapter
from openjiuwen_deepsearch.llm.llm_request_adapter import (
merge_thinking_extension,
resolve_llm_thinking_enabled,
)
def _llm_config(
*,
base_url: str,
model_name: str = "test-model",
model_type: str = "openai",
extension: dict | None = None,
) -> LLMConfig:
return LLMConfig(
model_name=model_name,
model_type=model_type,
base_url=base_url,
api_key=bytearray(b"test-key"),
extension=extension or {},
)
@pytest.mark.parametrize(
"base_url, model_name",
[
("https://api.deepseek.com", "deepseek-reasoner"),
("https://open.bigmodel.cn/api/paas/v4", "glm-4.7"),
("https://api.moonshot.cn/v1", "kimi-k2"),
("https://ark.cn-beijing.volces.com/api/v3", "doubao-seed"),
("https://api.modelarts-maas.com/v1/chat/completion", "huawei-maas-model"),
("https://api.modelarts-maas.com/v2/chat/completions", "huawei-maas-model"),
],
)
def test_merge_thinking_extension_uses_thinking_type(base_url, model_name):
config = _llm_config(base_url=base_url, model_name=model_name)
result = merge_thinking_extension(config, thinking_enabled=False)
assert result["extra_body"]["thinking"] == {"type": "disabled"}
def test_merge_thinking_extension_uses_dashscope_enable_thinking(caplog):
config = _llm_config(
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
extension={"extra_body": {"thinking": {"type": "enabled"}, "other": 1}},
)
caplog.set_level(logging.WARNING, logger=llm_request_adapter.__name__)
result = merge_thinking_extension(config, thinking_enabled=False)
assert result["extra_body"]["enable_thinking"] is False
assert result["extra_body"]["other"] == 1
assert "thinking" not in result["extra_body"]
assert "Existing thinking fields in LLMConfig.extension are overridden" in caplog.text
assert "extra_body.thinking" in caplog.text
def test_merge_thinking_extension_uses_siliconflow_top_level_field():
config = _llm_config(
base_url="https://api.siliconflow.cn/v1",
model_type="siliconflow",
extension={"extra_body": {"enable_thinking": True}},
)
result = merge_thinking_extension(config, thinking_enabled=False)
assert result["enable_thinking"] is False
assert "extra_body" in result
assert "enable_thinking" not in result["extra_body"]
def test_merge_thinking_extension_uses_huawei_openai_compatible_chat_template_kwargs():
config = _llm_config(
base_url="https://api.modelarts-maas.com/openai/v1",
)
result = merge_thinking_extension(config, thinking_enabled=False)
assert result["extra_body"]["chat_template_kwargs"] == {"enable_thinking": False}
assert "thinking" not in result["extra_body"]
def test_merge_thinking_extension_keeps_original_extension_unchanged():
original_extension = {"extra_body": {"thinking": {"type": "enabled"}}}
config = _llm_config(base_url="https://api.deepseek.com", extension=original_extension)
result = merge_thinking_extension(config, thinking_enabled=False)
assert result["extra_body"]["thinking"] == {"type": "disabled"}
assert original_extension == {"extra_body": {"thinking": {"type": "enabled"}}}
def test_merge_thinking_extension_warns_and_keeps_minimax_extension(caplog):
extension = {"extra_body": {"enable_thinking": True}}
config = _llm_config(base_url="https://api.minimax.io/v1", extension=extension)
caplog.set_level(logging.WARNING, logger=llm_request_adapter.__name__)
result = merge_thinking_extension(config, thinking_enabled=False)
assert result == extension
assert "does not support thinking switch" in caplog.text
assert "minimax" in caplog.text
def test_resolve_llm_thinking_enabled_accepts_runtime_service_config():
assert resolve_llm_thinking_enabled({"llm_thinking_enabled": "true"}) is True
assert resolve_llm_thinking_enabled({"llm_thinking_enabled": "false"}) is False
def test_create_llm_obj_passes_merged_extension_to_factory(monkeypatch):
captured = {}
class DummyFactory:
def get_model(self, params):
captured["params"] = params
return object()
monkeypatch.setattr(llm_wrapper, "LLMModelFactory", lambda: DummyFactory())
config = _llm_config(
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
model_name="qwen-plus",
)
result = llm_wrapper.create_llm_obj(config, thinking_enabled=False)
assert result["model_name"] == "qwen-plus"
assert captured["params"].extension["extra_body"]["enable_thinking"] is False
def test_create_llm_obj_skips_thinking_switch_by_default(monkeypatch):
captured = {}
class DummyFactory:
def get_model(self, params):
captured["params"] = params
return object()
monkeypatch.setattr(llm_wrapper, "LLMModelFactory", lambda: DummyFactory())
config = _llm_config(
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
model_name="qwen-plus",
extension={"extra_body": {"original": True}},
)
llm_wrapper.create_llm_obj(config)
assert captured["params"].extension == {"extra_body": {"original": True}}