fix: stay silent when reasoning is turned off on /v1/responses and warn on the Bedrock Responses fallback drop

This commit is contained in:
mateo-berri 2026-10-28 12:54:24 -07:00
parent d32087cd8e
commit 9eaba58c73
4 changed files with 36 additions and 7 deletions

View file

@ -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

View file

@ -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=(

View file

@ -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

View file

@ -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: