From 15c18ad6cdd6c9cc70e6ad1f5e31c3e5c36c4da5 Mon Sep 17 00:00:00 2001 From: kerry Date: Wed, 16 Sep 2026 23:27:07 +0000 Subject: [PATCH 1/7] fix(bedrock_mantle): accept verbosity on gpt-5.x chat completions Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- litellm/llms/bedrock_mantle/chat/transformation.py | 3 +++ .../test_bedrock_mantle_transformation.py | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/litellm/llms/bedrock_mantle/chat/transformation.py b/litellm/llms/bedrock_mantle/chat/transformation.py index a1153dffc93..5b69d7aff42 100644 --- a/litellm/llms/bedrock_mantle/chat/transformation.py +++ b/litellm/llms/bedrock_mantle/chat/transformation.py @@ -22,6 +22,7 @@ from litellm.llms.bedrock_mantle.common_utils import ( BEDROCK_MANTLE_DEFAULT_REGION, BedrockMantleAuthMixin, ) +from litellm.llms.openai.chat.gpt_5_transformation import is_gpt_reasoning_series_name from litellm.secret_managers.main import get_secret_str from litellm.types.llms.openai import AllMessageValues from litellm.types.router import GenericLiteLLMParams @@ -108,6 +109,8 @@ class BedrockMantleChatConfig(BedrockMantleAuthMixin, OpenAILikeChatConfig): def get_supported_openai_params(self, model: str) -> list: base_params: Final = super().get_supported_openai_params(model) + if is_gpt_reasoning_series_name(model) and "verbosity" not in base_params: + base_params.append("verbosity") try: if litellm.supports_reasoning(model=model, custom_llm_provider=self.custom_llm_provider): if "reasoning_effort" not in base_params: diff --git a/tests/test_litellm/llms/bedrock_mantle/test_bedrock_mantle_transformation.py b/tests/test_litellm/llms/bedrock_mantle/test_bedrock_mantle_transformation.py index c948dfb3553..15570eaec4d 100644 --- a/tests/test_litellm/llms/bedrock_mantle/test_bedrock_mantle_transformation.py +++ b/tests/test_litellm/llms/bedrock_mantle/test_bedrock_mantle_transformation.py @@ -257,6 +257,18 @@ class TestBedrockMantleConfig: assert "temperature" in params assert "stream" in params assert "max_tokens" in params + assert "verbosity" not in params + + def test_verbosity_passes_through_for_gpt_5_models(self): + cfg = BedrockMantleChatConfig() + assert "verbosity" in cfg.get_supported_openai_params("openai.gpt-5.6-sol") + optional_params = litellm.get_optional_params( + model="openai.gpt-5.6-sol", + custom_llm_provider="bedrock_mantle", + verbosity="low", + drop_params=False, + ) + assert optional_params["verbosity"] == "low" class TestBedrockMantleChatAuth: From e8f246bb6b36ba5e6d88bcbf3d43ba2a12082c84 Mon Sep 17 00:00:00 2001 From: kerry Date: Wed, 16 Sep 2026 23:32:32 +0000 Subject: [PATCH 2/7] fix(responses_bridge): forward verbosity as text.verbosity Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- .../transformation.py | 6 +++- ...responses_transformation_transformation.py | 33 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/litellm/completion_extras/litellm_responses_transformation/transformation.py b/litellm/completion_extras/litellm_responses_transformation/transformation.py index 5a6debc4af5..a76032854b7 100644 --- a/litellm/completion_extras/litellm_responses_transformation/transformation.py +++ b/litellm/completion_extras/litellm_responses_transformation/transformation.py @@ -502,7 +502,11 @@ class LiteLLMResponsesTransformationHandler(CompletionTransformationBridge): elif key == "response_format": text_format = self._transform_response_format_to_text_format(value) if text_format: - responses_api_request["text"] = text_format + existing_text = cast("dict[str, object]", responses_api_request["text"] if "text" in responses_api_request else {}) + responses_api_request["text"] = cast("ResponseText", {**existing_text, **text_format}) + elif key == "verbosity": + existing_text = cast("dict[str, object]", responses_api_request["text"] if "text" in responses_api_request else {}) + responses_api_request["text"] = cast("ResponseText", {**existing_text, "verbosity": value}) elif key == "tool_choice": responses_api_request["tool_choice"] = self._normalize_tool_choice_for_responses_api(value) elif key == "stream_options": diff --git a/tests/test_litellm/completion_extras/litellm_responses_transformation/test_completion_extras_litellm_responses_transformation_transformation.py b/tests/test_litellm/completion_extras/litellm_responses_transformation/test_completion_extras_litellm_responses_transformation_transformation.py index e4ada0a9b31..c326ad4a0f7 100644 --- a/tests/test_litellm/completion_extras/litellm_responses_transformation/test_completion_extras_litellm_responses_transformation_transformation.py +++ b/tests/test_litellm/completion_extras/litellm_responses_transformation/test_completion_extras_litellm_responses_transformation_transformation.py @@ -4287,3 +4287,36 @@ def test_system_string_after_a_developer_message_stays_in_input_in_client_order( assert instructions is None assert [item["role"] for item in input_items] == ["developer", "system", "user"] assert input_items[1] == _system_input_item("Be brief.") + + +def test_map_optional_params_verbosity_merges_into_text(): + """Chat verbosity must land on Responses text.verbosity alongside text.format regardless of key order.""" + from litellm.completion_extras.litellm_responses_transformation.transformation import ( + LiteLLMResponsesTransformationHandler, + ) + from litellm.types.llms.openai import ResponsesAPIOptionalRequestParams + + handler: Final = LiteLLMResponsesTransformationHandler() + + responses_api_request = ResponsesAPIOptionalRequestParams() + handler._map_optional_params_to_responses_api_request( + {"verbosity": "low", "response_format": {"type": "json_object"}}, + responses_api_request, + ) + assert responses_api_request["text"]["verbosity"] == "low" + assert responses_api_request["text"]["format"]["type"] == "json_object" + + reversed_request = ResponsesAPIOptionalRequestParams() + handler._map_optional_params_to_responses_api_request( + {"response_format": {"type": "json_object"}, "verbosity": "low"}, + reversed_request, + ) + assert reversed_request["text"]["verbosity"] == "low" + assert reversed_request["text"]["format"]["type"] == "json_object" + + verbosity_only_request = ResponsesAPIOptionalRequestParams() + handler._map_optional_params_to_responses_api_request( + {"verbosity": "low"}, + verbosity_only_request, + ) + assert verbosity_only_request["text"] == {"verbosity": "low"} From 438681be1af44cc5b846736a8a226a4083c4421f Mon Sep 17 00:00:00 2001 From: kerry Date: Wed, 16 Sep 2026 23:33:28 +0000 Subject: [PATCH 3/7] refactor(responses_bridge): share text merge helper Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- .../transformation.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/litellm/completion_extras/litellm_responses_transformation/transformation.py b/litellm/completion_extras/litellm_responses_transformation/transformation.py index a76032854b7..e1d915dca39 100644 --- a/litellm/completion_extras/litellm_responses_transformation/transformation.py +++ b/litellm/completion_extras/litellm_responses_transformation/transformation.py @@ -502,11 +502,11 @@ class LiteLLMResponsesTransformationHandler(CompletionTransformationBridge): elif key == "response_format": text_format = self._transform_response_format_to_text_format(value) if text_format: - existing_text = cast("dict[str, object]", responses_api_request["text"] if "text" in responses_api_request else {}) - responses_api_request["text"] = cast("ResponseText", {**existing_text, **text_format}) + responses_api_request["text"] = self._merge_text(responses_api_request, text_format) elif key == "verbosity": - existing_text = cast("dict[str, object]", responses_api_request["text"] if "text" in responses_api_request else {}) - responses_api_request["text"] = cast("ResponseText", {**existing_text, "verbosity": value}) + responses_api_request["text"] = self._merge_text( + responses_api_request, {"verbosity": cast(object, value)} + ) elif key == "tool_choice": responses_api_request["tool_choice"] = self._normalize_tool_choice_for_responses_api(value) elif key == "stream_options": @@ -522,6 +522,15 @@ class LiteLLMResponsesTransformationHandler(CompletionTransformationBridge): elif key == "web_search_options": self._add_web_search_tool(responses_api_request, value) + @staticmethod + def _merge_text( + responses_api_request: "ResponsesAPIOptionalRequestParams", update: Mapping[str, object] + ) -> "ResponseText": + existing: Final = cast( + "dict[str, object]", responses_api_request["text"] if "text" in responses_api_request else {} + ) + return cast("ResponseText", {**existing, **update}) + def _build_sanitized_litellm_params(self, litellm_params: dict) -> dict[str, object]: """Build sanitized litellm_params with merged metadata.""" responses_optional_param_keys: Final = set(ResponsesAPIOptionalRequestParams.__annotations__.keys()) From 255ef3bc267bea22259415c7f79a1f135a46de35 Mon Sep 17 00:00:00 2001 From: kerry Date: Wed, 16 Sep 2026 23:37:45 +0000 Subject: [PATCH 4/7] refactor(bedrock_mantle): build supported params without mutation Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- .../bedrock_mantle/chat/transformation.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/litellm/llms/bedrock_mantle/chat/transformation.py b/litellm/llms/bedrock_mantle/chat/transformation.py index 5b69d7aff42..41d93a8dd4d 100644 --- a/litellm/llms/bedrock_mantle/chat/transformation.py +++ b/litellm/llms/bedrock_mantle/chat/transformation.py @@ -109,15 +109,22 @@ class BedrockMantleChatConfig(BedrockMantleAuthMixin, OpenAILikeChatConfig): def get_supported_openai_params(self, model: str) -> list: base_params: Final = super().get_supported_openai_params(model) - if is_gpt_reasoning_series_name(model) and "verbosity" not in base_params: - base_params.append("verbosity") + extra_params: Final = tuple( + param + for param, supported in ( + ("verbosity", is_gpt_reasoning_series_name(model)), + ("reasoning_effort", self._supports_reasoning(model)), + ) + if supported and param not in base_params + ) + return [*base_params, *extra_params] + + def _supports_reasoning(self, model: str) -> bool: try: - if litellm.supports_reasoning(model=model, custom_llm_provider=self.custom_llm_provider): - if "reasoning_effort" not in base_params: - base_params.append("reasoning_effort") + return litellm.supports_reasoning(model=model, custom_llm_provider=self.custom_llm_provider) except Exception as e: verbose_logger.debug("BedrockMantleChatConfig: error checking reasoning support: %s", e) - return base_params + return False def get_model_response_iterator( self, From 92121242666fade26b8680063bdb9e5a749e4ce5 Mon Sep 17 00:00:00 2001 From: kerry Date: Wed, 16 Sep 2026 23:37:45 +0000 Subject: [PATCH 5/7] style(responses_bridge): use dict.get in text merge helper Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- .../litellm_responses_transformation/transformation.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/litellm/completion_extras/litellm_responses_transformation/transformation.py b/litellm/completion_extras/litellm_responses_transformation/transformation.py index e1d915dca39..eaf7f47552c 100644 --- a/litellm/completion_extras/litellm_responses_transformation/transformation.py +++ b/litellm/completion_extras/litellm_responses_transformation/transformation.py @@ -526,9 +526,7 @@ class LiteLLMResponsesTransformationHandler(CompletionTransformationBridge): def _merge_text( responses_api_request: "ResponsesAPIOptionalRequestParams", update: Mapping[str, object] ) -> "ResponseText": - existing: Final = cast( - "dict[str, object]", responses_api_request["text"] if "text" in responses_api_request else {} - ) + existing: Final = cast("dict[str, object]", dict(responses_api_request).get("text") or {}) return cast("ResponseText", {**existing, **update}) def _build_sanitized_litellm_params(self, litellm_params: dict) -> dict[str, object]: From b7a9042f1b2930303dd67ec316c43e48348b7909 Mon Sep 17 00:00:00 2001 From: kerry Date: Wed, 16 Sep 2026 23:43:04 +0000 Subject: [PATCH 6/7] style(responses_bridge): suppress type-discipline flags with reasons Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- .../transformation.py | 12 +++++++++--- litellm/llms/bedrock_mantle/chat/transformation.py | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/litellm/completion_extras/litellm_responses_transformation/transformation.py b/litellm/completion_extras/litellm_responses_transformation/transformation.py index eaf7f47552c..11fa2a2bab6 100644 --- a/litellm/completion_extras/litellm_responses_transformation/transformation.py +++ b/litellm/completion_extras/litellm_responses_transformation/transformation.py @@ -505,7 +505,8 @@ class LiteLLMResponsesTransformationHandler(CompletionTransformationBridge): responses_api_request["text"] = self._merge_text(responses_api_request, text_format) elif key == "verbosity": responses_api_request["text"] = self._merge_text( - responses_api_request, {"verbosity": cast(object, value)} + responses_api_request, + MappingProxyType({"verbosity": value}), # pyright: ignore[reportUnknownArgumentType] # untyped value ) elif key == "tool_choice": responses_api_request["tool_choice"] = self._normalize_tool_choice_for_responses_api(value) @@ -526,8 +527,13 @@ class LiteLLMResponsesTransformationHandler(CompletionTransformationBridge): def _merge_text( responses_api_request: "ResponsesAPIOptionalRequestParams", update: Mapping[str, object] ) -> "ResponseText": - existing: Final = cast("dict[str, object]", dict(responses_api_request).get("text") or {}) - return cast("ResponseText", {**existing, **update}) + existing: Final = cast( # cast-ok: text field is a ResponseText | dict[str, Any] | None union + "dict[str, object]", + dict(responses_api_request).get("text") or {}, # mutable-ok: one-shot merge seed + ) + return cast( # cast-ok: merged mapping is a valid ResponseText shape + "ResponseText", {**existing, **update} # mutable-ok: one-shot merged payload + ) def _build_sanitized_litellm_params(self, litellm_params: dict) -> dict[str, object]: """Build sanitized litellm_params with merged metadata.""" diff --git a/litellm/llms/bedrock_mantle/chat/transformation.py b/litellm/llms/bedrock_mantle/chat/transformation.py index 41d93a8dd4d..590919f1fb0 100644 --- a/litellm/llms/bedrock_mantle/chat/transformation.py +++ b/litellm/llms/bedrock_mantle/chat/transformation.py @@ -117,7 +117,7 @@ class BedrockMantleChatConfig(BedrockMantleAuthMixin, OpenAILikeChatConfig): ) if supported and param not in base_params ) - return [*base_params, *extra_params] + return [*base_params, *extra_params] # mutable-ok: fresh list required by the inherited signature def _supports_reasoning(self, model: str) -> bool: try: From bba15b13824d392bee91bf0e36ede1d99e84fc40 Mon Sep 17 00:00:00 2001 From: kerry Date: Wed, 16 Sep 2026 23:52:53 +0000 Subject: [PATCH 7/7] style(responses_bridge): apply ruff format Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- .../litellm_responses_transformation/transformation.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/litellm/completion_extras/litellm_responses_transformation/transformation.py b/litellm/completion_extras/litellm_responses_transformation/transformation.py index 11fa2a2bab6..1b976f5a48b 100644 --- a/litellm/completion_extras/litellm_responses_transformation/transformation.py +++ b/litellm/completion_extras/litellm_responses_transformation/transformation.py @@ -532,7 +532,8 @@ class LiteLLMResponsesTransformationHandler(CompletionTransformationBridge): dict(responses_api_request).get("text") or {}, # mutable-ok: one-shot merge seed ) return cast( # cast-ok: merged mapping is a valid ResponseText shape - "ResponseText", {**existing, **update} # mutable-ok: one-shot merged payload + "ResponseText", + {**existing, **update}, # mutable-ok: one-shot merged payload ) def _build_sanitized_litellm_params(self, litellm_params: dict) -> dict[str, object]: