From bf9e8ea9ef7eff06cbc58e143e5ba1de376b81c9 Mon Sep 17 00:00:00 2001 From: shivam Date: Fri, 11 Sep 2026 23:19:17 +0000 Subject: [PATCH] fix(bedrock_mantle): gate reasoning.summary on the OpenAI Responses path Mantle's /openai/v1/responses rejects reasoning.summary values other than "auto" with 400 unsupported_parameter. Drop it with a warning under drop_params, otherwise raise UnsupportedParamsError naming the remedy. Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- .../responses/transformation.py | 42 ++++++++++- ...bedrock_mantle_responses_transformation.py | 75 +++++++++++++++++++ 2 files changed, 113 insertions(+), 4 deletions(-) diff --git a/litellm/llms/bedrock_mantle/responses/transformation.py b/litellm/llms/bedrock_mantle/responses/transformation.py index bbbda4d14b6..98a0d4dbc90 100644 --- a/litellm/llms/bedrock_mantle/responses/transformation.py +++ b/litellm/llms/bedrock_mantle/responses/transformation.py @@ -56,6 +56,7 @@ _BEDROCK_MANTLE_SUPPORTED_RESPONSE_TOOL_TYPES: Final = frozenset( ) _BEDROCK_MANTLE_SUPPORTED_SERVICE_TIERS: Final = frozenset({"auto", "default"}) +_BEDROCK_MANTLE_OPENAI_PATH_SUPPORTED_REASONING_SUMMARIES: Final = frozenset({"auto"}) _CODEX_ADDITIONAL_TOOLS_INPUT_ITEM_TYPE: Final = "additional_tools" @@ -187,6 +188,35 @@ 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: + 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: + return params + if not drop_params: + raise litellm.utils.UnsupportedParamsError( + status_code=400, + message=( + f"bedrock_mantle does not support reasoning.summary={summary!r} for {model!r}; the Bedrock Mantle " + "OpenAI Responses path only accepts 'auto'. Set `drop_params: true` (litellm_settings or this " + 'deployment\'s litellm_params) to have LiteLLM drop it, or set `model_reasoning_summary = "auto"` ' + "in the client (Codex CLI: ~/.codex/config.toml)." + ), + ) + verbose_logger.warning( + "Bedrock Mantle Responses API: dropping unsupported reasoning.summary %r (supported: %s).", + summary, + sorted(_BEDROCK_MANTLE_OPENAI_PATH_SUPPORTED_REASONING_SUMMARIES), + ) + stripped: Final = {key: value for key, value in reasoning.items() if key != "summary"} + return ( + {**params, "reasoning": stripped} + if stripped + else {key: value for key, value in params.items() if key != "reasoning"} + ) + def transform_responses_api_request( self, model: str, @@ -343,12 +373,16 @@ class BedrockMantleResponsesAPIConfig(BedrockMantleAuthMixin, OpenAIResponsesAPI model: str, drop_params: bool, ) -> dict: - params: Final = self._handle_unsupported_service_tier( - super().map_openai_params( - response_api_optional_params=response_api_optional_params, - model=model, + params: Final = self._handle_unsupported_reasoning_summary( + self._handle_unsupported_service_tier( + super().map_openai_params( + response_api_optional_params=response_api_optional_params, + model=model, + drop_params=drop_params, + ), drop_params=drop_params, ), + model=model, drop_params=drop_params, ) 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 9457d5faaff..45f427defcd 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 @@ -539,6 +539,81 @@ class TestBedrockMantleServiceTier: assert "priority" in str(mock_warning.call_args) +class TestBedrockMantleReasoningSummary: + @pytest.mark.parametrize("summary", ["concise", "detailed"]) + def test_unsupported_reasoning_summary_dropped_when_drop_params_true(self, summary): + cfg = BedrockMantleResponsesAPIConfig() + params = cfg.map_openai_params( + response_api_optional_params={"reasoning": {"effort": "medium", "summary": summary}}, + model="openai.gpt-5.6-sol", + drop_params=True, + ) + assert params["reasoning"] == {"effort": "medium"} + + def test_reasoning_summary_only_field_drops_reasoning(self): + cfg = BedrockMantleResponsesAPIConfig() + params = cfg.map_openai_params( + response_api_optional_params={"reasoning": {"summary": "detailed"}}, + model="openai.gpt-5.6-sol", + drop_params=True, + ) + assert "reasoning" not in params + + @pytest.mark.parametrize("summary", ["concise", "detailed"]) + def test_unsupported_reasoning_summary_raises_when_drop_params_false(self, summary): + cfg = BedrockMantleResponsesAPIConfig() + with pytest.raises(litellm.UnsupportedParamsError) as excinfo: + cfg.map_openai_params( + response_api_optional_params={"reasoning": {"effort": "medium", "summary": summary}}, + model="openai.gpt-5.6-sol", + drop_params=False, + ) + assert summary in str(excinfo.value) + assert "reasoning.summary" in str(excinfo.value) + assert "drop_params" in str(excinfo.value) + + @pytest.mark.parametrize("drop_params", [True, False]) + def test_supported_reasoning_summary_kept(self, drop_params): + cfg = BedrockMantleResponsesAPIConfig() + params = cfg.map_openai_params( + response_api_optional_params={"reasoning": {"effort": "medium", "summary": "auto"}}, + model="openai.gpt-5.6-sol", + drop_params=drop_params, + ) + assert params["reasoning"] == {"effort": "medium", "summary": "auto"} + + def test_reasoning_summary_kept_on_standard_path(self): + cfg = BedrockMantleResponsesAPIConfig(use_openai_path=False) + params = cfg.map_openai_params( + response_api_optional_params={"reasoning": {"effort": "medium", "summary": "detailed"}}, + model="openai.gpt-oss-120b", + drop_params=False, + ) + assert params["reasoning"] == {"effort": "medium", "summary": "detailed"} + + def test_absent_reasoning_untouched(self): + cfg = BedrockMantleResponsesAPIConfig() + params = cfg.map_openai_params( + response_api_optional_params={"stream": True}, + model="openai.gpt-5.6-sol", + drop_params=False, + ) + assert params == {"stream": True} + + def test_drop_logged_at_warning_level(self): + from unittest.mock import patch + + cfg = BedrockMantleResponsesAPIConfig() + with patch("litellm.llms.bedrock_mantle.responses.transformation.verbose_logger.warning") as mock_warning: + 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) + + class TestBedrockMantleCodexRequestEndToEnd: def test_codex_priority_tier_request_becomes_mantle_acceptable(self): cfg = BedrockMantleResponsesAPIConfig()