mirror of
https://github.com/BerriAI/litellm.git
synced 2026-08-28 05:25:59 +00:00
fix(anthropic_messages): gate sampling params on /v1/messages like /chat/completions (#37868)
* fix(anthropic_messages): gate sampling params on /v1/messages like /chat/completions /v1/messages forwarded temperature/top_p/top_k raw to models that removed sampling params (supports_sampling_params: false — Claude 4.7+/Fable 5), producing provider 400s that router fallbacks mask as silent model downgrades. The chat path already gates these via AnthropicModelInfo._apply_sampling_param; reuse it in get_requested_anthropic_messages_optional_param so both endpoints agree: drop under drop_params, else raise the clean client-side 400. Fixes #35053 * test(anthropic): drive new sampling-param tests off the kwarg, not the global The five tests added here set `litellm.drop_params = True` under a manual try/finally. That trips TQ005 (module-global mutation, 10 new violations over the ceiling) and it leaks process-wide if the finally is ever skipped, which is what the save/restore conftest exists to paper over. `get_requested_anthropic_messages_optional_param` already takes `drop_params` as a kwarg, and that is the path /v1/messages actually uses, so pass it directly. `monkeypatch.setattr` pins the global to False so each test proves the per-request flag alone is sufficient and cannot pass on a leaked global. Verified: TQ gate clean, all 10 tests pass, and the 3 that assert the new gating still fail with the fix in utils.py reverted. --------- Co-authored-by: Mihidum Hettiyahandi <55163074+mihidumh@users.noreply.github.com>
This commit is contained in:
parent
7cb100af63
commit
770bd40f5d
2 changed files with 71 additions and 0 deletions
|
|
@ -44,6 +44,7 @@ class AnthropicMessagesRequestUtils:
|
|||
filtered_params: Final = {k: v for k, v in params.items() if k in valid_keys and v is not None}
|
||||
if model is not None:
|
||||
from litellm.llms.anthropic.chat.transformation import AnthropicConfig
|
||||
from litellm.llms.anthropic.common_utils import AnthropicModelInfo
|
||||
|
||||
AnthropicConfig._maybe_drop_speed_param(
|
||||
model=model,
|
||||
|
|
@ -51,6 +52,16 @@ class AnthropicMessagesRequestUtils:
|
|||
drop_params=drop_params,
|
||||
custom_llm_provider=custom_llm_provider,
|
||||
)
|
||||
for param in ("temperature", "top_p", "top_k"):
|
||||
if param in filtered_params:
|
||||
AnthropicModelInfo._apply_sampling_param( # pyright: ignore[reportPrivateUsage] # same gating the /chat/completions path applies; forking it would drift
|
||||
optional_params=filtered_params,
|
||||
model=model,
|
||||
param=param,
|
||||
value=filtered_params.pop(param),
|
||||
drop_params=drop_params,
|
||||
output_key=param,
|
||||
)
|
||||
return cast(AnthropicMessagesRequestOptionalParams, filtered_params)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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,61 @@ def test_drop_params_keeps_speed_for_supporting_model():
|
|||
litellm.drop_params = original
|
||||
|
||||
assert result == {"speed": "fast"}
|
||||
|
||||
|
||||
def test_drop_params_strips_sampling_params_for_unsupported_model(monkeypatch):
|
||||
# claude-opus-4-7 has supports_sampling_params: false in the model map; the
|
||||
# API 400s on these rather than ignoring them.
|
||||
monkeypatch.setattr(litellm, "drop_params", False)
|
||||
result = AnthropicMessagesRequestUtils.get_requested_anthropic_messages_optional_param(
|
||||
params={"temperature": 0.3, "top_p": 0.9, "top_k": 40, "stream": True},
|
||||
model="claude-opus-4-7",
|
||||
drop_params=True,
|
||||
)
|
||||
|
||||
assert result == {"stream": True}
|
||||
|
||||
|
||||
def test_drop_params_strips_sampling_params_for_provider_prefixed_model(monkeypatch):
|
||||
# Vertex-routed ids must resolve the same capability flag.
|
||||
monkeypatch.setattr(litellm, "drop_params", False)
|
||||
result = AnthropicMessagesRequestUtils.get_requested_anthropic_messages_optional_param(
|
||||
params={"temperature": 0.3, "top_p": 0.9, "top_k": 40},
|
||||
model="vertex_ai/claude-opus-4-7",
|
||||
drop_params=True,
|
||||
)
|
||||
|
||||
assert result == {}
|
||||
|
||||
|
||||
def test_sampling_params_kept_for_supporting_model(monkeypatch):
|
||||
monkeypatch.setattr(litellm, "drop_params", False)
|
||||
result = AnthropicMessagesRequestUtils.get_requested_anthropic_messages_optional_param(
|
||||
params={"temperature": 0.3, "top_p": 0.9, "top_k": 40},
|
||||
model="claude-sonnet-4-6",
|
||||
drop_params=True,
|
||||
)
|
||||
|
||||
assert result == {"temperature": 0.3, "top_p": 0.9, "top_k": 40}
|
||||
|
||||
|
||||
def test_temperature_1_kept_for_unsupported_model(monkeypatch):
|
||||
# temperature=1 is the one value these models still accept.
|
||||
monkeypatch.setattr(litellm, "drop_params", False)
|
||||
result = AnthropicMessagesRequestUtils.get_requested_anthropic_messages_optional_param(
|
||||
params={"temperature": 1},
|
||||
model="claude-opus-4-7",
|
||||
drop_params=True,
|
||||
)
|
||||
|
||||
assert result == {"temperature": 1}
|
||||
|
||||
|
||||
def test_sampling_param_raises_clean_400_without_drop_params(monkeypatch):
|
||||
monkeypatch.setattr(litellm, "drop_params", False)
|
||||
with pytest.raises(litellm.utils.UnsupportedParamsError, match="does not support temperature"):
|
||||
AnthropicMessagesRequestUtils.get_requested_anthropic_messages_optional_param(
|
||||
params={"temperature": 0.3},
|
||||
model="claude-opus-4-7",
|
||||
drop_params=False,
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue