From 0530c509a332e6597736db5a478c20d2386eda53 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Wed, 8 Apr 2026 05:33:47 +0900 Subject: [PATCH] fix(api): route openai/ and gpt- model prefixes to OpenAi provider metadata_for_model returned None for unknown models like openai/gpt-4.1-mini, causing detect_provider_kind to fall through to auth-sniffer order. If ANTHROPIC_API_KEY was set, the model was silently misrouted to Anthropic and the user got a confusing 'missing Anthropic credentials' error. Fix: add explicit prefix checks for 'openai/' and 'gpt-' in metadata_for_model so the model name wins over env-var presence. Regression test added: openai_namespaced_model_routes_to_openai_not_anthropic - 'openai/gpt-4.1-mini' routes to OpenAi - 'gpt-4o' routes to OpenAi Reported and reproduced by gaebal-gajae against current main. 81 api lib tests passing, 0 failing. --- rust/crates/api/src/providers/mod.rs | 34 ++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/rust/crates/api/src/providers/mod.rs b/rust/crates/api/src/providers/mod.rs index 36c01fd..b494303 100644 --- a/rust/crates/api/src/providers/mod.rs +++ b/rust/crates/api/src/providers/mod.rs @@ -169,6 +169,18 @@ pub fn metadata_for_model(model: &str) -> Option { default_base_url: openai_compat::DEFAULT_XAI_BASE_URL, }); } + // Explicit provider-namespaced models (e.g. "openai/gpt-4.1-mini") must + // route to the correct provider regardless of which auth env vars are set. + // Without this, detect_provider_kind falls through to the auth-sniffer + // order and misroutes to Anthropic if ANTHROPIC_API_KEY is present. + if canonical.starts_with("openai/") || canonical.starts_with("gpt-") { + return Some(ProviderMetadata { + provider: ProviderKind::OpenAi, + auth_env: "OPENAI_API_KEY", + base_url_env: "OPENAI_BASE_URL", + default_base_url: openai_compat::DEFAULT_OPENAI_BASE_URL, + }); + } None } @@ -352,6 +364,28 @@ mod tests { ); } + #[test] + fn openai_namespaced_model_routes_to_openai_not_anthropic() { + // Regression: "openai/gpt-4.1-mini" was misrouted to Anthropic when + // ANTHROPIC_API_KEY was set because metadata_for_model returned None + // and detect_provider_kind fell through to auth-sniffer order. + // The model prefix must win over env-var presence. + let kind = super::metadata_for_model("openai/gpt-4.1-mini") + .map(|m| m.provider) + .unwrap_or_else(|| detect_provider_kind("openai/gpt-4.1-mini")); + assert_eq!( + kind, + ProviderKind::OpenAi, + "openai/ prefix must route to OpenAi regardless of ANTHROPIC_API_KEY" + ); + + // Also cover bare gpt- prefix + let kind2 = super::metadata_for_model("gpt-4o") + .map(|m| m.provider) + .unwrap_or_else(|| detect_provider_kind("gpt-4o")); + assert_eq!(kind2, ProviderKind::OpenAi); + } + #[test] fn keeps_existing_max_token_heuristic() { assert_eq!(max_tokens_for_model("opus"), 32_000);