fix(api): 修复LLM manage端点目录查询返回列表无法透过Dict响应模型校验导致设置页500

This commit is contained in:
jxxghp
2026-08-16 08:27:21 +08:00
parent cd5b85eb6c
commit 98276a68a8
3 changed files with 35 additions and 2 deletions
+4 -2
View File
@@ -1,4 +1,4 @@
from typing import Any, Dict, Optional from typing import Any, Dict, List, Optional, Union
from fastapi import Depends, Request, Response from fastapi import Depends, Request, Response
from fastapi.responses import HTMLResponse from fastapi.responses import HTMLResponse
@@ -15,7 +15,9 @@ router = ResponseAPIRouter()
@router.post( @router.post(
"/manage", "/manage",
summary="LLM提供商统一管理", summary="LLM提供商统一管理",
response_model=schemas.Response[Dict[str, Any]], # 各动作 data 形态不一:目录查询返回列表,其余动作返回映射,
# 须用具体联合类型声明,而非单一开放映射
response_model=schemas.Response[Union[List[Dict[str, Any]], Dict[str, Any]]],
) )
async def manage_provider( async def manage_provider(
request: Request, request: Request,
+2
View File
@@ -637,6 +637,8 @@ def test_openapi_success_models_have_no_implicit_empty_nested_schemas():
"ManageRequest", "ManageRequest",
# 通用管理响应的 data 为模块自定义结构,按设计不固定字段。 # 通用管理响应的 data 为模块自定义结构,按设计不固定字段。
"Response_Dict_str__Any__", "Response_Dict_str__Any__",
# LLM 提供商管理响应的 data 目录查询为列表、其余动作为映射。
"Response_Union_List_Dict_str__Any____Dict_str__Any___",
} }
allowed_empty_components = {"McpJsonRpcEmptyResult"} allowed_empty_components = {"McpJsonRpcEmptyResult"}
violations = [] violations = []
+29
View File
@@ -279,3 +279,32 @@ def test_llm_manage_endpoint_accepts_empty_target(monkeypatch):
assert resp.success is True assert resp.success is True
assert captured["provider"] == "" assert captured["provider"] == ""
assert "callback_url" not in captured["params"] assert "callback_url" not in captured["params"]
def test_llm_manage_endpoint_response_model_accepts_list_data():
"""目录查询动作 data 为列表,响应模型须同时覆盖列表与映射形态。
回归守护:list_providers 返回 list[dict]
若响应模型声明为 Dict[str, Any] 会在序列化校验时直接 500;
同时受响应模型守护测试约束,不得使用 Any/JsonData 弱类型。
"""
from typing import Any, Dict, List, Union
from app.api.endpoints import llm as llm_endpoint
route = next(
r for r in llm_endpoint.router.routes if getattr(r, "path", "").endswith("/manage")
)
assert route.response_model is schemas.Response[
Union[List[Dict[str, Any]], Dict[str, Any]]
]
list_resp = schemas.Response[Union[List[Dict[str, Any]], Dict[str, Any]]](
success=True, message="", data=[{"id": "openai", "name": "OpenAI 兼容"}]
)
assert list_resp.data == [{"id": "openai", "name": "OpenAI 兼容"}]
dict_resp = schemas.Response[Union[List[Dict[str, Any]], Dict[str, Any]]](
success=True, message="", data={"models": ["gpt-4o"]}
)
assert dict_resp.data == {"models": ["gpt-4o"]}