Stringly typed config (#5463)

This commit is contained in:
Jack Amadeo
2025-10-30 15:13:32 -04:00
committed by GitHub
parent 1714990d42
commit 2970b5fa34
30 changed files with 243 additions and 275 deletions
+10 -13
View File
@@ -29,7 +29,7 @@ use crate::agents::tool_route_manager::ToolRouteManager;
use crate::agents::tool_router_index_manager::ToolRouterIndexManager;
use crate::agents::types::SessionConfig;
use crate::agents::types::{FrontendTool, SharedProvider, ToolResultReceiver};
use crate::config::{get_enabled_extensions, Config};
use crate::config::{get_enabled_extensions, Config, GooseMode};
use crate::context_mgmt::DEFAULT_COMPACTION_THRESHOLD;
use crate::conversation::{debug_conversation_fix, fix_conversation, Conversation};
use crate::mcp_utils::ToolResult;
@@ -73,7 +73,7 @@ pub struct ReplyContext {
pub tools: Vec<Tool>,
pub toolshim_tools: Vec<Tool>,
pub system_prompt: String,
pub goose_mode: String,
pub goose_mode: GooseMode,
pub initial_messages: Vec<Message>,
pub config: &'static Config,
}
@@ -193,7 +193,7 @@ impl Agent {
// Add permission inspector (medium-high priority)
// Note: mode will be updated dynamically based on session config
tool_inspection_manager.add_inspector(Box::new(PermissionInspector::new(
"smart_approve".to_string(),
GooseMode::SmartApprove,
std::collections::HashSet::new(), // readonly tools - will be populated from extension manager
std::collections::HashSet::new(), // regular tools - will be populated from extension manager
)));
@@ -264,7 +264,7 @@ impl Agent {
// Update permission inspector mode to match the session mode
self.tool_inspection_manager
.update_permission_inspector_mode(goose_mode.clone())
.update_permission_inspector_mode(goose_mode)
.await;
Ok(ReplyContext {
@@ -1030,8 +1030,7 @@ impl Agent {
yield AgentEvent::Message(msg);
}
let mode = goose_mode.clone();
if mode.as_str() == "chat" {
if goose_mode == GooseMode::Chat {
// Skip all tool calls in chat mode
for request in remaining_requests {
let mut response = message_tool_response.lock().await;
@@ -1258,15 +1257,13 @@ impl Agent {
}))
}
fn determine_goose_mode(session: Option<&SessionConfig>, config: &Config) -> String {
fn determine_goose_mode(session: Option<&SessionConfig>, config: &Config) -> GooseMode {
let mode = session.and_then(|s| s.execution_mode.as_deref());
match mode {
Some("foreground") => "chat".to_string(),
Some("background") => "auto".to_string(),
_ => config
.get_param("GOOSE_MODE")
.unwrap_or_else(|_| "auto".to_string()),
Some("foreground") => GooseMode::Chat,
Some("background") => GooseMode::Auto,
_ => config.get_goose_mode().unwrap_or(GooseMode::Auto),
}
}
@@ -1525,7 +1522,7 @@ impl Agent {
// but it doesn't know and the plumbing looks complicated.
let config = Config::global();
let provider_name: String = config
.get_param("GOOSE_PROVIDER")
.get_goose_provider()
.expect("No provider configured. Run 'goose configure' first");
let settings = Settings {
+10 -9
View File
@@ -3,13 +3,16 @@ use chrono::DateTime;
use chrono::Utc;
use serde::Serialize;
use serde_json::Value;
use std::borrow::Cow;
use std::collections::HashMap;
use crate::agents::extension::ExtensionInfo;
use crate::agents::recipe_tools::dynamic_task_tools::should_enabled_subagents;
use crate::agents::router_tools::llm_search_tool_prompt;
use crate::{config::Config, prompt_template, utils::sanitize_unicode_tags};
use crate::{
config::{Config, GooseMode},
prompt_template,
utils::sanitize_unicode_tags,
};
const MAX_EXTENSIONS: usize = 5;
const MAX_TOOLS: usize = 50;
@@ -34,7 +37,7 @@ struct SystemPromptContext {
current_date_time: String,
#[serde(skip_serializing_if = "Option::is_none")]
extension_tool_limits: Option<(usize, usize)>,
goose_mode: String,
goose_mode: GooseMode,
is_autonomous: bool,
enable_subagents: bool,
max_extensions: usize,
@@ -106,9 +109,7 @@ impl<'a> SystemPromptBuilder<'a, PromptManager> {
.collect();
let config = Config::global();
let goose_mode = config
.get_param("GOOSE_MODE")
.unwrap_or_else(|_| Cow::from("auto"));
let goose_mode = config.get_goose_mode().unwrap_or(GooseMode::Auto);
let extension_tool_limits = self
.extension_tool_count
@@ -119,8 +120,8 @@ impl<'a> SystemPromptBuilder<'a, PromptManager> {
tool_selection_strategy: self.router_enabled.then(llm_search_tool_prompt),
current_date_time: self.manager.current_date_timestamp.clone(),
extension_tool_limits,
goose_mode: goose_mode.to_string(),
is_autonomous: goose_mode == "auto",
goose_mode,
is_autonomous: goose_mode == GooseMode::Auto,
enable_subagents: should_enabled_subagents(self.model_name.as_str()),
max_extensions: MAX_EXTENSIONS,
max_tools: MAX_TOOLS,
@@ -137,7 +138,7 @@ impl<'a> SystemPromptBuilder<'a, PromptManager> {
});
let mut system_prompt_extras = self.manager.system_prompt_extras.clone();
if goose_mode == "chat" {
if goose_mode == GooseMode::Chat {
system_prompt_extras.push(
"Right now you are in the chat only mode, no access to any tool use and system."
.to_string(),
@@ -9,6 +9,7 @@ use crate::agents::subagent_execution_tool::{
task_types::{Task, TaskType},
};
use crate::agents::tool_execution::ToolCallResult;
use crate::config::GooseMode;
use crate::recipe::{Recipe, RecipeBuilder};
use anyhow::{anyhow, Result};
use rmcp::model::{Content, ErrorCode, ErrorData, Tool, ToolAnnotations};
@@ -93,7 +94,7 @@ pub struct TaskParameter {
pub fn should_enabled_subagents(model_name: &str) -> bool {
let config = crate::config::Config::global();
let is_autonomous = config.get_param("GOOSE_MODE").unwrap_or("auto".to_string()) == "auto";
let is_autonomous = config.get_goose_mode().unwrap_or(GooseMode::Auto) == GooseMode::Auto;
if !is_autonomous {
return false;
}
+40 -33
View File
@@ -1,8 +1,9 @@
use crate::config::paths::Paths;
use crate::config::GooseMode;
use fs2::FileExt;
use keyring::Entry;
use once_cell::sync::OnceCell;
use serde::Deserialize;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashMap;
use std::env;
@@ -143,6 +144,11 @@ macro_rules! declare_param {
self.get_param(stringify!($param_name))
}
}
paste::paste! {
pub fn [<set_ $param_name:lower>](&self, v: impl Into<$param_type>) -> Result<(), ConfigError> {
self.set_param(stringify!($param_name), &v.into())
}
}
};
}
@@ -551,7 +557,10 @@ impl Config {
}
// 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> {
pub fn set<V>(&self, key: &str, value: &V, is_secret: bool) -> Result<(), ConfigError>
where
V: Serialize,
{
if is_secret {
self.set_secret(key, value)
} else {
@@ -606,17 +615,10 @@ 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_param(&self, key: &str, value: Value) -> Result<(), ConfigError> {
// Lock before reading to prevent race condition.
pub fn set_param<V: Serialize>(&self, key: &str, value: V) -> Result<(), ConfigError> {
let _guard = self.guard.lock().unwrap();
// Load current values with recovery if needed
let mut values = self.load_values()?;
// Modify values
values.insert(key.to_string(), value);
// Save all values using the atomic write approach
values.insert(key.to_string(), serde_json::to_value(&value)?);
self.save_values(values)
}
@@ -689,12 +691,15 @@ impl Config {
/// Returns a ConfigError if:
/// - There is an error accessing the keyring
/// - There is an error serializing the value
pub fn set_secret(&self, key: &str, value: Value) -> Result<(), ConfigError> {
pub fn set_secret<V>(&self, key: &str, value: &V) -> Result<(), ConfigError>
where
V: Serialize,
{
// Lock before reading to prevent race condition.
let _guard = self.guard.lock().unwrap();
let mut values = self.load_secrets()?;
values.insert(key.to_string(), value);
values.insert(key.to_string(), serde_json::to_value(value)?);
match &self.secrets {
SecretStorage::Keyring { service } => {
@@ -742,6 +747,9 @@ impl Config {
}
declare_param!(GOOSE_SEARCH_PATHS, Vec<String>);
declare_param!(GOOSE_MODE, GooseMode);
declare_param!(GOOSE_PROVIDER, String);
declare_param!(GOOSE_MODEL, String);
}
/// Load init-config.yaml from workspace root if it exists.
@@ -819,7 +827,7 @@ mod tests {
let config = Config::new(temp_file.path(), TEST_KEYRING_SERVICE)?;
// Set a simple string value
config.set_param("test_key", Value::String("test_value".to_string()))?;
config.set_param("test_key", "test_value")?;
// Test simple string retrieval
let value: String = config.get_param("test_key")?;
@@ -874,8 +882,8 @@ mod tests {
let temp_file = NamedTempFile::new().unwrap();
let config = Config::new(temp_file.path(), TEST_KEYRING_SERVICE)?;
config.set_param("key1", Value::String("value1".to_string()))?;
config.set_param("key2", Value::Number(42.into()))?;
config.set_param("key1", "value1")?;
config.set_param("key2", 42)?;
// Read the file directly to check YAML formatting
let content = std::fs::read_to_string(temp_file.path())?;
@@ -890,12 +898,11 @@ mod tests {
let temp_file = NamedTempFile::new().unwrap();
let config = Config::new(temp_file.path(), TEST_KEYRING_SERVICE)?;
config.set_param("key", Value::String("value".to_string()))?;
config.set_param("test_key", "test_value")?;
config.set_param("another_key", 42)?;
config.set_param("third_key", true)?;
let value: String = config.get_param("key")?;
assert_eq!(value, "value");
config.delete("key")?;
let _values = config.load_values()?;
let result: Result<String, ConfigError> = config.get_param("key");
assert!(matches!(result, Err(ConfigError::NotFound(_))));
@@ -909,7 +916,7 @@ mod tests {
let secrets_file = NamedTempFile::new().unwrap();
let config = Config::new_with_file_secrets(config_file.path(), secrets_file.path())?;
config.set_secret("key", Value::String("value".to_string()))?;
config.set_secret("key", &"value")?;
let value: String = config.get_secret("key")?;
assert_eq!(value, "value");
@@ -930,7 +937,7 @@ mod tests {
let config = Config::new(temp_file.path(), TEST_KEYRING_SERVICE)?;
// Test setting and getting a simple secret
config.set_secret("api_key", Value::String("secret123".to_string()))?;
config.set_secret("api_key", &Value::String("secret123".to_string()))?;
let value: String = config.get_secret("api_key")?;
assert_eq!(value, "secret123");
@@ -957,8 +964,8 @@ mod tests {
let config = Config::new(temp_file.path(), TEST_KEYRING_SERVICE)?;
// Set multiple secrets
config.set_secret("key1", Value::String("secret1".to_string()))?;
config.set_secret("key2", Value::String("secret2".to_string()))?;
config.set_secret("key1", &Value::String("secret1".to_string()))?;
config.set_secret("key2", &Value::String("secret2".to_string()))?;
// Verify both exist
let value1: String = config.get_secret("key1")?;
@@ -1056,7 +1063,7 @@ mod tests {
let config = Config::new(temp_file.path(), TEST_KEYRING_SERVICE)?;
// Create a valid config first
config.set_param("key1", Value::String("value1".to_string()))?;
config.set_param("key1", "value1")?;
// Verify the backup was created by the first write
let backup_paths = config.get_backup_paths();
@@ -1066,7 +1073,7 @@ mod tests {
}
// Make another write to ensure backup is created
config.set_param("key2", Value::Number(42.into()))?;
config.set_param("key2", 42)?;
// Check again
for (i, path) in backup_paths.iter().enumerate() {
@@ -1160,15 +1167,15 @@ mod tests {
let config = Config::new(config_path, TEST_KEYRING_SERVICE)?;
// First, create a config with some data
config.set_param("test_key_backup", Value::String("backup_value".to_string()))?;
config.set_param("another_key", Value::Number(42.into()))?;
config.set_param("test_key_backup", "backup_value")?;
config.set_param("another_key", 42)?;
// Verify the backup was created
let backup_paths = config.get_backup_paths();
let primary_backup = &backup_paths[0]; // .bak file
// Make sure we have a backup by doing another write
config.set_param("third_key", Value::Bool(true))?;
config.set_param("third_key", true)?;
assert!(primary_backup.exists(), "Backup should exist after writes");
// Now delete the main config file to simulate it being lost
@@ -1204,7 +1211,7 @@ mod tests {
let config = Config::new(temp_file.path(), TEST_KEYRING_SERVICE)?;
// Set initial values
config.set_param("key1", Value::String("value1".to_string()))?;
config.set_param("key1", "value1")?;
// Verify the config file exists and is valid
assert!(temp_file.path().exists());
@@ -1225,7 +1232,7 @@ mod tests {
// Create multiple versions to test rotation
for i in 1..=7 {
config.set_param("version", Value::Number(i.into()))?;
config.set_param("version", i)?;
}
let backup_paths = config.get_backup_paths();
@@ -1460,7 +1467,7 @@ mod tests {
let config = Config::new(temp_file.path(), TEST_KEYRING_SERVICE)?;
// Set value in config file
config.set_param("test_precedence", Value::String("file_value".to_string()))?;
config.set_param("test_precedence", "file_value")?;
// Verify file value is returned when no env var
let value: String = config.get_param("test_precedence")?;
@@ -97,7 +97,7 @@ pub fn create_custom_provider(
let api_key_name = generate_api_key_name(&id);
let config = Config::global();
config.set_secret(&api_key_name, serde_json::Value::String(api_key))?;
config.set_secret(&api_key_name, &api_key)?;
let model_infos: Vec<ModelInfo> = models
.into_iter()
@@ -147,10 +147,7 @@ pub fn update_custom_provider(
let config = Config::global();
if !api_key.is_empty() {
config.set_secret(
&existing_config.api_key_env,
serde_json::Value::String(api_key),
)?;
config.set_secret(&existing_config.api_key_env, &api_key)?;
}
if editable {
+1 -1
View File
@@ -35,7 +35,7 @@ impl ExperimentManager {
Self::refresh_experiments(&mut experiments);
experiments.insert(name.to_string(), enabled);
config.set_param("experiments", serde_json::to_value(experiments)?)?;
config.set_param("experiments", experiments)?;
Ok(())
}
+3 -9
View File
@@ -101,15 +101,9 @@ fn get_extensions_map() -> HashMap<String, ExtensionEntry> {
fn save_extensions_map(extensions: HashMap<String, ExtensionEntry>) {
let config = Config::global();
match serde_json::to_value(extensions) {
Ok(value) => {
if let Err(e) = config.set_param(EXTENSIONS_CONFIG_KEY, value) {
tracing::debug!("Failed to save extensions config: {}", e);
}
}
Err(e) => {
tracing::debug!("Failed to serialize extensions: {}", e);
}
if let Err(e) = config.set_param(EXTENSIONS_CONFIG_KEY, &extensions) {
// TODO(jack) why is this just a debug statement?
tracing::debug!("Failed to save extensions config: {}", e);
}
}
+26
View File
@@ -0,0 +1,26 @@
use std::str::FromStr;
use serde::{Deserialize, Serialize};
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum GooseMode {
Auto,
Approve,
SmartApprove,
Chat,
}
impl FromStr for GooseMode {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"auto" => Ok(GooseMode::Auto),
"approve" => Ok(GooseMode::Approve),
"smart_approve" => Ok(GooseMode::SmartApprove),
"chat" => Ok(GooseMode::Chat),
_ => Err(format!("invalid mode: {}", s)),
}
}
}
+2
View File
@@ -2,6 +2,7 @@ pub mod base;
pub mod declarative_providers;
mod experiments;
pub mod extensions;
pub mod goose_mode;
pub mod paths;
pub mod permission;
pub mod search_path;
@@ -16,6 +17,7 @@ pub use extensions::{
get_all_extension_names, get_all_extensions, get_enabled_extensions, get_extension_by_name,
is_extension_enabled, remove_extension, set_extension, set_extension_enabled, ExtensionEntry,
};
pub use goose_mode::GooseMode;
pub use permission::PermissionManager;
pub use signup_openrouter::configure_openrouter;
pub use signup_tetrate::configure_tetrate;
@@ -162,14 +162,10 @@ impl PkceAuthFlow {
pub use self::PkceAuthFlow as OpenRouterAuth;
use crate::config::Config;
use serde_json::Value;
pub fn configure_openrouter(config: &Config, api_key: String) -> Result<()> {
config.set_secret("OPENROUTER_API_KEY", Value::String(api_key))?;
config.set_param("GOOSE_PROVIDER", Value::String("openrouter".to_string()))?;
config.set_param(
"GOOSE_MODEL",
Value::String(OPENROUTER_DEFAULT_MODEL.to_string()),
)?;
config.set_secret("OPENROUTER_API_KEY", &api_key)?;
config.set_goose_provider("openrouter")?;
config.set_goose_model(OPENROUTER_DEFAULT_MODEL)?;
Ok(())
}
@@ -163,14 +163,10 @@ impl PkceAuthFlow {
pub use self::PkceAuthFlow as TetrateAuth;
use crate::config::Config;
use serde_json::Value;
pub fn configure_tetrate(config: &Config, api_key: String) -> Result<()> {
config.set_secret("TETRATE_API_KEY", Value::String(api_key))?;
config.set_param("GOOSE_PROVIDER", Value::String("tetrate".to_string()))?;
config.set_param(
"GOOSE_MODEL",
Value::String(TETRATE_DEFAULT_MODEL.to_string()),
)?;
config.set_secret("TETRATE_API_KEY", &api_key)?;
config.set_goose_provider("tetrate")?;
config.set_goose_model(TETRATE_DEFAULT_MODEL)?;
Ok(())
}
@@ -76,12 +76,9 @@ fn test_configure_tetrate() {
config.get_secret::<String>("TETRATE_API_KEY").unwrap(),
test_key
);
assert_eq!(config.get_goose_provider().unwrap(), "tetrate");
assert_eq!(
config.get_param::<String>("GOOSE_PROVIDER").unwrap(),
"tetrate"
);
assert_eq!(
config.get_param::<String>("GOOSE_MODEL").unwrap(),
config.get_goose_model().unwrap(),
TETRATE_DEFAULT_MODEL.to_string()
);
}
+1 -2
View File
@@ -27,9 +27,8 @@ pub async fn save_credentials(
token_response,
};
let value = serde_json::to_value(&credentials)?;
let key = secret_key(name);
config.set_secret(&key, value)?;
config.set_secret(&key, &credentials)?;
Ok(())
}
@@ -1,6 +1,6 @@
use crate::agents::extension_manager_extension::MANAGE_EXTENSIONS_TOOL_NAME_COMPLETE;
use crate::config::permission::PermissionLevel;
use crate::config::PermissionManager;
use crate::config::{GooseMode, PermissionManager};
use crate::conversation::message::{Message, ToolRequest};
use crate::permission::permission_judge::PermissionCheckResult;
use crate::tool_inspection::{InspectionAction, InspectionResult, ToolInspector};
@@ -12,7 +12,7 @@ use tokio::sync::Mutex;
/// Permission Inspector that handles tool permission checking
pub struct PermissionInspector {
mode: Arc<Mutex<String>>,
mode: Arc<Mutex<GooseMode>>,
readonly_tools: HashSet<String>,
regular_tools: HashSet<String>,
pub permission_manager: Arc<Mutex<PermissionManager>>,
@@ -20,7 +20,7 @@ pub struct PermissionInspector {
impl PermissionInspector {
pub fn new(
mode: String,
mode: GooseMode,
readonly_tools: HashSet<String>,
regular_tools: HashSet<String>,
) -> Self {
@@ -33,7 +33,7 @@ impl PermissionInspector {
}
pub fn with_permission_manager(
mode: String,
mode: GooseMode,
readonly_tools: HashSet<String>,
regular_tools: HashSet<String>,
permission_manager: Arc<Mutex<PermissionManager>>,
@@ -47,7 +47,7 @@ impl PermissionInspector {
}
/// Update the mode of this permission inspector
pub async fn update_mode(&self, new_mode: String) {
pub async fn update_mode(&self, new_mode: GooseMode) {
let mut mode = self.mode.lock().await;
*mode = new_mode;
}
@@ -139,45 +139,42 @@ impl ToolInspector for PermissionInspector {
if let Ok(tool_call) = &request.tool_call {
let tool_name = &tool_call.name;
// Handle different modes
let action = if *mode == "chat" {
// In chat mode, all tools are skipped (handled elsewhere)
continue;
} else if *mode == "auto" {
// In auto mode, all tools are approved
InspectionAction::Allow
} else {
// Smart mode - check permissions
// 1. Check user-defined permission first
if let Some(level) = permission_manager.get_user_permission(tool_name) {
match level {
PermissionLevel::AlwaysAllow => InspectionAction::Allow,
PermissionLevel::NeverAllow => InspectionAction::Deny,
PermissionLevel::AskBefore => InspectionAction::RequireApproval(None),
let action = match *mode {
GooseMode::Chat => continue,
GooseMode::Auto => InspectionAction::Allow,
GooseMode::Approve | GooseMode::SmartApprove => {
// 1. Check user-defined permission first
if let Some(level) = permission_manager.get_user_permission(tool_name) {
match level {
PermissionLevel::AlwaysAllow => InspectionAction::Allow,
PermissionLevel::NeverAllow => InspectionAction::Deny,
PermissionLevel::AskBefore => {
InspectionAction::RequireApproval(None)
}
}
}
// 2. Check if it's a readonly or regular tool (both pre-approved)
else if self.readonly_tools.contains(tool_name.as_ref())
|| self.regular_tools.contains(tool_name.as_ref())
{
InspectionAction::Allow
}
// 4. Special case for extension management
else if tool_name == MANAGE_EXTENSIONS_TOOL_NAME_COMPLETE {
InspectionAction::RequireApproval(Some(
"Extension management requires approval for security".to_string(),
))
}
// 5. Default: require approval for unknown tools
else {
InspectionAction::RequireApproval(None)
}
}
// 2. Check if it's a readonly or regular tool (both pre-approved)
else if self.readonly_tools.contains(tool_name.as_ref())
|| self.regular_tools.contains(tool_name.as_ref())
{
InspectionAction::Allow
}
// 4. Special case for extension management
else if tool_name == MANAGE_EXTENSIONS_TOOL_NAME_COMPLETE {
InspectionAction::RequireApproval(Some(
"Extension management requires approval for security".to_string(),
))
}
// 5. Default: require approval for unknown tools
else {
InspectionAction::RequireApproval(None)
}
};
let reason = match &action {
InspectionAction::Allow => {
if *mode == "auto" {
if *mode == GooseMode::Auto {
"Auto mode - all tools approved".to_string()
} else if self.readonly_tools.contains(tool_name.as_ref()) {
"Tool marked as read-only".to_string()
+3 -17
View File
@@ -10,7 +10,7 @@ use tokio::process::Command;
use super::base::{ConfigKey, Provider, ProviderMetadata, ProviderUsage, Usage};
use super::errors::ProviderError;
use super::utils::RequestLog;
use crate::config::Config;
use crate::config::{Config, GooseMode};
use crate::conversation::message::{Message, MessageContent};
use crate::model::ModelConfig;
use rmcp::model::Tool;
@@ -338,10 +338,8 @@ impl ClaudeCodeProvider {
// Add permission mode based on GOOSE_MODE setting
let config = Config::global();
if let Ok(goose_mode) = config.get_param::<String>("GOOSE_MODE") {
if goose_mode.as_str() == "auto" {
cmd.arg("--permission-mode").arg("acceptEdits");
}
if let Ok(GooseMode::Auto) = config.get_goose_mode() {
cmd.arg("--permission-mode").arg("acceptEdits");
}
cmd.stdout(Stdio::piped()).stderr(Stdio::piped());
@@ -523,18 +521,6 @@ mod tests {
use super::ModelConfig;
use super::*;
#[test]
fn test_permission_mode_flag_construction() {
// Test that in auto mode, the --permission-mode acceptEdits flag is added
std::env::set_var("GOOSE_MODE", "auto");
let config = Config::global();
let goose_mode: String = config.get_param("GOOSE_MODE").unwrap();
assert_eq!(goose_mode, "auto");
std::env::remove_var("GOOSE_MODE");
}
#[tokio::test]
async fn test_claude_code_invalid_model_no_fallback() {
// Test that an invalid model is kept as-is (no fallback)
+2 -2
View File
@@ -235,7 +235,7 @@ impl GithubCopilotProvider {
.get_access_token()
.await
.context("unable to login into github")?;
config.set_secret("GITHUB_COPILOT_TOKEN", Value::String(token.clone()))?;
config.set_secret("GITHUB_COPILOT_TOKEN", &token)?;
token
}
_ => return Err(err.into()),
@@ -500,7 +500,7 @@ impl Provider for GithubCopilotProvider {
// Save the token
config
.set_secret("GITHUB_COPILOT_TOKEN", Value::String(token))
.set_secret("GITHUB_COPILOT_TOKEN", &token)
.map_err(|e| ProviderError::ExecutionError(format!("Failed to save token: {}", e)))?;
Ok(())
+7 -2
View File
@@ -6,6 +6,7 @@ use super::utils::{
get_model, handle_response_openai_compat, handle_status_openai_compat, RequestLog,
};
use crate::config::declarative_providers::DeclarativeProviderConfig;
use crate::config::GooseMode;
use crate::conversation::message::Message;
use crate::conversation::Conversation;
@@ -199,8 +200,12 @@ impl Provider for OllamaProvider {
tools: &[Tool],
) -> Result<(Message, ProviderUsage), ProviderError> {
let config = crate::config::Config::global();
let goose_mode = config.get_param("GOOSE_MODE").unwrap_or("auto".to_string());
let filtered_tools = if goose_mode == "chat" { &[] } else { tools };
let goose_mode = config.get_goose_mode().unwrap_or(GooseMode::Auto);
let filtered_tools = if goose_mode == GooseMode::Chat {
&[]
} else {
tools
};
let payload = create_request(
&self.model,
+2 -2
View File
@@ -1104,7 +1104,7 @@ async fn run_scheduled_job_internal(
agent_provider = provider;
} else {
let global_config = Config::global();
let provider_name: String = match global_config.get_param("GOOSE_PROVIDER") {
let provider_name: String = match global_config.get_goose_provider() {
Ok(name) => name,
Err(_) => return Err(JobExecutionError {
job_id: job.id.clone(),
@@ -1114,7 +1114,7 @@ async fn run_scheduled_job_internal(
}),
};
let model_name: String =
match global_config.get_param("GOOSE_MODEL") {
match global_config.get_goose_model() {
Ok(name) => name,
Err(_) => return Err(JobExecutionError {
job_id: job.id.clone(),
+2 -1
View File
@@ -2,6 +2,7 @@ use anyhow::Result;
use async_trait::async_trait;
use std::collections::HashMap;
use crate::config::GooseMode;
use crate::conversation::message::{Message, ToolRequest};
use crate::permission::permission_inspector::PermissionInspector;
use crate::permission::permission_judge::PermissionCheckResult;
@@ -116,7 +117,7 @@ impl ToolInspectionManager {
}
/// Update the permission inspector's mode
pub async fn update_permission_inspector_mode(&self, mode: String) {
pub async fn update_permission_inspector_mode(&self, mode: GooseMode) {
for inspector in &self.inspectors {
if inspector.name() == "permission" {
// Downcast to PermissionInspector to access update_mode method
+2 -8
View File
@@ -301,16 +301,10 @@ mod tests {
// Set values in config
test_config
.set_param(
"otel_exporter_otlp_endpoint",
serde_json::Value::String("http://config:4318".to_string()),
)
.set_param("otel_exporter_otlp_endpoint", "http://config:4318")
.unwrap();
test_config
.set_param(
"otel_exporter_otlp_timeout",
serde_json::Value::Number(3000.into()),
)
.set_param("otel_exporter_otlp_timeout", 3000)
.unwrap();
// Test that from_config reads from the config file