From 9eaba58c7308c1317f48d9282c04aa628ce5520e Mon Sep 17 00:00:00 2001 From: mateo-berri <277851410+mateo-berri@users.noreply.github.com> Date: Wed, 28 Oct 2026 12:54:24 -0700 Subject: [PATCH] fix: stay silent when reasoning is turned off on /v1/responses and warn on the Bedrock Responses fallback drop --- litellm/llms/bedrock/responses/transformation.py | 3 ++- litellm/llms/openai/responses/transformation.py | 12 +++++++----- .../responses/test_bedrock_openai_responses.py | 15 ++++++++++++++- .../test_openai_responses_transformation.py | 13 +++++++++++++ 4 files changed, 36 insertions(+), 7 deletions(-) diff --git a/litellm/llms/bedrock/responses/transformation.py b/litellm/llms/bedrock/responses/transformation.py index bf936399e83..94e59b6e303 100644 --- a/litellm/llms/bedrock/responses/transformation.py +++ b/litellm/llms/bedrock/responses/transformation.py @@ -56,6 +56,7 @@ from litellm.llms.bedrock.common_utils import ( bedrock_reasoning_effort_disabled, bedrock_supports_openai_responses, ) +from litellm.llms.openai.chat.gpt_reasoning_transformation import DROP_REFUSED_REASONING_EFFORT_WARNING from litellm.llms.openai.responses.transformation import OpenAIResponsesAPIConfig from litellm.secret_managers.main import get_secret_str from litellm.types.llms.openai import ResponseInputParam, ResponsesAPIOptionalRequestParams @@ -173,7 +174,7 @@ def _without_disabled_reasoning_effort( ), status_code=400, ) - verbose_logger.debug("Dropping unsupported `reasoning.effort=%s` for Bedrock model=%s.", effort, model) + verbose_logger.warning(DROP_REFUSED_REASONING_EFFORT_WARNING, "reasoning.effort", effort, model, model) rest: Final = {key: value for key, value in reasoning.items() if key != "effort"} without_reasoning: Final = {key: value for key, value in params.items() if key != "reasoning"} return {**without_reasoning, "reasoning": rest} if rest else without_reasoning diff --git a/litellm/llms/openai/responses/transformation.py b/litellm/llms/openai/responses/transformation.py index 4eda47bc8f2..4c6760c73b9 100644 --- a/litellm/llms/openai/responses/transformation.py +++ b/litellm/llms/openai/responses/transformation.py @@ -330,10 +330,11 @@ class OpenAIResponsesAPIConfig(BaseResponsesAPIConfig): @staticmethod def _requests_reasoning_effort(reasoning: object) -> bool: - effort: Final = ( - reasoning.get("effort") if isinstance(reasoning, Mapping) else getattr(reasoning, "effort", None) - ) - return effort is not None + return OpenAIResponsesAPIConfig._requested_effort(reasoning) is not None + + @staticmethod + def _requested_effort(reasoning: object) -> object: + return reasoning.get("effort") if isinstance(reasoning, Mapping) else getattr(reasoning, "effort", None) @staticmethod def _enforce_min_max_output_tokens(max_output_tokens: "int | None") -> "int | None": @@ -406,7 +407,8 @@ class OpenAIResponsesAPIConfig(BaseResponsesAPIConfig): ): if drop_params or litellm.drop_params: dropped_reasoning: Final = params.pop("reasoning", None) - verbose_logger.warning(DROP_UNSUPPORTED_REASONING_WARNING, dropped_reasoning, model) + if self._requested_effort(dropped_reasoning) != "none": + verbose_logger.warning(DROP_UNSUPPORTED_REASONING_WARNING, dropped_reasoning, model) else: raise litellm.UnsupportedParamsError( message=( diff --git a/tests/unit/llms/bedrock/responses/test_bedrock_openai_responses.py b/tests/unit/llms/bedrock/responses/test_bedrock_openai_responses.py index ffc24c308cd..e8efc9970e5 100644 --- a/tests/unit/llms/bedrock/responses/test_bedrock_openai_responses.py +++ b/tests/unit/llms/bedrock/responses/test_bedrock_openai_responses.py @@ -14,7 +14,7 @@ import pytest import litellm from litellm.llms.bedrock.common_utils import bedrock_supports_openai_responses -from litellm.llms.bedrock.responses.transformation import BedrockOpenAIResponsesConfig +from litellm.llms.bedrock.responses.transformation import BedrockOpenAIResponsesConfig, _without_disabled_reasoning_effort from litellm.responses.file_search.emulated_handler import should_use_emulated_file_search from litellm.responses.utils import ResponsesAPIRequestUtils from litellm.types.router import GenericLiteLLMParams @@ -357,6 +357,19 @@ class TestDisabledReasoningEffort: ] assert len(dropped) == 1 and model in dropped[0] + def test_bedrock_disabled_effort_drop_warns_on_its_own( + self, local_model_cost_map: None, caplog: pytest.LogCaptureFixture + ) -> None: + with caplog.at_level(logging.WARNING, logger="LiteLLM"): + params: Final = _without_disabled_reasoning_effort( + {"reasoning": {"effort": "minimal"}, "max_output_tokens": 64}, MODEL, True, () + ) + assert params == {"max_output_tokens": 64} + dropped: Final = [ + r.getMessage() for r in caplog.records if "Dropping reasoning.effort='minimal'" in r.getMessage() + ] + assert len(dropped) == 1 and MODEL in dropped[0] + def test_effort_only_reasoning_is_removed_when_dropped(self, local_model_cost_map): params = _cfg().map_openai_params( response_api_optional_params={"reasoning": {"effort": "minimal"}}, model=MODEL, drop_params=True diff --git a/tests/unit/llms/openai/responses/test_openai_responses_transformation.py b/tests/unit/llms/openai/responses/test_openai_responses_transformation.py index 59788a3a299..e37b8717bf3 100644 --- a/tests/unit/llms/openai/responses/test_openai_responses_transformation.py +++ b/tests/unit/llms/openai/responses/test_openai_responses_transformation.py @@ -2426,6 +2426,19 @@ class TestResponsesSurfaceSharesTheEffortRule: assert len(drop_warnings) == 1 assert all(fragment in drop_warnings[0] for fragment in ("'medium'", "gpt-4o", "supports_reasoning")) + def test_turning_reasoning_off_for_a_model_without_supports_reasoning_drops_it_silently( + self, local_model_cost_map: None, caplog: pytest.LogCaptureFixture + ) -> None: + with caplog.at_level(logging.WARNING, logger="LiteLLM"): + mapped: Final = OpenAIResponsesAPIConfig().map_openai_params( + response_api_optional_params={"reasoning": {"effort": "none", "summary": "auto"}}, + model="gpt-4o", + drop_params=True, + ) + + assert "reasoning" not in mapped + assert not [record for record in caplog.records if "Dropping" in record.getMessage()] + def test_a_forwarded_effort_logs_no_drop_warning( self, local_model_cost_map: None, caplog: pytest.LogCaptureFixture ) -> None: