feat: route future Claude models to Anthropic provider via pattern matching

Add pattern-based matching for Claude model names so that future models
(e.g., claude-opus-4-9, claude-sonnet-5-0) are automatically routed to
the Anthropic provider without requiring model_prices_and_context_window.json
updates.

The pattern matches: claude-{opus|sonnet|haiku}-{major}-{minor}[-YYYYMMDD]

https://claude.ai/code/session_017asCVDN5jBFMBcZRjiQR6C
This commit is contained in:
mateo-berri 2026-05-29 00:05:39 +00:00
parent 5e2d75d75d
commit 8a31571bc1
No known key found for this signature in database
2 changed files with 118 additions and 0 deletions

View file

@ -71,6 +71,29 @@ def _is_azure_claude_model(model: str) -> bool:
return False
import re
_CLAUDE_PATTERN = re.compile(
r"^claude-(?:opus|sonnet|haiku)-\d+-\d+(?:-\d{8})?$", re.IGNORECASE
)
def _matches_claude_model_pattern(model: str) -> bool:
"""
Check if a model string matches the Claude model naming pattern.
Matches patterns like:
- claude-opus-4-7
- claude-sonnet-4-6
- claude-haiku-4-5
- claude-opus-5-1-20270101 (with optional date suffix)
This allows future Claude models to be routed to the Anthropic provider
without requiring updates to model_prices_and_context_window.json.
"""
return _CLAUDE_PATTERN.match(model) is not None
def handle_cohere_chat_model_custom_llm_provider(
model: str, custom_llm_provider: Optional[str] = None
) -> Tuple[str, Optional[str]]:
@ -398,6 +421,9 @@ def get_llm_provider( # noqa: PLR0915
custom_llm_provider = "anthropic_text"
else:
custom_llm_provider = "anthropic"
## anthropic - pattern-based matching for future Claude models
elif _matches_claude_model_pattern(model):
custom_llm_provider = "anthropic"
## cohere
elif model in litellm.cohere_models or model in litellm.cohere_embedding_models:
custom_llm_provider = "cohere"

View file

@ -478,3 +478,95 @@ def test_get_llm_provider_use_proxy_arg_true_with_direct_args():
assert key == arg_api_key # Should use the argument key
assert base == arg_api_base # Should use the argument base
# -------- Tests for Claude model pattern matching ---------
class TestClaudeModelPatternMatching:
"""
Tests for _matches_claude_model_pattern which routes future Claude models
to the Anthropic provider without requiring model_prices_and_context_window.json updates.
"""
def test_matches_claude_opus_pattern(self):
"""Test claude-opus-X-Y pattern matching."""
from litellm.litellm_core_utils.get_llm_provider_logic import (
_matches_claude_model_pattern,
)
assert _matches_claude_model_pattern("claude-opus-4-7") is True
assert _matches_claude_model_pattern("claude-opus-4-9") is True
assert _matches_claude_model_pattern("claude-opus-5-1") is True
def test_matches_claude_sonnet_pattern(self):
"""Test claude-sonnet-X-Y pattern matching."""
from litellm.litellm_core_utils.get_llm_provider_logic import (
_matches_claude_model_pattern,
)
assert _matches_claude_model_pattern("claude-sonnet-4-6") is True
assert _matches_claude_model_pattern("claude-sonnet-5-0") is True
def test_matches_claude_haiku_pattern(self):
"""Test claude-haiku-X-Y pattern matching."""
from litellm.litellm_core_utils.get_llm_provider_logic import (
_matches_claude_model_pattern,
)
assert _matches_claude_model_pattern("claude-haiku-4-5") is True
assert _matches_claude_model_pattern("claude-haiku-5-0") is True
def test_matches_claude_with_date_suffix(self):
"""Test claude model pattern with date suffix."""
from litellm.litellm_core_utils.get_llm_provider_logic import (
_matches_claude_model_pattern,
)
assert _matches_claude_model_pattern("claude-opus-5-1-20270101") is True
assert _matches_claude_model_pattern("claude-sonnet-4-7-20260601") is True
assert _matches_claude_model_pattern("claude-haiku-4-6-20251201") is True
def test_rejects_non_claude_models(self):
"""Test that non-Claude models are not matched."""
from litellm.litellm_core_utils.get_llm_provider_logic import (
_matches_claude_model_pattern,
)
assert _matches_claude_model_pattern("gpt-4") is False
assert _matches_claude_model_pattern("mistral-large") is False
assert _matches_claude_model_pattern("llama-3") is False
def test_rejects_invalid_claude_patterns(self):
"""Test that invalid Claude model patterns are not matched."""
from litellm.litellm_core_utils.get_llm_provider_logic import (
_matches_claude_model_pattern,
)
# Wrong order (variant before name)
assert _matches_claude_model_pattern("claude-4-opus") is False
# Missing version numbers
assert _matches_claude_model_pattern("claude-opus") is False
# Old format (claude-3-opus instead of claude-opus-3)
assert _matches_claude_model_pattern("claude-3-opus-20240229") is False
# Invalid variant
assert _matches_claude_model_pattern("claude-mini-4-5") is False
def test_get_llm_provider_future_claude_model(self):
"""Test that get_llm_provider routes future Claude models to anthropic."""
model, custom_llm_provider, dynamic_api_key, api_base = (
litellm.get_llm_provider(
model="claude-opus-4-9",
)
)
assert custom_llm_provider == "anthropic"
assert model == "claude-opus-4-9"
def test_get_llm_provider_future_claude_model_with_date(self):
"""Test that get_llm_provider routes future Claude models with date suffix."""
model, custom_llm_provider, dynamic_api_key, api_base = (
litellm.get_llm_provider(
model="claude-opus-5-1-20270101",
)
)
assert custom_llm_provider == "anthropic"
assert model == "claude-opus-5-1-20270101"