From 6b8f5f90dfe25569b2ba55e6c74889e7385c37ad Mon Sep 17 00:00:00 2001 From: jxxghp Date: Fri, 2 Oct 2026 23:10:42 +0800 Subject: [PATCH] fix(agent): type and cover encoded api bodies --- app/agent/tools/impl/api.py | 2 +- tests/test_agent_api_gateway.py | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/app/agent/tools/impl/api.py b/app/agent/tools/impl/api.py index 04e1ba7b2..222a15e35 100644 --- a/app/agent/tools/impl/api.py +++ b/app/agent/tools/impl/api.py @@ -80,7 +80,7 @@ class MoviePilotApiInput(BaseModel): # type: ignore[misc] ), ) - @field_validator("body", mode="before") + @field_validator("body", mode="before") # type: ignore[misc] @classmethod def _restore_json_string_body(cls, value: Any) -> Any: """模型在联合类型 schema 下可能把 body 编码为 JSON 字符串,入模前还原。""" diff --git a/tests/test_agent_api_gateway.py b/tests/test_agent_api_gateway.py index cea600e17..281576155 100644 --- a/tests/test_agent_api_gateway.py +++ b/tests/test_agent_api_gateway.py @@ -237,6 +237,22 @@ def test_local_agent_tool_restores_json_encoded_object_bodies() -> None: assert isinstance(restored["body"], dict) assert restored["body"]["torrent_in"]["enclosure"] == body["torrent_in"]["enclosure"] + # LangChain 入模同样必须还原,否则 canonical_arguments 通过后仍会在 Pydantic 阶段失败。 + restored_model = MoviePilotApiInput.model_validate( + { + "operation_id": "download.add", + "body": json.dumps(body, ensure_ascii=False), + } + ) + assert isinstance(restored_model.body, dict) + assert restored_model.body["torrent_in"]["enclosure"] == body["torrent_in"]["enclosure"] + + # 固定的 system.upgrade.dev 字面量继续作为唯一合法字符串请求体。 + dev_model = MoviePilotApiInput.model_validate( + {"operation_id": "system.upgrade.dev", "body": "dev"} + ) + assert dev_model.body == "dev" + # 无法还原为对象/数组的非法字符串仍按合同报错。 with pytest.raises(ValueError): tool.canonical_arguments(