Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 48 additions & 12 deletions crates/goose-cli/src/commands/configure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -436,12 +436,12 @@ fn select_model_from_list(
provider_meta: &goose::providers::base::ProviderMetadata,
) -> anyhow::Result<String> {
const MAX_MODELS: usize = 10;
const UNLISTED_MODEL_KEY: &str = "__unlisted__";

// Smart model selection:
// If we have more than MAX_MODELS models, show the recommended models with additional search option.
// Otherwise, show all models without search.

if models.len() > MAX_MODELS {
// Get recommended models from provider metadata
let recommended_models: Vec<String> = provider_meta
.known_models
.iter()
Expand All @@ -464,32 +464,68 @@ fn select_model_from_list(
),
);

if provider_meta.allows_unlisted_models {
model_items.push((
UNLISTED_MODEL_KEY.to_string(),
"Enter a model not listed...".to_string(),
"",
));
}

let selection = cliclack::select("Select a model:")
.items(&model_items)
.interact()?;

if selection == "search_all" {
Ok(interactive_model_search(models)?)
} else if selection == UNLISTED_MODEL_KEY {
prompt_unlisted_model(provider_meta)
} else {
Ok(selection)
}
} else {
Ok(interactive_model_search(models)?)
}
} else {
// just a few models, show all without search for better UX
Ok(cliclack::select("Select a model:")
.items(
&models
.iter()
.map(|m| (m, m.as_str(), ""))
.collect::<Vec<_>>(),
)
.interact()?
.to_string())
let mut model_items: Vec<(String, String, &str)> =
models.iter().map(|m| (m.clone(), m.clone(), "")).collect();

if provider_meta.allows_unlisted_models {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should just always allow this for any provider? Since we now have the ability, we might as well let the user opt to do this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think most providers expose a model‑listing API (Vertex AI is the exception), so offering an ‘unlisted model’ option for those providers is less useful and can lead to invalid selections and subsequent error when configuring the provider.

model_items.push((
UNLISTED_MODEL_KEY.to_string(),
"Enter a model not listed...".to_string(),
"",
));
}

let selection = cliclack::select("Select a model:")
.items(&model_items)
.interact()?;

if selection == UNLISTED_MODEL_KEY {
prompt_unlisted_model(provider_meta)
} else {
Ok(selection)
}
}
}

fn prompt_unlisted_model(
provider_meta: &goose::providers::base::ProviderMetadata,
) -> anyhow::Result<String> {
let model: String = cliclack::input("Enter the model name:")
.placeholder(&provider_meta.default_model)
.validate(|input: &String| {
if input.trim().is_empty() {
Err("Please enter a model name")
} else {
Ok(())
}
})
.interact()?;
Ok(model.trim().to_string())
}

fn try_store_secret(config: &Config, key_name: &str, value: String) -> anyhow::Result<bool> {
match config.set_secret(key_name, &value) {
Ok(_) => Ok(true),
Expand Down
12 changes: 12 additions & 0 deletions crates/goose/src/providers/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ pub struct ProviderMetadata {
pub model_doc_link: String,
/// Required configuration keys
pub config_keys: Vec<ConfigKey>,
/// Whether this provider allows entering model names not in the fetched list
#[serde(default)]
pub allows_unlisted_models: bool,
}

impl ProviderMetadata {
Expand Down Expand Up @@ -138,6 +141,7 @@ impl ProviderMetadata {
.collect(),
model_doc_link: model_doc_link.to_string(),
config_keys,
allows_unlisted_models: false,
}
}

Expand All @@ -158,6 +162,7 @@ impl ProviderMetadata {
known_models: models,
model_doc_link: model_doc_link.to_string(),
config_keys,
allows_unlisted_models: false,
}
}

Expand All @@ -170,8 +175,15 @@ impl ProviderMetadata {
known_models: vec![],
model_doc_link: "".to_string(),
config_keys: vec![],
allows_unlisted_models: false,
}
}

/// Set allows_unlisted_models flag (builder pattern)
pub fn with_unlisted_models(mut self) -> Self {
self.allows_unlisted_models = true;
self
}
}

/// Configuration key metadata for provider setup
Expand Down
Loading