From 92221383e545329486adf8ae936648030e2d0876 Mon Sep 17 00:00:00 2001 From: mateo-berri <277851410+mateo-berri@users.noreply.github.com> Date: Thu, 29 Oct 2026 07:00:22 -0700 Subject: [PATCH] fix(anthropic): reject background on /v1/messages to the Responses bridge unless drop_params drops it --- .../messages/responses_adapters/handler.py | 25 +++++++++++++- .../test_responses_adapters_handler.py | 33 +++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/litellm/llms/anthropic/messages/responses_adapters/handler.py b/litellm/llms/anthropic/messages/responses_adapters/handler.py index 9b22170c9db..fadfdd45579 100644 --- a/litellm/llms/anthropic/messages/responses_adapters/handler.py +++ b/litellm/llms/anthropic/messages/responses_adapters/handler.py @@ -60,6 +60,28 @@ def _forwarded_kwargs(extra_kwargs: Mapping[str, object] | None) -> Mapping[str, return extra_kwargs or {} +def _drops_background(forwarded_kwargs: Mapping[str, object]) -> bool: + additional_drop_params: Final = forwarded_kwargs.get("additional_drop_params") + return drops_unsupported_params(forwarded_kwargs.get("drop_params")) or ( + isinstance(additional_drop_params, list) and "background" in additional_drop_params + ) + + +def _reject_background_mode(model: str, forwarded_kwargs: Mapping[str, object]) -> None: + if forwarded_kwargs.get("background") is None or _drops_background(forwarded_kwargs): + return + provider: Final = forwarded_kwargs.get("custom_llm_provider") + raise litellm.UnsupportedParamsError( + model=model, + llm_provider=provider if isinstance(provider, str) else None, + message=( + f"/v1/messages does not support parameters: ['background'], for model={model}. " + "A background run answers with a response id the Anthropic Messages API has no way to retrieve. " + "To drop it, set `litellm.drop_params=True` or for proxy:\n\n`litellm_settings:\n drop_params: true`\n" + ), + ) + + def _provider_returns_encrypted_reasoning(model: str, custom_llm_provider: object) -> bool: provider: Final = ( custom_llm_provider if isinstance(custom_llm_provider, str) else litellm.get_llm_provider(model=model)[1] @@ -162,6 +184,7 @@ def _build_responses_kwargs( """ forwarded_kwargs: Final = _forwarded_kwargs(extra_kwargs) reject_malformed_tool_result_text(messages, model, forwarded_kwargs) + _reject_background_mode(model, forwarded_kwargs) block_rewrite: Final = _prompt_cache_block_rewrite(model, forwarded_kwargs) request_messages: Final[AnthropicRequestMessages] = ( [ @@ -237,7 +260,7 @@ def _build_responses_kwargs( responses_kwargs["stream"] = True # Forward litellm-specific kwargs (api_key, api_base, logging obj, etc.) - excluded: Final = CONVERTED_STREAM_KEYS | {"anthropic_messages"} + excluded: Final = CONVERTED_STREAM_KEYS | {"anthropic_messages", "background"} for key, value in forwarded_kwargs.items(): if key == "litellm_logging_obj" and value is not None: from litellm.litellm_core_utils.litellm_logging import ( diff --git a/tests/unit/llms/anthropic/messages/responses_adapters/test_responses_adapters_handler.py b/tests/unit/llms/anthropic/messages/responses_adapters/test_responses_adapters_handler.py index bba5413fbdf..6adbfe4fe65 100644 --- a/tests/unit/llms/anthropic/messages/responses_adapters/test_responses_adapters_handler.py +++ b/tests/unit/llms/anthropic/messages/responses_adapters/test_responses_adapters_handler.py @@ -683,6 +683,39 @@ def test_tool_result_text_block_without_text_still_reaches_the_model_as_empty_te ] +@pytest.mark.parametrize("background", [True, False]) +def test_background_answers_400_without_drop_params(background: bool) -> None: + with pytest.raises(litellm.UnsupportedParamsError) as rejected: + _build_responses_kwargs( + model="openai/gpt-5.6", + extra_kwargs={**OPENAI_API, "background": background}, + max_tokens=1024, + messages=MESSAGES, + ) + + assert rejected.value.status_code == 400 + assert "['background']" in rejected.value.message + + +@pytest.mark.parametrize( + "drop_setting", + [ + pytest.param({"drop_params": True}, id="drop_params"), + pytest.param({"additional_drop_params": ["background"]}, id="additional_drop_params"), + ], +) +def test_dropped_background_never_reaches_the_responses_request(drop_setting: Mapping[str, object]) -> None: + responses_kwargs: Final = _build_responses_kwargs( + model="openai/gpt-5.6", + extra_kwargs={**OPENAI_API, **drop_setting, "background": True}, + max_tokens=1024, + messages=MESSAGES, + ) + + assert "background" not in responses_kwargs + assert responses_kwargs["max_output_tokens"] == 1024 + + REASONING_MODEL: Final = "gpt-bridge-reasoning-cost" REASONING_RATES: Final = { "input_cost_per_token": 2e-06,