from types import SimpleNamespace
import pytest
from pydantic import ValidationError
from server.schemas.deepsearch_run import DeepSearchRequest
def _build_request() -> DeepSearchRequest:
"""构造 DeepSearch 路由测试所需的最小请求对象。
Returns:
DeepSearchRequest: 可用于 `_prepare_stream_context` 的请求对象。
"""
return DeepSearchRequest(
space_id="space-1",
conversation_id="conversation-1",
message="hello",
llm_config={
"general": {
"model_name": "mock-model",
"model_type": "openai",
"base_url": "https://example.com/v1",
"api_key": "secret",
}
},
web_search_config={
"web_search_config_id": 1,
"max_web_search_results": 5,
},
info_collector_search_method="web",
search_mode="research",
execution_method="parallel",
)
def test_deep_search_request_accepts_agent_llm_timeouts():
"""验证请求模型允许传入按 agent 配置的 LLM 总超时。
Returns:
None.
"""
request = DeepSearchRequest(
space_id="space-1",
conversation_id="conversation-1",
message="hello",
llm_config={
"general": {
"model_name": "mock-model",
"model_type": "openai",
"base_url": "https://example.com/v1",
"api_key": "secret",
}
},
web_search_config={
"web_search_config_id": 1,
"max_web_search_results": 5,
},
info_collector_search_method="web",
search_mode="research",
execution_method="parallel",
agent_llm_timeouts={"default": 300, "sub_reporter": 120},
)
assert request.agent_llm_timeouts == {"default": 300, "sub_reporter": 120}
def test_deep_search_request_rejects_invalid_conversation_id():
with pytest.raises(ValidationError) as exc_info:
DeepSearchRequest(
space_id="space-1",
conversation_id="has space",
message="hello",
llm_config={
"general": {
"model_name": "mock-model",
"model_type": "openai",
"base_url": "https://example.com/v1",
"api_key": "secret",
}
},
web_search_config={
"web_search_config_id": 1,
"max_web_search_results": 5,
},
info_collector_search_method="web",
search_mode="research",
execution_method="parallel",
)
assert "conversation_id" in str(exc_info.value)
def test_agent_llm_timeouts_no_longer_validate_at_request_boundary():
"""验证请求模型不再在入口层校验 agent_llm_timeouts。
Returns:
None.
"""
request = DeepSearchRequest(
space_id="space-1",
conversation_id="conversation-1",
message="hello",
llm_config={
"general": {
"model_name": "mock-model",
"model_type": "openai",
"base_url": "https://example.com/v1",
"api_key": "secret",
}
},
web_search_config={
"web_search_config_id": 1,
"max_web_search_results": 5,
},
info_collector_search_method="web",
search_mode="research",
execution_method="parallel",
agent_llm_timeouts={"sub_reporter": -120},
)
assert request.agent_llm_timeouts == {"sub_reporter": -120}
def test_prepare_stream_context_builds_agent_config_once(monkeypatch):
"""验证流式上下文准备阶段只构建一次 agent 配置。
Args:
monkeypatch: pytest 提供的运行时打桩工具。
Returns:
None.
"""
from server.routers import deepsearch_run
fake_agent = SimpleNamespace(research_name="demo")
fake_config = {
"search_mode": "research",
"execution_method": "parallel",
}
build_call_count = 0
deepsearch_run.agent_manager._agent_cache.clear()
def _fake_build_agent_config(request: DeepSearchRequest, db):
"""记录配置构建次数并返回伪配置。
Args:
request: DeepSearch 请求对象。
db: 数据库会话对象。
Returns:
dict: 供测试使用的最小 agent 配置。
"""
del request, db
nonlocal build_call_count
build_call_count += 1
return fake_config
monkeypatch.setattr(deepsearch_run.agent_manager, "build_agent_config", _fake_build_agent_config)
monkeypatch.setattr(
deepsearch_run.agent_manager._agent_factory,
"create_agent",
lambda config: fake_agent,
)
request, agent, run_kwargs = deepsearch_run._prepare_stream_context(_build_request(), object())
assert request.conversation_id == "conversation-1"
assert agent is fake_agent
assert run_kwargs["agent_config"] == fake_config
assert build_call_count == 1