From 5f194d6e5cfdb684ad59ad74987f58b2726301b2 Mon Sep 17 00:00:00 2001 From: Abhijay Jain Date: Thu, 16 Jul 2026 03:44:59 +0530 Subject: [PATCH] fix: register LiteLLM with refresh_only inventory so model picker lists models (#10489) --- crates/goose/src/providers/init.rs | 56 ++++++++++++++++++++- crates/goose/src/providers/inventory/mod.rs | 14 ++++++ crates/goose/src/providers/litellm.rs | 4 ++ 3 files changed, 73 insertions(+), 1 deletion(-) diff --git a/crates/goose/src/providers/init.rs b/crates/goose/src/providers/init.rs index 459d78031..bb19a1f9a 100644 --- a/crates/goose/src/providers/init.rs +++ b/crates/goose/src/providers/init.rs @@ -116,7 +116,18 @@ async fn init_registry() -> RwLock { Some(registrations::huggingface_inventory()), ); registry.register::(true); - registry.register::(false); + registry.register_with_inventory::( + false, + Some(registrations::refresh_only().with_configured(|| { + let config = crate::config::Config::global(); + config + .get_param::("LITELLM_HOST") + .is_ok() + || config + .get_secret::("LITELLM_API_KEY") + .is_ok() + })), + ); registry.register::(true); registry.register_with_inventory::( true, @@ -467,4 +478,47 @@ mod tests { std::env::remove_var("GOOSE_PATH_ROOT"); } + + #[tokio::test] + async fn test_litellm_supports_inventory_refresh() { + let entry = get_from_registry("litellm") + .await + .expect("litellm should be registered"); + assert!( + entry.supports_inventory_refresh(), + "litellm must support inventory refresh so the model picker calls fetch_supported_models" + ); + } + + #[tokio::test] + async fn test_litellm_configured_without_api_key() { + let _guard = env_lock::lock_env([ + ("LITELLM_API_KEY", None::<&str>), + ("LITELLM_HOST", Some("http://localhost:4000")), + ]); + + let entry = get_from_registry("litellm") + .await + .expect("litellm should be registered"); + assert!( + entry.inventory_configured(), + "litellm should be considered configured when LITELLM_HOST is set without an API key" + ); + } + + #[tokio::test] + async fn test_litellm_not_configured_without_any_settings() { + let _guard = env_lock::lock_env([ + ("LITELLM_API_KEY", None::<&str>), + ("LITELLM_HOST", None::<&str>), + ]); + + let entry = get_from_registry("litellm") + .await + .expect("litellm should be registered"); + assert!( + !entry.inventory_configured(), + "litellm should not be considered configured when no settings are present" + ); + } } diff --git a/crates/goose/src/providers/inventory/mod.rs b/crates/goose/src/providers/inventory/mod.rs index 517779939..25ef89d3d 100644 --- a/crates/goose/src/providers/inventory/mod.rs +++ b/crates/goose/src/providers/inventory/mod.rs @@ -1013,6 +1013,20 @@ fn enrich_model_ids_with_canonical( provider_family: &str, model_ids: &[String], ) -> Vec { + if provider_family == "litellm" { + return model_ids + .iter() + .map(|id| InventoryModel { + id: id.clone(), + name: id.clone(), + family: None, + context_limit: None, + reasoning: None, + recommended: false, + }) + .collect(); + } + let mut models: Vec = Vec::new(); let mut seen_names: HashSet = HashSet::new(); diff --git a/crates/goose/src/providers/litellm.rs b/crates/goose/src/providers/litellm.rs index 4f3d8525f..87b5ceb27 100644 --- a/crates/goose/src/providers/litellm.rs +++ b/crates/goose/src/providers/litellm.rs @@ -264,6 +264,10 @@ impl Provider for LiteLLMProvider { )) } + fn skip_canonical_filtering(&self) -> bool { + true + } + async fn fetch_supported_models(&self) -> Result, ProviderError> { let models = self.get_or_fetch_models().await?; Ok(models.iter().map(|m| m.name.clone()).collect())