diff --git a/litellm/llms/snowflake/chat/transformation.py b/litellm/llms/snowflake/chat/transformation.py index e11cab4138d..3e590680a75 100644 --- a/litellm/llms/snowflake/chat/transformation.py +++ b/litellm/llms/snowflake/chat/transformation.py @@ -219,17 +219,32 @@ class SnowflakeConfig(SnowflakeBaseConfig, OpenAIGPTConfig): tool_choice: Tool choice in OpenAI format (str or dict) Returns: - Tool choice in Snowflake format (always an object) + Tool choice in Snowflake format (always an object, never a string) - OpenAI format (string): "auto", "required", "none" - OpenAI format (object): {"type": "function", "function": {"name": "get_weather"}} + OpenAI format (string): + "auto", "required", "none" - Snowflake format (string values become objects): {"type": "auto"} - Snowflake format (specific tool): {"type": "tool", "name": ["get_weather"]} + OpenAI format (dict): + {"type": "function", "function": {"name": "get_weather"}} + + Snowflake format: + {"type": "auto"} / {"type": "any"} / {"type": "none"} + {"type": "tool", "name": ["get_weather"]} + + Snowflake's API (like Anthropic) requires tool_choice as an object + with a "type" field, not as a bare string. """ if isinstance(tool_choice, str): - # Snowflake requires object format: {"type": "auto"} not string "auto" - return {"type": tool_choice} + # Snowflake requires object format, not string. + # Map OpenAI string values to Snowflake object format. + # "required" maps to "any" (Snowflake/Anthropic convention). + _type_map = { + "auto": "auto", + "required": "any", + "none": "none", + } + mapped_type = _type_map.get(tool_choice, tool_choice) + return {"type": mapped_type} if isinstance(tool_choice, dict): if tool_choice.get("type") == "function": diff --git a/tests/test_litellm/llms/snowflake/chat/test_snowflake_chat_transformation.py b/tests/test_litellm/llms/snowflake/chat/test_snowflake_chat_transformation.py index 3c1fa52cb09..5bb4942dde6 100644 --- a/tests/test_litellm/llms/snowflake/chat/test_snowflake_chat_transformation.py +++ b/tests/test_litellm/llms/snowflake/chat/test_snowflake_chat_transformation.py @@ -107,12 +107,19 @@ class TestSnowflakeToolTransformation: """ Test that string tool_choice values are transformed to Snowflake object format. - Snowflake requires tool_choice to be an object, not a string. - Ref: https://docs.snowflake.com/en/developer-guide/snowflake-rest-api/reference/cortex-inference#post--api-v2-cortex-inference-complete-req-body-schema + Snowflake's API (like Anthropic) requires tool_choice as an object + with a "type" field, not as a bare string. OpenAI's "required" maps + to Snowflake's "any". """ config = SnowflakeConfig() - for value in ["auto", "required", "none"]: + expected_mappings = { + "auto": {"type": "auto"}, + "required": {"type": "any"}, + "none": {"type": "none"}, + } + + for value, expected in expected_mappings.items(): optional_params = {"tool_choice": value} transformed_request = config.transform_request( @@ -123,8 +130,10 @@ class TestSnowflakeToolTransformation: headers={}, ) - # Snowflake requires object format: {"type": "auto"} not string "auto" - assert transformed_request["tool_choice"] == {"type": value} + assert transformed_request["tool_choice"] == expected, ( + f"tool_choice='{value}' should be transformed to {expected}, " + f"got {transformed_request['tool_choice']}" + ) def test_transform_response_with_tool_calls(self): """