From 371e436da47aa2a6407c61313c53930a91352977 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 29 Jul 2026 06:07:17 +0000 Subject: [PATCH] fix(anthropic): gate sampling params on /v1/messages by supports_sampling_params --- .../messages/utils.py | 16 +++++++ .../test_request_optional_param_utils.py | 47 +++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/litellm/llms/anthropic/experimental_pass_through/messages/utils.py b/litellm/llms/anthropic/experimental_pass_through/messages/utils.py index c8060d41fad..729ea45f304 100644 --- a/litellm/llms/anthropic/experimental_pass_through/messages/utils.py +++ b/litellm/llms/anthropic/experimental_pass_through/messages/utils.py @@ -1,12 +1,16 @@ from functools import lru_cache from typing import Any, Dict, FrozenSet, List, cast, get_type_hints +from litellm.llms.anthropic.common_utils import AnthropicModelInfo from litellm.types.llms.anthropic import AnthropicMessagesRequestOptionalParams from litellm.types.llms.anthropic_messages.anthropic_response import ( AnthropicMessagesResponse, ) +_SAMPLING_PARAMS: frozenset[str] = frozenset(("temperature", "top_p", "top_k")) + + @lru_cache(maxsize=1) def _anthropic_messages_optional_param_keys() -> FrozenSet[str]: """ @@ -51,6 +55,18 @@ class AnthropicMessagesRequestUtils: drop_params=drop_params, custom_llm_provider=custom_llm_provider, ) + for param in _SAMPLING_PARAMS: + if param not in filtered_params: + continue + value = filtered_params.pop(param) + AnthropicModelInfo._apply_sampling_param( + optional_params=filtered_params, + model=model, + param=param, + value=value, + drop_params=drop_params, + output_key=param, + ) return cast(AnthropicMessagesRequestOptionalParams, filtered_params) diff --git a/tests/test_litellm/llms/anthropic/experimental_pass_through/messages/test_request_optional_param_utils.py b/tests/test_litellm/llms/anthropic/experimental_pass_through/messages/test_request_optional_param_utils.py index f0252e13336..cb97978f6de 100644 --- a/tests/test_litellm/llms/anthropic/experimental_pass_through/messages/test_request_optional_param_utils.py +++ b/tests/test_litellm/llms/anthropic/experimental_pass_through/messages/test_request_optional_param_utils.py @@ -6,6 +6,8 @@ Regression tests for the /v1/messages request-parse fast paths: while resolving the (static) type hints only once per process. """ +import pytest + import litellm from litellm.llms.anthropic.experimental_pass_through.messages.utils import ( AnthropicMessagesRequestUtils, @@ -88,3 +90,48 @@ def test_drop_params_keeps_speed_for_supporting_model(): litellm.drop_params = original assert result == {"speed": "fast"} + + +@pytest.mark.parametrize("param,value", [("temperature", 0.3), ("top_p", 0.9), ("top_k", 40)]) +def test_sampling_params_dropped_for_models_without_sampling_support(param, value): + original = litellm.drop_params + litellm.drop_params = True + try: + result = AnthropicMessagesRequestUtils.get_requested_anthropic_messages_optional_param( + params={param: value, "max_tokens": 16}, + model="claude-opus-4-8", + ) + finally: + litellm.drop_params = original + + assert result == {"max_tokens": 16} + + +@pytest.mark.parametrize("param,value", [("temperature", 0.3), ("top_p", 0.9), ("top_k", 40)]) +def test_sampling_params_raise_without_drop_params(param, value): + original = litellm.drop_params + litellm.drop_params = False + try: + with pytest.raises(litellm.utils.UnsupportedParamsError): + AnthropicMessagesRequestUtils.get_requested_anthropic_messages_optional_param( + params={param: value}, + model="claude-opus-4-8", + ) + finally: + litellm.drop_params = original + + +def test_sampling_params_kept_for_supporting_model(): + result = AnthropicMessagesRequestUtils.get_requested_anthropic_messages_optional_param( + params={"temperature": 0.3, "top_p": 0.9, "top_k": 40}, + model="claude-sonnet-4-6", + ) + assert result == {"temperature": 0.3, "top_p": 0.9, "top_k": 40} + + +def test_temperature_one_allowed_for_model_without_sampling_support(): + result = AnthropicMessagesRequestUtils.get_requested_anthropic_messages_optional_param( + params={"temperature": 1}, + model="claude-opus-4-8", + ) + assert result == {"temperature": 1}