mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-10 03:28:53 +00:00
fix(e2e): long_context sonnet-4-6, complexity router assert, UI create modal
long_context_1m used claude-sonnet-4-5 which is 200k-capped; switch those cells to sonnet-4-6 (1M) and register the aliases. Harden complexity router registration wait and accept alias or provider-prefixed spend models. Soften create-key modal open against ALB redirect races
This commit is contained in:
parent
ad57c5d1c2
commit
4ee161a152
10 changed files with 68 additions and 42 deletions
|
|
@ -82,10 +82,11 @@ def test_yaml_has_no_unused_declarations() -> None:
|
|||
)
|
||||
|
||||
|
||||
def test_load_returns_fifteen_deployments() -> None:
|
||||
"""The compat matrix is 3 tiers x 5 provider surfaces = 15. Pin the
|
||||
count so a future edit to the yaml can't silently drop a tier."""
|
||||
assert len(load_all_deployments()) == 15
|
||||
def test_load_returns_expected_deployment_count() -> None:
|
||||
"""3 tiers x 5 surfaces = 15 base deployments, plus sonnet-4-6 on each
|
||||
surface for long_context_1m (sonnet-4-5 is 200k-capped). Pin the count
|
||||
so a future edit to the yaml can't silently drop a tier."""
|
||||
assert len(load_all_deployments()) == 20
|
||||
|
||||
|
||||
def test_deployments_are_hashable_and_frozen() -> None:
|
||||
|
|
|
|||
|
|
@ -66,11 +66,10 @@ from claude_code.cli_driver import (
|
|||
)
|
||||
|
||||
|
||||
# Haiku 4.5 is excluded -- only Sonnet 4.6 and Opus 4.7 support the
|
||||
# 1M-context beta. See module docstring for the per-cell-aggregator
|
||||
# rationale.
|
||||
# Haiku 4.5 is excluded (200k window). Sonnet 4.5 is also 200k-capped on
|
||||
# the Anthropic API; long_context uses sonnet-4-6 (1M) + opus-4-7.
|
||||
ANTHROPIC_MODELS: Sequence[str] = (
|
||||
"claude-sonnet-4-5",
|
||||
"claude-sonnet-4-6",
|
||||
"claude-opus-4-7",
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ from claude_code.cli_driver import (
|
|||
# 1M-context beta. See module docstring for the per-cell-aggregator
|
||||
# rationale.
|
||||
AZURE_MODELS: Sequence[str] = (
|
||||
"claude-sonnet-4-5-azure",
|
||||
"claude-sonnet-4-6-azure",
|
||||
"claude-opus-4-7-azure",
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ from claude_code.cli_driver import (
|
|||
# 1M-context beta. See module docstring for the per-cell-aggregator
|
||||
# rationale.
|
||||
BEDROCK_CONVERSE_MODELS: Sequence[str] = (
|
||||
"claude-sonnet-4-5-bedrock-converse",
|
||||
"claude-sonnet-4-6-bedrock-converse",
|
||||
"claude-opus-4-7-bedrock-converse",
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ from claude_code.cli_driver import (
|
|||
# 1M-context beta. See module docstring for the per-cell-aggregator
|
||||
# rationale.
|
||||
BEDROCK_INVOKE_MODELS: Sequence[str] = (
|
||||
"claude-sonnet-4-5-bedrock-invoke",
|
||||
"claude-sonnet-4-6-bedrock-invoke",
|
||||
"claude-opus-4-7-bedrock-invoke",
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ from claude_code.cli_driver import (
|
|||
# 1M-context beta. See module docstring for the per-cell-aggregator
|
||||
# rationale.
|
||||
VERTEX_AI_MODELS: Sequence[str] = (
|
||||
"claude-sonnet-4-5-vertex",
|
||||
"claude-sonnet-4-6-vertex",
|
||||
"claude-opus-4-7-vertex",
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -25,14 +25,15 @@ model_list:
|
|||
litellm_params:
|
||||
model: anthropic/claude-sonnet-4-5
|
||||
api_key: os.environ/ANTHROPIC_API_KEY
|
||||
extra_headers:
|
||||
anthropic-beta: "context-1m-2025-08-07"
|
||||
# 1M-context sonnet for long_context_1m only (sonnet-4-5 is capped at 200k).
|
||||
- model_name: claude-sonnet-4-6
|
||||
litellm_params:
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
api_key: os.environ/ANTHROPIC_API_KEY
|
||||
- model_name: claude-opus-4-7
|
||||
litellm_params:
|
||||
model: anthropic/claude-opus-4-7
|
||||
api_key: os.environ/ANTHROPIC_API_KEY
|
||||
extra_headers:
|
||||
anthropic-beta: "context-1m-2025-08-07"
|
||||
|
||||
# ---- Bedrock (InvokeModel) ----
|
||||
- model_name: claude-haiku-4-5-bedrock-invoke
|
||||
|
|
@ -43,14 +44,14 @@ model_list:
|
|||
litellm_params:
|
||||
model: bedrock/us.anthropic.claude-sonnet-4-5-20250929-v1:0
|
||||
aws_region_name: us-east-1
|
||||
extra_headers:
|
||||
anthropic-beta: "context-1m-2025-08-07"
|
||||
- model_name: claude-sonnet-4-6-bedrock-invoke
|
||||
litellm_params:
|
||||
model: bedrock/us.anthropic.claude-sonnet-4-6
|
||||
aws_region_name: us-east-1
|
||||
- model_name: claude-opus-4-7-bedrock-invoke
|
||||
litellm_params:
|
||||
model: bedrock/us.anthropic.claude-opus-4-7
|
||||
aws_region_name: us-east-1
|
||||
extra_headers:
|
||||
anthropic-beta: "context-1m-2025-08-07"
|
||||
|
||||
# ---- Bedrock (Converse) ----
|
||||
- model_name: claude-haiku-4-5-bedrock-converse
|
||||
|
|
@ -61,14 +62,14 @@ model_list:
|
|||
litellm_params:
|
||||
model: bedrock/converse/us.anthropic.claude-sonnet-4-5-20250929-v1:0
|
||||
aws_region_name: us-east-1
|
||||
extra_headers:
|
||||
anthropic-beta: "context-1m-2025-08-07"
|
||||
- model_name: claude-sonnet-4-6-bedrock-converse
|
||||
litellm_params:
|
||||
model: bedrock/converse/us.anthropic.claude-sonnet-4-6
|
||||
aws_region_name: us-east-1
|
||||
- model_name: claude-opus-4-7-bedrock-converse
|
||||
litellm_params:
|
||||
model: bedrock/converse/us.anthropic.claude-opus-4-7
|
||||
aws_region_name: us-east-1
|
||||
extra_headers:
|
||||
anthropic-beta: "context-1m-2025-08-07"
|
||||
|
||||
# ---- Vertex AI ----
|
||||
# `use_in_pass_through: true` registers each deployment's
|
||||
|
|
@ -90,16 +91,18 @@ model_list:
|
|||
vertex_project: os.environ/VERTEXAI_PROJECT
|
||||
vertex_location: global
|
||||
use_in_pass_through: true
|
||||
extra_headers:
|
||||
anthropic-beta: "context-1m-2025-08-07"
|
||||
- model_name: claude-sonnet-4-6-vertex
|
||||
litellm_params:
|
||||
model: vertex_ai/claude-sonnet-4-6
|
||||
vertex_project: os.environ/VERTEXAI_PROJECT
|
||||
vertex_location: global
|
||||
use_in_pass_through: true
|
||||
- model_name: claude-opus-4-7-vertex
|
||||
litellm_params:
|
||||
model: vertex_ai/claude-opus-4-7
|
||||
vertex_project: os.environ/VERTEXAI_PROJECT
|
||||
vertex_location: global
|
||||
use_in_pass_through: true
|
||||
extra_headers:
|
||||
anthropic-beta: "context-1m-2025-08-07"
|
||||
|
||||
# ---- Microsoft Foundry (Anthropic deployments on Azure) ----
|
||||
- model_name: claude-haiku-4-5-azure
|
||||
|
|
@ -112,15 +115,16 @@ model_list:
|
|||
model: azure_ai/claude-sonnet-4-5
|
||||
api_base: os.environ/AZURE_AI_API_BASE
|
||||
api_key: os.environ/AZURE_AI_API_KEY
|
||||
extra_headers:
|
||||
anthropic-beta: "context-1m-2025-08-07"
|
||||
- model_name: claude-sonnet-4-6-azure
|
||||
litellm_params:
|
||||
model: azure_ai/claude-sonnet-4-6
|
||||
api_base: os.environ/AZURE_AI_API_BASE
|
||||
api_key: os.environ/AZURE_AI_API_KEY
|
||||
- model_name: claude-opus-4-7-azure
|
||||
litellm_params:
|
||||
model: azure_ai/claude-opus-4-7
|
||||
api_base: os.environ/AZURE_AI_API_BASE
|
||||
api_key: os.environ/AZURE_AI_API_KEY
|
||||
extra_headers:
|
||||
anthropic-beta: "context-1m-2025-08-07"
|
||||
|
||||
general_settings:
|
||||
# Claude Code sends provider-specific headers (e.g. anthropic-beta) we
|
||||
|
|
|
|||
|
|
@ -46,8 +46,16 @@ def _models_dropdown_texts(page: Page, must_contain: str) -> list[str]:
|
|||
|
||||
|
||||
def _open_create_key_modal(page: Page) -> None:
|
||||
page.goto(f"{UI_BASE_URL}/ui/api-keys/?create=true")
|
||||
expect(page.locator(".ant-modal").first).to_be_visible()
|
||||
# Stage ALB sometimes races an auth redirect that aborts the first goto
|
||||
# to /ui/api-keys/?create=true. Land on the list first, then open create.
|
||||
page.goto(f"{UI_BASE_URL}/ui/api-keys/", wait_until="domcontentloaded")
|
||||
page.goto(f"{UI_BASE_URL}/ui/api-keys/?create=true", wait_until="domcontentloaded")
|
||||
modal = page.locator(".ant-modal").first
|
||||
try:
|
||||
expect(modal).to_be_visible(timeout=15_000)
|
||||
except AssertionError:
|
||||
page.get_by_role("button", name="+ Create New Key").click()
|
||||
expect(modal).to_be_visible(timeout=15_000)
|
||||
|
||||
|
||||
def _select_team(page: Page, alias: str) -> None:
|
||||
|
|
|
|||
|
|
@ -98,12 +98,18 @@ def _ensure_complexity_smart_router( # pyright: ignore[reportUnusedFunction] #
|
|||
|
||||
Compose already declares it in docker-compose.yml; stage does not. Register
|
||||
via /model/new when missing and tear down only what we created.
|
||||
|
||||
Always re-check servability after registration: a bare /model/new 200 is not
|
||||
enough if control→data propagation lags (stage) or the data plane filters
|
||||
the virtual name. Without this the chat cell fails with a vague
|
||||
``Invalid model name`` 400 instead of a registration error.
|
||||
"""
|
||||
gateway = client.gateway
|
||||
if _model_is_servable(gateway, ROUTER_MODEL):
|
||||
yield
|
||||
return
|
||||
|
||||
model_id: str | None = None
|
||||
try:
|
||||
model_id = _register_router_model(gateway)
|
||||
except (AssertionError, RequestException) as exc:
|
||||
|
|
@ -117,6 +123,12 @@ def _ensure_complexity_smart_router( # pyright: ignore[reportUnusedFunction] #
|
|||
|
||||
try:
|
||||
_await_router_model_servable(gateway)
|
||||
if not _model_is_servable(gateway, ROUTER_MODEL):
|
||||
raise AssertionError(
|
||||
f"{ROUTER_MODEL!r} registered as {model_id!r} but still missing "
|
||||
f"from /v1/models after wait; data-plane sync failed"
|
||||
)
|
||||
yield
|
||||
finally:
|
||||
gateway.delete_model(model_id)
|
||||
if model_id is not None:
|
||||
gateway.delete_model(model_id)
|
||||
|
|
|
|||
|
|
@ -30,9 +30,11 @@ ROUTER_MODEL = "complexity-smart-router"
|
|||
# Lexically simple (heuristic -> SIMPLE) but a hard reasoning question (LLM -> above SIMPLE).
|
||||
LEXICALLY_SIMPLE_HARD_PROMPT = "Is P equal to NP?"
|
||||
# SIMPLE tier backend; served only when the classifier silently falls back to heuristic.
|
||||
HEURISTIC_TIER_MODEL = "openai/gpt-5.5"
|
||||
# Spend logs may store the alias (gpt-5.5) or the provider-prefixed form depending on
|
||||
# how the deployment is registered (compose vs /model/new).
|
||||
HEURISTIC_TIER_MODELS = frozenset({"openai/gpt-5.5", "gpt-5.5"})
|
||||
# MEDIUM/COMPLEX/REASONING tier backend; served only when the LLM classifier runs.
|
||||
LLM_TIER_MODEL = "anthropic/claude-haiku-4-5"
|
||||
LLM_TIER_MODELS = frozenset({"anthropic/claude-haiku-4-5", "claude-haiku-4-5"})
|
||||
|
||||
|
||||
class TestComplexityRouterLlmClassifier:
|
||||
|
|
@ -54,9 +56,9 @@ class TestComplexityRouterLlmClassifier:
|
|||
|
||||
rows = client.gateway.poll_logs_for_key(scoped_key, min_rows=1)
|
||||
served = [row.model for row in rows]
|
||||
assert served == [LLM_TIER_MODEL], (
|
||||
f"expected the request to be served by {LLM_TIER_MODEL!r} (the higher-tier "
|
||||
f"backend the LLM classifier picks for a hard prompt), but the spend log shows "
|
||||
f"{served!r}. {HEURISTIC_TIER_MODEL!r} means the LLM classifier silently failed "
|
||||
f"and the router fell back to heuristic scoring (SIMPLE) - the pre-fix regression"
|
||||
assert served and all(model in LLM_TIER_MODELS for model in served), (
|
||||
f"expected the request to be served by one of {sorted(LLM_TIER_MODELS)!r} "
|
||||
f"(higher-tier backend the LLM classifier picks for a hard prompt), but the "
|
||||
f"spend log shows {served!r}. One of {sorted(HEURISTIC_TIER_MODELS)!r} means "
|
||||
f"the LLM classifier silently failed or scored SIMPLE (heuristic/fallback path)"
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue