From 3705e7bcce45d12e344871450f7d296ae60aaa3f Mon Sep 17 00:00:00 2001 From: mateo-berri <277851410+mateo-berri@users.noreply.github.com> Date: Fri, 6 Nov 2026 01:56:11 -0800 Subject: [PATCH] fix(bedrock): keep a Responses batch row's drop_params and keep it out of passthrough rows --- litellm/llms/bedrock/files/transformation.py | 8 +++-- .../test_bedrock_files_transformation.py | 32 ++++++++++++------- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/litellm/llms/bedrock/files/transformation.py b/litellm/llms/bedrock/files/transformation.py index 931160f3266..65f402195a5 100644 --- a/litellm/llms/bedrock/files/transformation.py +++ b/litellm/llms/bedrock/files/transformation.py @@ -1021,7 +1021,11 @@ class BedrockFilesConfig(BaseAWSLLM, BaseFilesConfig): model), so `input`, `instructions`, `max_output_tokens` and the tool params translate identically in batch and real time. """ - return responses_batch_body_to_chat_body(openai_request_body) + chat_body: Final = responses_batch_body_to_chat_body(openai_request_body) + drop_params: Final = openai_request_body.get("drop_params") + if drop_params is None: + return chat_body + return _frozen_mapping(chain(chat_body.items(), (("drop_params", drop_params),))) @staticmethod def _transform_batch_body_to_chat_body( @@ -1119,7 +1123,7 @@ class BedrockFilesConfig(BaseAWSLLM, BaseFilesConfig): # like openai.gpt-oss-*, qwen, deepseek, etc.) --- return { "messages": messages, - **optional_params, + **{k: v for k, v in optional_params.items() if k != "drop_params"}, } def _resolve_batch_record_model_and_provider( diff --git a/tests/unit/llms/bedrock/files/test_bedrock_files_transformation.py b/tests/unit/llms/bedrock/files/test_bedrock_files_transformation.py index 349247b2ff6..c411a85a9f8 100644 --- a/tests/unit/llms/bedrock/files/test_bedrock_files_transformation.py +++ b/tests/unit/llms/bedrock/files/test_bedrock_files_transformation.py @@ -100,16 +100,15 @@ class TestBedrockFilesTransformation: assert result[0]["modelInput"]["max_tokens"] == 10 @staticmethod - def _nova_row(**body_params: object) -> dict[str, object]: + def _nova_row( + url: str = "/v1/chat/completions", model: str = "us.amazon.nova-pro-v1:0", **body_params: object + ) -> dict[str, object]: + prompt: Final = {"input": "hi"} if url == "/v1/responses" else {"messages": [{"role": "user", "content": "hi"}]} return { "custom_id": "nova-tier-1", "method": "POST", - "url": "/v1/chat/completions", - "body": { - "model": "us.amazon.nova-pro-v1:0", - "messages": [{"role": "user", "content": "hi"}], - **body_params, - }, + "url": url, + "body": {"model": model, **prompt, **body_params}, } def test_nova_row_with_null_service_tier_sends_no_tier(self): @@ -119,18 +118,29 @@ class TestBedrockFilesTransformation: assert "serviceTier" not in result[0]["modelInput"] - def test_nova_row_with_unmapped_service_tier_fails_the_row_like_real_time(self): + @pytest.mark.parametrize("url", ["/v1/chat/completions", "/v1/responses"]) + def test_nova_row_with_unmapped_service_tier_fails_the_row_like_real_time(self, url: str): with pytest.raises(litellm.UnsupportedParamsError, match="ultrafast"): BedrockFilesConfig().transform_openai_jsonl_content_to_bedrock_jsonl_content( - [self._nova_row(service_tier="ultrafast")] + [self._nova_row(url, service_tier="ultrafast")] ) - def test_nova_row_level_drop_params_drops_the_unmapped_service_tier(self): + @pytest.mark.parametrize("url", ["/v1/chat/completions", "/v1/responses"]) + def test_nova_row_level_drop_params_drops_the_unmapped_service_tier(self, url: str): result: Final = BedrockFilesConfig().transform_openai_jsonl_content_to_bedrock_jsonl_content( - [self._nova_row(service_tier="ultrafast", drop_params=True)] + [self._nova_row(url, service_tier="ultrafast", drop_params=True)] ) assert "serviceTier" not in result[0]["modelInput"] + assert "drop_params" not in json.dumps(result[0]["modelInput"]) + + @pytest.mark.parametrize("url", ["/v1/chat/completions", "/v1/responses"]) + def test_passthrough_row_keeps_row_level_drop_params_out_of_the_model_input(self, url: str): + result: Final = BedrockFilesConfig().transform_openai_jsonl_content_to_bedrock_jsonl_content( + [self._nova_row(url, "openai.gpt-oss-120b-1:0", drop_params=True)] + ) + + assert "drop_params" not in result[0]["modelInput"] def test_nova_text_only_uses_converse_format(self): """