feat: update config endpoints for use with providers (#1563)
This commit is contained in:
@@ -140,10 +140,10 @@ pub async fn run_benchmark(
|
||||
|
||||
let config = Config::global();
|
||||
let goose_model: String = config
|
||||
.get("GOOSE_MODEL")
|
||||
.get_param("GOOSE_MODEL")
|
||||
.expect("No model configured. Run 'goose configure' first");
|
||||
let provider_name: String = config
|
||||
.get("GOOSE_PROVIDER")
|
||||
.get_param("GOOSE_PROVIDER")
|
||||
.expect("No provider configured. Run 'goose configure' first");
|
||||
|
||||
let mut results = BenchmarkResults::new(provider_name.clone());
|
||||
|
||||
@@ -184,7 +184,7 @@ pub async fn configure_provider_dialog() -> Result<bool, Box<dyn Error>> {
|
||||
.collect();
|
||||
|
||||
// Get current default provider if it exists
|
||||
let current_provider: Option<String> = config.get("GOOSE_PROVIDER").ok();
|
||||
let current_provider: Option<String> = config.get_param("GOOSE_PROVIDER").ok();
|
||||
let default_provider = current_provider.unwrap_or_default();
|
||||
|
||||
// Select provider
|
||||
@@ -219,7 +219,7 @@ pub async fn configure_provider_dialog() -> Result<bool, Box<dyn Error>> {
|
||||
if key.secret {
|
||||
config.set_secret(&key.name, Value::String(env_value))?;
|
||||
} else {
|
||||
config.set(&key.name, Value::String(env_value))?;
|
||||
config.set_param(&key.name, Value::String(env_value))?;
|
||||
}
|
||||
let _ = cliclack::log::info(format!("Saved {} to config file", key.name));
|
||||
}
|
||||
@@ -229,7 +229,7 @@ pub async fn configure_provider_dialog() -> Result<bool, Box<dyn Error>> {
|
||||
let existing: Result<String, _> = if key.secret {
|
||||
config.get_secret(&key.name)
|
||||
} else {
|
||||
config.get(&key.name)
|
||||
config.get_param(&key.name)
|
||||
};
|
||||
|
||||
match existing {
|
||||
@@ -252,7 +252,7 @@ pub async fn configure_provider_dialog() -> Result<bool, Box<dyn Error>> {
|
||||
if key.secret {
|
||||
config.set_secret(&key.name, Value::String(new_value))?;
|
||||
} else {
|
||||
config.set(&key.name, Value::String(new_value))?;
|
||||
config.set_param(&key.name, Value::String(new_value))?;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -278,7 +278,7 @@ pub async fn configure_provider_dialog() -> Result<bool, Box<dyn Error>> {
|
||||
if key.secret {
|
||||
config.set_secret(&key.name, Value::String(value))?;
|
||||
} else {
|
||||
config.set(&key.name, Value::String(value))?;
|
||||
config.set_param(&key.name, Value::String(value))?;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -325,8 +325,8 @@ pub async fn configure_provider_dialog() -> Result<bool, Box<dyn Error>> {
|
||||
match result {
|
||||
Ok((_message, _usage)) => {
|
||||
// Update config with new values only if the test succeeds
|
||||
config.set("GOOSE_PROVIDER", Value::String(provider_name.to_string()))?;
|
||||
config.set("GOOSE_MODEL", Value::String(model.clone()))?;
|
||||
config.set_param("GOOSE_PROVIDER", Value::String(provider_name.to_string()))?;
|
||||
config.set_param("GOOSE_MODEL", Value::String(model.clone()))?;
|
||||
cliclack::outro("Configuration saved successfully")?;
|
||||
Ok(true)
|
||||
}
|
||||
@@ -708,15 +708,15 @@ pub fn configure_goose_mode_dialog() -> Result<(), Box<dyn Error>> {
|
||||
|
||||
match mode {
|
||||
"auto" => {
|
||||
config.set("GOOSE_MODE", Value::String("auto".to_string()))?;
|
||||
config.set_param("GOOSE_MODE", Value::String("auto".to_string()))?;
|
||||
cliclack::outro("Set to Auto Mode - full file modification enabled")?;
|
||||
}
|
||||
"approve" => {
|
||||
config.set("GOOSE_MODE", Value::String("approve".to_string()))?;
|
||||
config.set_param("GOOSE_MODE", Value::String("approve".to_string()))?;
|
||||
cliclack::outro("Set to Approve Mode - modifications require approval")?;
|
||||
}
|
||||
"chat" => {
|
||||
config.set("GOOSE_MODE", Value::String("chat".to_string()))?;
|
||||
config.set_param("GOOSE_MODE", Value::String("chat".to_string()))?;
|
||||
cliclack::outro("Set to Chat Mode - no tools or modifications enabled")?;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
@@ -738,15 +738,15 @@ pub fn configure_tool_output_dialog() -> Result<(), Box<dyn Error>> {
|
||||
|
||||
match tool_log_level {
|
||||
"high" => {
|
||||
config.set("GOOSE_CLI_MIN_PRIORITY", Value::from(0.8))?;
|
||||
config.set_param("GOOSE_CLI_MIN_PRIORITY", Value::from(0.8))?;
|
||||
cliclack::outro("Showing tool output of high importance only.")?;
|
||||
}
|
||||
"medium" => {
|
||||
config.set("GOOSE_CLI_MIN_PRIORITY", Value::from(0.2))?;
|
||||
config.set_param("GOOSE_CLI_MIN_PRIORITY", Value::from(0.2))?;
|
||||
cliclack::outro("Showing tool output of medium importance.")?;
|
||||
}
|
||||
"all" => {
|
||||
config.set("GOOSE_CLI_MIN_PRIORITY", Value::from(0.0))?;
|
||||
config.set_param("GOOSE_CLI_MIN_PRIORITY", Value::from(0.0))?;
|
||||
cliclack::outro("Showing all tool output.")?;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
|
||||
@@ -21,11 +21,11 @@ pub async fn build_session(
|
||||
let config = Config::global();
|
||||
|
||||
let provider_name: String = config
|
||||
.get("GOOSE_PROVIDER")
|
||||
.get_param("GOOSE_PROVIDER")
|
||||
.expect("No provider configured. Run 'goose configure' first");
|
||||
|
||||
let model: String = config
|
||||
.get("GOOSE_MODEL")
|
||||
.get_param("GOOSE_MODEL")
|
||||
.expect("No model configured. Run 'goose configure' first");
|
||||
let model_config = goose::model::ModelConfig::new(model.clone());
|
||||
let provider =
|
||||
@@ -137,7 +137,7 @@ pub async fn build_session(
|
||||
.await;
|
||||
|
||||
// Only override system prompt if a system override exists
|
||||
let system_prompt_file: Option<String> = config.get("GOOSE_SYSTEM_PROMPT_FILE_PATH").ok();
|
||||
let system_prompt_file: Option<String> = config.get_param("GOOSE_SYSTEM_PROMPT_FILE_PATH").ok();
|
||||
if let Some(ref path) = system_prompt_file {
|
||||
let override_prompt =
|
||||
std::fs::read_to_string(path).expect("Failed to read system prompt file");
|
||||
|
||||
@@ -343,7 +343,7 @@ impl Session {
|
||||
}
|
||||
|
||||
config
|
||||
.set("GOOSE_MODE", Value::String(mode.to_string()))
|
||||
.set_param("GOOSE_MODE", Value::String(mode.to_string()))
|
||||
.unwrap();
|
||||
println!("Goose mode set to '{}'", mode);
|
||||
continue;
|
||||
|
||||
@@ -150,7 +150,7 @@ fn render_tool_response(resp: &ToolResponse, theme: Theme, debug: bool) {
|
||||
}
|
||||
|
||||
let min_priority = config
|
||||
.get::<f32>("GOOSE_CLI_MIN_PRIORITY")
|
||||
.get_param::<f32>("GOOSE_CLI_MIN_PRIORITY")
|
||||
.ok()
|
||||
.unwrap_or(0.0);
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
use utoipa::OpenApi;
|
||||
|
||||
use goose::providers::base::ConfigKey;
|
||||
use goose::providers::base::ProviderMetadata;
|
||||
|
||||
#[allow(dead_code)] // Used by utoipa for OpenAPI generation
|
||||
#[derive(OpenApi)]
|
||||
#[openapi(
|
||||
@@ -10,13 +13,19 @@ use utoipa::OpenApi;
|
||||
super::routes::config_management::add_extension,
|
||||
super::routes::config_management::remove_extension,
|
||||
super::routes::config_management::update_extension,
|
||||
super::routes::config_management::read_all_config
|
||||
super::routes::config_management::read_all_config,
|
||||
super::routes::config_management::providers
|
||||
),
|
||||
components(schemas(
|
||||
super::routes::config_management::UpsertConfigQuery,
|
||||
super::routes::config_management::ConfigKeyQuery,
|
||||
super::routes::config_management::ExtensionQuery,
|
||||
super::routes::config_management::ConfigResponse
|
||||
super::routes::config_management::ConfigResponse,
|
||||
super::routes::config_management::ProvidersResponse,
|
||||
super::routes::config_management::ProvidersResponse,
|
||||
super::routes::config_management::ProviderDetails,
|
||||
ProviderMetadata,
|
||||
ConfigKey
|
||||
))
|
||||
)]
|
||||
pub struct ApiDoc;
|
||||
|
||||
@@ -121,7 +121,7 @@ async fn create_agent(
|
||||
let config = Config::global();
|
||||
let model = payload.model.unwrap_or_else(|| {
|
||||
config
|
||||
.get("GOOSE_MODEL")
|
||||
.get_param("GOOSE_MODEL")
|
||||
.expect("Did not find a model on payload or in env")
|
||||
});
|
||||
let model_config = ModelConfig::new(model);
|
||||
|
||||
@@ -5,25 +5,42 @@ use axum::{
|
||||
Json, Router,
|
||||
};
|
||||
use goose::config::Config;
|
||||
use http::StatusCode;
|
||||
use goose::providers::base::ProviderMetadata;
|
||||
use goose::providers::providers as get_providers;
|
||||
use http::{HeaderMap, StatusCode};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
use tokio::sync::Mutex;
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
use crate::state::AppState;
|
||||
|
||||
fn verify_secret_key(headers: &HeaderMap, state: &AppState) -> Result<StatusCode, StatusCode> {
|
||||
// Verify secret key
|
||||
let secret_key = headers
|
||||
.get("X-Secret-Key")
|
||||
.and_then(|value| value.to_str().ok())
|
||||
.ok_or(StatusCode::UNAUTHORIZED)?;
|
||||
|
||||
if secret_key != state.secret_key {
|
||||
Err(StatusCode::UNAUTHORIZED)
|
||||
} else {
|
||||
Ok(StatusCode::OK)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, ToSchema)]
|
||||
pub struct UpsertConfigQuery {
|
||||
pub key: String,
|
||||
pub value: Value,
|
||||
pub is_secret: Option<bool>,
|
||||
pub is_secret: bool,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, ToSchema)]
|
||||
pub struct ConfigKeyQuery {
|
||||
pub key: String,
|
||||
pub is_secret: bool,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, ToSchema)]
|
||||
@@ -37,6 +54,22 @@ pub struct ConfigResponse {
|
||||
pub config: HashMap<String, Value>,
|
||||
}
|
||||
|
||||
// Define a new structure to encapsulate the provider details along with configuration status
|
||||
#[derive(Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct ProviderDetails {
|
||||
/// Unique identifier and name of the provider
|
||||
pub name: String,
|
||||
/// Metadata about the provider
|
||||
pub metadata: ProviderMetadata,
|
||||
/// Indicates whether the provider is fully configured
|
||||
pub is_configured: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, ToSchema)]
|
||||
pub struct ProvidersResponse {
|
||||
pub providers: Vec<ProviderDetails>,
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
post,
|
||||
path = "/config/upsert",
|
||||
@@ -47,16 +80,15 @@ pub struct ConfigResponse {
|
||||
)
|
||||
)]
|
||||
pub async fn upsert_config(
|
||||
State(_state): State<Arc<Mutex<HashMap<String, Value>>>>,
|
||||
State(state): State<AppState>,
|
||||
headers: HeaderMap,
|
||||
Json(query): Json<UpsertConfigQuery>,
|
||||
) -> Result<Json<Value>, StatusCode> {
|
||||
let config = Config::global();
|
||||
// Use the helper function to verify the secret key
|
||||
verify_secret_key(&headers, &state)?;
|
||||
|
||||
let result = if query.is_secret.unwrap_or(false) {
|
||||
config.set_secret(&query.key, query.value)
|
||||
} else {
|
||||
config.set(&query.key, query.value)
|
||||
};
|
||||
let config = Config::global();
|
||||
let result = config.set(&query.key, query.value, query.is_secret);
|
||||
|
||||
match result {
|
||||
Ok(_) => Ok(Json(Value::String(format!("Upserted key {}", query.key)))),
|
||||
@@ -75,9 +107,13 @@ pub async fn upsert_config(
|
||||
)
|
||||
)]
|
||||
pub async fn remove_config(
|
||||
State(_state): State<Arc<Mutex<HashMap<String, Value>>>>,
|
||||
State(state): State<AppState>,
|
||||
headers: HeaderMap,
|
||||
Json(query): Json<ConfigKeyQuery>,
|
||||
) -> Result<Json<String>, StatusCode> {
|
||||
// Use the helper function to verify the secret key
|
||||
verify_secret_key(&headers, &state)?;
|
||||
|
||||
let config = Config::global();
|
||||
|
||||
match config.delete(&query.key) {
|
||||
@@ -96,13 +132,25 @@ pub async fn remove_config(
|
||||
)
|
||||
)]
|
||||
pub async fn read_config(
|
||||
State(_state): State<Arc<Mutex<HashMap<String, Value>>>>,
|
||||
State(state): State<AppState>,
|
||||
headers: HeaderMap,
|
||||
Json(query): Json<ConfigKeyQuery>,
|
||||
) -> Result<Json<Value>, StatusCode> {
|
||||
verify_secret_key(&headers, &state)?;
|
||||
|
||||
let config = Config::global();
|
||||
|
||||
match config.get::<Value>(&query.key) {
|
||||
Ok(value) => Ok(Json(value)),
|
||||
match config.get(&query.key, query.is_secret) {
|
||||
// Always get the actual value
|
||||
Ok(value) => {
|
||||
if query.is_secret {
|
||||
// If it's marked as secret, return a boolean indicating presence
|
||||
Ok(Json(Value::Bool(true)))
|
||||
} else {
|
||||
// Return the actual value if not secret
|
||||
Ok(Json(value))
|
||||
}
|
||||
}
|
||||
Err(_) => Err(StatusCode::NOT_FOUND),
|
||||
}
|
||||
}
|
||||
@@ -118,20 +166,25 @@ pub async fn read_config(
|
||||
)
|
||||
)]
|
||||
pub async fn add_extension(
|
||||
State(_state): State<Arc<Mutex<HashMap<String, Value>>>>,
|
||||
State(state): State<AppState>,
|
||||
headers: HeaderMap,
|
||||
Json(extension): Json<ExtensionQuery>,
|
||||
) -> Result<Json<String>, StatusCode> {
|
||||
// Use the helper function to verify the secret key
|
||||
verify_secret_key(&headers, &state)?;
|
||||
|
||||
let config = Config::global();
|
||||
|
||||
// Get current extensions or initialize empty map
|
||||
let mut extensions: HashMap<String, Value> =
|
||||
config.get("extensions").unwrap_or_else(|_| HashMap::new());
|
||||
let mut extensions: HashMap<String, Value> = config
|
||||
.get_param("extensions")
|
||||
.unwrap_or_else(|_| HashMap::new());
|
||||
|
||||
// Add new extension
|
||||
extensions.insert(extension.name.clone(), extension.config);
|
||||
|
||||
// Save updated extensions
|
||||
match config.set(
|
||||
match config.set_param(
|
||||
"extensions",
|
||||
Value::Object(extensions.into_iter().collect()),
|
||||
) {
|
||||
@@ -151,13 +204,17 @@ pub async fn add_extension(
|
||||
)
|
||||
)]
|
||||
pub async fn remove_extension(
|
||||
State(_state): State<Arc<Mutex<HashMap<String, Value>>>>,
|
||||
State(state): State<AppState>,
|
||||
headers: HeaderMap,
|
||||
Json(query): Json<ConfigKeyQuery>,
|
||||
) -> Result<Json<String>, StatusCode> {
|
||||
// Use the helper function to verify the secret key
|
||||
verify_secret_key(&headers, &state)?;
|
||||
|
||||
let config = Config::global();
|
||||
|
||||
// Get current extensions
|
||||
let mut extensions: HashMap<String, Value> = match config.get("extensions") {
|
||||
let mut extensions: HashMap<String, Value> = match config.get_param("extensions") {
|
||||
Ok(exts) => exts,
|
||||
Err(_) => return Err(StatusCode::NOT_FOUND),
|
||||
};
|
||||
@@ -165,7 +222,7 @@ pub async fn remove_extension(
|
||||
// Remove extension if it exists
|
||||
if extensions.remove(&query.key).is_some() {
|
||||
// Save updated extensions
|
||||
match config.set(
|
||||
match config.set_param(
|
||||
"extensions",
|
||||
Value::Object(extensions.into_iter().collect()),
|
||||
) {
|
||||
@@ -185,8 +242,12 @@ pub async fn remove_extension(
|
||||
)
|
||||
)]
|
||||
pub async fn read_all_config(
|
||||
State(_state): State<Arc<Mutex<HashMap<String, Value>>>>,
|
||||
State(state): State<AppState>,
|
||||
headers: HeaderMap,
|
||||
) -> Result<Json<ConfigResponse>, StatusCode> {
|
||||
// Use the helper function to verify the secret key
|
||||
verify_secret_key(&headers, &state)?;
|
||||
|
||||
let config = Config::global();
|
||||
|
||||
// Load values from config file
|
||||
@@ -206,13 +267,17 @@ pub async fn read_all_config(
|
||||
)
|
||||
)]
|
||||
pub async fn update_extension(
|
||||
State(_state): State<Arc<Mutex<HashMap<String, Value>>>>,
|
||||
State(state): State<AppState>,
|
||||
headers: HeaderMap,
|
||||
Json(extension): Json<ExtensionQuery>,
|
||||
) -> Result<Json<String>, StatusCode> {
|
||||
// Use the helper function to verify the secret key
|
||||
verify_secret_key(&headers, &state)?;
|
||||
|
||||
let config = Config::global();
|
||||
|
||||
// Get current extensions
|
||||
let mut extensions: HashMap<String, Value> = match config.get("extensions") {
|
||||
let mut extensions: HashMap<String, Value> = match config.get_param("extensions") {
|
||||
Ok(exts) => exts,
|
||||
Err(_) => return Err(StatusCode::NOT_FOUND),
|
||||
};
|
||||
@@ -226,7 +291,7 @@ pub async fn update_extension(
|
||||
extensions.insert(extension.name.clone(), extension.config);
|
||||
|
||||
// Save updated extensions
|
||||
match config.set(
|
||||
match config.set_param(
|
||||
"extensions",
|
||||
Value::Object(extensions.into_iter().collect()),
|
||||
) {
|
||||
@@ -235,6 +300,66 @@ pub async fn update_extension(
|
||||
}
|
||||
}
|
||||
|
||||
// Modified providers function using the new response type
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/config/providers",
|
||||
responses(
|
||||
(status = 200, description = "All configuration values retrieved successfully", body = [ProviderDetails])
|
||||
)
|
||||
)]
|
||||
pub async fn providers(
|
||||
State(state): State<AppState>,
|
||||
headers: HeaderMap,
|
||||
) -> Result<Json<Vec<ProviderDetails>>, StatusCode> {
|
||||
verify_secret_key(&headers, &state)?;
|
||||
|
||||
// Fetch the list of providers, which are likely stored in the AppState or can be retrieved via a function call
|
||||
let providers_metadata = get_providers();
|
||||
|
||||
// Construct the response by checking configuration status for each provider
|
||||
let providers_response: Vec<ProviderDetails> = providers_metadata
|
||||
.into_iter()
|
||||
.map(|metadata| {
|
||||
// Check if the provider is configured (this will depend on how you track configuration status)
|
||||
let is_configured = check_provider_configured(&metadata);
|
||||
|
||||
ProviderDetails {
|
||||
name: metadata.name.clone(),
|
||||
metadata,
|
||||
is_configured,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(Json(providers_response))
|
||||
}
|
||||
|
||||
fn check_provider_configured(metadata: &ProviderMetadata) -> bool {
|
||||
let config = Config::global();
|
||||
|
||||
// Check all required keys for the provider
|
||||
for key in &metadata.config_keys {
|
||||
if key.required {
|
||||
let key_name = &key.name;
|
||||
|
||||
// First, check if the key is set in the environment
|
||||
let is_set_in_env = env::var(key_name).is_ok();
|
||||
|
||||
// If not set in environment, check the config file based on whether it's a secret or not
|
||||
let is_set_in_config = config.get(key_name, key.secret).is_ok();
|
||||
|
||||
// If the key is neither in the environment nor in the config, the provider is not configured
|
||||
if !is_set_in_env && !is_set_in_config {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If all required keys are accounted for, the provider is considered configured
|
||||
true
|
||||
}
|
||||
|
||||
pub fn routes(state: AppState) -> Router {
|
||||
Router::new()
|
||||
.route("/config", get(read_all_config))
|
||||
@@ -244,5 +369,6 @@ pub fn routes(state: AppState) -> Router {
|
||||
.route("/config/extension", post(add_extension))
|
||||
.route("/config/extension", put(update_extension))
|
||||
.route("/config/extension", delete(remove_extension))
|
||||
.with_state(state.config)
|
||||
.route("/config/providers", get(providers))
|
||||
.with_state(state)
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ async fn store_config(
|
||||
let result = if request.is_secret {
|
||||
config.set_secret(&request.key, Value::String(request.value))
|
||||
} else {
|
||||
config.set(&request.key, Value::String(request.value))
|
||||
config.set_param(&request.key, Value::String(request.value))
|
||||
};
|
||||
match result {
|
||||
Ok(_) => Ok(Json(ConfigResponse { error: false })),
|
||||
@@ -87,7 +87,7 @@ static PROVIDER_ENV_REQUIREMENTS: Lazy<HashMap<String, ProviderConfig>> = Lazy::
|
||||
fn check_key_status(config: &Config, key: &str) -> (bool, Option<String>) {
|
||||
if let Ok(_value) = std::env::var(key) {
|
||||
(true, Some("env".to_string()))
|
||||
} else if config.get::<String>(key).is_ok() {
|
||||
} else if config.get_param::<String>(key).is_ok() {
|
||||
(true, Some("yaml".to_string()))
|
||||
} else if config.get_secret::<String>(key).is_ok() {
|
||||
(true, Some("keyring".to_string()))
|
||||
@@ -171,7 +171,7 @@ pub async fn get_config(
|
||||
|
||||
// Fetch the configuration value. Right now we don't allow get a secret.
|
||||
let config = Config::global();
|
||||
let value = if let Ok(config_value) = config.get::<String>(&query.key) {
|
||||
let value = if let Ok(config_value) = config.get_param::<String>(&query.key) {
|
||||
Some(config_value)
|
||||
} else if let Ok(env_value) = std::env::var(&query.key) {
|
||||
Some(env_value)
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::error::Error;
|
||||
use goose::config::Config;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum KeyLocation {
|
||||
Environment,
|
||||
ConfigFile,
|
||||
Keychain,
|
||||
NotFound
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct KeyInfo {
|
||||
pub name: String,
|
||||
pub is_set: bool,
|
||||
pub location: KeyLocation,
|
||||
pub is_secret: bool,
|
||||
pub value: Option<String>, // Only populated for non-secret keys that are set
|
||||
}
|
||||
|
||||
/// Inspects a configuration key to determine if it's set, its location, and value (for non-secret keys)
|
||||
pub fn inspect_key(
|
||||
key_name: &str,
|
||||
is_secret: bool,
|
||||
) -> Result<KeyInfo, Box<dyn Error>> {
|
||||
let config = Config::global();
|
||||
|
||||
// Check environment variable first
|
||||
let env_value = std::env::var(key_name).ok();
|
||||
|
||||
if let Some(value) = env_value {
|
||||
return Ok(KeyInfo {
|
||||
name: key_name.to_string(),
|
||||
is_set: true,
|
||||
location: KeyLocation::Environment,
|
||||
is_secret,
|
||||
// Only include value for non-secret keys
|
||||
value: if !is_secret { Some(value) } else { None },
|
||||
});
|
||||
}
|
||||
|
||||
// Check config store
|
||||
let config_result = if is_secret {
|
||||
config.get_secret(key_name).map(|v| (v, true))
|
||||
} else {
|
||||
config.get(key_name).map(|v| (v, false))
|
||||
};
|
||||
|
||||
match config_result {
|
||||
Ok((value, is_secret_actual)) => {
|
||||
// Determine location based on whether it's a secret value
|
||||
let location = if is_secret_actual {
|
||||
KeyLocation::Keychain
|
||||
} else {
|
||||
KeyLocation::ConfigFile
|
||||
};
|
||||
|
||||
Ok(KeyInfo {
|
||||
name: key_name.to_string(),
|
||||
is_set: true,
|
||||
location,
|
||||
is_secret: is_secret_actual,
|
||||
// Only include value for non-secret keys
|
||||
value: if !is_secret_actual { Some(value) } else { None },
|
||||
})
|
||||
},
|
||||
Err(_) => {
|
||||
Ok(KeyInfo {
|
||||
name: key_name.to_string(),
|
||||
is_set: false,
|
||||
location: KeyLocation::NotFound,
|
||||
is_secret,
|
||||
value: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Inspects multiple keys at once
|
||||
pub fn inspect_keys(
|
||||
keys: &[(String, bool)], // (name, is_secret) pairs
|
||||
) -> Result<Vec<KeyInfo>, Box<dyn Error>> {
|
||||
let mut results = Vec::new();
|
||||
|
||||
for (key_name, is_secret) in keys {
|
||||
let info = inspect_key(key_name, *is_secret)?;
|
||||
results.push(info);
|
||||
}
|
||||
|
||||
Ok(results)
|
||||
}
|
||||
@@ -60,6 +60,7 @@ serde_yaml = "0.9.34"
|
||||
once_cell = "1.20.2"
|
||||
etcetera = "0.8.0"
|
||||
rand = "0.8.5"
|
||||
utoipa = { version = "4.1" }
|
||||
|
||||
# For Bedrock provider
|
||||
aws-config = { version = "1.1.7", features = ["behavior-version-latest"] }
|
||||
|
||||
@@ -351,7 +351,7 @@ impl Capabilities {
|
||||
|
||||
let mut system_prompt_extensions = self.system_prompt_extensions.clone();
|
||||
let config = Config::global();
|
||||
let goose_mode = config.get("GOOSE_MODE").unwrap_or("auto".to_string());
|
||||
let goose_mode = config.get_param("GOOSE_MODE").unwrap_or("auto".to_string());
|
||||
if goose_mode == "chat" {
|
||||
system_prompt_extensions.push(
|
||||
"Right now you are in the chat only mode, no access to any tool use and system."
|
||||
|
||||
@@ -50,7 +50,7 @@ impl AgentFactory {
|
||||
pub fn configured_version() -> String {
|
||||
let config = Config::global();
|
||||
config
|
||||
.get::<String>("GOOSE_AGENT")
|
||||
.get_param::<String>("GOOSE_AGENT")
|
||||
.unwrap_or_else(|_| Self::default_version().to_string())
|
||||
}
|
||||
|
||||
|
||||
@@ -177,7 +177,7 @@ impl Agent for SummarizeAgent {
|
||||
|
||||
// Load settings from config
|
||||
let config = Config::global();
|
||||
let goose_mode = config.get("GOOSE_MODE").unwrap_or("auto".to_string());
|
||||
let goose_mode = config.get_param("GOOSE_MODE").unwrap_or("auto".to_string());
|
||||
|
||||
// we add in the 2 resource tools if any extensions support resources
|
||||
// TODO: make sure there is no collision with another extension's tool name
|
||||
|
||||
@@ -171,7 +171,7 @@ impl Agent for TruncateAgent {
|
||||
|
||||
// Load settings from config
|
||||
let config = Config::global();
|
||||
let goose_mode = config.get("GOOSE_MODE").unwrap_or("auto".to_string());
|
||||
let goose_mode = config.get_param("GOOSE_MODE").unwrap_or("auto".to_string());
|
||||
|
||||
// we add in the 2 resource tools if any extensions support resources
|
||||
// TODO: make sure there is no collision with another extension's tool name
|
||||
|
||||
@@ -78,7 +78,7 @@ impl From<keyring::Error> for ConfigError {
|
||||
///
|
||||
/// // Get a string value
|
||||
/// let config = Config::global();
|
||||
/// let api_key: String = config.get("OPENAI_API_KEY").unwrap();
|
||||
/// let api_key: String = config.get_param("OPENAI_API_KEY").unwrap();
|
||||
///
|
||||
/// // Get a complex type
|
||||
/// #[derive(Deserialize)]
|
||||
@@ -87,7 +87,7 @@ impl From<keyring::Error> for ConfigError {
|
||||
/// port: u16,
|
||||
/// }
|
||||
///
|
||||
/// let server_config: ServerConfig = config.get("server").unwrap();
|
||||
/// let server_config: ServerConfig = config.get_param("server").unwrap();
|
||||
/// ```
|
||||
///
|
||||
/// # Naming Convention
|
||||
@@ -204,7 +204,25 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a configuration value.
|
||||
// check all possible places for a parameter
|
||||
pub fn get(&self, key: &str, is_secret: bool) -> Result<Value, ConfigError> {
|
||||
if is_secret {
|
||||
self.get_secret(key)
|
||||
} else {
|
||||
self.get_param(key)
|
||||
}
|
||||
}
|
||||
|
||||
// save a parameter in the appropriate location based on if it's secret or not
|
||||
pub fn set(&self, key: &str, value: Value, is_secret: bool) -> Result<(), ConfigError> {
|
||||
if is_secret {
|
||||
self.set_secret(key, value)
|
||||
} else {
|
||||
self.set_param(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a configuration value (non-secret).
|
||||
///
|
||||
/// This will attempt to get the value from:
|
||||
/// 1. Environment variable with the exact key name
|
||||
@@ -220,7 +238,7 @@ impl Config {
|
||||
/// - The key doesn't exist in either environment or config file
|
||||
/// - The value cannot be deserialized into the requested type
|
||||
/// - There is an error reading the config file
|
||||
pub fn get<T: for<'de> Deserialize<'de>>(&self, key: &str) -> Result<T, ConfigError> {
|
||||
pub fn get_param<T: for<'de> Deserialize<'de>>(&self, key: &str) -> Result<T, ConfigError> {
|
||||
// First check environment variables (convert to uppercase)
|
||||
let env_key = key.to_uppercase();
|
||||
if let Ok(val) = env::var(&env_key) {
|
||||
@@ -239,7 +257,7 @@ impl Config {
|
||||
.and_then(|v| Ok(serde_json::from_value(v.clone())?))
|
||||
}
|
||||
|
||||
/// Set a configuration value in the config file.
|
||||
/// Set a configuration value in the config file (non-secret).
|
||||
///
|
||||
/// This will immediately write the value to the config file. The value
|
||||
/// can be any type that can be serialized to JSON/YAML.
|
||||
@@ -252,7 +270,7 @@ impl Config {
|
||||
/// Returns a ConfigError if:
|
||||
/// - There is an error reading or writing the config file
|
||||
/// - There is an error serializing the value
|
||||
pub fn set(&self, key: &str, value: Value) -> Result<(), ConfigError> {
|
||||
pub fn set_param(&self, key: &str, value: Value) -> Result<(), ConfigError> {
|
||||
let mut values = self.load_values()?;
|
||||
values.insert(key.to_string(), value);
|
||||
|
||||
@@ -377,15 +395,15 @@ mod tests {
|
||||
let config = Config::new(temp_file.path(), TEST_KEYRING_SERVICE)?;
|
||||
|
||||
// Set a simple string value
|
||||
config.set("test_key", Value::String("test_value".to_string()))?;
|
||||
config.set_param("test_key", Value::String("test_value".to_string()))?;
|
||||
|
||||
// Test simple string retrieval
|
||||
let value: String = config.get("test_key")?;
|
||||
let value: String = config.get_param("test_key")?;
|
||||
assert_eq!(value, "test_value");
|
||||
|
||||
// Test with environment variable override
|
||||
std::env::set_var("TEST_KEY", "env_value");
|
||||
let value: String = config.get("test_key")?;
|
||||
let value: String = config.get_param("test_key")?;
|
||||
assert_eq!(value, "env_value");
|
||||
|
||||
Ok(())
|
||||
@@ -403,7 +421,7 @@ mod tests {
|
||||
let config = Config::new(temp_file.path(), TEST_KEYRING_SERVICE)?;
|
||||
|
||||
// Set a complex value
|
||||
config.set(
|
||||
config.set_param(
|
||||
"complex_key",
|
||||
serde_json::json!({
|
||||
"field1": "hello",
|
||||
@@ -411,7 +429,7 @@ mod tests {
|
||||
}),
|
||||
)?;
|
||||
|
||||
let value: TestStruct = config.get("complex_key")?;
|
||||
let value: TestStruct = config.get_param("complex_key")?;
|
||||
assert_eq!(value.field1, "hello");
|
||||
assert_eq!(value.field2, 42);
|
||||
|
||||
@@ -423,7 +441,7 @@ mod tests {
|
||||
let temp_file = NamedTempFile::new().unwrap();
|
||||
let config = Config::new(temp_file.path(), TEST_KEYRING_SERVICE).unwrap();
|
||||
|
||||
let result: Result<String, ConfigError> = config.get("nonexistent_key");
|
||||
let result: Result<String, ConfigError> = config.get_param("nonexistent_key");
|
||||
assert!(matches!(result, Err(ConfigError::NotFound(_))));
|
||||
}
|
||||
|
||||
@@ -432,8 +450,8 @@ mod tests {
|
||||
let temp_file = NamedTempFile::new().unwrap();
|
||||
let config = Config::new(temp_file.path(), TEST_KEYRING_SERVICE)?;
|
||||
|
||||
config.set("key1", Value::String("value1".to_string()))?;
|
||||
config.set("key2", Value::Number(42.into()))?;
|
||||
config.set_param("key1", Value::String("value1".to_string()))?;
|
||||
config.set_param("key2", Value::Number(42.into()))?;
|
||||
|
||||
// Read the file directly to check YAML formatting
|
||||
let content = std::fs::read_to_string(temp_file.path())?;
|
||||
@@ -448,14 +466,14 @@ mod tests {
|
||||
let temp_file = NamedTempFile::new().unwrap();
|
||||
let config = Config::new(temp_file.path(), TEST_KEYRING_SERVICE)?;
|
||||
|
||||
config.set("key", Value::String("value".to_string()))?;
|
||||
config.set_param("key", Value::String("value".to_string()))?;
|
||||
|
||||
let value: String = config.get("key")?;
|
||||
let value: String = config.get_param("key")?;
|
||||
assert_eq!(value, "value");
|
||||
|
||||
config.delete("key")?;
|
||||
|
||||
let result: Result<String, ConfigError> = config.get("key");
|
||||
let result: Result<String, ConfigError> = config.get_param("key");
|
||||
assert!(matches!(result, Err(ConfigError::NotFound(_))));
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -18,7 +18,8 @@ impl ExperimentManager {
|
||||
/// - Removes experiments not in `ALL_EXPERIMENTS`.
|
||||
pub fn get_all() -> Result<Vec<(String, bool)>> {
|
||||
let config = Config::global();
|
||||
let mut experiments: HashMap<String, bool> = config.get("experiments").unwrap_or_default();
|
||||
let mut experiments: HashMap<String, bool> =
|
||||
config.get_param("experiments").unwrap_or_default();
|
||||
Self::refresh_experiments(&mut experiments);
|
||||
|
||||
Ok(experiments.into_iter().collect())
|
||||
@@ -27,12 +28,13 @@ impl ExperimentManager {
|
||||
/// Enable or disable an experiment
|
||||
pub fn set_enabled(name: &str, enabled: bool) -> Result<()> {
|
||||
let config = Config::global();
|
||||
let mut experiments: HashMap<String, bool> =
|
||||
config.get("experiments").unwrap_or_else(|_| HashMap::new());
|
||||
let mut experiments: HashMap<String, bool> = config
|
||||
.get_param("experiments")
|
||||
.unwrap_or_else(|_| HashMap::new());
|
||||
Self::refresh_experiments(&mut experiments);
|
||||
experiments.insert(name.to_string(), enabled);
|
||||
|
||||
config.set("experiments", serde_json::to_value(experiments)?)?;
|
||||
config.set_param("experiments", serde_json::to_value(experiments)?)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ impl ExtensionManager {
|
||||
let config = Config::global();
|
||||
|
||||
// Try to get the extension entry
|
||||
let extensions: HashMap<String, ExtensionEntry> = match config.get("extensions") {
|
||||
let extensions: HashMap<String, ExtensionEntry> = match config.get_param("extensions") {
|
||||
Ok(exts) => exts,
|
||||
Err(super::ConfigError::NotFound(_)) => {
|
||||
// Initialize with default developer extension
|
||||
@@ -37,7 +37,7 @@ impl ExtensionManager {
|
||||
},
|
||||
},
|
||||
)]);
|
||||
config.set("extensions", serde_json::to_value(&defaults)?)?;
|
||||
config.set_param("extensions", serde_json::to_value(&defaults)?)?;
|
||||
defaults
|
||||
}
|
||||
Err(e) => return Err(e.into()),
|
||||
@@ -56,11 +56,12 @@ impl ExtensionManager {
|
||||
pub fn set(entry: ExtensionEntry) -> Result<()> {
|
||||
let config = Config::global();
|
||||
|
||||
let mut extensions: HashMap<String, ExtensionEntry> =
|
||||
config.get("extensions").unwrap_or_else(|_| HashMap::new());
|
||||
let mut extensions: HashMap<String, ExtensionEntry> = config
|
||||
.get_param("extensions")
|
||||
.unwrap_or_else(|_| HashMap::new());
|
||||
|
||||
extensions.insert(entry.config.name().parse()?, entry);
|
||||
config.set("extensions", serde_json::to_value(extensions)?)?;
|
||||
config.set_param("extensions", serde_json::to_value(extensions)?)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -68,11 +69,12 @@ impl ExtensionManager {
|
||||
pub fn remove(name: &str) -> Result<()> {
|
||||
let config = Config::global();
|
||||
|
||||
let mut extensions: HashMap<String, ExtensionEntry> =
|
||||
config.get("extensions").unwrap_or_else(|_| HashMap::new());
|
||||
let mut extensions: HashMap<String, ExtensionEntry> = config
|
||||
.get_param("extensions")
|
||||
.unwrap_or_else(|_| HashMap::new());
|
||||
|
||||
extensions.remove(name);
|
||||
config.set("extensions", serde_json::to_value(extensions)?)?;
|
||||
config.set_param("extensions", serde_json::to_value(extensions)?)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -80,12 +82,13 @@ impl ExtensionManager {
|
||||
pub fn set_enabled(name: &str, enabled: bool) -> Result<()> {
|
||||
let config = Config::global();
|
||||
|
||||
let mut extensions: HashMap<String, ExtensionEntry> =
|
||||
config.get("extensions").unwrap_or_else(|_| HashMap::new());
|
||||
let mut extensions: HashMap<String, ExtensionEntry> = config
|
||||
.get_param("extensions")
|
||||
.unwrap_or_else(|_| HashMap::new());
|
||||
|
||||
if let Some(entry) = extensions.get_mut(name) {
|
||||
entry.enabled = enabled;
|
||||
config.set("extensions", serde_json::to_value(extensions)?)?;
|
||||
config.set_param("extensions", serde_json::to_value(extensions)?)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -94,7 +97,7 @@ impl ExtensionManager {
|
||||
pub fn get_all() -> Result<Vec<ExtensionEntry>> {
|
||||
let config = Config::global();
|
||||
let extensions: HashMap<String, ExtensionEntry> =
|
||||
config.get("extensions").unwrap_or_default();
|
||||
config.get_param("extensions").unwrap_or_default();
|
||||
Ok(Vec::from_iter(extensions.values().cloned()))
|
||||
}
|
||||
|
||||
@@ -102,15 +105,16 @@ impl ExtensionManager {
|
||||
pub fn get_all_names() -> Result<Vec<String>> {
|
||||
let config = Config::global();
|
||||
Ok(config
|
||||
.get("extensions")
|
||||
.get_param("extensions")
|
||||
.unwrap_or_else(|_| get_keys(Default::default())))
|
||||
}
|
||||
|
||||
/// Check if an extension is enabled
|
||||
pub fn is_enabled(name: &str) -> Result<bool> {
|
||||
let config = Config::global();
|
||||
let extensions: HashMap<String, ExtensionEntry> =
|
||||
config.get("extensions").unwrap_or_else(|_| HashMap::new());
|
||||
let extensions: HashMap<String, ExtensionEntry> = config
|
||||
.get_param("extensions")
|
||||
.unwrap_or_else(|_| HashMap::new());
|
||||
|
||||
Ok(extensions.get(name).map(|e| e.enabled).unwrap_or(false))
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ impl AnthropicProvider {
|
||||
let config = crate::config::Config::global();
|
||||
let api_key: String = config.get_secret("ANTHROPIC_API_KEY")?;
|
||||
let host: String = config
|
||||
.get("ANTHROPIC_HOST")
|
||||
.get_param("ANTHROPIC_HOST")
|
||||
.unwrap_or_else(|_| "https://api.anthropic.com".to_string());
|
||||
|
||||
let client = Client::builder()
|
||||
|
||||
@@ -40,10 +40,10 @@ impl AzureProvider {
|
||||
pub fn from_env(model: ModelConfig) -> Result<Self> {
|
||||
let config = crate::config::Config::global();
|
||||
let api_key: String = config.get_secret("AZURE_OPENAI_API_KEY")?;
|
||||
let endpoint: String = config.get("AZURE_OPENAI_ENDPOINT")?;
|
||||
let deployment_name: String = config.get("AZURE_OPENAI_DEPLOYMENT_NAME")?;
|
||||
let endpoint: String = config.get_param("AZURE_OPENAI_ENDPOINT")?;
|
||||
let deployment_name: String = config.get_param("AZURE_OPENAI_DEPLOYMENT_NAME")?;
|
||||
let api_version: String = config
|
||||
.get("AZURE_OPENAI_API_VERSION")
|
||||
.get_param("AZURE_OPENAI_API_VERSION")
|
||||
.unwrap_or_else(|_| AZURE_DEFAULT_API_VERSION.to_string());
|
||||
|
||||
let client = Client::builder()
|
||||
@@ -109,18 +109,8 @@ impl Provider for AzureProvider {
|
||||
vec![
|
||||
ConfigKey::new("AZURE_OPENAI_API_KEY", true, true, None),
|
||||
ConfigKey::new("AZURE_OPENAI_ENDPOINT", true, false, None),
|
||||
ConfigKey::new(
|
||||
"AZURE_OPENAI_DEPLOYMENT_NAME",
|
||||
true,
|
||||
false,
|
||||
Some("Name of your Azure OpenAI deployment"),
|
||||
),
|
||||
ConfigKey::new(
|
||||
"AZURE_OPENAI_API_VERSION",
|
||||
false,
|
||||
false,
|
||||
Some("Azure OpenAI API version, default: 2024-10-21"),
|
||||
),
|
||||
ConfigKey::new("AZURE_OPENAI_DEPLOYMENT_NAME", true, false, None),
|
||||
ConfigKey::new("AZURE_OPENAI_API_VERSION", false, false, Some("2024-10-21")),
|
||||
],
|
||||
)
|
||||
}
|
||||
|
||||
@@ -5,9 +5,10 @@ use super::errors::ProviderError;
|
||||
use crate::message::Message;
|
||||
use crate::model::ModelConfig;
|
||||
use mcp_core::tool::Tool;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Metadata about a provider's configuration requirements and capabilities
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
|
||||
pub struct ProviderMetadata {
|
||||
/// The unique identifier for this provider
|
||||
pub name: String,
|
||||
@@ -60,7 +61,7 @@ impl ProviderMetadata {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
|
||||
pub struct ConfigKey {
|
||||
pub name: String,
|
||||
pub required: bool,
|
||||
|
||||
@@ -83,7 +83,7 @@ impl DatabricksProvider {
|
||||
|
||||
// For compatibility for now we check both config and secret for databricks host
|
||||
// but it is not actually a secret value
|
||||
let mut host: Result<String, ConfigError> = config.get("DATABRICKS_HOST");
|
||||
let mut host: Result<String, ConfigError> = config.get_param("DATABRICKS_HOST");
|
||||
|
||||
if host.is_err() {
|
||||
host = config.get_secret("DATABRICKS_HOST")
|
||||
|
||||
@@ -146,7 +146,7 @@ impl GcpVertexAIProvider {
|
||||
/// * `model` - Configuration for the model to be used
|
||||
async fn new_async(model: ModelConfig) -> Result<Self> {
|
||||
let config = crate::config::Config::global();
|
||||
let project_id = config.get("GCP_PROJECT_ID")?;
|
||||
let project_id = config.get_param("GCP_PROJECT_ID")?;
|
||||
let location = Self::determine_location(config)?;
|
||||
let host = format!("https://{}-aiplatform.googleapis.com", location);
|
||||
|
||||
@@ -173,25 +173,25 @@ impl GcpVertexAIProvider {
|
||||
/// Loads retry configuration from environment variables or uses defaults.
|
||||
fn load_retry_config(config: &crate::config::Config) -> RetryConfig {
|
||||
let max_retries = config
|
||||
.get("GCP_MAX_RETRIES")
|
||||
.get_param("GCP_MAX_RETRIES")
|
||||
.ok()
|
||||
.and_then(|v: String| v.parse::<usize>().ok())
|
||||
.unwrap_or(DEFAULT_MAX_RETRIES);
|
||||
|
||||
let initial_interval_ms = config
|
||||
.get("GCP_INITIAL_RETRY_INTERVAL_MS")
|
||||
.get_param("GCP_INITIAL_RETRY_INTERVAL_MS")
|
||||
.ok()
|
||||
.and_then(|v: String| v.parse::<u64>().ok())
|
||||
.unwrap_or(DEFAULT_INITIAL_RETRY_INTERVAL_MS);
|
||||
|
||||
let backoff_multiplier = config
|
||||
.get("GCP_BACKOFF_MULTIPLIER")
|
||||
.get_param("GCP_BACKOFF_MULTIPLIER")
|
||||
.ok()
|
||||
.and_then(|v: String| v.parse::<f64>().ok())
|
||||
.unwrap_or(DEFAULT_BACKOFF_MULTIPLIER);
|
||||
|
||||
let max_interval_ms = config
|
||||
.get("GCP_MAX_RETRY_INTERVAL_MS")
|
||||
.get_param("GCP_MAX_RETRY_INTERVAL_MS")
|
||||
.ok()
|
||||
.and_then(|v: String| v.parse::<u64>().ok())
|
||||
.unwrap_or(DEFAULT_MAX_RETRY_INTERVAL_MS);
|
||||
@@ -211,7 +211,7 @@ impl GcpVertexAIProvider {
|
||||
/// 2. Global default location (Iowa)
|
||||
fn determine_location(config: &crate::config::Config) -> Result<String> {
|
||||
Ok(config
|
||||
.get("GCP_LOCATION")
|
||||
.get_param("GCP_LOCATION")
|
||||
.ok()
|
||||
.filter(|location: &String| !location.trim().is_empty())
|
||||
.unwrap_or_else(|| Iowa.to_string()))
|
||||
|
||||
@@ -50,7 +50,7 @@ impl GoogleProvider {
|
||||
let config = crate::config::Config::global();
|
||||
let api_key: String = config.get_secret("GOOGLE_API_KEY")?;
|
||||
let host: String = config
|
||||
.get("GOOGLE_HOST")
|
||||
.get_param("GOOGLE_HOST")
|
||||
.unwrap_or_else(|_| GOOGLE_API_HOST.to_string());
|
||||
|
||||
let client = Client::builder()
|
||||
|
||||
@@ -39,7 +39,7 @@ impl GroqProvider {
|
||||
let config = crate::config::Config::global();
|
||||
let api_key: String = config.get_secret("GROQ_API_KEY")?;
|
||||
let host: String = config
|
||||
.get("GROQ_HOST")
|
||||
.get_param("GROQ_HOST")
|
||||
.unwrap_or_else(|_| GROQ_API_HOST.to_string());
|
||||
|
||||
let client = Client::builder()
|
||||
|
||||
@@ -39,7 +39,7 @@ impl OllamaProvider {
|
||||
pub fn from_env(model: ModelConfig) -> Result<Self> {
|
||||
let config = crate::config::Config::global();
|
||||
let host: String = config
|
||||
.get("OLLAMA_HOST")
|
||||
.get_param("OLLAMA_HOST")
|
||||
.unwrap_or_else(|_| OLLAMA_HOST.to_string());
|
||||
|
||||
let client = Client::builder()
|
||||
|
||||
@@ -47,13 +47,13 @@ impl OpenAiProvider {
|
||||
let config = crate::config::Config::global();
|
||||
let api_key: String = config.get_secret("OPENAI_API_KEY")?;
|
||||
let host: String = config
|
||||
.get("OPENAI_HOST")
|
||||
.get_param("OPENAI_HOST")
|
||||
.unwrap_or_else(|_| "https://api.openai.com".to_string());
|
||||
let base_path: String = config
|
||||
.get("OPENAI_BASE_PATH")
|
||||
.get_param("OPENAI_BASE_PATH")
|
||||
.unwrap_or_else(|_| "v1/chat/completions".to_string());
|
||||
let organization: Option<String> = config.get("OPENAI_ORGANIZATION").ok();
|
||||
let project: Option<String> = config.get("OPENAI_PROJECT").ok();
|
||||
let organization: Option<String> = config.get_param("OPENAI_ORGANIZATION").ok();
|
||||
let project: Option<String> = config.get_param("OPENAI_PROJECT").ok();
|
||||
let client = Client::builder()
|
||||
.timeout(Duration::from_secs(600))
|
||||
.build()?;
|
||||
|
||||
@@ -44,7 +44,7 @@ impl OpenRouterProvider {
|
||||
let config = crate::config::Config::global();
|
||||
let api_key: String = config.get_secret("OPENROUTER_API_KEY")?;
|
||||
let host: String = config
|
||||
.get("OPENROUTER_HOST")
|
||||
.get_param("OPENROUTER_HOST")
|
||||
.unwrap_or_else(|_| "https://openrouter.ai".to_string());
|
||||
|
||||
let client = Client::builder()
|
||||
|
||||
Reference in New Issue
Block a user