From 2027549c43eb14ce2303938b2ac6b55f364d609a Mon Sep 17 00:00:00 2001 From: Oxygen56 Date: Fri, 2 Oct 2026 03:00:28 +0800 Subject: [PATCH 1/2] fix: preserve reasoning_effort for GPT-4 chat models --- litellm/llms/azure/chat/gpt_transformation.py | 5 +- .../llms/openai/chat/gpt_transformation.py | 8 ++ tests/llm_translation/test_optional_params.py | 103 ++++++++---------- 3 files changed, 56 insertions(+), 60 deletions(-) diff --git a/litellm/llms/azure/chat/gpt_transformation.py b/litellm/llms/azure/chat/gpt_transformation.py index 355714c0daf..4dcdc02d47b 100644 --- a/litellm/llms/azure/chat/gpt_transformation.py +++ b/litellm/llms/azure/chat/gpt_transformation.py @@ -103,7 +103,7 @@ class AzureOpenAIConfig(BaseConfig): return super().get_config() def get_supported_openai_params(self, model: str) -> list[str]: - return [ + supported_params: Final = [ "temperature", "n", "stream", @@ -135,6 +135,9 @@ 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: diff --git a/litellm/llms/openai/chat/gpt_transformation.py b/litellm/llms/openai/chat/gpt_transformation.py index 3b38825c83d..73a9b2d6fee 100644 --- a/litellm/llms/openai/chat/gpt_transformation.py +++ b/litellm/llms/openai/chat/gpt_transformation.py @@ -182,6 +182,8 @@ 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 @@ -192,6 +194,12 @@ 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, diff --git a/tests/llm_translation/test_optional_params.py b/tests/llm_translation/test_optional_params.py index 58446014bdf..fe597b490bd 100644 --- a/tests/llm_translation/test_optional_params.py +++ b/tests/llm_translation/test_optional_params.py @@ -45,24 +45,18 @@ 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 @@ -141,6 +135,28 @@ 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 @@ -263,9 +279,7 @@ 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, @@ -499,10 +513,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 + ) ) @@ -532,9 +546,7 @@ 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", @@ -551,9 +563,7 @@ 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", @@ -601,9 +611,7 @@ 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", @@ -658,9 +666,7 @@ 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", @@ -679,16 +685,12 @@ 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) @@ -751,9 +753,7 @@ 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,9 +862,7 @@ 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(): @@ -1067,32 +1065,23 @@ 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 @@ -1201,9 +1190,7 @@ 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 @@ -2007,9 +1994,7 @@ 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( From 7bf9ec40a8a6546ede753411b73c7c53a784ea18 Mon Sep 17 00:00:00 2001 From: Oxygen56 Date: Fri, 2 Oct 2026 06:29:18 +0800 Subject: [PATCH 2/2] fix: reject unsupported reasoning_effort with drop_params --- litellm/llms/azure/chat/gpt_transformation.py | 5 +- .../llms/openai/chat/gpt_transformation.py | 8 -- litellm/utils.py | 9 ++ tests/llm_translation/test_optional_params.py | 103 ++++++++++-------- tests/unit/test_utils.py | 36 ++++++ 5 files changed, 105 insertions(+), 56 deletions(-) diff --git a/litellm/llms/azure/chat/gpt_transformation.py b/litellm/llms/azure/chat/gpt_transformation.py index 4dcdc02d47b..355714c0daf 100644 --- a/litellm/llms/azure/chat/gpt_transformation.py +++ b/litellm/llms/azure/chat/gpt_transformation.py @@ -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: diff --git a/litellm/llms/openai/chat/gpt_transformation.py b/litellm/llms/openai/chat/gpt_transformation.py index 73a9b2d6fee..3b38825c83d 100644 --- a/litellm/llms/openai/chat/gpt_transformation.py +++ b/litellm/llms/openai/chat/gpt_transformation.py @@ -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, diff --git a/litellm/utils.py b/litellm/utils.py index b0a7e4f1a68..63412f1f006 100644 --- a/litellm/utils.py +++ b/litellm/utils.py @@ -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) diff --git a/tests/llm_translation/test_optional_params.py b/tests/llm_translation/test_optional_params.py index fe597b490bd..58446014bdf 100644 --- a/tests/llm_translation/test_optional_params.py +++ b/tests/llm_translation/test_optional_params.py @@ -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( diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py index 4c36f99d2c8..0164c764f7a 100644 --- a/tests/unit/test_utils.py +++ b/tests/unit/test_utils.py @@ -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):