mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-11 03:38:38 +00:00
fix: reject unsupported reasoning_effort with drop_params
This commit is contained in:
parent
2027549c43
commit
7bf9ec40a8
5 changed files with 105 additions and 56 deletions
|
|
@ -103,7 +103,7 @@ class AzureOpenAIConfig(BaseConfig):
|
|||
return super().get_config()
|
||||
|
||||
def get_supported_openai_params(self, model: str) -> list[str]:
|
||||
supported_params: Final = [
|
||||
return [
|
||||
"temperature",
|
||||
"n",
|
||||
"stream",
|
||||
|
|
@ -135,9 +135,6 @@ class AzureOpenAIConfig(BaseConfig):
|
|||
"prompt_cache_key",
|
||||
"store",
|
||||
]
|
||||
if litellm.OpenAIGPTConfig.supports_reasoning_effort_passthrough(model):
|
||||
supported_params.append("reasoning_effort")
|
||||
return supported_params
|
||||
|
||||
@classmethod
|
||||
def requires_max_completion_tokens(cls, model: str) -> bool:
|
||||
|
|
|
|||
|
|
@ -182,8 +182,6 @@ class OpenAIGPTConfig(BaseLLMModelInfo, BaseConfig):
|
|||
model_specific_params.append(
|
||||
"user"
|
||||
) # user is not a param supported by all openai-compatible endpoints - e.g. azure ai
|
||||
if OpenAIGPTConfig.supports_reasoning_effort_passthrough(model):
|
||||
model_specific_params.append("reasoning_effort")
|
||||
return base_params + model_specific_params
|
||||
|
||||
@staticmethod
|
||||
|
|
@ -194,12 +192,6 @@ class OpenAIGPTConfig(BaseLLMModelInfo, BaseConfig):
|
|||
or model_for_check in litellm.open_ai_text_completion_models
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def supports_reasoning_effort_passthrough(model: str) -> bool:
|
||||
raw_model: Final = model.split("responses/", 1)[1] if "responses/" in model else model
|
||||
model_for_check: Final = raw_model.split("/", 1)[1] if "/" in raw_model else raw_model
|
||||
return model_for_check.startswith(("gpt-4.1", "gpt-4o"))
|
||||
|
||||
def _map_openai_params(
|
||||
self,
|
||||
non_default_params: dict,
|
||||
|
|
|
|||
|
|
@ -4503,6 +4503,15 @@ def get_optional_params(
|
|||
unsupported_params[k] = non_default_params[k]
|
||||
|
||||
if unsupported_params:
|
||||
if "reasoning_effort" in unsupported_params and custom_llm_provider in ("openai", "azure"):
|
||||
raise UnsupportedParamsError(
|
||||
status_code=500,
|
||||
message=(
|
||||
f"{custom_llm_provider} does not support reasoning_effort for model={model}. "
|
||||
"reasoning_effort cannot be silently dropped. To forward it to the provider, "
|
||||
"send allowed_openai_params=['reasoning_effort'] in your request."
|
||||
),
|
||||
)
|
||||
if litellm.drop_params is True or (drop_params is not None and drop_params is True):
|
||||
for k in unsupported_params:
|
||||
non_default_params.pop(k, None)
|
||||
|
|
|
|||
|
|
@ -45,18 +45,24 @@ def test_supports_system_message():
|
|||
|
||||
## confirm you can make a openai call with this param
|
||||
|
||||
response = litellm.completion(model="gpt-3.5-turbo", messages=new_messages, supports_system_message=False)
|
||||
response = litellm.completion(
|
||||
model="gpt-3.5-turbo", messages=new_messages, supports_system_message=False
|
||||
)
|
||||
|
||||
assert isinstance(response, litellm.ModelResponse)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("stop_sequence, expected_count", [("\n", 0), (["\n"], 0), (["finish_reason"], 1)])
|
||||
@pytest.mark.parametrize(
|
||||
"stop_sequence, expected_count", [("\n", 0), (["\n"], 0), (["finish_reason"], 1)]
|
||||
)
|
||||
def test_anthropic_optional_params(stop_sequence, expected_count):
|
||||
"""
|
||||
Test if whitespace character optional param is dropped by anthropic
|
||||
"""
|
||||
litellm.drop_params = True
|
||||
optional_params = get_optional_params(model="claude-3", custom_llm_provider="anthropic", stop=stop_sequence)
|
||||
optional_params = get_optional_params(
|
||||
model="claude-3", custom_llm_provider="anthropic", stop=stop_sequence
|
||||
)
|
||||
assert len(optional_params) == expected_count
|
||||
|
||||
|
||||
|
|
@ -135,28 +141,6 @@ def test_get_optional_params_with_allowed_openai_params():
|
|||
assert optional_params["reasoning_effort"] == reasoning_effort
|
||||
|
||||
|
||||
@pytest.mark.parametrize("custom_llm_provider", ["openai", "azure"])
|
||||
@pytest.mark.parametrize("model", ["gpt-4.1", "gpt-4.1-mini", "gpt-4o", "gpt-4o-mini"])
|
||||
def test_gpt4_reasoning_effort_is_not_silently_dropped(custom_llm_provider, model):
|
||||
optional_params = get_optional_params(
|
||||
model=model,
|
||||
custom_llm_provider=custom_llm_provider,
|
||||
reasoning_effort="low",
|
||||
drop_params=True,
|
||||
)
|
||||
|
||||
assert optional_params["reasoning_effort"] == "low"
|
||||
|
||||
optional_params_without_drop = get_optional_params(
|
||||
model=model,
|
||||
custom_llm_provider=custom_llm_provider,
|
||||
reasoning_effort="low",
|
||||
drop_params=False,
|
||||
)
|
||||
|
||||
assert optional_params_without_drop["reasoning_effort"] == "low"
|
||||
|
||||
|
||||
def test_allowed_openai_params_does_not_forward_unset_params():
|
||||
"""
|
||||
Regression test for https://github.com/BerriAI/litellm/issues/25697
|
||||
|
|
@ -279,7 +263,9 @@ def test_bedrock_optional_params_simple(model):
|
|||
("bedrock/cohere.embed-multilingual-v3", True, None),
|
||||
],
|
||||
)
|
||||
def test_bedrock_optional_params_embeddings_dimension(model, expected_dimensions, dimensions_kwarg):
|
||||
def test_bedrock_optional_params_embeddings_dimension(
|
||||
model, expected_dimensions, dimensions_kwarg
|
||||
):
|
||||
litellm.drop_params = True
|
||||
optional_params = get_optional_params_embeddings(
|
||||
model=model,
|
||||
|
|
@ -513,10 +499,10 @@ def test_azure_tool_choice(api_version):
|
|||
if api_version == "2024-07-01":
|
||||
assert optional_params["tool_choice"] == "required"
|
||||
else:
|
||||
assert "tool_choice" not in optional_params, (
|
||||
"tool choice should not be present. Got - tool_choice={} for api version={}".format(
|
||||
optional_params["tool_choice"], api_version
|
||||
)
|
||||
assert (
|
||||
"tool_choice" not in optional_params
|
||||
), "tool choice should not be present. Got - tool_choice={} for api version={}".format(
|
||||
optional_params["tool_choice"], api_version
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -546,7 +532,9 @@ def test_dynamic_drop_params(drop_params):
|
|||
|
||||
|
||||
def test_dynamic_drop_params_e2e():
|
||||
with patch("litellm.llms.custom_httpx.http_handler.HTTPHandler.post", new=MagicMock()) as mock_response:
|
||||
with patch(
|
||||
"litellm.llms.custom_httpx.http_handler.HTTPHandler.post", new=MagicMock()
|
||||
) as mock_response:
|
||||
try:
|
||||
response = litellm.completion(
|
||||
model="command-r-08-2024",
|
||||
|
|
@ -563,7 +551,9 @@ def test_dynamic_drop_params_e2e():
|
|||
|
||||
|
||||
def test_dynamic_pass_additional_params():
|
||||
with patch("litellm.llms.custom_httpx.http_handler.HTTPHandler.post", new=MagicMock()) as mock_response:
|
||||
with patch(
|
||||
"litellm.llms.custom_httpx.http_handler.HTTPHandler.post", new=MagicMock()
|
||||
) as mock_response:
|
||||
try:
|
||||
response = litellm.completion(
|
||||
model="command-r-08-2024",
|
||||
|
|
@ -611,7 +601,9 @@ def test_dynamic_drop_params_parallel_tool_calls():
|
|||
"""
|
||||
https://github.com/BerriAI/litellm/issues/4584
|
||||
"""
|
||||
with patch("litellm.llms.custom_httpx.http_handler.HTTPHandler.post", new=MagicMock()) as mock_response:
|
||||
with patch(
|
||||
"litellm.llms.custom_httpx.http_handler.HTTPHandler.post", new=MagicMock()
|
||||
) as mock_response:
|
||||
try:
|
||||
response = litellm.completion(
|
||||
model="command-r-08-2024",
|
||||
|
|
@ -666,7 +658,9 @@ def test_dynamic_drop_additional_params_stream_options():
|
|||
|
||||
|
||||
def test_dynamic_drop_additional_params_e2e():
|
||||
with patch("litellm.llms.custom_httpx.http_handler.HTTPHandler.post", new=MagicMock()) as mock_response:
|
||||
with patch(
|
||||
"litellm.llms.custom_httpx.http_handler.HTTPHandler.post", new=MagicMock()
|
||||
) as mock_response:
|
||||
try:
|
||||
response = litellm.completion(
|
||||
model="command-r-08-2024",
|
||||
|
|
@ -685,12 +679,16 @@ def test_dynamic_drop_additional_params_e2e():
|
|||
|
||||
|
||||
def test_get_optional_params_image_gen():
|
||||
response = litellm.utils.get_optional_params_image_gen(aws_region_name="us-east-1", custom_llm_provider="openai")
|
||||
response = litellm.utils.get_optional_params_image_gen(
|
||||
aws_region_name="us-east-1", custom_llm_provider="openai"
|
||||
)
|
||||
|
||||
print(response)
|
||||
|
||||
assert "aws_region_name" not in response
|
||||
response = litellm.utils.get_optional_params_image_gen(aws_region_name="us-east-1", custom_llm_provider="bedrock")
|
||||
response = litellm.utils.get_optional_params_image_gen(
|
||||
aws_region_name="us-east-1", custom_llm_provider="bedrock"
|
||||
)
|
||||
|
||||
print(response)
|
||||
|
||||
|
|
@ -753,7 +751,9 @@ def test_vertex_safety_settings(provider):
|
|||
},
|
||||
]
|
||||
|
||||
optional_params = get_optional_params(model="gemini-1.5-pro", custom_llm_provider=provider)
|
||||
optional_params = get_optional_params(
|
||||
model="gemini-1.5-pro", custom_llm_provider=provider
|
||||
)
|
||||
assert len(optional_params) == 1
|
||||
|
||||
|
||||
|
|
@ -862,7 +862,9 @@ def _check_additional_properties(schema):
|
|||
if isinstance(schema, dict):
|
||||
# Remove the 'additionalProperties' key if it exists and is set to False
|
||||
if "additionalProperties" in schema or "strict" in schema:
|
||||
raise ValueError("additionalProperties and strict should not be in the schema")
|
||||
raise ValueError(
|
||||
"additionalProperties and strict should not be in the schema"
|
||||
)
|
||||
|
||||
# Recursively process all dictionary values
|
||||
for key, value in schema.items():
|
||||
|
|
@ -1065,23 +1067,32 @@ def test_vertex_schema_field():
|
|||
)
|
||||
print(optional_params)
|
||||
print(optional_params["tools"][0]["function_declarations"][0])
|
||||
assert "$schema" not in optional_params["tools"][0]["function_declarations"][0]["parameters"]
|
||||
assert (
|
||||
"$schema"
|
||||
not in optional_params["tools"][0]["function_declarations"][0]["parameters"]
|
||||
)
|
||||
|
||||
|
||||
def test_watsonx_tool_choice():
|
||||
optional_params = get_optional_params(model="gemini-1.5-pro", custom_llm_provider="watsonx", tool_choice="auto")
|
||||
optional_params = get_optional_params(
|
||||
model="gemini-1.5-pro", custom_llm_provider="watsonx", tool_choice="auto"
|
||||
)
|
||||
print(optional_params)
|
||||
assert optional_params["tool_choice_option"] == "auto"
|
||||
|
||||
|
||||
def test_watsonx_text_top_k():
|
||||
optional_params = get_optional_params(model="gemini-1.5-pro", custom_llm_provider="watsonx_text", top_k=10)
|
||||
optional_params = get_optional_params(
|
||||
model="gemini-1.5-pro", custom_llm_provider="watsonx_text", top_k=10
|
||||
)
|
||||
print(optional_params)
|
||||
assert optional_params["top_k"] == 10
|
||||
|
||||
|
||||
def test_together_ai_model_params():
|
||||
optional_params = get_optional_params(model="together_ai", custom_llm_provider="together_ai", logprobs=1)
|
||||
optional_params = get_optional_params(
|
||||
model="together_ai", custom_llm_provider="together_ai", logprobs=1
|
||||
)
|
||||
print(optional_params)
|
||||
assert optional_params["logprobs"] == 1
|
||||
|
||||
|
|
@ -1190,7 +1201,9 @@ def test_groq_response_format_json_schema():
|
|||
|
||||
|
||||
def test_gemini_frequency_penalty():
|
||||
optional_params = get_optional_params(model="gemini-1.5-flash", custom_llm_provider="gemini", frequency_penalty=0.5)
|
||||
optional_params = get_optional_params(
|
||||
model="gemini-1.5-flash", custom_llm_provider="gemini", frequency_penalty=0.5
|
||||
)
|
||||
assert optional_params["frequency_penalty"] == 0.5
|
||||
|
||||
|
||||
|
|
@ -1994,7 +2007,9 @@ def test_validate_openai_optional_params_integration():
|
|||
mock_response.usage.completion_tokens = 5
|
||||
mock_response.usage.total_tokens = 15
|
||||
|
||||
mock_client.return_value.chat.completions.create.return_value = mock_response
|
||||
mock_client.return_value.chat.completions.create.return_value = (
|
||||
mock_response
|
||||
)
|
||||
|
||||
# Call completion with more than 4 stop sequences
|
||||
response = litellm.completion(
|
||||
|
|
|
|||
|
|
@ -6100,6 +6100,42 @@ class TestFinalOptionalParamsLineRedaction:
|
|||
assert "'temperature': 0.25" in printed
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"custom_llm_provider, model",
|
||||
[
|
||||
("openai", "gpt-4.1"),
|
||||
("openai", "gpt-4.1-mini"),
|
||||
("openai", "gpt-4o"),
|
||||
("openai", "gpt-4o-mini"),
|
||||
("azure", "gpt-4.1"),
|
||||
("azure", "gpt-4.1-mini"),
|
||||
("azure", "gpt-4o"),
|
||||
("azure", "gpt-4o-mini"),
|
||||
("azure", "azure/eu/gpt-4o-2024-08-06"),
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize("request_drop, global_drop", [(True, False), (None, True)])
|
||||
def test_unsupported_reasoning_effort_is_not_silently_dropped(
|
||||
custom_llm_provider: str,
|
||||
model: str,
|
||||
request_drop: bool | None,
|
||||
global_drop: bool,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
from litellm.utils import get_optional_params
|
||||
|
||||
# https://github.com/BerriAI/litellm/issues/40470, verified 2026-10-02.
|
||||
# https://github.com/BerriAI/litellm/pull/44060#discussion_r4159472144, verified 2026-10-02.
|
||||
monkeypatch.setattr(litellm, "drop_params", global_drop)
|
||||
with pytest.raises(litellm.UnsupportedParamsError, match="reasoning_effort"):
|
||||
get_optional_params(
|
||||
model=model,
|
||||
custom_llm_provider=custom_llm_provider,
|
||||
reasoning_effort="low",
|
||||
drop_params=request_drop,
|
||||
)
|
||||
|
||||
|
||||
class TestDropParamsStringCoercion:
|
||||
@pytest.mark.parametrize("drop_params", ["true", "True", True])
|
||||
def test_truthy_drop_params_drops_unsupported_temperature(self, drop_params, monkeypatch):
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue