diff --git a/app/agent/tools/impl/api.py b/app/agent/tools/impl/api.py index c5e39f740..c24e6776f 100644 --- a/app/agent/tools/impl/api.py +++ b/app/agent/tools/impl/api.py @@ -83,11 +83,15 @@ class MoviePilotApiTool(MoviePilotTool): ] description: str = ( "Call allowlisted MoviePilot business APIs, including versioned automatic media classification. " - "Use the domain Skill to select operation_id, " + "Read the matching domain Skill before the first call, then select operation_id, " "parameters, and failure handling. For collection counts, use the smallest documented " "page and read collection.total_count instead of querying the database after item " "truncation. External MCP tools/list exposes one complete oneOf branch per operation. " - "Arbitrary URLs, commands, and authentication endpoints are forbidden." + "Common contracts: subscription.find uses path_params.media_id and query.media_source; " + "subscription.list accepts only query.page and query.count; site.list accepts only " + "query.page, query.count, query.name, and query.status; download.add puts torrent_in " + "with title/enclosure beside media_source/media_id in body. Arbitrary URLs, commands, " + "and authentication endpoints are forbidden." ) require_admin: bool = False args_schema: Type[BaseModel] = MoviePilotApiInput diff --git a/tests/test_agent_api_gateway.py b/tests/test_agent_api_gateway.py index 588ad819a..c1c5df4ee 100644 --- a/tests/test_agent_api_gateway.py +++ b/tests/test_agent_api_gateway.py @@ -148,6 +148,16 @@ def test_api_tool_message_displays_secret_safe_major_parameters() -> None: assert "sk-secret-value" not in secret_message +def test_api_tool_description_keeps_split_skill_contracts_visible_at_call_time() -> None: + """即使模型尚未读取 Skill,网关描述也要提示最容易误用的字段位置。""" + description = MoviePilotApiTool(session_id="session", user_id="api_user").description + + assert "subscription.find uses path_params.media_id" in description + assert "subscription.list accepts only query.page and query.count" in description + assert "site.list accepts only query.page, query.count, query.name, and query.status" in description + assert "download.add puts torrent_in" in description + + def test_music_operations_expose_bidirectional_artist_album_navigation() -> None: """音乐 Skill 必须完整暴露作品到作者、作者到作品及关联浏览合同。""" schema = MoviePilotApiTool(session_id="session", user_id="api_user").get_mcp_input_schema()