Dont exit silently when storing api key fails (#5260)

Co-authored-by: Douwe Osinga <douwe@squareup.com>
This commit is contained in:
Douwe Osinga
2025-10-28 15:28:31 -04:00
committed by GitHub
parent 4034f3fcef
commit 41e5c053db
3 changed files with 185 additions and 210 deletions
+17 -27
View File
@@ -78,19 +78,19 @@ async fn get_or_create_session_id(
}
let Some(id) = identifier else {
if resume {
return if resume {
let sessions = SessionManager::list_sessions().await?;
let session_id = sessions
.first()
.map(|s| s.id.clone())
.ok_or_else(|| anyhow::anyhow!("No session found to resume"))?;
return Ok(Some(session_id));
Ok(Some(session_id))
} else {
let session =
SessionManager::create_session(std::env::current_dir()?, "CLI Session".to_string())
.await?;
return Ok(Some(session.id));
}
Ok(Some(session.id))
};
};
if let Some(session_id) = id.session_id {
@@ -818,7 +818,7 @@ pub struct RecipeInfo {
pub retry_config: Option<goose::agents::types::RetryConfig>,
}
pub async fn cli() -> Result<()> {
pub async fn cli() -> anyhow::Result<()> {
let cli = Cli::parse();
if let Err(e) = crate::project_tracker::update_project_tracker(None, None) {
@@ -850,20 +850,17 @@ pub async fn cli() -> Result<()> {
match cli.command {
Some(Command::Configure {}) => {
let _ = handle_configure().await;
return Ok(());
handle_configure().await?;
}
Some(Command::Info { verbose }) => {
handle_info(verbose)?;
return Ok(());
}
Some(Command::Mcp { name }) => {
crate::logging::setup_logging(Some(&format!("mcp-{name}")), None)?;
let _ = goose_mcp::mcp_server_runner::run_mcp_server(&name).await;
goose_mcp::mcp_server_runner::run_mcp_server(&name).await?;
}
Some(Command::Acp {}) => {
let _ = run_acp_agent().await;
return Ok(());
run_acp_agent().await?;
}
Some(Command::Session {
command,
@@ -884,13 +881,9 @@ pub async fn cli() -> Result<()> {
ascending,
working_dir,
limit,
}) => {
handle_session_list(format, ascending, working_dir, limit).await?;
Ok(())
}
}) => Ok(handle_session_list(format, ascending, working_dir, limit).await?),
Some(SessionCommand::Remove { id, regex }) => {
handle_session_remove(id, regex).await?;
return Ok(());
Ok(handle_session_remove(id, regex).await?)
}
Some(SessionCommand::Export {
identifier,
@@ -1183,7 +1176,7 @@ pub async fn cli() -> Result<()> {
.await;
if interactive {
let _ = session.interactive(input_config.contents).await;
session.interactive(input_config.contents).await?;
} else if let Some(contents) = input_config.contents {
let session_start = std::time::Instant::now();
let session_type = if recipe_info.is_some() {
@@ -1237,8 +1230,9 @@ pub async fn cli() -> Result<()> {
result?;
} else {
eprintln!("Error: no text provided for prompt in headless mode");
std::process::exit(1);
return Err(anyhow::anyhow!(
"no text provided for prompt in headless mode"
));
}
return Ok(());
@@ -1290,8 +1284,7 @@ pub async fn cli() -> Result<()> {
BenchCommand::Selectors { config } => BenchRunner::list_selectors(config)?,
BenchCommand::InitConfig { name } => {
let mut config = BenchRunConfig::default();
let cwd =
std::env::current_dir().expect("Failed to get current working directory");
let cwd = std::env::current_dir()?;
config.output_dir = Some(cwd);
config.save(name);
}
@@ -1334,7 +1327,7 @@ pub async fn cli() -> Result<()> {
}
None => {
return if !Config::global().exists() {
let _ = handle_configure().await;
handle_configure().await?;
Ok(())
} else {
// Run session command by default
@@ -1364,10 +1357,7 @@ pub async fn cli() -> Result<()> {
retry_config: None,
})
.await;
if let Err(e) = session.interactive(None).await {
eprintln!("Session ended with error: {}", e);
std::process::exit(1);
}
session.interactive(None).await?;
Ok(())
};
}
+168 -182
View File
@@ -11,7 +11,10 @@ use goose::config::extensions::{
name_to_key, remove_extension, set_extension, set_extension_enabled,
};
use goose::config::permission::PermissionLevel;
use goose::config::{Config, ConfigError, ExperimentManager, ExtensionEntry, PermissionManager};
use goose::config::signup_tetrate::TetrateAuth;
use goose::config::{
configure_tetrate, Config, ConfigError, ExperimentManager, ExtensionEntry, PermissionManager,
};
use goose::conversation::message::Message;
use goose::model::ModelConfig;
use goose::providers::{create, providers};
@@ -19,13 +22,12 @@ use rmcp::model::{Tool, ToolAnnotations};
use rmcp::object;
use serde_json::Value;
use std::collections::HashMap;
use std::error::Error;
// useful for light themes where there is no dicernible colour contrast between
// cursor-selected and cursor-unselected items.
const MULTISELECT_VISIBILITY_HINT: &str = "<";
pub async fn handle_configure() -> Result<(), Box<dyn Error>> {
pub async fn handle_configure() -> anyhow::Result<()> {
let config = Config::global();
if !config.exists() {
@@ -235,8 +237,8 @@ pub async fn handle_configure() -> Result<(), Box<dyn Error>> {
"toggle" => toggle_extensions_dialog(),
"add" => configure_extensions_dialog(),
"remove" => remove_extension_dialog(),
"settings" => configure_settings_dialog().await.and(Ok(())),
"providers" => configure_provider_dialog().await.and(Ok(())),
"settings" => configure_settings_dialog().await,
"providers" => configure_provider_dialog().await.map(|_| ()),
"custom_providers" => configure_custom_provider_dialog(),
_ => unreachable!(),
}
@@ -244,10 +246,7 @@ pub async fn handle_configure() -> Result<(), Box<dyn Error>> {
}
/// Helper function to handle OAuth configuration for a provider
async fn handle_oauth_configuration(
provider_name: &str,
key_name: &str,
) -> Result<(), Box<dyn Error>> {
async fn handle_oauth_configuration(provider_name: &str, key_name: &str) -> anyhow::Result<()> {
let _ = cliclack::log::info(format!(
"Configuring {} using OAuth device code flow...",
key_name
@@ -263,17 +262,24 @@ async fn handle_oauth_configuration(
}
Err(e) => {
let _ = cliclack::log::error(format!("Failed to authenticate: {}", e));
Err(format!("OAuth authentication failed for {}: {}", key_name, e).into())
Err(anyhow::anyhow!(
"OAuth authentication failed for {}: {}",
key_name,
e
))
}
},
Err(e) => {
let _ = cliclack::log::error(format!("Failed to create provider for OAuth: {}", e));
Err(format!("Failed to create provider for OAuth: {}", e).into())
Err(anyhow::anyhow!(
"Failed to create provider for OAuth: {}",
e
))
}
}
}
fn interactive_model_search(models: &[String]) -> Result<String, Box<dyn Error>> {
fn interactive_model_search(models: &[String]) -> anyhow::Result<String> {
const MAX_VISIBLE: usize = 30;
let mut query = String::new();
@@ -355,7 +361,7 @@ fn interactive_model_search(models: &[String]) -> Result<String, Box<dyn Error>>
fn select_model_from_list(
models: &[String],
provider_meta: &goose::providers::base::ProviderMetadata,
) -> Result<String, Box<dyn std::error::Error>> {
) -> anyhow::Result<String> {
const MAX_MODELS: usize = 10;
// Smart model selection:
// If we have more than MAX_MODELS models, show the recommended models with additional search option.
@@ -411,8 +417,20 @@ fn select_model_from_list(
}
}
/// Dialog for configuring the A provider and model
pub async fn configure_provider_dialog() -> Result<bool, Box<dyn Error>> {
fn try_store_secret(config: &Config, key_name: &str, value: String) -> anyhow::Result<bool> {
match config.set_secret(key_name, Value::String(value)) {
Ok(_) => Ok(true),
Err(e) => {
cliclack::outro(style(format!(
"Failed to store {} securely: {}. Please ensure your system's secure storage is accessible. Alternatively you can run with GOOSE_DISABLE_KEYRING=true or set the key in your environment variables",
key_name, e
)).on_red().white())?;
Ok(false)
}
}
}
pub async fn configure_provider_dialog() -> anyhow::Result<bool> {
// Get global config instance
let config = Config::global();
@@ -462,7 +480,9 @@ pub async fn configure_provider_dialog() -> Result<bool, Box<dyn Error>> {
.interact()?
{
if key.secret {
config.set_secret(&key.name, Value::String(env_value))?;
if !try_store_secret(config, &key.name, env_value)? {
return Ok(false);
}
} else {
config.set_param(&key.name, Value::String(env_value))?;
}
@@ -502,7 +522,9 @@ pub async fn configure_provider_dialog() -> Result<bool, Box<dyn Error>> {
};
if key.secret {
config.set_secret(&key.name, Value::String(value))?;
if !try_store_secret(config, &key.name, value)? {
return Ok(false);
}
} else {
config.set_param(&key.name, Value::String(value))?;
}
@@ -510,7 +532,6 @@ pub async fn configure_provider_dialog() -> Result<bool, Box<dyn Error>> {
}
}
Err(_) => {
// Check if this key uses OAuth flow
if key.oauth_flow {
handle_oauth_configuration(provider_name, &key.name).await?;
} else {
@@ -640,7 +661,7 @@ pub async fn configure_provider_dialog() -> Result<bool, Box<dyn Error>> {
/// Configure extensions that can be used with goose
/// Dialog for toggling which extensions are enabled/disabled
pub fn toggle_extensions_dialog() -> Result<(), Box<dyn Error>> {
pub fn toggle_extensions_dialog() -> anyhow::Result<()> {
let extensions = get_all_extensions();
if extensions.is_empty() {
@@ -692,7 +713,7 @@ pub fn toggle_extensions_dialog() -> Result<(), Box<dyn Error>> {
Ok(())
}
pub fn configure_extensions_dialog() -> Result<(), Box<dyn Error>> {
pub fn configure_extensions_dialog() -> anyhow::Result<()> {
let extension_type = cliclack::select("What type of extension would you like to add?")
.item(
"built-in",
@@ -1105,7 +1126,7 @@ pub fn configure_extensions_dialog() -> Result<(), Box<dyn Error>> {
Ok(())
}
pub fn remove_extension_dialog() -> Result<(), Box<dyn Error>> {
pub fn remove_extension_dialog() -> anyhow::Result<()> {
let extensions = get_all_extensions();
// Create a list of extension names and their enabled status
@@ -1160,7 +1181,7 @@ pub fn remove_extension_dialog() -> Result<(), Box<dyn Error>> {
Ok(())
}
pub async fn configure_settings_dialog() -> Result<(), Box<dyn Error>> {
pub async fn configure_settings_dialog() -> anyhow::Result<()> {
let setting_type = cliclack::select("What setting would you like to configure?")
.item("goose_mode", "goose mode", "Configure goose mode")
.item(
@@ -1231,7 +1252,7 @@ pub async fn configure_settings_dialog() -> Result<(), Box<dyn Error>> {
Ok(())
}
pub fn configure_goose_mode_dialog() -> Result<(), Box<dyn Error>> {
pub fn configure_goose_mode_dialog() -> anyhow::Result<()> {
let config = Config::global();
// Check if GOOSE_MODE is set as an environment variable
@@ -1284,7 +1305,7 @@ pub fn configure_goose_mode_dialog() -> Result<(), Box<dyn Error>> {
Ok(())
}
pub fn configure_goose_router_strategy_dialog() -> Result<(), Box<dyn Error>> {
pub fn configure_goose_router_strategy_dialog() -> anyhow::Result<()> {
let config = Config::global();
let enable_router = cliclack::select("Would you like to enable smart tool routing?")
@@ -1314,7 +1335,7 @@ pub fn configure_goose_router_strategy_dialog() -> Result<(), Box<dyn Error>> {
Ok(())
}
pub fn configure_tool_output_dialog() -> Result<(), Box<dyn Error>> {
pub fn configure_tool_output_dialog() -> anyhow::Result<()> {
let config = Config::global();
// Check if GOOSE_CLI_MIN_PRIORITY is set as an environment variable
if std::env::var("GOOSE_CLI_MIN_PRIORITY").is_ok() {
@@ -1347,7 +1368,7 @@ pub fn configure_tool_output_dialog() -> Result<(), Box<dyn Error>> {
/// Configure experiment features that can be used with goose
/// Dialog for toggling which experiments are enabled/disabled
pub fn toggle_experiments_dialog() -> Result<(), Box<dyn Error>> {
pub fn toggle_experiments_dialog() -> anyhow::Result<()> {
let experiments = ExperimentManager::get_all()?;
if experiments.is_empty() {
@@ -1385,7 +1406,7 @@ pub fn toggle_experiments_dialog() -> Result<(), Box<dyn Error>> {
Ok(())
}
pub async fn configure_tool_permissions_dialog() -> Result<(), Box<dyn Error>> {
pub async fn configure_tool_permissions_dialog() -> anyhow::Result<()> {
let mut extensions: Vec<String> = get_enabled_extensions()
.into_iter()
.map(|ext| ext.name().clone())
@@ -1537,7 +1558,7 @@ pub async fn configure_tool_permissions_dialog() -> Result<(), Box<dyn Error>> {
Ok(())
}
fn configure_recipe_dialog() -> Result<(), Box<dyn Error>> {
fn configure_recipe_dialog() -> anyhow::Result<()> {
let key_name = GOOSE_RECIPE_GITHUB_REPO_CONFIG_KEY;
let config = Config::global();
let default_recipe_repo = std::env::var(key_name)
@@ -1559,7 +1580,7 @@ fn configure_recipe_dialog() -> Result<(), Box<dyn Error>> {
Ok(())
}
fn configure_scheduler_dialog() -> Result<(), Box<dyn Error>> {
fn configure_scheduler_dialog() -> anyhow::Result<()> {
let config = Config::global();
// Check if GOOSE_SCHEDULER_TYPE is set as an environment variable
@@ -1613,7 +1634,7 @@ fn configure_scheduler_dialog() -> Result<(), Box<dyn Error>> {
Ok(())
}
pub fn configure_max_turns_dialog() -> Result<(), Box<dyn Error>> {
pub fn configure_max_turns_dialog() -> anyhow::Result<()> {
let config = Config::global();
let current_max_turns: u32 = config.get_param("GOOSE_MAX_TURNS").unwrap_or(1000);
@@ -1646,205 +1667,170 @@ pub fn configure_max_turns_dialog() -> Result<(), Box<dyn Error>> {
}
/// Handle OpenRouter authentication
pub async fn handle_openrouter_auth() -> Result<(), Box<dyn Error>> {
pub async fn handle_openrouter_auth() -> anyhow::Result<()> {
use goose::config::{configure_openrouter, signup_openrouter::OpenRouterAuth};
use goose::conversation::message::Message;
use goose::providers::create;
// Use the OpenRouter authentication flow
let mut auth_flow = OpenRouterAuth::new()?;
match auth_flow.complete_flow().await {
Ok(api_key) => {
println!("\nAuthentication complete!");
let api_key = auth_flow.complete_flow().await?;
println!("\nAuthentication complete!");
// Get config instance
let config = Config::global();
// Get config instance
let config = Config::global();
// Use the existing configure_openrouter function to set everything up
println!("\nConfiguring OpenRouter...");
if let Err(e) = configure_openrouter(config, api_key) {
eprintln!("Failed to configure OpenRouter: {}", e);
return Err(e.into());
}
// Use the existing configure_openrouter function to set everything up
println!("\nConfiguring OpenRouter...");
configure_openrouter(config, api_key)?;
println!("✓ OpenRouter configuration complete");
println!("✓ Models configured successfully");
println!("✓ OpenRouter configuration complete");
println!("✓ Models configured successfully");
// Test configuration - get the model that was configured
println!("\nTesting configuration...");
let configured_model: String = config.get_param("GOOSE_MODEL")?;
let model_config = match goose::model::ModelConfig::new(&configured_model) {
Ok(config) => config,
Err(e) => {
eprintln!("⚠️ Invalid model configuration: {}", e);
eprintln!(
"Your settings have been saved. Please check your model configuration."
);
return Ok(());
}
};
// Test configuration - get the model that was configured
println!("\nTesting configuration...");
let configured_model: String = config.get_param("GOOSE_MODEL")?;
let model_config = match goose::model::ModelConfig::new(&configured_model) {
Ok(config) => config,
Err(e) => {
eprintln!("⚠️ Invalid model configuration: {}", e);
eprintln!("Your settings have been saved. Please check your model configuration.");
return Ok(());
}
};
match create("openrouter", model_config).await {
Ok(provider) => {
// Simple test request
let test_result = provider
.complete(
"You are goose, an AI assistant.",
&[Message::user().with_text("Say 'Configuration test successful!'")],
&[],
)
.await;
match create("openrouter", model_config).await {
Ok(provider) => {
// Simple test request
let test_result = provider
.complete(
"You are goose, an AI assistant.",
&[Message::user().with_text("Say 'Configuration test successful!'")],
&[],
)
.await;
match test_result {
Ok(_) => {
println!("✓ Configuration test passed!");
match test_result {
Ok(_) => {
println!("✓ Configuration test passed!");
// Enable the developer extension by default if not already enabled
let entries = get_all_extensions();
let has_developer = entries
.iter()
.any(|e| e.config.name() == "developer" && e.enabled);
// Enable the developer extension by default if not already enabled
let entries = get_all_extensions();
let has_developer = entries
.iter()
.any(|e| e.config.name() == "developer" && e.enabled);
if !has_developer {
set_extension(ExtensionEntry {
enabled: true,
config: ExtensionConfig::Builtin {
name: "developer".to_string(),
display_name: Some(
goose::config::DEFAULT_DISPLAY_NAME.to_string(),
),
timeout: Some(goose::config::DEFAULT_EXTENSION_TIMEOUT),
bundled: Some(true),
description: "Developer extension".to_string(),
available_tools: Vec::new(),
},
});
println!("✓ Developer extension enabled");
}
cliclack::outro("OpenRouter setup complete! You can now use goose.")?;
}
Err(e) => {
eprintln!("⚠️ Configuration test failed: {}", e);
eprintln!("Your settings have been saved, but there may be an issue with the connection.");
}
if !has_developer {
set_extension(ExtensionEntry {
enabled: true,
config: ExtensionConfig::Builtin {
name: "developer".to_string(),
display_name: Some(goose::config::DEFAULT_DISPLAY_NAME.to_string()),
timeout: Some(goose::config::DEFAULT_EXTENSION_TIMEOUT),
bundled: Some(true),
description: "Developer extension".to_string(),
available_tools: Vec::new(),
},
});
println!("✓ Developer extension enabled");
}
cliclack::outro("OpenRouter setup complete! You can now use goose.")?;
}
Err(e) => {
eprintln!("⚠️ Failed to create provider for testing: {}", e);
eprintln!("Your settings have been saved. Please check your configuration.");
eprintln!("⚠️ Configuration test failed: {}", e);
eprintln!("Your settings have been saved, but there may be an issue with the connection.");
}
}
}
Err(e) => {
eprintln!("Authentication failed: {}", e);
return Err(e.into());
eprintln!("⚠️ Failed to create provider for testing: {}", e);
eprintln!("Your settings have been saved. Please check your configuration.");
}
}
Ok(())
}
/// Handle Tetrate Agent Router Service authentication
pub async fn handle_tetrate_auth() -> Result<(), Box<dyn Error>> {
use goose::config::{configure_tetrate, signup_tetrate::TetrateAuth};
use goose::conversation::message::Message;
use goose::providers::create;
// Use the Tetrate Agent Router Service authentication flow
pub async fn handle_tetrate_auth() -> anyhow::Result<()> {
let mut auth_flow = TetrateAuth::new()?;
match auth_flow.complete_flow().await {
Ok(api_key) => {
println!("\nAuthentication complete!");
let api_key = auth_flow.complete_flow().await?;
let config = Config::global();
println!("\nAuthentication complete!");
// Use the existing configure_tetrate function to set everything up
println!("\nConfiguring Tetrate Agent Router Service...");
if let Err(e) = configure_tetrate(config, api_key) {
eprintln!("Failed to configure Tetrate Agent Router Service: {}", e);
return Err(e.into());
}
let config = Config::global();
println!(" Tetrate Agent Router Service configuration complete");
println!("✓ Models configured successfully");
println!("\nConfiguring Tetrate Agent Router Service...");
configure_tetrate(config, api_key)?;
// Test configuration - get the model that was configured
println!("\nTesting configuration...");
let configured_model: String = config.get_param("GOOSE_MODEL")?;
let model_config = match goose::model::ModelConfig::new(&configured_model) {
Ok(config) => config,
Err(e) => {
eprintln!("⚠️ Invalid model configuration: {}", e);
eprintln!(
"Your settings have been saved. Please check your model configuration."
);
return Ok(());
}
};
println!("✓ Tetrate Agent Router Service configuration complete");
println!("✓ Models configured successfully");
match create("tetrate", model_config).await {
Ok(provider) => {
// Simple test request
let test_result = provider
.complete(
"You are goose, an AI assistant.",
&[Message::user().with_text("Say 'Configuration test successful!'")],
&[],
)
.await;
// Test configuration
println!("\nTesting configuration...");
let configured_model: String = config.get_param("GOOSE_MODEL")?;
let model_config = match goose::model::ModelConfig::new(&configured_model) {
Ok(config) => config,
Err(e) => {
eprintln!("⚠️ Invalid model configuration: {}", e);
eprintln!("Your settings have been saved. Please check your model configuration.");
return Ok(());
}
};
match test_result {
Ok(_) => {
println!("✓ Configuration test passed!");
match create("tetrate", model_config).await {
Ok(provider) => {
let test_result = provider
.complete(
"You are goose, an AI assistant.",
&[Message::user().with_text("Say 'Configuration test successful!'")],
&[],
)
.await;
// Enable the developer extension by default if not already enabled
let entries = get_all_extensions();
let has_developer = entries
.iter()
.any(|e| e.config.name() == "developer" && e.enabled);
match test_result {
Ok(_) => {
println!("✓ Configuration test passed!");
if !has_developer {
set_extension(ExtensionEntry {
enabled: true,
config: ExtensionConfig::Builtin {
name: "developer".to_string(),
display_name: Some(
goose::config::DEFAULT_DISPLAY_NAME.to_string(),
),
timeout: Some(goose::config::DEFAULT_EXTENSION_TIMEOUT),
bundled: Some(true),
description: "Developer extension".to_string(),
available_tools: Vec::new(),
},
});
println!("✓ Developer extension enabled");
}
let entries = get_all_extensions();
let has_developer = entries
.iter()
.any(|e| e.config.name() == "developer" && e.enabled);
cliclack::outro("Tetrate Agent Router Service setup complete! You can now use goose.")?;
}
Err(e) => {
eprintln!("⚠️ Configuration test failed: {}", e);
eprintln!("Your settings have been saved, but there may be an issue with the connection.");
}
if !has_developer {
set_extension(ExtensionEntry {
enabled: true,
config: ExtensionConfig::Builtin {
name: "developer".to_string(),
display_name: Some(goose::config::DEFAULT_DISPLAY_NAME.to_string()),
timeout: Some(goose::config::DEFAULT_EXTENSION_TIMEOUT),
bundled: Some(true),
description: "Developer extension".to_string(),
available_tools: Vec::new(),
},
});
println!("✓ Developer extension enabled");
}
cliclack::outro(
"Tetrate Agent Router Service setup complete! You can now use goose.",
)?;
}
Err(e) => {
eprintln!("⚠️ Failed to create provider for testing: {}", e);
eprintln!("Your settings have been saved. Please check your configuration.");
eprintln!("⚠️ Configuration test failed: {}", e);
eprintln!("Your settings have been saved, but there may be an issue with the connection.");
}
}
}
Err(e) => {
eprintln!("Authentication failed: {}", e);
return Err(e.into());
eprintln!("⚠️ Failed to create provider for testing: {}", e);
eprintln!("Your settings have been saved. Please check your configuration.");
}
}
Ok(())
}
fn add_provider() -> Result<(), Box<dyn Error>> {
fn add_provider() -> anyhow::Result<()> {
let provider_type = cliclack::select("What type of API is this?")
.item(
"openai_compatible",
@@ -1924,7 +1910,7 @@ fn add_provider() -> Result<(), Box<dyn Error>> {
Ok(())
}
fn remove_provider() -> Result<(), Box<dyn Error>> {
fn remove_provider() -> anyhow::Result<()> {
let custom_providers_dir = goose::config::declarative_providers::custom_providers_dir();
let custom_providers = if custom_providers_dir.exists() {
goose::config::declarative_providers::load_custom_providers(&custom_providers_dir)?
@@ -1951,7 +1937,7 @@ fn remove_provider() -> Result<(), Box<dyn Error>> {
Ok(())
}
pub fn configure_custom_provider_dialog() -> Result<(), Box<dyn Error>> {
pub fn configure_custom_provider_dialog() -> anyhow::Result<()> {
let action = cliclack::select("What would you like to do?")
.item(
"add",
-1
View File
@@ -30,7 +30,6 @@ async fn main() -> Result<()> {
}
}
// Then shutdown the providers
goose::tracing::shutdown_otlp();
}