mirror of
https://github.com/aaif-goose/goose.git
synced 2026-07-03 14:10:03 +02:00
Feat: Added custom headers and toggle keyring CLI options (#5017)
Signed-off-by: Blair Allan <Blairallan@icloud.com> Co-authored-by: dianed-square <73617011+dianed-square@users.noreply.github.com>
This commit is contained in:
@@ -1174,6 +1174,11 @@ pub async fn configure_settings_dialog() -> anyhow::Result<()> {
|
||||
"Max Turns",
|
||||
"Set maximum number of turns without user input",
|
||||
)
|
||||
.item(
|
||||
"keyring",
|
||||
"Secret Storage",
|
||||
"Configure how secrets are stored (keyring vs file)",
|
||||
)
|
||||
.item(
|
||||
"experiment",
|
||||
"Toggle Experiment",
|
||||
@@ -1206,6 +1211,9 @@ pub async fn configure_settings_dialog() -> anyhow::Result<()> {
|
||||
"max_turns" => {
|
||||
configure_max_turns_dialog()?;
|
||||
}
|
||||
"keyring" => {
|
||||
configure_keyring_dialog()?;
|
||||
}
|
||||
"experiment" => {
|
||||
toggle_experiments_dialog()?;
|
||||
}
|
||||
@@ -1225,7 +1233,6 @@ pub async fn configure_settings_dialog() -> anyhow::Result<()> {
|
||||
pub fn configure_goose_mode_dialog() -> anyhow::Result<()> {
|
||||
let config = Config::global();
|
||||
|
||||
// Check if GOOSE_MODE is set as an environment variable
|
||||
if std::env::var("GOOSE_MODE").is_ok() {
|
||||
let _ = cliclack::log::info("Notice: GOOSE_MODE environment variable is set and will override the configuration here.");
|
||||
}
|
||||
@@ -1293,7 +1300,7 @@ pub fn configure_goose_router_strategy_dialog() -> anyhow::Result<()> {
|
||||
|
||||
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() {
|
||||
let _ = cliclack::log::info("Notice: GOOSE_CLI_MIN_PRIORITY environment variable is set and will override the configuration here.");
|
||||
}
|
||||
@@ -1322,6 +1329,60 @@ pub fn configure_tool_output_dialog() -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn configure_keyring_dialog() -> anyhow::Result<()> {
|
||||
let config = Config::global();
|
||||
|
||||
if std::env::var("GOOSE_DISABLE_KEYRING").is_ok() {
|
||||
let _ = cliclack::log::info("Notice: GOOSE_DISABLE_KEYRING environment variable is set and will override the configuration here.");
|
||||
}
|
||||
|
||||
let currently_disabled = config.get_param::<String>("GOOSE_DISABLE_KEYRING").is_ok();
|
||||
|
||||
let current_status = if currently_disabled {
|
||||
"Disabled (using file-based storage)"
|
||||
} else {
|
||||
"Enabled (using system keyring)"
|
||||
};
|
||||
|
||||
let _ = cliclack::log::info(format!("Current secret storage: {}", current_status));
|
||||
let _ = cliclack::log::warning("Note: Disabling the keyring stores secrets in a plain text file (~/.config/goose/secrets.yaml)");
|
||||
|
||||
let storage_option = cliclack::select("How would you like to store secrets?")
|
||||
.item(
|
||||
"keyring",
|
||||
"System Keyring (recommended)",
|
||||
"Use secure system keyring for storing API keys and secrets",
|
||||
)
|
||||
.item(
|
||||
"file",
|
||||
"File-based Storage",
|
||||
"Store secrets in a local file (useful when keyring access is restricted)",
|
||||
)
|
||||
.interact()?;
|
||||
|
||||
match storage_option {
|
||||
"keyring" => {
|
||||
// Set to empty string to enable keyring (absence or empty = enabled)
|
||||
config.set_param("GOOSE_DISABLE_KEYRING", Value::String("".to_string()))?;
|
||||
cliclack::outro("Secret storage set to system keyring (secure)")?;
|
||||
let _ =
|
||||
cliclack::log::info("You may need to restart goose for this change to take effect");
|
||||
}
|
||||
"file" => {
|
||||
// Set the disable flag to use file storage
|
||||
config.set_param("GOOSE_DISABLE_KEYRING", Value::String("true".to_string()))?;
|
||||
cliclack::outro(
|
||||
"Secret storage set to file (~/.config/goose/secrets.yaml). Keep this file secure!",
|
||||
)?;
|
||||
let _ =
|
||||
cliclack::log::info("You may need to restart goose for this change to take effect");
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Configure experiment features that can be used with goose
|
||||
/// Dialog for toggling which experiments are enabled/disabled
|
||||
pub fn toggle_experiments_dialog() -> anyhow::Result<()> {
|
||||
@@ -1740,6 +1801,50 @@ pub async fn handle_tetrate_auth() -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Prompts the user to collect custom HTTP headers for a provider.
|
||||
fn collect_custom_headers() -> anyhow::Result<Option<std::collections::HashMap<String, String>>> {
|
||||
let use_custom_headers = cliclack::confirm("Does this provider require custom headers?")
|
||||
.initial_value(false)
|
||||
.interact()?;
|
||||
|
||||
if !use_custom_headers {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let mut custom_headers = std::collections::HashMap::new();
|
||||
|
||||
loop {
|
||||
let header_name: String = cliclack::input("Header name:")
|
||||
.placeholder("e.g., x-origin-client-id")
|
||||
.required(false)
|
||||
.interact()?;
|
||||
|
||||
if header_name.is_empty() {
|
||||
break;
|
||||
}
|
||||
|
||||
let header_value: String = cliclack::password(format!("Value for '{}':", header_name))
|
||||
.mask('▪')
|
||||
.interact()?;
|
||||
|
||||
custom_headers.insert(header_name, header_value);
|
||||
|
||||
let add_more = cliclack::confirm("Add another header?")
|
||||
.initial_value(false)
|
||||
.interact()?;
|
||||
|
||||
if !add_more {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if custom_headers.is_empty() {
|
||||
Ok(None)
|
||||
} else {
|
||||
Ok(Some(custom_headers))
|
||||
}
|
||||
}
|
||||
|
||||
fn add_provider() -> anyhow::Result<()> {
|
||||
let provider_type = cliclack::select("What type of API is this?")
|
||||
.item(
|
||||
@@ -1807,6 +1912,13 @@ fn add_provider() -> anyhow::Result<()> {
|
||||
.initial_value(true)
|
||||
.interact()?;
|
||||
|
||||
// Ask about custom headers for OpenAI compatible providers
|
||||
let headers = if provider_type == "openai_compatible" {
|
||||
collect_custom_headers()?
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
create_custom_provider(
|
||||
provider_type,
|
||||
display_name.clone(),
|
||||
@@ -1814,6 +1926,7 @@ fn add_provider() -> anyhow::Result<()> {
|
||||
api_key,
|
||||
models,
|
||||
Some(supports_streaming),
|
||||
headers,
|
||||
)?;
|
||||
|
||||
cliclack::outro(format!("Custom provider added: {}", display_name))?;
|
||||
|
||||
@@ -87,6 +87,7 @@ pub struct UpdateCustomProviderRequest {
|
||||
pub api_key: String,
|
||||
pub models: Vec<String>,
|
||||
pub supports_streaming: Option<bool>,
|
||||
pub headers: Option<std::collections::HashMap<String, String>>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, ToSchema)]
|
||||
@@ -706,6 +707,7 @@ pub async fn create_custom_provider(
|
||||
request.api_key,
|
||||
request.models,
|
||||
request.supports_streaming,
|
||||
request.headers,
|
||||
)
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
|
||||
|
||||
@@ -92,6 +92,7 @@ pub fn create_custom_provider(
|
||||
api_key: String,
|
||||
models: Vec<String>,
|
||||
supports_streaming: Option<bool>,
|
||||
headers: Option<HashMap<String, String>>,
|
||||
) -> Result<DeclarativeProviderConfig> {
|
||||
let id = generate_id(&display_name);
|
||||
let api_key_name = generate_api_key_name(&id);
|
||||
@@ -117,7 +118,7 @@ pub fn create_custom_provider(
|
||||
api_key_env: api_key_name,
|
||||
base_url: api_url,
|
||||
models: model_infos,
|
||||
headers: None,
|
||||
headers,
|
||||
timeout_seconds: None,
|
||||
supports_streaming,
|
||||
};
|
||||
|
||||
@@ -5275,6 +5275,13 @@
|
||||
"engine": {
|
||||
"type": "string"
|
||||
},
|
||||
"headers": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
},
|
||||
"nullable": true
|
||||
},
|
||||
"models": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
|
||||
@@ -935,6 +935,9 @@ export type UpdateCustomProviderRequest = {
|
||||
api_url: string;
|
||||
display_name: string;
|
||||
engine: string;
|
||||
headers?: {
|
||||
[key: string]: string;
|
||||
} | null;
|
||||
models: Array<string>;
|
||||
supports_streaming?: boolean | null;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user