From 0f9eba4de0b69165c33bba9e725d5d7aa6ee66ff Mon Sep 17 00:00:00 2001 From: Ishaan Jaffer Date: Fri, 10 Apr 2026 11:43:02 -0700 Subject: [PATCH] test(anthropic): add advisor tool transformation tests --- .../test_anthropic_chat_transformation.py | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/tests/test_litellm/llms/anthropic/chat/test_anthropic_chat_transformation.py b/tests/test_litellm/llms/anthropic/chat/test_anthropic_chat_transformation.py index 10a3c107367..8fa679a7ac7 100644 --- a/tests/test_litellm/llms/anthropic/chat/test_anthropic_chat_transformation.py +++ b/tests/test_litellm/llms/anthropic/chat/test_anthropic_chat_transformation.py @@ -12,6 +12,7 @@ from litellm.llms.anthropic.chat.transformation import AnthropicConfig from litellm.llms.anthropic.experimental_pass_through.messages.transformation import ( AnthropicMessagesConfig, ) +from litellm.types.llms.anthropic import ANTHROPIC_BETA_HEADER_VALUES from litellm.types.utils import ServerToolUse @@ -3399,3 +3400,106 @@ def test_extract_response_content_thinking_block_null_thinking(): assert len(thinking_blocks) == 1 assert thinking_blocks[0]["thinking"] == "Let me think..." assert "Done" in text + + +def test_advisor_tool_map_tool_helper(): + """advisor_20260301 tool type should not raise ValueError.""" + config = AnthropicConfig() + tool = { + "type": "advisor_20260301", + "name": "advisor", + "model": "claude-opus-4-6", + } + returned_tool, mcp_server = config._map_tool_helper(tool) # type: ignore + assert returned_tool is not None + assert returned_tool["type"] == "advisor_20260301" + assert returned_tool["model"] == "claude-opus-4-6" + assert mcp_server is None + + +def test_advisor_tool_map_tool_helper_with_optional_fields(): + """advisor_20260301 tool with max_uses and caching should be mapped correctly.""" + config = AnthropicConfig() + tool = { + "type": "advisor_20260301", + "name": "advisor", + "model": "claude-opus-4-6", + "max_uses": 3, + "caching": {"type": "ephemeral", "ttl": "5m"}, + } + returned_tool, _ = config._map_tool_helper(tool) # type: ignore + assert returned_tool is not None + assert returned_tool["max_uses"] == 3 + assert returned_tool["caching"] == {"type": "ephemeral", "ttl": "5m"} + + +def test_advisor_tool_map_tool_helper_missing_model(): + """advisor_20260301 without model should raise ValueError.""" + config = AnthropicConfig() + tool = {"type": "advisor_20260301", "name": "advisor"} + with pytest.raises(ValueError, match="valid model"): + config._map_tool_helper(tool) # type: ignore + + +def test_advisor_beta_header_injected(): + """advisor-tool-2026-03-01 beta header is auto-injected when advisor tool is present.""" + config = AnthropicConfig() + headers: dict = {} + optional_params = { + "tools": [ + { + "type": "advisor_20260301", + "name": "advisor", + "model": "claude-opus-4-6", + } + ] + } + result = config.update_headers_with_optional_anthropic_beta(headers, optional_params) + assert ANTHROPIC_BETA_HEADER_VALUES.ADVISOR_TOOL_2026_03_01.value in result.get( + "anthropic-beta", "" + ) + + +def test_advisor_beta_header_not_injected_without_tool(): + """advisor-tool-2026-03-01 beta header is NOT added when advisor tool is absent.""" + config = AnthropicConfig() + headers: dict = {} + optional_params: dict = {"tools": []} + result = config.update_headers_with_optional_anthropic_beta(headers, optional_params) + assert "advisor-tool-2026-03-01" not in result.get("anthropic-beta", "") + + +def test_advisor_tool_result_preserved_in_response(): + """advisor_tool_result blocks are preserved in tool_results (not dropped).""" + config = AnthropicConfig() + completion_response = { + "content": [ + {"type": "text", "text": "Consulting advisor."}, + { + "type": "server_tool_use", + "id": "srvtoolu_abc123", + "name": "advisor", + "input": {}, + }, + { + "type": "advisor_tool_result", + "tool_use_id": "srvtoolu_abc123", + "content": {"type": "advisor_result", "text": "Use a channel-based pattern."}, + }, + {"type": "text", "text": "Here is the implementation."}, + ] + } + text, _, _, _, tool_calls, _, tool_results, _ = config.extract_response_content( + completion_response + ) + assert "Consulting advisor." in text + assert "Here is the implementation." in text + # server_tool_use (advisor) should be a tool_call + assert len(tool_calls) == 1 + assert tool_calls[0]["function"]["name"] == "advisor" + assert tool_calls[0]["id"] == "srvtoolu_abc123" + # advisor_tool_result should be in tool_results + assert tool_results is not None + assert len(tool_results) == 1 + assert tool_results[0]["type"] == "advisor_tool_result" + assert tool_results[0]["tool_use_id"] == "srvtoolu_abc123"