test(anthropic): cover sync /v1/messages context-1m path and pin tests to our beta constant

Add the context-1m beta through the immutable all_betas union instead of mutating the
betas set, assert against ANTHROPIC_BETA_HEADER_VALUES rather than the vendor string, and
move the tests to the latest Sonnet model
This commit is contained in:
hx 2026-10-15 19:22:55 +08:00
parent 3e651127ae
commit c65046e75f
4 changed files with 48 additions and 22 deletions

View file

@ -1254,9 +1254,7 @@ class AnthropicModelInfo(BaseLLMModelInfo):
wif_minted: bool = False,
context_1m_requested: bool = False,
) -> dict:
betas: Final[set[str]] = set()
if context_1m_requested:
betas.add(ANTHROPIC_BETA_HEADER_VALUES.CONTEXT_1M_2025_08_07.value)
betas: Final = set()
# Anthropic no longer requires the prompt-caching beta header
# Prompt caching now works automatically when cache_control is used in messages
# Reference: https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching
@ -1313,6 +1311,7 @@ class AnthropicModelInfo(BaseLLMModelInfo):
betas.update(user_anthropic_beta_headers)
all_betas: Final = betas.union(
(ANTHROPIC_BETA_HEADER_VALUES.CONTEXT_1M_2025_08_07.value,) if context_1m_requested else (),
(ANTHROPIC_THINKING_DISPLAY_UPDATES_BETA_HEADER,) if is_thinking_display_updates_used else (),
(ANTHROPIC_MID_CONVERSATION_TOOL_CHANGES_BETA_HEADER,) if is_mid_conversation_tool_change_used else (),
)

View file

@ -9827,14 +9827,17 @@ def test_transform_request_treats_context_1m_model_as_its_base_model(optional_pa
headers={},
)
assert transform("claude-sonnet-4-6[1m]") == transform("claude-sonnet-4-6")
assert transform("claude-sonnet-5-5[1m]") == transform("claude-sonnet-5-5")
@pytest.mark.parametrize(
"model,expected_betas",
[
("anthropic/claude-sonnet-4-6[1m]", {"context-1m-2025-08-07", "interleaved-thinking-2025-05-14"}),
("anthropic/claude-sonnet-4-6", {"interleaved-thinking-2025-05-14"}),
(
"anthropic/claude-sonnet-5-5[1m]",
{ANTHROPIC_BETA_HEADER_VALUES.CONTEXT_1M_2025_08_07.value, "interleaved-thinking-2025-05-14"},
),
("anthropic/claude-sonnet-5-5", {"interleaved-thinking-2025-05-14"}),
],
)
async def test_acompletion_context_1m_suffix_sends_base_model_with_beta(
@ -9852,7 +9855,7 @@ async def test_acompletion_context_1m_suffix_sends_base_model_with_beta(
"id": "msg_context_1m",
"type": "message",
"role": "assistant",
"model": "claude-sonnet-4-6",
"model": "claude-sonnet-5-5",
"content": [{"type": "text", "text": "hi"}],
"stop_reason": "end_turn",
"usage": {"input_tokens": 1, "output_tokens": 1},
@ -9867,5 +9870,5 @@ async def test_acompletion_context_1m_suffix_sends_base_model_with_beta(
)
request: Final = route.calls.last.request
assert json.loads(request.content)["model"] == "claude-sonnet-4-6"
assert json.loads(request.content)["model"] == "claude-sonnet-5-5"
assert {beta.strip() for beta in request.headers["anthropic-beta"].split(",")} == expected_betas

View file

@ -6,13 +6,36 @@ import respx
import litellm
from litellm import Router
from litellm.llms.anthropic.pass_through.messages.transformation import AnthropicMessagesConfig
from litellm.types.llms.anthropic import ANTHROPIC_BETA_HEADER_VALUES
@pytest.mark.parametrize("model,expects_context_1m", [("claude-sonnet-5-5[1m]", True), ("claude-sonnet-5-5", False)])
def test_sync_messages_environment_adds_context_1m_beta_only_for_suffixed_model(
model: str, expects_context_1m: bool
) -> None:
headers, _ = AnthropicMessagesConfig().validate_anthropic_messages_environment(
headers={"anthropic-beta": "interleaved-thinking-2025-05-14"},
model=model,
messages=[{"role": "user", "content": "hi"}],
optional_params={},
litellm_params={},
api_key="test",
)
betas: Final = {beta.strip() for beta in headers["anthropic-beta"].split(",")}
assert (ANTHROPIC_BETA_HEADER_VALUES.CONTEXT_1M_2025_08_07.value in betas) is expects_context_1m
assert "interleaved-thinking-2025-05-14" in betas
@pytest.mark.parametrize(
"deployment_model,expected_betas",
[
("anthropic/claude-sonnet-4-6[1m]", {"context-1m-2025-08-07", "interleaved-thinking-2025-05-14"}),
("anthropic/claude-sonnet-4-6", {"interleaved-thinking-2025-05-14"}),
(
"anthropic/claude-sonnet-5-5[1m]",
{ANTHROPIC_BETA_HEADER_VALUES.CONTEXT_1M_2025_08_07.value, "interleaved-thinking-2025-05-14"},
),
("anthropic/claude-sonnet-5-5", {"interleaved-thinking-2025-05-14"}),
],
)
async def test_router_messages_context_1m_deployment_sends_base_model_with_beta(
@ -30,7 +53,7 @@ async def test_router_messages_context_1m_deployment_sends_base_model_with_beta(
"id": "msg_context_1m",
"type": "message",
"role": "assistant",
"model": "claude-sonnet-4-6",
"model": "claude-sonnet-5-5",
"content": [{"type": "text", "text": "hi"}],
"stop_reason": "end_turn",
"usage": {"input_tokens": 1, "output_tokens": 1},
@ -39,19 +62,19 @@ async def test_router_messages_context_1m_deployment_sends_base_model_with_beta(
router: Final = Router(
model_list=[
{
"model_name": "claude-sonnet-4-6[1m]",
"model_name": "claude-sonnet-5-5[1m]",
"litellm_params": {"model": deployment_model, "api_key": "test"},
}
]
)
await router.aanthropic_messages(
model="claude-sonnet-4-6[1m]",
model="claude-sonnet-5-5[1m]",
messages=[{"role": "user", "content": "hi"}],
max_tokens=16,
extra_headers={"anthropic-beta": "interleaved-thinking-2025-05-14"},
)
request: Final = route.calls.last.request
assert json.loads(request.content)["model"] == "claude-sonnet-4-6"
assert json.loads(request.content)["model"] == "claude-sonnet-5-5"
assert {beta.strip() for beta in request.headers["anthropic-beta"].split(",")} == expected_betas

View file

@ -4524,12 +4524,12 @@ def test_shared_legacy_thinking_translation_drops_a_non_numeric_budget_under_dro
@pytest.mark.parametrize(
"model,base_model",
[
("claude-sonnet-4-6[1m]", "claude-sonnet-4-6"),
("claude-sonnet-4-6[1M]", "claude-sonnet-4-6"),
("claude-sonnet-4-6", "claude-sonnet-4-6"),
("claude-[1m]-sonnet-4-6", "claude-[1m]-sonnet-4-6"),
("claude-sonnet-4-6[1m][1m]", "claude-sonnet-4-6[1m]"),
("claude-sonnet-4-6[200k]", "claude-sonnet-4-6[200k]"),
("claude-sonnet-5-5[1m]", "claude-sonnet-5-5"),
("claude-sonnet-5-5[1M]", "claude-sonnet-5-5"),
("claude-sonnet-5-5", "claude-sonnet-5-5"),
("claude-[1m]-sonnet-5-5", "claude-[1m]-sonnet-5-5"),
("claude-sonnet-5-5[1m][1m]", "claude-sonnet-5-5[1m]"),
("claude-sonnet-5-5[200k]", "claude-sonnet-5-5[200k]"),
],
)
def test_context_1m_suffix_is_only_a_trailing_marker(model: str, base_model: str) -> None:
@ -4539,11 +4539,12 @@ def test_context_1m_suffix_is_only_a_trailing_marker(model: str, base_model: str
assert has_context_1m_suffix(model) is (model != base_model)
@pytest.mark.parametrize("model,expects_context_1m", [("claude-sonnet-4-6[1m]", True), ("claude-sonnet-4-6", False)])
@pytest.mark.parametrize("model,expects_context_1m", [("claude-sonnet-5-5[1m]", True), ("claude-sonnet-5-5", False)])
def test_validate_environment_adds_context_1m_beta_only_for_suffixed_model(
model: str, expects_context_1m: bool
) -> None:
from litellm.llms.anthropic.common_utils import AnthropicModelInfo
from litellm.types.llms.anthropic import ANTHROPIC_BETA_HEADER_VALUES
headers: Final = AnthropicModelInfo().validate_environment(
headers={"anthropic-beta": "interleaved-thinking-2025-05-14"},
@ -4555,5 +4556,5 @@ def test_validate_environment_adds_context_1m_beta_only_for_suffixed_model(
)
betas: Final = {beta.strip() for beta in headers["anthropic-beta"].split(",")}
assert ("context-1m-2025-08-07" in betas) is expects_context_1m
assert (ANTHROPIC_BETA_HEADER_VALUES.CONTEXT_1M_2025_08_07.value in betas) is expects_context_1m
assert "interleaved-thinking-2025-05-14" in betas