fix(fallback-generalizations): cover bare Claude majors in baseline and routing, require claude- prefix in adaptive gate

This commit is contained in:
mateo-berri 2026-07-11 10:42:47 -07:00
parent 81e639398a
commit 6fa088224b
4 changed files with 57 additions and 21 deletions

View file

@ -45059,16 +45059,16 @@
},
{
"name": "anthropic-claude-ids",
"pattern": "^claude-[a-z]+-\\d+[-.]\\d+(?:-\\d{8})?$",
"description": "A bare Claude family-major-minor id, optionally with an 8-digit date suffix, anchored to the whole name. Routes an unmapped Claude id that carries no provider namespace to the Anthropic API.",
"pattern": "^claude-[a-z]+-\\d+(?:[-.]\\d+)?(?:-\\d{8})?$",
"description": "A bare Claude family-major id with an optional minor and an optional 8-digit date suffix, anchored to the whole name, so claude-newfamily-5 routes like claude-newfamily-5-1 does. Routes an unmapped Claude id that carries no provider namespace to the Anthropic API.",
"model_info": {
"litellm_provider": "anthropic"
}
},
{
"name": "claude-family-baseline",
"pattern": "claude-[a-z]+-\\d+[-.]\\d+(?:-\\d{8})?",
"description": "Any Claude family-major-minor id, optionally with an 8-digit date suffix, under any provider namespace (bare, bedrock-dotted, vertex, databricks, ...). Carries the model-family facts every Claude shares; it carries no pricing, so cost stays on the standard unpriced behavior rather than a guessed number.",
"pattern": "claude-[a-z]+-\\d+(?:[-.]\\d+)?(?:-\\d{8})?",
"description": "Any Claude family-major id with an optional minor and an optional 8-digit date suffix, under any provider namespace (bare, bedrock-dotted, vertex, databricks, ...), so bare majors like claude-newfamily-5 get the same baseline as claude-newfamily-5-1. Carries the model-family facts every Claude shares; it carries no pricing, so cost stays on the standard unpriced behavior rather than a guessed number.",
"model_info": {
"mode": "chat",
"max_input_tokens": 200000,
@ -45088,8 +45088,8 @@
},
{
"name": "claude-adaptive-thinking",
"pattern": "(?:opus|sonnet|haiku)[-._](?:4[-._](?:[6-9]|[1-9]\\d)(?!\\d)|(?:[5-9]|[1-9]\\d{1,})[-._]\\d{1,2}(?!\\d))|claude-[a-z]+-(?:[5-9]|[1-9]\\d)(?!\\d)(?:[-._]\\d{1,2}(?!\\d))?",
"description": "Claude opus/sonnet/haiku at version 4.6 or higher (4.6 through 4.99, then any later major-minor), plus any claude-<family>- id at major version 5 or higher, bare major or major-minor, so a new family shaped like claude-fable-5 is covered by the same gate as the core families. 4.x coverage stays limited to opus/sonnet/haiku. The minor is capped at two digits so an 8-digit date suffix such as claude-opus-4-20250514 is never read as a >= 4.6 minor. Turns on adaptive thinking for new versions and new families with no code change.",
"pattern": "claude-[a-z]+-(?:4[-._](?:[6-9]|[1-9]\\d)(?!\\d)|(?:[5-9]|[1-9]\\d)(?!\\d)(?:[-._]\\d{1,2}(?!\\d))?)",
"description": "Claude at version 4.6 or higher, in any id shape that contains claude-<family>-: minors 4.6 through 4.99, any later major-minor, and bare 5+ majors so a new family shaped like claude-fable-5 matches. Requiring the claude- prefix keeps non-Claude names such as team-sonnet-5-1 out. The minor is capped at two digits so an 8-digit date suffix such as claude-opus-4-20250514 is never read as a >= 4.6 minor. Turns on adaptive thinking for new versions and new families with no code change.",
"model_info": {
"supports_adaptive_thinking": true
}

View file

@ -45292,16 +45292,16 @@
},
{
"name": "anthropic-claude-ids",
"pattern": "^claude-[a-z]+-\\d+[-.]\\d+(?:-\\d{8})?$",
"description": "A bare Claude family-major-minor id, optionally with an 8-digit date suffix, anchored to the whole name. Routes an unmapped Claude id that carries no provider namespace to the Anthropic API.",
"pattern": "^claude-[a-z]+-\\d+(?:[-.]\\d+)?(?:-\\d{8})?$",
"description": "A bare Claude family-major id with an optional minor and an optional 8-digit date suffix, anchored to the whole name, so claude-newfamily-5 routes like claude-newfamily-5-1 does. Routes an unmapped Claude id that carries no provider namespace to the Anthropic API.",
"model_info": {
"litellm_provider": "anthropic"
}
},
{
"name": "claude-family-baseline",
"pattern": "claude-[a-z]+-\\d+[-.]\\d+(?:-\\d{8})?",
"description": "Any Claude family-major-minor id, optionally with an 8-digit date suffix, under any provider namespace (bare, bedrock-dotted, vertex, databricks, ...). Carries the model-family facts every Claude shares; it carries no pricing, so cost stays on the standard unpriced behavior rather than a guessed number.",
"pattern": "claude-[a-z]+-\\d+(?:[-.]\\d+)?(?:-\\d{8})?",
"description": "Any Claude family-major id with an optional minor and an optional 8-digit date suffix, under any provider namespace (bare, bedrock-dotted, vertex, databricks, ...), so bare majors like claude-newfamily-5 get the same baseline as claude-newfamily-5-1. Carries the model-family facts every Claude shares; it carries no pricing, so cost stays on the standard unpriced behavior rather than a guessed number.",
"model_info": {
"mode": "chat",
"max_input_tokens": 200000,
@ -45321,8 +45321,8 @@
},
{
"name": "claude-adaptive-thinking",
"pattern": "(?:opus|sonnet|haiku)[-._](?:4[-._](?:[6-9]|[1-9]\\d)(?!\\d)|(?:[5-9]|[1-9]\\d{1,})[-._]\\d{1,2}(?!\\d))|claude-[a-z]+-(?:[5-9]|[1-9]\\d)(?!\\d)(?:[-._]\\d{1,2}(?!\\d))?",
"description": "Claude opus/sonnet/haiku at version 4.6 or higher (4.6 through 4.99, then any later major-minor), plus any claude-<family>- id at major version 5 or higher, bare major or major-minor, so a new family shaped like claude-fable-5 is covered by the same gate as the core families. 4.x coverage stays limited to opus/sonnet/haiku. The minor is capped at two digits so an 8-digit date suffix such as claude-opus-4-20250514 is never read as a >= 4.6 minor. Turns on adaptive thinking for new versions and new families with no code change.",
"pattern": "claude-[a-z]+-(?:4[-._](?:[6-9]|[1-9]\\d)(?!\\d)|(?:[5-9]|[1-9]\\d)(?!\\d)(?:[-._]\\d{1,2}(?!\\d))?)",
"description": "Claude at version 4.6 or higher, in any id shape that contains claude-<family>-: minors 4.6 through 4.99, any later major-minor, and bare 5+ majors so a new family shaped like claude-fable-5 matches. Requiring the claude- prefix keeps non-Claude names such as team-sonnet-5-1 out. The minor is capped at two digits so an 8-digit date suffix such as claude-opus-4-20250514 is never read as a >= 4.6 minor. Turns on adaptive thinking for new versions and new families with no code change.",
"model_info": {
"supports_adaptive_thinking": true
}

View file

@ -427,15 +427,51 @@ def test_shipped_rules_flag_bare_5_plus_majors_of_any_family(shipped_cost_map):
assert matched["supports_mid_conversation_system"] is True
def test_shipped_adaptive_rule_keeps_4x_coverage_to_core_families(shipped_cost_map):
"""The family-agnostic adaptive branch starts at major 5; a non-core family at
4.x gets the 4.8+ mid-conversation flag and baseline caps but never adaptive."""
model = "claude-newfam-4-9"
def test_shipped_version_gates_are_family_agnostic_at_4x(shipped_cost_map):
"""Both version gates apply to any claude-<family>- id, 4.x included: a non-core
family at 4.9 gets adaptive and mid-conversation, while the same family at 4.5
gets baseline only. Only opus/sonnet/haiku ever shipped 4.x ids, so the
family-agnostic 4.6+ gate changes nothing for real models."""
high = litellm.get_model_info("claude-newfam-4-9", custom_llm_provider="anthropic")
assert high["supports_adaptive_thinking"] is True
assert high["supports_mid_conversation_system"] is True
assert high["supports_function_calling"] is True
low = litellm.get_model_info("claude-newfam-4-5", custom_llm_provider="anthropic")
assert low.get("supports_adaptive_thinking") is None
assert low.get("supports_mid_conversation_system") is None
assert low["supports_function_calling"] is True
def test_shipped_rules_give_bare_majors_the_full_baseline_union(shipped_cost_map):
"""A bare-major unmapped id (no minor) resolves the same baseline union as its
major-minor sibling: the baseline pattern's minor is optional, so claude-newt-5
is not left with version flags but no mode, token limits, or capability facts."""
model = "anthropic/claude-newt-5"
assert model not in litellm.model_cost
info = litellm.get_model_info(model, custom_llm_provider="anthropic")
assert info["supports_mid_conversation_system"] is True
assert info.get("supports_adaptive_thinking") is None
info = litellm.get_model_info(model)
assert info["litellm_provider"] == "anthropic"
assert info["mode"] == "chat"
assert info["max_tokens"] == 64000
assert info["supports_function_calling"] is True
assert info["supports_adaptive_thinking"] is True
assert info["supports_mid_conversation_system"] is True
def test_shipped_routing_rule_covers_bare_majors(shipped_cost_map):
_, provider, _, _ = litellm.get_llm_provider(model="claude-newt-5")
assert provider == "anthropic"
def test_shipped_adaptive_rule_requires_claude_prefix(shipped_cost_map):
"""A non-Claude name embedding a core-family 4.6+/5.x version substring must not
resolve from the rules; serving it a zero-priced rule entry would silently
swallow cost tracking for arbitrary custom deployment names."""
model = "openai/team-sonnet-5-1-alias"
assert model not in litellm.model_cost
assert match_capability_generalizations("team-sonnet-5-1-alias") is None
with pytest.raises(Exception):
litellm.get_model_info(model)
def test_shipped_exact_entry_beats_rules(shipped_cost_map):

View file

@ -1685,8 +1685,8 @@ class TestClaudeOpus48AdaptiveThinking:
self, local_model_cost_map, model
):
"""Provider-prefixed or suffixed Claude names that resolve to no mapped entry
still resolve to adaptive when their opus/sonnet/haiku family version is >= 4.6
or any family's major version is >= 5. The version gate is the declarative
still resolve to adaptive when the id carries claude-<family>- at version 4.6
or higher, bare 5+ majors included. The version gate is the declarative
``claude-adaptive-thinking`` rule, so 5.x, 6.x and any later family are covered
with no code change."""
import litellm