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",
|
"Max Turns",
|
||||||
"Set maximum number of turns without user input",
|
"Set maximum number of turns without user input",
|
||||||
)
|
)
|
||||||
|
.item(
|
||||||
|
"keyring",
|
||||||
|
"Secret Storage",
|
||||||
|
"Configure how secrets are stored (keyring vs file)",
|
||||||
|
)
|
||||||
.item(
|
.item(
|
||||||
"experiment",
|
"experiment",
|
||||||
"Toggle Experiment",
|
"Toggle Experiment",
|
||||||
@@ -1206,6 +1211,9 @@ pub async fn configure_settings_dialog() -> anyhow::Result<()> {
|
|||||||
"max_turns" => {
|
"max_turns" => {
|
||||||
configure_max_turns_dialog()?;
|
configure_max_turns_dialog()?;
|
||||||
}
|
}
|
||||||
|
"keyring" => {
|
||||||
|
configure_keyring_dialog()?;
|
||||||
|
}
|
||||||
"experiment" => {
|
"experiment" => {
|
||||||
toggle_experiments_dialog()?;
|
toggle_experiments_dialog()?;
|
||||||
}
|
}
|
||||||
@@ -1225,7 +1233,6 @@ pub async fn configure_settings_dialog() -> anyhow::Result<()> {
|
|||||||
pub fn configure_goose_mode_dialog() -> anyhow::Result<()> {
|
pub fn configure_goose_mode_dialog() -> anyhow::Result<()> {
|
||||||
let config = Config::global();
|
let config = Config::global();
|
||||||
|
|
||||||
// Check if GOOSE_MODE is set as an environment variable
|
|
||||||
if std::env::var("GOOSE_MODE").is_ok() {
|
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.");
|
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<()> {
|
pub fn configure_tool_output_dialog() -> anyhow::Result<()> {
|
||||||
let config = Config::global();
|
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() {
|
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.");
|
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(())
|
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
|
/// Configure experiment features that can be used with goose
|
||||||
/// Dialog for toggling which experiments are enabled/disabled
|
/// Dialog for toggling which experiments are enabled/disabled
|
||||||
pub fn toggle_experiments_dialog() -> anyhow::Result<()> {
|
pub fn toggle_experiments_dialog() -> anyhow::Result<()> {
|
||||||
@@ -1740,6 +1801,50 @@ pub async fn handle_tetrate_auth() -> anyhow::Result<()> {
|
|||||||
Ok(())
|
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<()> {
|
fn add_provider() -> anyhow::Result<()> {
|
||||||
let provider_type = cliclack::select("What type of API is this?")
|
let provider_type = cliclack::select("What type of API is this?")
|
||||||
.item(
|
.item(
|
||||||
@@ -1807,6 +1912,13 @@ fn add_provider() -> anyhow::Result<()> {
|
|||||||
.initial_value(true)
|
.initial_value(true)
|
||||||
.interact()?;
|
.interact()?;
|
||||||
|
|
||||||
|
// Ask about custom headers for OpenAI compatible providers
|
||||||
|
let headers = if provider_type == "openai_compatible" {
|
||||||
|
collect_custom_headers()?
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
create_custom_provider(
|
create_custom_provider(
|
||||||
provider_type,
|
provider_type,
|
||||||
display_name.clone(),
|
display_name.clone(),
|
||||||
@@ -1814,6 +1926,7 @@ fn add_provider() -> anyhow::Result<()> {
|
|||||||
api_key,
|
api_key,
|
||||||
models,
|
models,
|
||||||
Some(supports_streaming),
|
Some(supports_streaming),
|
||||||
|
headers,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
cliclack::outro(format!("Custom provider added: {}", display_name))?;
|
cliclack::outro(format!("Custom provider added: {}", display_name))?;
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ pub struct UpdateCustomProviderRequest {
|
|||||||
pub api_key: String,
|
pub api_key: String,
|
||||||
pub models: Vec<String>,
|
pub models: Vec<String>,
|
||||||
pub supports_streaming: Option<bool>,
|
pub supports_streaming: Option<bool>,
|
||||||
|
pub headers: Option<std::collections::HashMap<String, String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, ToSchema)]
|
#[derive(Deserialize, ToSchema)]
|
||||||
@@ -706,6 +707,7 @@ pub async fn create_custom_provider(
|
|||||||
request.api_key,
|
request.api_key,
|
||||||
request.models,
|
request.models,
|
||||||
request.supports_streaming,
|
request.supports_streaming,
|
||||||
|
request.headers,
|
||||||
)
|
)
|
||||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||||
|
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ pub fn create_custom_provider(
|
|||||||
api_key: String,
|
api_key: String,
|
||||||
models: Vec<String>,
|
models: Vec<String>,
|
||||||
supports_streaming: Option<bool>,
|
supports_streaming: Option<bool>,
|
||||||
|
headers: Option<HashMap<String, String>>,
|
||||||
) -> Result<DeclarativeProviderConfig> {
|
) -> Result<DeclarativeProviderConfig> {
|
||||||
let id = generate_id(&display_name);
|
let id = generate_id(&display_name);
|
||||||
let api_key_name = generate_api_key_name(&id);
|
let api_key_name = generate_api_key_name(&id);
|
||||||
@@ -117,7 +118,7 @@ pub fn create_custom_provider(
|
|||||||
api_key_env: api_key_name,
|
api_key_env: api_key_name,
|
||||||
base_url: api_url,
|
base_url: api_url,
|
||||||
models: model_infos,
|
models: model_infos,
|
||||||
headers: None,
|
headers,
|
||||||
timeout_seconds: None,
|
timeout_seconds: None,
|
||||||
supports_streaming,
|
supports_streaming,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5275,6 +5275,13 @@
|
|||||||
"engine": {
|
"engine": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"headers": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
"models": {
|
"models": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
|
|||||||
@@ -935,6 +935,9 @@ export type UpdateCustomProviderRequest = {
|
|||||||
api_url: string;
|
api_url: string;
|
||||||
display_name: string;
|
display_name: string;
|
||||||
engine: string;
|
engine: string;
|
||||||
|
headers?: {
|
||||||
|
[key: string]: string;
|
||||||
|
} | null;
|
||||||
models: Array<string>;
|
models: Array<string>;
|
||||||
supports_streaming?: boolean | null;
|
supports_streaming?: boolean | null;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user