From a27e9c5ff91b9831f878c493bd2456ed8f372135 Mon Sep 17 00:00:00 2001 From: TheArchitectit Date: Wed, 17 Jun 2026 13:17:07 -0500 Subject: [PATCH] fix(team): qualify bare sub-agent models for custom-openai provider MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the user's active provider is custom-openai, bare model names like 'claude-haiku-4-5-20251001' (saved by /setup as subagentModel) don't route through the custom endpoint — ProviderClient::from_model dispatches them to the Anthropic provider instead, which has no credentials. Add qualify_for_provider() that prefixes bare models with 'custom/' when the provider config is custom-openai so they share the session's endpoint. Applied to both the explicit model override and the subagentModel fallback path in resolve_agent_model(). Co-Authored-By: Claude Fable 5 --- rust/crates/tools/src/lib.rs | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/rust/crates/tools/src/lib.rs b/rust/crates/tools/src/lib.rs index 29ae9229..ecd4a170 100644 --- a/rust/crates/tools/src/lib.rs +++ b/rust/crates/tools/src/lib.rs @@ -5635,11 +5635,11 @@ The following patterns, pitfalls, and style guidelines were documented by previo fn resolve_agent_model(model: Option<&str>) -> String { if let Some(m) = model.map(str::trim).filter(|m| !m.is_empty()) { - return m.to_string(); + return qualify_for_provider(m); } // subagentModel (if set) pins the sub-agent model. if let Some(fast) = load_subagent_model_from_config() { - return fast; + return qualify_for_provider(&fast); } // Otherwise default to the session's configured `model` so sub-agents use // the same provider the user is actually connected with, rather than the @@ -5665,6 +5665,24 @@ fn load_subagent_model_from_config() -> Option { config.subagent_model().map(str::to_string) } +/// When the user's active provider is `custom-openai`, bare model names +/// (e.g. "claude-haiku-4-5-20251001") need a `custom/` prefix so +/// `ProviderClient::from_model` routes them through the custom endpoint +/// instead of dispatching to the Anthropic provider (which has no creds). +fn qualify_for_provider(model: &str) -> String { + if model.starts_with("custom/") || model.contains('/') { + return model.to_string(); + } + let cwd = std::env::current_dir().unwrap_or_default(); + let Ok(config) = ConfigLoader::default_for(&cwd).load() else { + return model.to_string(); + }; + if config.provider().kind() == Some("custom-openai") { + return format!("custom/{model}"); + } + model.to_string() +} + fn allowed_tools_for_subagent(subagent_type: &str) -> BTreeSet { let tools = match subagent_type { "Explore" => vec![