fix(anthropic): apply the background check to extra_body on the /v1/messages Responses bridge

litellm merges extra_body into the upstream Responses request, so background inside it started a background run past the top-level check. It now answers 400 without drop_params and is stripped from extra_body when dropped.
This commit is contained in:
mateo-berri 2026-11-06 13:43:08 -08:00
parent b70ef69180
commit 2d243a3f4a
2 changed files with 31 additions and 5 deletions

View file

@ -179,8 +179,19 @@ def _drops_background(forwarded_kwargs: Mapping[str, object]) -> bool:
)
def _requests_background(forwarded_kwargs: Mapping[str, object]) -> bool:
extra_body: Final = as_str_mapping(forwarded_kwargs.get("extra_body"))
return forwarded_kwargs.get("background") is not None or (
extra_body is not None and extra_body.get("background") is not None
)
def _without_background(extra_body: Mapping[str, object]) -> Mapping[str, object]:
return {key: value for key, value in extra_body.items() if key != "background"}
def _reject_background_mode(model: str, forwarded_kwargs: Mapping[str, object]) -> None:
if forwarded_kwargs.get("background") is None or _drops_background(forwarded_kwargs):
if not _requests_background(forwarded_kwargs) or _drops_background(forwarded_kwargs):
return
provider: Final = forwarded_kwargs.get("custom_llm_provider")
raise litellm.UnsupportedParamsError(
@ -396,6 +407,8 @@ def _build_responses_kwargs(
# Responses API result back to a ModelResponse for the row.
setattr(value, "call_type", CallTypes.anthropic_messages.value)
responses_kwargs[key] = value
elif key == "extra_body" and (extra_body := as_str_mapping(value)) is not None:
responses_kwargs[key] = _without_background(extra_body)
elif key not in excluded and key not in responses_kwargs and value is not None:
responses_kwargs[key] = value

View file

@ -684,12 +684,19 @@ 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:
@pytest.mark.parametrize(
"background_request",
[
pytest.param({"background": True}, id="background-true"),
pytest.param({"background": False}, id="background-false"),
pytest.param({"extra_body": {"background": True}}, id="extra-body-background"),
],
)
def test_background_answers_400_without_drop_params(background_request: Mapping[str, object]) -> None:
with pytest.raises(litellm.UnsupportedParamsError) as rejected:
_build_responses_kwargs(
model="openai/gpt-5.6",
extra_kwargs={**OPENAI_API, "background": background},
extra_kwargs={**OPENAI_API, **background_request},
max_tokens=1024,
messages=MESSAGES,
)
@ -708,12 +715,18 @@ def test_background_answers_400_without_drop_params(background: bool) -> None:
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},
extra_kwargs={
**OPENAI_API,
**drop_setting,
"background": True,
"extra_body": {"background": True, "service_tier": "priority"},
},
max_tokens=1024,
messages=MESSAGES,
)
assert "background" not in responses_kwargs
assert responses_kwargs["extra_body"] == {"service_tier": "priority"}
assert responses_kwargs["max_output_tokens"] == 1024