From 37a1b859d7327b1d895e0640d0862e04f07c727c Mon Sep 17 00:00:00 2001 From: shivam Date: Fri, 11 Sep 2026 23:34:14 +0000 Subject: [PATCH] fix(bedrock_mantle): harden reasoning summary validation Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- .../responses/transformation.py | 18 +++++++++++----- ...bedrock_mantle_responses_transformation.py | 21 +++++++++++++------ 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/litellm/llms/bedrock_mantle/responses/transformation.py b/litellm/llms/bedrock_mantle/responses/transformation.py index 98a0d4dbc90..c43b03b2ba9 100644 --- a/litellm/llms/bedrock_mantle/responses/transformation.py +++ b/litellm/llms/bedrock_mantle/responses/transformation.py @@ -188,12 +188,16 @@ class BedrockMantleResponsesAPIConfig(BedrockMantleAuthMixin, OpenAIResponsesAPI ) return {key: value for key, value in params.items() if key != "service_tier"} - def _handle_unsupported_reasoning_summary(self, params: dict, model: str, drop_params: bool) -> dict: + def _handle_unsupported_reasoning_summary( + self, params: dict[str, object], model: str, drop_params: bool + ) -> dict[str, object]: reasoning: Final = params.get("reasoning") if not self.use_openai_path or not isinstance(reasoning, dict): return params summary: Final = reasoning.get("summary") - if summary is None or summary in _BEDROCK_MANTLE_OPENAI_PATH_SUPPORTED_REASONING_SUMMARIES: + if summary is None or ( + isinstance(summary, str) and summary in _BEDROCK_MANTLE_OPENAI_PATH_SUPPORTED_REASONING_SUMMARIES + ): return params if not drop_params: raise litellm.utils.UnsupportedParamsError( @@ -210,11 +214,15 @@ class BedrockMantleResponsesAPIConfig(BedrockMantleAuthMixin, OpenAIResponsesAPI summary, sorted(_BEDROCK_MANTLE_OPENAI_PATH_SUPPORTED_REASONING_SUMMARIES), ) - stripped: Final = {key: value for key, value in reasoning.items() if key != "summary"} + stripped: Final = { # mutable-ok: dynamic reasoning fields must remain a mutable dict + key: value for key, value in reasoning.items() if key != "summary" + } return ( - {**params, "reasoning": stripped} + {**params, "reasoning": stripped} # mutable-ok: downstream parameter filtering needs a mutable dict if stripped - else {key: value for key, value in params.items() if key != "reasoning"} + else { # mutable-ok: downstream parameter filtering needs a mutable dict + key: value for key, value in params.items() if key != "reasoning" + } ) def transform_responses_api_request( diff --git a/tests/test_litellm/llms/bedrock_mantle/test_bedrock_mantle_responses_transformation.py b/tests/test_litellm/llms/bedrock_mantle/test_bedrock_mantle_responses_transformation.py index 45f427defcd..40566261c84 100644 --- a/tests/test_litellm/llms/bedrock_mantle/test_bedrock_mantle_responses_transformation.py +++ b/tests/test_litellm/llms/bedrock_mantle/test_bedrock_mantle_responses_transformation.py @@ -572,6 +572,16 @@ class TestBedrockMantleReasoningSummary: assert "reasoning.summary" in str(excinfo.value) assert "drop_params" in str(excinfo.value) + def test_unhashable_reasoning_summary_raises_unsupported_params_error(self): + cfg = BedrockMantleResponsesAPIConfig() + with pytest.raises(litellm.UnsupportedParamsError) as excinfo: + cfg.map_openai_params( + response_api_optional_params={"reasoning": {"summary": ["detailed"]}}, + model="openai.gpt-5.6-sol", + drop_params=False, + ) + assert "reasoning.summary" in str(excinfo.value) + @pytest.mark.parametrize("drop_params", [True, False]) def test_supported_reasoning_summary_kept(self, drop_params): cfg = BedrockMantleResponsesAPIConfig() @@ -600,18 +610,17 @@ class TestBedrockMantleReasoningSummary: ) assert params == {"stream": True} - def test_drop_logged_at_warning_level(self): - from unittest.mock import patch - + def test_drop_logged_at_warning_level(self, caplog): cfg = BedrockMantleResponsesAPIConfig() - with patch("litellm.llms.bedrock_mantle.responses.transformation.verbose_logger.warning") as mock_warning: + with caplog.at_level(logging.WARNING, logger="LiteLLM"): cfg.map_openai_params( response_api_optional_params={"reasoning": {"effort": "medium", "summary": "detailed"}}, model="openai.gpt-5.6-sol", drop_params=True, ) - assert mock_warning.call_count == 1 - assert "detailed" in str(mock_warning.call_args) + warnings = [record for record in caplog.records if "dropping unsupported reasoning.summary" in record.getMessage()] + assert len(warnings) == 1 + assert "detailed" in warnings[0].getMessage() class TestBedrockMantleCodexRequestEndToEnd: