fix(anthropic): allow effort='max' on Claude Opus 4.7

Anthropic's Messages API accepts `output_config.effort="max"` on
`claude-opus-4-7-*` models, but `_apply_output_config` hardcoded the
gate to `_is_opus_4_6_model`, so any request hitting LiteLLM with
Opus 4.7 + effort=max was rejected with a 400 before reaching Anthropic.

This was preserved on purpose in #25867 (day-0 4.7 PR) under the old
assumption that `max` was Opus-4.6-only. The Anthropic API has since
extended `max` support to Opus 4.7.

Allow the effort=max guard to also accept Opus 4.7. Update the two
existing rejection tests to match the new error message and add a new
regression test for Opus 4.7.

Fixes #25957
This commit is contained in:
shang309073819 2026-04-17 14:52:00 +00:00
parent 2f22a1293e
commit de196e4c41
2 changed files with 32 additions and 7 deletions

View file

@ -1534,11 +1534,15 @@ class AnthropicConfig(AnthropicModelInfo, BaseConfig):
f"Invalid effort value: {effort}. Must be one of: "
f"'high', 'medium', 'low', 'xhigh', 'max'"
)
# ``max`` is Claude Opus 4.6 only (not Sonnet 4.6, not Opus 4.5/4.7).
# Keep this hardcoded so the error message is specific and stable.
if effort == "max" and not self._is_opus_4_6_model(model):
# ``max`` is supported by Claude Opus 4.6 and Opus 4.7 (not Sonnet 4.6,
# not Opus 4.5). The upstream Anthropic API accepts effort=max on both
# Opus 4.6 and 4.7, so we keep both substring checks here for
# date-variant tolerance (e.g. claude-opus-4-7-20260408). See #25957.
if effort == "max" and not (
self._is_opus_4_6_model(model) or self._is_opus_4_7_model(model)
):
raise ValueError(
f"effort='max' is only supported by Claude Opus 4.6. "
f"effort='max' is only supported by Claude Opus 4.6 and 4.7. "
f"Got model: {model}"
)
# ``xhigh`` is data-driven via ``supports_xhigh_reasoning_effort`` so

View file

@ -1654,7 +1654,7 @@ def test_max_effort_rejected_for_opus_45():
messages = [{"role": "user", "content": "Test"}]
with pytest.raises(
ValueError, match="effort='max' is only supported by Claude Opus 4.6"
ValueError, match="effort='max' is only supported by Claude Opus 4.6 and 4.7"
):
optional_params = {"output_config": {"effort": "max"}}
config.transform_request(
@ -2213,12 +2213,12 @@ def test_reasoning_effort_does_not_set_output_config_for_older_models():
def test_max_effort_rejected_for_sonnet_46():
"""Test that effort='max' is rejected for Sonnet 4.6 (only Opus 4.6 supports max)."""
"""Test that effort='max' is rejected for Sonnet 4.6 (Sonnet 4.6 doesn't support max)."""
config = AnthropicConfig()
messages = [{"role": "user", "content": "Test"}]
with pytest.raises(
ValueError, match="effort='max' is only supported by Claude Opus 4.6"
ValueError, match="effort='max' is only supported by Claude Opus 4.6 and 4.7"
):
config.transform_request(
model="claude-sonnet-4-6-20260219",
@ -2245,6 +2245,27 @@ def test_max_effort_accepted_for_opus_46():
assert result["output_config"]["effort"] == "max"
def test_max_effort_accepted_for_opus_47():
"""Regression for #25957 - effort='max' must work for Opus 4.7.
Anthropic's Messages API accepts ``output_config.effort='max'`` on
``claude-opus-4-7-*`` models. The previous hardcoded ``_is_opus_4_6_model``
guard rejected the request before it ever reached Anthropic.
"""
config = AnthropicConfig()
messages = [{"role": "user", "content": "Test"}]
result = config.transform_request(
model="claude-opus-4-7-20260416",
messages=messages,
optional_params={"output_config": {"effort": "max"}},
litellm_params={},
headers={},
)
assert result["output_config"]["effort"] == "max"
def test_effort_beta_header_not_injected_for_46_models():
"""
Test that is_effort_used returns False for Claude 4.6 models.