From 235fa47d154ef1f14deca10c05826278dc19059a Mon Sep 17 00:00:00 2001 From: ciregenz Date: Mon, 15 Jun 2026 11:59:11 -0700 Subject: [PATCH] [eric] providers: openai own-key keeps cp-openai/ prefix so 9router can route it --- backend/apps/agents/providers/registry.py | 7 +++++++ backend/tests/test_v2_invariants.py | 22 ++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/backend/apps/agents/providers/registry.py b/backend/apps/agents/providers/registry.py index 27f0c535..587b1ff7 100644 --- a/backend/apps/agents/providers/registry.py +++ b/backend/apps/agents/providers/registry.py @@ -244,6 +244,13 @@ def resolve_model_id_for_sdk(short_name: str, settings: AppSettings) -> str: if entry.get("route") == "cc": return entry.get("router_model_id", entry.get("model_id", short_name)) if entry.get("route") == "api": + # OpenAI own-key still rides 9Router (the cp-openai node fixes max_tokens + # + translates Anthropic->OpenAI), so it MUST keep its cp-openai/ routing + # prefix or 9Router has no node to dispatch to. Anthropic own-key goes + # straight to api.anthropic.com and Gemini own-key via the local proxy, + # both on the bare id. + if entry.get("api") == "openai": + return entry.get("router_model_id", entry.get("model_id", short_name)) return entry.get("model_id", short_name) if entry.get("route") == "openrouter": return entry.get("router_model_id", short_name) diff --git a/backend/tests/test_v2_invariants.py b/backend/tests/test_v2_invariants.py index 9842674e..f7c37a0c 100644 --- a/backend/tests/test_v2_invariants.py +++ b/backend/tests/test_v2_invariants.py @@ -479,6 +479,28 @@ async def test_resolve_aux_model_openrouter_priority_after_subs(): assert model_id == "cx/gpt-5.4-mini", f"got {model_id}" +def test_resolve_sdk_openai_own_key_keeps_cp_openai_prefix(): + """OpenAI own-key dispatch points the SDK at 9Router, which routes by + prefix to our cp-openai passthrough node; handing it the bare `gpt-5.5` + matched no node and silently dropped every request before it reached + OpenAI (0 requests on the dashboard). The resolver must keep the + cp-openai/ prefix for the openai route while Anthropic/Gemini own-key + stay on the bare id (they go direct / via the local proxy).""" + from backend.apps.agents.providers.registry import resolve_model_id_for_sdk + from backend.apps.settings.models import AppSettings + s = AppSettings() + s.openai_api_key = "sk-test" + for v, expected in ( + ("gpt-5.5-api", "cp-openai/gpt-5.5"), + ("gpt-5.4-api", "cp-openai/gpt-5.4"), + ("gpt-5.4-mini-api", "cp-openai/gpt-5.4-mini"), + ): + assert resolve_model_id_for_sdk(v, s) == expected, f"{v} -> {resolve_model_id_for_sdk(v, s)}" + # Non-OpenAI own-key lanes must NOT gain a 9Router prefix. + assert resolve_model_id_for_sdk("gemini-3.5-flash-api", s) == "gemini-3.5-flash" + assert resolve_model_id_for_sdk("opus-4-8-api", s) == "claude-opus-4-8" + + # =========================================================================== # Group E, 9Router-streamed 401 detection # ===========================================================================