diff --git a/backend/apps/agents/providers/registry.py b/backend/apps/agents/providers/registry.py index 619048e6..3b1f0d17 100644 --- a/backend/apps/agents/providers/registry.py +++ b/backend/apps/agents/providers/registry.py @@ -66,14 +66,8 @@ BUILTIN_MODELS: dict[str, list[dict[str, Any]]] = { {"value": "haiku-cc", "label": "Claude Haiku 4.5", "context_window": 200_000, "model_id": "claude-haiku-4-5", "router_model_id": "cc/claude-haiku-4-5-20251001", "api": "anthropic", "reasoning": True, "route": "cc"}, - # Fable 5 (released 2026-05-28): new flagship tier ABOVE Opus, 1M ctx, - # 128k out, $10/$50. The cc/ sub row is on trial: brand-new ids have 404'd - # our pinned 9Router 0.3.60 before (GPT-5.5's cx entry did) and Claude-sub - # serving of Fable is unverified, so pull this row if it errors live. - {"value": "fable-5-cc", "label": "Claude Fable 5", "context_window": 1_000_000, - "model_id": "claude-fable-5", "router_model_id": "cc/claude-fable-5", "api": "anthropic", "reasoning": True, "route": "cc"}, - {"value": "fable-5-api", "label": "Claude Fable 5 (API key)", "context_window": 1_000_000, - "model_id": "claude-fable-5", "router_model_id": "claude-fable-5", "api": "anthropic", "reasoning": True, "route": "api"}, + # Fable 5 pulled: the model got banned, so both its cc/ sub and api-key + # rows are gone. Don't re-add without confirming access is restored. {"value": "opus-4-8-api", "label": "Claude Opus 4.8 (API key)", "context_window": 1_000_000, "model_id": "claude-opus-4-8", "router_model_id": "claude-opus-4-8", "api": "anthropic", "reasoning": True, "route": "api"}, {"value": "opus-4-7-api", "label": "Claude Opus 4.7 (API key)", "context_window": 1_000_000, @@ -128,9 +122,9 @@ BUILTIN_MODELS: dict[str, list[dict[str, Any]]] = { # allowlists (every other shipped Gemini sub model IS in 0.3.60), so gc/ # gemini-3.5-flash would 404. Re-add the gc/ entry once 9Router is bumped # past 0.3.60 (gated by the WebSearch-translation regression; see CLAUDE.md). - {"value": "gemini-3.1-pro", "label": "Gemini 3.1 Pro", - "context_window": 1_000_000, "router_model_id": "gc/gemini-3.1-pro-preview", - "api": "gemini-cli", "subscription_only": True, "reasoning": True}, + # gemini-3.1-pro pulled (both sub + api-key rows): Antigravity can't serve + # it (its -high variant 400s) and the AI Studio key 429s pro-preview hard, + # so it had no working lane and only sold a dead option. {"value": "gemini-3.1-flash-lite", "label": "Gemini 3.1 Flash Lite", "context_window": 1_000_000, "router_model_id": "gc/gemini-3.1-flash-lite-preview", "api": "gemini-cli", "subscription_only": True, "reasoning": True}, @@ -144,9 +138,6 @@ BUILTIN_MODELS: dict[str, list[dict[str, Any]]] = { {"value": "gemini-3.5-flash-api", "label": "Gemini 3.5 Flash (API key)", "context_window": 1_000_000, "router_model_id": "gemini-3.5-flash", "model_id": "gemini-3.5-flash", "api": "gemini", "reasoning": True, "route": "api"}, - {"value": "gemini-3.1-pro-api", "label": "Gemini 3.1 Pro (API key)", - "context_window": 1_000_000, "router_model_id": "gemini-3.1-pro-preview", "model_id": "gemini-3.1-pro-preview", - "api": "gemini", "reasoning": True, "route": "api"}, {"value": "gemini-3.1-flash-lite-api", "label": "Gemini 3.1 Flash Lite (API key)", "context_window": 1_000_000, "router_model_id": "gemini-3.1-flash-lite-preview", "model_id": "gemini-3.1-flash-lite-preview", "api": "gemini", "reasoning": True, "route": "api"}, @@ -426,7 +417,6 @@ COST_PER_1M_TOKENS: dict[tuple[str, str], tuple[float, float]] = { ("Anthropic", "opus"): (5.0, 25.0), ("Anthropic", "opus-4-7"): (5.0, 25.0), ("Anthropic", "opus-4-8"): (5.0, 25.0), - ("Anthropic", "fable-5-api"): (10.0, 50.0), ("Anthropic", "haiku"): (1.0, 5.0), # OpenAI; Codex subscription path, user pays nothing per token ("OpenAI", "gpt-5.5"): (0.0, 0.0), @@ -434,7 +424,6 @@ COST_PER_1M_TOKENS: dict[tuple[str, str], tuple[float, float]] = { ("OpenAI", "gpt-5.4-mini"): (0.0, 0.0), # Google; Gemini CLI subscription path, user pays nothing per token ("Google", "gemini-3.5-flash"): (0.0, 0.0), - ("Google", "gemini-3.1-pro"): (0.0, 0.0), ("Google", "gemini-3.1-flash-lite"): (0.0, 0.0), ("Google", "gemini-3-flash"): (0.0, 0.0), ("Google", "gemini-2.5-pro"): (0.0, 0.0), diff --git a/backend/tests/test_v2_invariants.py b/backend/tests/test_v2_invariants.py index f5fa1dd6..6b7f0bf3 100644 --- a/backend/tests/test_v2_invariants.py +++ b/backend/tests/test_v2_invariants.py @@ -514,8 +514,6 @@ def test_resolve_sdk_gemini_prefers_antigravity_over_api_key(): with patch.object(registry, "_antigravity_connected", return_value=True): # flash IS AG-serveable -> AG wins over the key assert registry.resolve_model_id_for_sdk("gemini-3-flash", s) == "ag/gemini-3-flash" - # pro is NOT AG-serveable (404/400 on AG) -> falls back to the key - assert registry.resolve_model_id_for_sdk("gemini-3.1-pro", s) == "gemini/gemini-3.1-pro-preview" with patch.object(registry, "_antigravity_connected", return_value=False): # AG not connected -> key assert registry.resolve_model_id_for_sdk("gemini-3-flash", s) == "gemini/gemini-3-flash-preview" @@ -525,6 +523,20 @@ def test_resolve_sdk_gemini_prefers_antigravity_over_api_key(): assert registry.resolve_model_id_for_sdk("gemini-3-flash", s2) == "gc/gemini-3-flash-preview" +def test_banned_models_not_offered(): + """Claude Fable (banned) and Gemini 3.1 Pro (no working lane: AG can't serve + it, AI Studio key 429s pro-preview) were pulled from the picker. Guard so a + refactor can't silently re-list a model that can't run.""" + from backend.apps.agents.providers.registry import BUILTIN_MODELS + all_values = {m["value"] for models in BUILTIN_MODELS.values() for m in models} + for dead in ("fable-5-cc", "fable-5-api", "gemini-3.1-pro", "gemini-3.1-pro-api"): + assert dead not in all_values, f"{dead} is back in the picker" + # No 'fable' or '3.1 pro' label survives in any provider group either. + all_labels = " | ".join(m["label"].lower() for models in BUILTIN_MODELS.values() for m in models) + assert "fable" not in all_labels + assert "3.1 pro" not in all_labels + + # =========================================================================== # Group E, 9Router-streamed 401 detection # ===========================================================================