From 9ee8280c3c22027fdbf62b61616fa327f3d2cc66 Mon Sep 17 00:00:00 2001 From: Jack Amadeo Date: Tue, 21 Oct 2025 15:08:33 -0400 Subject: [PATCH 1/9] chipping away at the stringly typed --- crates/goose-cli/src/commands/configure.rs | 26 +++++----- crates/goose-cli/src/session/mod.rs | 36 +++++-------- crates/goose-server/src/routes/agent.rs | 14 +++-- crates/goose/src/agents/agent.rs | 19 ++++--- crates/goose/src/agents/prompt_manager.rs | 52 ++++++++----------- crates/goose/src/agents/reply_parts.rs | 4 +- crates/goose/src/config/base.rs | 9 ++-- crates/goose/src/config/mod.rs | 25 +++++++++ .../src/permission/permission_inspector.rs | 16 +++--- crates/goose/src/providers/claude_code.rs | 21 ++------ crates/goose/src/providers/ollama.rs | 9 +++- crates/goose/src/tool_inspection.rs | 3 +- 12 files changed, 117 insertions(+), 117 deletions(-) diff --git a/crates/goose-cli/src/commands/configure.rs b/crates/goose-cli/src/commands/configure.rs index 692a998d231..9a89065bb2a 100644 --- a/crates/goose-cli/src/commands/configure.rs +++ b/crates/goose-cli/src/commands/configure.rs @@ -14,7 +14,9 @@ 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::{ + Config, ConfigError, ExperimentManager, ExtensionEntry, GooseMode, PermissionManager, +}; use goose::conversation::message::Message; use goose::model::ModelConfig; use goose::providers::{create, providers}; @@ -1244,45 +1246,41 @@ pub fn configure_goose_mode_dialog() -> Result<(), Box> { let mode = cliclack::select("Which goose mode would you like to configure?") .item( - "auto", + GooseMode::Auto, "Auto Mode", "Full file modification, extension usage, edit, create and delete files freely" ) .item( - "approve", + GooseMode::Approve, "Approve Mode", "All tools, extensions and file modifications will require human approval" ) .item( - "smart_approve", + GooseMode::SmartApprove, "Smart Approve Mode", "Editing, creating, deleting files and using extensions will require human approval" ) .item( - "chat", + GooseMode::Chat, "Chat Mode", "Engage with the selected provider without using tools, extensions, or file modification" ) .interact()?; + config.set_param("GOOSE_MODE", mode)?; match mode { - "auto" => { - config.set_param("GOOSE_MODE", Value::String("auto".to_string()))?; + GooseMode::Auto => { cliclack::outro("Set to Auto Mode - full file modification enabled")?; } - "approve" => { - config.set_param("GOOSE_MODE", Value::String("approve".to_string()))?; + GooseMode::Approve => { cliclack::outro("Set to Approve Mode - all tools and modifications require approval")?; } - "smart_approve" => { - config.set_param("GOOSE_MODE", Value::String("smart_approve".to_string()))?; + GooseMode::SmartApprove => { cliclack::outro("Set to Smart Approve Mode - modifications require approval")?; } - "chat" => { - config.set_param("GOOSE_MODE", Value::String("chat".to_string()))?; + GooseMode::Chat => { cliclack::outro("Set to Chat Mode - no tools or modifications enabled")?; } - _ => unreachable!(), }; Ok(()) } diff --git a/crates/goose-cli/src/session/mod.rs b/crates/goose-cli/src/session/mod.rs index 133b3aef488..65799a23a2f 100644 --- a/crates/goose-cli/src/session/mod.rs +++ b/crates/goose-cli/src/session/mod.rs @@ -10,6 +10,7 @@ mod thinking; use crate::session::task_execution_display::{ format_task_execution_notification, TASK_EXECUTION_NOTIFICATION_TYPE, }; +use goose::config::GooseMode; use goose::conversation::Conversation; use std::io::Write; @@ -533,25 +534,19 @@ impl CliSession { Err(e) => output::render_error(&e.to_string()), } } - input::InputResult::GooseMode(mode) => { + input::InputResult::GooseMode(mode_arg) => { save_history(&mut editor); let config = Config::global(); - let mode = mode.to_lowercase(); - - // Check if mode is valid - if !["auto", "approve", "chat", "smart_approve"].contains(&mode.as_str()) { + if let Ok(mode) = GooseMode::try_from(&mode_arg) { + config.set_param("GOOSE_MODE", mode).unwrap(); + output::goose_mode_message(&format!("Goose mode set to '{}'", &mode_arg)); + } else { output::render_error(&format!( - "Invalid mode '{}'. Mode must be one of: auto, approve, chat", - mode + "Invalid mode '{}'. Mode must be one of: auto, approve, smart_approve, chat", + mode_arg )); - continue; } - - config - .set_param("GOOSE_MODE", Value::String(mode.to_string())) - .unwrap(); - output::goose_mode_message(&format!("Goose mode set to '{}'", mode)); continue; } input::InputResult::Plan(options) => { @@ -779,12 +774,9 @@ impl CliSession { self.run_mode = RunMode::Normal; // set goose mode: auto if that isn't already the case let config = Config::global(); - let curr_goose_mode = - config.get_param("GOOSE_MODE").unwrap_or("auto".to_string()); - if curr_goose_mode != "auto" { - config - .set_param("GOOSE_MODE", Value::String("auto".to_string())) - .unwrap(); + let curr_goose_mode = config.get_param("GOOSE_MODE").unwrap_or(GooseMode::Auto); + if curr_goose_mode != GooseMode::Auto { + config.set_param("GOOSE_MODE", GooseMode::Auto).unwrap(); } // clear the messages before acting on the plan @@ -799,10 +791,8 @@ impl CliSession { output::hide_thinking(); // Reset run & goose mode - if curr_goose_mode != "auto" { - config - .set_param("GOOSE_MODE", Value::String(curr_goose_mode.to_string())) - .unwrap(); + if curr_goose_mode != GooseMode::Auto { + config.set_param("GOOSE_MODE", curr_goose_mode).unwrap(); } } else { // add the plan response (assistant message) & carry the conversation forward diff --git a/crates/goose-server/src/routes/agent.rs b/crates/goose-server/src/routes/agent.rs index d488167ab50..194ccd405b3 100644 --- a/crates/goose-server/src/routes/agent.rs +++ b/crates/goose-server/src/routes/agent.rs @@ -7,7 +7,7 @@ use axum::{ routing::{get, post}, Json, Router, }; -use goose::config::PermissionManager; +use goose::config::{GooseMode, PermissionManager}; use goose::model::ModelConfig; use goose::providers::create; @@ -262,7 +262,7 @@ async fn get_tools( Query(query): Query, ) -> Result>, StatusCode> { let config = Config::global(); - let goose_mode = config.get_param("GOOSE_MODE").unwrap_or("auto".to_string()); + let goose_mode = config.get_param("GOOSE_MODE").unwrap_or(GooseMode::Auto); let agent = state.get_agent_for_route(query.session_id).await?; let permission_manager = PermissionManager::default(); @@ -273,14 +273,12 @@ async fn get_tools( .map(|tool| { let permission = permission_manager .get_user_permission(&tool.name) - .or_else(|| { - if goose_mode == "smart_approve" { + .or_else(|| match goose_mode { + GooseMode::SmartApprove => { permission_manager.get_smart_approve_permission(&tool.name) - } else if goose_mode == "approve" { - Some(PermissionLevel::AskBefore) - } else { - None } + GooseMode::Approve => Some(PermissionLevel::AskBefore), + _ => None, }); ToolInfo::new( diff --git a/crates/goose/src/agents/agent.rs b/crates/goose/src/agents/agent.rs index b2ade9ea89f..db54cf498e5 100644 --- a/crates/goose/src/agents/agent.rs +++ b/crates/goose/src/agents/agent.rs @@ -32,7 +32,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, ToolResultReceiver}; -use crate::config::{get_enabled_extensions, get_extension_by_name, Config}; +use crate::config::{get_enabled_extensions, get_extension_by_name, Config, GooseMode}; use crate::context_mgmt::DEFAULT_COMPACTION_THRESHOLD; use crate::conversation::{debug_conversation_fix, fix_conversation, Conversation}; use crate::mcp_utils::ToolResult; @@ -74,7 +74,7 @@ pub struct ReplyContext { pub tools: Vec, pub toolshim_tools: Vec, pub system_prompt: String, - pub goose_mode: String, + pub goose_mode: GooseMode, pub initial_messages: Vec, pub config: &'static Config, } @@ -192,7 +192,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 ))); @@ -263,7 +263,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 { @@ -1177,8 +1177,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; @@ -1393,15 +1392,15 @@ 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(), + Some("foreground") => GooseMode::Chat, + Some("background") => GooseMode::Auto, _ => config .get_param("GOOSE_MODE") - .unwrap_or_else(|_| "auto".to_string()), + .unwrap_or_else(|_| GooseMode::Auto), } } diff --git a/crates/goose/src/agents/prompt_manager.rs b/crates/goose/src/agents/prompt_manager.rs index 67948068531..ff4540bd64a 100644 --- a/crates/goose/src/agents/prompt_manager.rs +++ b/crates/goose/src/agents/prompt_manager.rs @@ -1,9 +1,11 @@ use chrono::Utc; +use serde::Serialize; use serde_json::Value; use std::collections::HashMap; use crate::agents::extension::ExtensionInfo; use crate::agents::router_tools::llm_search_tool_prompt; +use crate::config::GooseMode; use crate::providers::base::get_current_model; use crate::{config::Config, prompt_template, utils::sanitize_unicode_tags}; @@ -19,6 +21,16 @@ impl Default for PromptManager { } } +#[derive(Serialize)] +struct SystemPromptContext { + extensions: Vec, + tool_selection_strategy: Option, + current_date_time: String, + suggest_disable: String, + goose_mode: GooseMode, + is_autonomous: bool, +} + impl PromptManager { pub fn new() -> Self { PromptManager { @@ -70,7 +82,6 @@ impl PromptManager { model_name: Option<&str>, router_enabled: bool, ) -> String { - let mut context: HashMap<&str, Value> = HashMap::new(); let mut extensions_info = extensions_info.clone(); // Add frontend instructions to extensions_info to simplify json rendering @@ -90,39 +101,22 @@ impl PromptManager { }) .collect(); - context.insert( - "extensions", - serde_json::to_value(sanitized_extensions_info).unwrap(), - ); - - if router_enabled { - context.insert( - "tool_selection_strategy", - Value::String(llm_search_tool_prompt()), - ); - } - - context.insert( - "current_date_time", - Value::String(self.current_date_timestamp.clone()), - ); - - // Add the suggestion about disabling extensions if flag is true - context.insert( - "suggest_disable", - Value::String(suggest_disable_extensions_prompt.to_string()), - ); - - // Add the mode to the context for conditional rendering let config = Config::global(); - let goose_mode = config.get_param("GOOSE_MODE").unwrap_or("auto".to_string()); - context.insert("goose_mode", Value::String(goose_mode.clone())); - context.insert("is_autonomous", Value::Bool(goose_mode == "auto")); + let goose_mode = config.get_param("GOOSE_MODE").unwrap_or(GooseMode::Auto); // First check the global store, and only if it's not available, fall back to the provided model_name let model_to_use: Option = get_current_model().or_else(|| model_name.map(|s| s.to_string())); + let context = SystemPromptContext { + extensions: sanitized_extensions_info, + tool_selection_strategy: router_enabled.then(llm_search_tool_prompt), + current_date_time: self.current_date_timestamp.clone(), + suggest_disable: suggest_disable_extensions_prompt.to_string(), + goose_mode, + is_autonomous: goose_mode == GooseMode::Auto, + }; + // Conditionally load the override prompt or the global system prompt let base_prompt = if let Some(override_prompt) = &self.system_prompt_override { let sanitized_override_prompt = sanitize_unicode_tags(override_prompt); @@ -145,7 +139,7 @@ impl PromptManager { }; let mut system_prompt_extras = self.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(), diff --git a/crates/goose/src/agents/reply_parts.rs b/crates/goose/src/agents/reply_parts.rs index c4dd379b688..0a5b3c9c53b 100644 --- a/crates/goose/src/agents/reply_parts.rs +++ b/crates/goose/src/agents/reply_parts.rs @@ -6,6 +6,7 @@ use futures::stream::StreamExt; use tracing::debug; use super::super::agents::Agent; +use crate::config::GooseMode; use crate::conversation::message::{Message, MessageContent, ToolRequest}; use crate::conversation::Conversation; use crate::providers::base::{stream_from_single_message, MessageStream, Provider, ProviderUsage}; @@ -41,7 +42,8 @@ impl Agent { let mut tools = self.list_tools_for_router().await; 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_param("GOOSE_MODE").unwrap_or(GooseMode::Auto) == GooseMode::Auto; // If router is disabled and no tools were returned, fall back to regular tools if !router_enabled && tools.is_empty() { diff --git a/crates/goose/src/config/base.rs b/crates/goose/src/config/base.rs index 3cde60d3b42..a6243913c1a 100644 --- a/crates/goose/src/config/base.rs +++ b/crates/goose/src/config/base.rs @@ -2,7 +2,7 @@ use crate::config::paths::Paths; 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; @@ -596,7 +596,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> { + pub fn set_param(&self, key: &str, value: V) -> Result<(), ConfigError> + where + V: Serialize, + { // Lock before reading to prevent race condition. let _guard = self.guard.lock().unwrap(); @@ -604,7 +607,7 @@ impl Config { let mut values = self.load_values()?; // Modify values - values.insert(key.to_string(), value); + values.insert(key.to_string(), serde_json::to_value(value)?); // Save all values using the atomic write approach self.save_values(values) diff --git a/crates/goose/src/config/mod.rs b/crates/goose/src/config/mod.rs index 3ab6f3497ff..9ceb79d3e29 100644 --- a/crates/goose/src/config/mod.rs +++ b/crates/goose/src/config/mod.rs @@ -16,6 +16,8 @@ pub use extensions::{ is_extension_enabled, remove_extension, set_extension, set_extension_enabled, ExtensionEntry, }; pub use permission::PermissionManager; +use serde::Deserialize; +use serde::Serialize; pub use signup_openrouter::configure_openrouter; pub use signup_tetrate::configure_tetrate; @@ -23,3 +25,26 @@ pub use extensions::DEFAULT_DISPLAY_NAME; pub use extensions::DEFAULT_EXTENSION; pub use extensions::DEFAULT_EXTENSION_DESCRIPTION; pub use extensions::DEFAULT_EXTENSION_TIMEOUT; + +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum GooseMode { + Auto, + Approve, + SmartApprove, + Chat, +} + +impl TryFrom<&String> for GooseMode { + type Error = String; + + fn try_from(value: &String) -> Result { + match value.as_str() { + "auto" => Ok(GooseMode::Auto), + "approve" => Ok(GooseMode::Approve), + "smart_approve" => Ok(GooseMode::SmartApprove), + "chat" => Ok(GooseMode::Chat), + _ => Err(format!("invalid mode: {}", value)), + } + } +} diff --git a/crates/goose/src/permission/permission_inspector.rs b/crates/goose/src/permission/permission_inspector.rs index 9cb392bc85c..aca12e1a4c6 100644 --- a/crates/goose/src/permission/permission_inspector.rs +++ b/crates/goose/src/permission/permission_inspector.rs @@ -1,6 +1,6 @@ use crate::agents::platform_tools::PLATFORM_MANAGE_EXTENSIONS_TOOL_NAME; 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>, + mode: Arc>, readonly_tools: HashSet, regular_tools: HashSet, pub permission_manager: Arc>, @@ -20,7 +20,7 @@ pub struct PermissionInspector { impl PermissionInspector { pub fn new( - mode: String, + mode: GooseMode, readonly_tools: HashSet, regular_tools: HashSet, ) -> Self { @@ -33,7 +33,7 @@ impl PermissionInspector { } pub fn with_permission_manager( - mode: String, + mode: GooseMode, readonly_tools: HashSet, regular_tools: HashSet, permission_manager: Arc>, @@ -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; } @@ -140,10 +140,10 @@ impl ToolInspector for PermissionInspector { let tool_name = &tool_call.name; // Handle different modes - let action = if *mode == "chat" { + let action = if *mode == GooseMode::Chat { // In chat mode, all tools are skipped (handled elsewhere) continue; - } else if *mode == "auto" { + } else if *mode == GooseMode::Auto { // In auto mode, all tools are approved InspectionAction::Allow } else { @@ -177,7 +177,7 @@ impl ToolInspector for PermissionInspector { 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() diff --git a/crates/goose/src/providers/claude_code.rs b/crates/goose/src/providers/claude_code.rs index 57100402879..824f2c9b233 100644 --- a/crates/goose/src/providers/claude_code.rs +++ b/crates/goose/src/providers/claude_code.rs @@ -10,7 +10,7 @@ use tokio::process::Command; use super::base::{ConfigKey, Provider, ProviderMetadata, ProviderUsage, Usage}; use super::errors::ProviderError; use super::utils::emit_debug_trace; -use crate::config::Config; +use crate::config::{Config, GooseMode}; use crate::conversation::message::{Message, MessageContent}; use crate::model::ModelConfig; use rmcp::model::Tool; @@ -333,12 +333,9 @@ impl ClaudeCodeProvider { cmd.arg("--verbose").arg("--output-format").arg("json"); - // Add permission mode based on GOOSE_MODE setting let config = Config::global(); - if let Ok(goose_mode) = config.get_param::("GOOSE_MODE") { - if goose_mode.as_str() == "auto" { - cmd.arg("--permission-mode").arg("acceptEdits"); - } + if let Ok(GooseMode::Auto) = config.get_param("GOOSE_MODE") { + cmd.arg("--permission-mode").arg("acceptEdits"); } cmd.stdout(Stdio::piped()).stderr(Stdio::piped()); @@ -515,18 +512,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) diff --git a/crates/goose/src/providers/ollama.rs b/crates/goose/src/providers/ollama.rs index e1e0b5b2000..64dac7ea64c 100644 --- a/crates/goose/src/providers/ollama.rs +++ b/crates/goose/src/providers/ollama.rs @@ -4,6 +4,7 @@ use super::errors::ProviderError; use super::retry::ProviderRetry; use super::utils::{get_model, handle_response_openai_compat, handle_status_openai_compat}; use crate::config::declarative_providers::DeclarativeProviderConfig; +use crate::config::GooseMode; use crate::conversation::message::Message; use crate::conversation::Conversation; @@ -190,8 +191,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_param("GOOSE_MODE").unwrap_or(GooseMode::Auto); + let filtered_tools = if goose_mode == GooseMode::Chat { + &[] + } else { + tools + }; let payload = create_request( &self.model, diff --git a/crates/goose/src/tool_inspection.rs b/crates/goose/src/tool_inspection.rs index 56f1cdce66a..2e372c91ae9 100644 --- a/crates/goose/src/tool_inspection.rs +++ b/crates/goose/src/tool_inspection.rs @@ -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 From 04615345da5de80ad2ec6e41d136863a46c47f62 Mon Sep 17 00:00:00 2001 From: Jack Amadeo Date: Tue, 21 Oct 2025 15:11:31 -0400 Subject: [PATCH 2/9] clippy --- crates/goose/src/agents/agent.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/goose/src/agents/agent.rs b/crates/goose/src/agents/agent.rs index db54cf498e5..e425ec7076b 100644 --- a/crates/goose/src/agents/agent.rs +++ b/crates/goose/src/agents/agent.rs @@ -1398,9 +1398,7 @@ impl Agent { match mode { Some("foreground") => GooseMode::Chat, Some("background") => GooseMode::Auto, - _ => config - .get_param("GOOSE_MODE") - .unwrap_or_else(|_| GooseMode::Auto), + _ => config.get_param("GOOSE_MODE").unwrap_or(GooseMode::Auto), } } From 3bf8011da21156e488e5c214797f0fc22e0b808f Mon Sep 17 00:00:00 2001 From: Jack Amadeo Date: Tue, 21 Oct 2025 15:24:51 -0400 Subject: [PATCH 3/9] Add a snapshot test --- Cargo.lock | 12 ++++ crates/goose/Cargo.toml | 1 + crates/goose/src/agents/prompt_manager.rs | 24 +++++++ ...ents__prompt_manager__tests__snapshot.snap | 65 +++++++++++++++++++ 4 files changed, 102 insertions(+) create mode 100644 crates/goose/src/agents/snapshots/goose__agents__prompt_manager__tests__snapshot.snap diff --git a/Cargo.lock b/Cargo.lock index c6d27a30111..2626ac1b769 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2608,6 +2608,7 @@ dependencies = [ "futures", "include_dir", "indoc", + "insta", "jsonschema", "jsonwebtoken", "keyring", @@ -3518,6 +3519,17 @@ dependencies = [ "generic-array", ] +[[package]] +name = "insta" +version = "1.43.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46fdb647ebde000f43b5b53f773c30cf9b0cb4300453208713fa38b2c70935a0" +dependencies = [ + "console", + "once_cell", + "similar", +] + [[package]] name = "interpolate_name" version = "0.2.4" diff --git a/crates/goose/Cargo.toml b/crates/goose/Cargo.toml index da53ae2420e..7e492b68948 100644 --- a/crates/goose/Cargo.toml +++ b/crates/goose/Cargo.toml @@ -102,6 +102,7 @@ unicode-normalization = "0.1" oauth2 = "5.0.0" schemars = { version = "1.0.4", default-features = false, features = ["derive"] } +insta = "1.43.2" [target.'cfg(target_os = "windows")'.dependencies] winapi = { version = "0.3", features = ["wincred"] } diff --git a/crates/goose/src/agents/prompt_manager.rs b/crates/goose/src/agents/prompt_manager.rs index 3b5e26aed8e..7f14c7acd31 100644 --- a/crates/goose/src/agents/prompt_manager.rs +++ b/crates/goose/src/agents/prompt_manager.rs @@ -1,3 +1,5 @@ +#[cfg(test)] +use chrono::DateTime; use chrono::Utc; use serde_json::Value; use std::collections::HashMap; @@ -30,6 +32,16 @@ impl PromptManager { } } + #[cfg(test)] + pub fn with_timestamp(dt: DateTime) -> Self { + PromptManager { + system_prompt_override: None, + system_prompt_extras: Vec::new(), + // Use the fixed current date time so that prompt cache can be used. + current_date_timestamp: dt.format("%Y-%m-%d %H:%M:%S").to_string(), + } + } + /// Add an additional instruction to the system prompt pub fn add_system_prompt_extra(&mut self, instruction: String) { self.system_prompt_extras.push(instruction); @@ -144,6 +156,8 @@ impl PromptManager { #[cfg(test)] mod tests { + use insta::assert_snapshot; + use super::*; #[test] @@ -254,4 +268,14 @@ mod tests { assert!(result.contains("Extension help")); assert!(result.contains("hidden instructions")); } + + #[test] + fn test_snapshot() { + let manager = PromptManager::with_timestamp(DateTime::::from_timestamp(0, 0).unwrap()); + + let system_prompt = + manager.build_system_prompt(vec![], None, Value::String("".to_string()), None, false); + + assert_snapshot!(system_prompt) + } } diff --git a/crates/goose/src/agents/snapshots/goose__agents__prompt_manager__tests__snapshot.snap b/crates/goose/src/agents/snapshots/goose__agents__prompt_manager__tests__snapshot.snap new file mode 100644 index 00000000000..b5930982cec --- /dev/null +++ b/crates/goose/src/agents/snapshots/goose__agents__prompt_manager__tests__snapshot.snap @@ -0,0 +1,65 @@ +--- +source: crates/goose/src/agents/prompt_manager.rs +expression: system_prompt +--- +You are a general-purpose AI agent called goose, created by Block, the parent company of Square, CashApp, and Tidal. +goose is being developed as an open-source software project. + +The current date is 1970-01-01 00:00:00. + +goose uses LLM providers with tool calling capability. You can be used with different language models (gpt-4o, +claude-sonnet-4, o1, llama-3.2, deepseek-r1, etc). +These models have varying knowledge cut-off dates depending on when they were trained, but typically it's between 5-10 +months prior to the current date. + +# Extensions + +Extensions allow other applications to provide context to goose. Extensions connect goose to different data sources and +tools. +You are capable of dynamically plugging into new extensions and learning how to use them. You solve higher level +problems using the tools in these extensions, and can interact with multiple at once. +Use the search_available_extensions tool to find additional extensions to enable to help with your task. To enable +extensions, use the enable_extension tool and provide the extension_name. You should only enable extensions found from +the search_available_extensions tool. + + +No extensions are defined. You should let the user know that they should add extensions. + + + + +# Suggestion + +"" + + + + +# sub agents + +Execute self contained tasks where step-by-step visibility is not important through subagents. + +- Delegate via `dynamic_task__create_task` for: result-only operations, parallelizable work, multi-part requests, + verification, exploration +- Parallel subagents for multiple operations, single subagents for independent work +- Explore solutions in parallel — launch parallel subagents with different approaches (if non-interfering) +- Provide all needed context — subagents cannot see your context +- Use extension filters to limit resource access +- Use return_last_only when only a summary or simple answer is required — inform subagent of this choice. + + +# Response Guidelines + +- Use Markdown formatting for all responses. +- Follow best practices for Markdown, including: + - Using headers for organization. + - Bullet points for lists. + - Links formatted correctly, either as linked text (e.g., [this is linked text](https://example.com)) or automatic + links using angle brackets (e.g., ). +- For code examples, use fenced code blocks by placing triple backticks (` ``` `) before and after the code. Include the + language identifier after the opening backticks (e.g., ` ```python `) to enable syntax highlighting. +- Ensure clarity, conciseness, and proper formatting to enhance readability and usability. + +# Additional Instructions: + +Right now you are *NOT* in the chat only mode and have access to tool use and system. From c743cf4fc76b2a6e6975928dfe1426806529c894 Mon Sep 17 00:00:00 2001 From: Jack Amadeo Date: Tue, 21 Oct 2025 16:16:21 -0400 Subject: [PATCH 4/9] snapshots --- crates/goose/src/agents/prompt_manager.rs | 21 ++++- ..._agents__prompt_manager__tests__basic.snap | 65 +++++++++++++ ..._prompt_manager__tests__one_extension.snap | 94 +++++++++++++++++++ 3 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 crates/goose/src/agents/snapshots/goose__agents__prompt_manager__tests__basic.snap create mode 100644 crates/goose/src/agents/snapshots/goose__agents__prompt_manager__tests__one_extension.snap diff --git a/crates/goose/src/agents/prompt_manager.rs b/crates/goose/src/agents/prompt_manager.rs index 7f14c7acd31..8f1628ef250 100644 --- a/crates/goose/src/agents/prompt_manager.rs +++ b/crates/goose/src/agents/prompt_manager.rs @@ -270,7 +270,7 @@ mod tests { } #[test] - fn test_snapshot() { + fn test_basic() { let manager = PromptManager::with_timestamp(DateTime::::from_timestamp(0, 0).unwrap()); let system_prompt = @@ -278,4 +278,23 @@ mod tests { assert_snapshot!(system_prompt) } + + #[test] + fn test_one_extension() { + let manager = PromptManager::with_timestamp(DateTime::::from_timestamp(0, 0).unwrap()); + + let system_prompt = manager.build_system_prompt( + vec![ExtensionInfo::new( + "test", + "how to use this extension", + true, + )], + None, + Value::String("".to_string()), + None, + true, + ); + + assert_snapshot!(system_prompt) + } } diff --git a/crates/goose/src/agents/snapshots/goose__agents__prompt_manager__tests__basic.snap b/crates/goose/src/agents/snapshots/goose__agents__prompt_manager__tests__basic.snap new file mode 100644 index 00000000000..b5930982cec --- /dev/null +++ b/crates/goose/src/agents/snapshots/goose__agents__prompt_manager__tests__basic.snap @@ -0,0 +1,65 @@ +--- +source: crates/goose/src/agents/prompt_manager.rs +expression: system_prompt +--- +You are a general-purpose AI agent called goose, created by Block, the parent company of Square, CashApp, and Tidal. +goose is being developed as an open-source software project. + +The current date is 1970-01-01 00:00:00. + +goose uses LLM providers with tool calling capability. You can be used with different language models (gpt-4o, +claude-sonnet-4, o1, llama-3.2, deepseek-r1, etc). +These models have varying knowledge cut-off dates depending on when they were trained, but typically it's between 5-10 +months prior to the current date. + +# Extensions + +Extensions allow other applications to provide context to goose. Extensions connect goose to different data sources and +tools. +You are capable of dynamically plugging into new extensions and learning how to use them. You solve higher level +problems using the tools in these extensions, and can interact with multiple at once. +Use the search_available_extensions tool to find additional extensions to enable to help with your task. To enable +extensions, use the enable_extension tool and provide the extension_name. You should only enable extensions found from +the search_available_extensions tool. + + +No extensions are defined. You should let the user know that they should add extensions. + + + + +# Suggestion + +"" + + + + +# sub agents + +Execute self contained tasks where step-by-step visibility is not important through subagents. + +- Delegate via `dynamic_task__create_task` for: result-only operations, parallelizable work, multi-part requests, + verification, exploration +- Parallel subagents for multiple operations, single subagents for independent work +- Explore solutions in parallel — launch parallel subagents with different approaches (if non-interfering) +- Provide all needed context — subagents cannot see your context +- Use extension filters to limit resource access +- Use return_last_only when only a summary or simple answer is required — inform subagent of this choice. + + +# Response Guidelines + +- Use Markdown formatting for all responses. +- Follow best practices for Markdown, including: + - Using headers for organization. + - Bullet points for lists. + - Links formatted correctly, either as linked text (e.g., [this is linked text](https://example.com)) or automatic + links using angle brackets (e.g., ). +- For code examples, use fenced code blocks by placing triple backticks (` ``` `) before and after the code. Include the + language identifier after the opening backticks (e.g., ` ```python `) to enable syntax highlighting. +- Ensure clarity, conciseness, and proper formatting to enhance readability and usability. + +# Additional Instructions: + +Right now you are *NOT* in the chat only mode and have access to tool use and system. diff --git a/crates/goose/src/agents/snapshots/goose__agents__prompt_manager__tests__one_extension.snap b/crates/goose/src/agents/snapshots/goose__agents__prompt_manager__tests__one_extension.snap new file mode 100644 index 00000000000..43cf8c5478c --- /dev/null +++ b/crates/goose/src/agents/snapshots/goose__agents__prompt_manager__tests__one_extension.snap @@ -0,0 +1,94 @@ +--- +source: crates/goose/src/agents/prompt_manager.rs +expression: system_prompt +--- +You are a general-purpose AI agent called goose, created by Block, the parent company of Square, CashApp, and Tidal. +goose is being developed as an open-source software project. + +The current date is 1970-01-01 00:00:00. + +goose uses LLM providers with tool calling capability. You can be used with different language models (gpt-4o, +claude-sonnet-4, o1, llama-3.2, deepseek-r1, etc). +These models have varying knowledge cut-off dates depending on when they were trained, but typically it's between 5-10 +months prior to the current date. + +# Extensions + +Extensions allow other applications to provide context to goose. Extensions connect goose to different data sources and +tools. +You are capable of dynamically plugging into new extensions and learning how to use them. You solve higher level +problems using the tools in these extensions, and can interact with multiple at once. +Use the search_available_extensions tool to find additional extensions to enable to help with your task. To enable +extensions, use the enable_extension tool and provide the extension_name. You should only enable extensions found from +the search_available_extensions tool. + + +Because you dynamically load extensions, your conversation history may refer +to interactions with extensions that are not currently active. The currently +active extensions are below. Each of these extensions provides tools that are +in your tool specification. + + + +## test + + +test supports resources, you can use platform__read_resource, +and platform__list_resources on this extension. + +### Instructions +how to use this extension + + + + + + +# Suggestion + +"" + + +# LLM Tool Selection Instructions + Important: the user has opted to dynamically enable tools, so although an extension could be enabled, \ + please invoke the llm search tool to actually retrieve the most relevant tools to use according to the user's messages. + For example, if the user has 3 extensions enabled, but they are asking for a tool to read a pdf file, \ + you would invoke the llm_search tool to find the most relevant read pdf tool. + By dynamically enabling tools, you (goose) as the agent save context window space and allow the user to dynamically retrieve the most relevant tools. + Be sure to format a query packed with relevant keywords to search for the most relevant tools. + In addition to the extension names available to you, you also have platform extension tools available to you. + The platform extension contains the following tools: + - platform__search_available_extensions + - platform__manage_extensions + - platform__read_resource + - platform__list_resources + + +# sub agents + +Execute self contained tasks where step-by-step visibility is not important through subagents. + +- Delegate via `dynamic_task__create_task` for: result-only operations, parallelizable work, multi-part requests, + verification, exploration +- Parallel subagents for multiple operations, single subagents for independent work +- Explore solutions in parallel — launch parallel subagents with different approaches (if non-interfering) +- Provide all needed context — subagents cannot see your context +- Use extension filters to limit resource access +- Use return_last_only when only a summary or simple answer is required — inform subagent of this choice. + + +# Response Guidelines + +- Use Markdown formatting for all responses. +- Follow best practices for Markdown, including: + - Using headers for organization. + - Bullet points for lists. + - Links formatted correctly, either as linked text (e.g., [this is linked text](https://example.com)) or automatic + links using angle brackets (e.g., ). +- For code examples, use fenced code blocks by placing triple backticks (` ``` `) before and after the code. Include the + language identifier after the opening backticks (e.g., ` ```python `) to enable syntax highlighting. +- Ensure clarity, conciseness, and proper formatting to enhance readability and usability. + +# Additional Instructions: + +Right now you are *NOT* in the chat only mode and have access to tool use and system. From e0a7d432871dcb119346a62b622e1d0e3d448668 Mon Sep 17 00:00:00 2001 From: Jack Amadeo Date: Tue, 21 Oct 2025 16:18:16 -0400 Subject: [PATCH 5/9] old snapshot --- ...ents__prompt_manager__tests__snapshot.snap | 65 ------------------- 1 file changed, 65 deletions(-) delete mode 100644 crates/goose/src/agents/snapshots/goose__agents__prompt_manager__tests__snapshot.snap diff --git a/crates/goose/src/agents/snapshots/goose__agents__prompt_manager__tests__snapshot.snap b/crates/goose/src/agents/snapshots/goose__agents__prompt_manager__tests__snapshot.snap deleted file mode 100644 index b5930982cec..00000000000 --- a/crates/goose/src/agents/snapshots/goose__agents__prompt_manager__tests__snapshot.snap +++ /dev/null @@ -1,65 +0,0 @@ ---- -source: crates/goose/src/agents/prompt_manager.rs -expression: system_prompt ---- -You are a general-purpose AI agent called goose, created by Block, the parent company of Square, CashApp, and Tidal. -goose is being developed as an open-source software project. - -The current date is 1970-01-01 00:00:00. - -goose uses LLM providers with tool calling capability. You can be used with different language models (gpt-4o, -claude-sonnet-4, o1, llama-3.2, deepseek-r1, etc). -These models have varying knowledge cut-off dates depending on when they were trained, but typically it's between 5-10 -months prior to the current date. - -# Extensions - -Extensions allow other applications to provide context to goose. Extensions connect goose to different data sources and -tools. -You are capable of dynamically plugging into new extensions and learning how to use them. You solve higher level -problems using the tools in these extensions, and can interact with multiple at once. -Use the search_available_extensions tool to find additional extensions to enable to help with your task. To enable -extensions, use the enable_extension tool and provide the extension_name. You should only enable extensions found from -the search_available_extensions tool. - - -No extensions are defined. You should let the user know that they should add extensions. - - - - -# Suggestion - -"" - - - - -# sub agents - -Execute self contained tasks where step-by-step visibility is not important through subagents. - -- Delegate via `dynamic_task__create_task` for: result-only operations, parallelizable work, multi-part requests, - verification, exploration -- Parallel subagents for multiple operations, single subagents for independent work -- Explore solutions in parallel — launch parallel subagents with different approaches (if non-interfering) -- Provide all needed context — subagents cannot see your context -- Use extension filters to limit resource access -- Use return_last_only when only a summary or simple answer is required — inform subagent of this choice. - - -# Response Guidelines - -- Use Markdown formatting for all responses. -- Follow best practices for Markdown, including: - - Using headers for organization. - - Bullet points for lists. - - Links formatted correctly, either as linked text (e.g., [this is linked text](https://example.com)) or automatic - links using angle brackets (e.g., ). -- For code examples, use fenced code blocks by placing triple backticks (` ``` `) before and after the code. Include the - language identifier after the opening backticks (e.g., ` ```python `) to enable syntax highlighting. -- Ensure clarity, conciseness, and proper formatting to enhance readability and usability. - -# Additional Instructions: - -Right now you are *NOT* in the chat only mode and have access to tool use and system. From d7b1573171873f630fd2e4cd676bd66c5ee89fd6 Mon Sep 17 00:00:00 2001 From: Jack Amadeo Date: Tue, 21 Oct 2025 16:20:34 -0400 Subject: [PATCH 6/9] merge --- crates/goose/src/agents/prompt_manager.rs | 11 ++++++--- ..._agents__prompt_manager__tests__basic.snap | 16 ++++++------- ..._prompt_manager__tests__one_extension.snap | 24 +++++++++---------- 3 files changed, 28 insertions(+), 23 deletions(-) diff --git a/crates/goose/src/agents/prompt_manager.rs b/crates/goose/src/agents/prompt_manager.rs index 8f1628ef250..c72268bb83a 100644 --- a/crates/goose/src/agents/prompt_manager.rs +++ b/crates/goose/src/agents/prompt_manager.rs @@ -273,8 +273,13 @@ mod tests { fn test_basic() { let manager = PromptManager::with_timestamp(DateTime::::from_timestamp(0, 0).unwrap()); - let system_prompt = - manager.build_system_prompt(vec![], None, Value::String("".to_string()), None, false); + let system_prompt = manager.build_system_prompt( + vec![], + None, + Value::String("".to_string()), + "gpt-4o", + false, + ); assert_snapshot!(system_prompt) } @@ -291,7 +296,7 @@ mod tests { )], None, Value::String("".to_string()), - None, + "gpt-4o", true, ); diff --git a/crates/goose/src/agents/snapshots/goose__agents__prompt_manager__tests__basic.snap b/crates/goose/src/agents/snapshots/goose__agents__prompt_manager__tests__basic.snap index b5930982cec..768a225dcb5 100644 --- a/crates/goose/src/agents/snapshots/goose__agents__prompt_manager__tests__basic.snap +++ b/crates/goose/src/agents/snapshots/goose__agents__prompt_manager__tests__basic.snap @@ -18,9 +18,12 @@ Extensions allow other applications to provide context to goose. Extensions conn tools. You are capable of dynamically plugging into new extensions and learning how to use them. You solve higher level problems using the tools in these extensions, and can interact with multiple at once. -Use the search_available_extensions tool to find additional extensions to enable to help with your task. To enable -extensions, use the enable_extension tool and provide the extension_name. You should only enable extensions found from -the search_available_extensions tool. + +If the Extension Manager extension is enabled, you can use the search_available_extensions tool to discover additional +extensions that can help with your task. To enable or disable extensions, use the manage_extensions tool with the +extension_name. You should only enable extensions found from the search_available_extensions tool. +If Extension Manager is not available, you can only work with currently enabled extensions and cannot dynamically load +new ones. No extensions are defined. You should let the user know that they should add extensions. @@ -35,6 +38,7 @@ No extensions are defined. You should let the user know that they should add ext + # sub agents Execute self contained tasks where step-by-step visibility is not important through subagents. @@ -46,7 +50,7 @@ Execute self contained tasks where step-by-step visibility is not important thro - Provide all needed context — subagents cannot see your context - Use extension filters to limit resource access - Use return_last_only when only a summary or simple answer is required — inform subagent of this choice. - + # Response Guidelines @@ -59,7 +63,3 @@ Execute self contained tasks where step-by-step visibility is not important thro - For code examples, use fenced code blocks by placing triple backticks (` ``` `) before and after the code. Include the language identifier after the opening backticks (e.g., ` ```python `) to enable syntax highlighting. - Ensure clarity, conciseness, and proper formatting to enhance readability and usability. - -# Additional Instructions: - -Right now you are *NOT* in the chat only mode and have access to tool use and system. diff --git a/crates/goose/src/agents/snapshots/goose__agents__prompt_manager__tests__one_extension.snap b/crates/goose/src/agents/snapshots/goose__agents__prompt_manager__tests__one_extension.snap index 43cf8c5478c..7bf2feff30b 100644 --- a/crates/goose/src/agents/snapshots/goose__agents__prompt_manager__tests__one_extension.snap +++ b/crates/goose/src/agents/snapshots/goose__agents__prompt_manager__tests__one_extension.snap @@ -18,9 +18,12 @@ Extensions allow other applications to provide context to goose. Extensions conn tools. You are capable of dynamically plugging into new extensions and learning how to use them. You solve higher level problems using the tools in these extensions, and can interact with multiple at once. -Use the search_available_extensions tool to find additional extensions to enable to help with your task. To enable -extensions, use the enable_extension tool and provide the extension_name. You should only enable extensions found from -the search_available_extensions tool. + +If the Extension Manager extension is enabled, you can use the search_available_extensions tool to discover additional +extensions that can help with your task. To enable or disable extensions, use the manage_extensions tool with the +extension_name. You should only enable extensions found from the search_available_extensions tool. +If Extension Manager is not available, you can only work with currently enabled extensions and cannot dynamically load +new ones. Because you dynamically load extensions, your conversation history may refer @@ -58,12 +61,13 @@ how to use this extension Be sure to format a query packed with relevant keywords to search for the most relevant tools. In addition to the extension names available to you, you also have platform extension tools available to you. The platform extension contains the following tools: - - platform__search_available_extensions - - platform__manage_extensions - - platform__read_resource - - platform__list_resources + - search_available_extensions + - manage_extensions + - read_resource + - list_resources + # sub agents Execute self contained tasks where step-by-step visibility is not important through subagents. @@ -75,7 +79,7 @@ Execute self contained tasks where step-by-step visibility is not important thro - Provide all needed context — subagents cannot see your context - Use extension filters to limit resource access - Use return_last_only when only a summary or simple answer is required — inform subagent of this choice. - + # Response Guidelines @@ -88,7 +92,3 @@ Execute self contained tasks where step-by-step visibility is not important thro - For code examples, use fenced code blocks by placing triple backticks (` ``` `) before and after the code. Include the language identifier after the opening backticks (e.g., ` ```python `) to enable syntax highlighting. - Ensure clarity, conciseness, and proper formatting to enhance readability and usability. - -# Additional Instructions: - -Right now you are *NOT* in the chat only mode and have access to tool use and system. From 25dc000907f0f4ea344dfcd7932b5accafa0dcc5 Mon Sep 17 00:00:00 2001 From: Jack Amadeo Date: Tue, 21 Oct 2025 16:42:51 -0400 Subject: [PATCH 7/9] default empty string --- crates/goose/src/prompts/system.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/goose/src/prompts/system.md b/crates/goose/src/prompts/system.md index 5a0c55cf947..6d8d3431991 100644 --- a/crates/goose/src/prompts/system.md +++ b/crates/goose/src/prompts/system.md @@ -50,7 +50,7 @@ No extensions are defined. You should let the user know that they should add ext {{suggest_disable}} {% endif %} -{{tool_selection_strategy}} +{{tool_selection_strategy|default("")}} {% if enable_subagents %} # sub agents From 8c1f62f497e4417db3298da1cb44f466604a215b Mon Sep 17 00:00:00 2001 From: Jack Amadeo Date: Tue, 21 Oct 2025 20:20:10 -0400 Subject: [PATCH 8/9] omit none --- crates/goose/src/agents/prompt_manager.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/goose/src/agents/prompt_manager.rs b/crates/goose/src/agents/prompt_manager.rs index 9a5639c71b8..f5126776d06 100644 --- a/crates/goose/src/agents/prompt_manager.rs +++ b/crates/goose/src/agents/prompt_manager.rs @@ -26,6 +26,7 @@ impl Default for PromptManager { #[derive(Serialize)] struct SystemPromptContext { extensions: Vec, + #[serde(skip_serializing_if = "Option::is_none")] tool_selection_strategy: Option, current_date_time: String, suggest_disable: String, From 6980f0fa9bee32e83ffa6a7de044e36a1a912465 Mon Sep 17 00:00:00 2001 From: Jack Amadeo Date: Tue, 21 Oct 2025 20:20:26 -0400 Subject: [PATCH 9/9] Revert "default empty string" This reverts commit 25dc000907f0f4ea344dfcd7932b5accafa0dcc5. --- crates/goose/src/prompts/system.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/goose/src/prompts/system.md b/crates/goose/src/prompts/system.md index 6d8d3431991..5a0c55cf947 100644 --- a/crates/goose/src/prompts/system.md +++ b/crates/goose/src/prompts/system.md @@ -50,7 +50,7 @@ No extensions are defined. You should let the user know that they should add ext {{suggest_disable}} {% endif %} -{{tool_selection_strategy|default("")}} +{{tool_selection_strategy}} {% if enable_subagents %} # sub agents