mirror of
https://github.com/aljazceru/goose.git
synced 2025-12-19 07:04:21 +01:00
Goose recipes have settings now (#2397)
Co-authored-by: Douwe Osinga <douwe@squareup.com> Co-authored-by: Lifei Zhou <lifei@squareup.com>
This commit is contained in:
@@ -19,7 +19,7 @@ use crate::commands::session::{handle_session_list, handle_session_remove};
|
|||||||
use crate::logging::setup_logging;
|
use crate::logging::setup_logging;
|
||||||
use crate::recipes::recipe::{explain_recipe_with_parameters, load_recipe_as_template};
|
use crate::recipes::recipe::{explain_recipe_with_parameters, load_recipe_as_template};
|
||||||
use crate::session;
|
use crate::session;
|
||||||
use crate::session::{build_session, SessionBuilderConfig};
|
use crate::session::{build_session, SessionBuilderConfig, SessionSettings};
|
||||||
use goose_bench::bench_config::BenchRunConfig;
|
use goose_bench::bench_config::BenchRunConfig;
|
||||||
use goose_bench::runners::bench_runner::BenchRunner;
|
use goose_bench::runners::bench_runner::BenchRunner;
|
||||||
use goose_bench::runners::eval_runner::EvalRunner;
|
use goose_bench::runners::eval_runner::EvalRunner;
|
||||||
@@ -552,6 +552,7 @@ enum CliProviderVariant {
|
|||||||
Ollama,
|
Ollama,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
struct InputConfig {
|
struct InputConfig {
|
||||||
contents: Option<String>,
|
contents: Option<String>,
|
||||||
extensions_override: Option<Vec<ExtensionConfig>>,
|
extensions_override: Option<Vec<ExtensionConfig>>,
|
||||||
@@ -630,6 +631,7 @@ pub async fn cli() -> Result<()> {
|
|||||||
builtins,
|
builtins,
|
||||||
extensions_override: None,
|
extensions_override: None,
|
||||||
additional_system_prompt: None,
|
additional_system_prompt: None,
|
||||||
|
settings: None,
|
||||||
debug,
|
debug,
|
||||||
max_tool_repetitions,
|
max_tool_repetitions,
|
||||||
interactive: true, // Session command is always interactive
|
interactive: true, // Session command is always interactive
|
||||||
@@ -676,18 +678,22 @@ pub async fn cli() -> Result<()> {
|
|||||||
params,
|
params,
|
||||||
explain,
|
explain,
|
||||||
}) => {
|
}) => {
|
||||||
let input_config = match (instructions, input_text, recipe, explain) {
|
let (input_config, session_settings) = match (instructions, input_text, recipe, explain)
|
||||||
|
{
|
||||||
(Some(file), _, _, _) if file == "-" => {
|
(Some(file), _, _, _) if file == "-" => {
|
||||||
let mut input = String::new();
|
let mut input = String::new();
|
||||||
std::io::stdin()
|
std::io::stdin()
|
||||||
.read_to_string(&mut input)
|
.read_to_string(&mut input)
|
||||||
.expect("Failed to read from stdin");
|
.expect("Failed to read from stdin");
|
||||||
|
|
||||||
InputConfig {
|
(
|
||||||
contents: Some(input),
|
InputConfig {
|
||||||
extensions_override: None,
|
contents: Some(input),
|
||||||
additional_system_prompt: None,
|
extensions_override: None,
|
||||||
}
|
additional_system_prompt: None,
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
(Some(file), _, _, _) => {
|
(Some(file), _, _, _) => {
|
||||||
let contents = std::fs::read_to_string(&file).unwrap_or_else(|err| {
|
let contents = std::fs::read_to_string(&file).unwrap_or_else(|err| {
|
||||||
@@ -697,17 +703,23 @@ pub async fn cli() -> Result<()> {
|
|||||||
);
|
);
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
});
|
});
|
||||||
|
(
|
||||||
|
InputConfig {
|
||||||
|
contents: Some(contents),
|
||||||
|
extensions_override: None,
|
||||||
|
additional_system_prompt: None,
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
(_, Some(text), _, _) => (
|
||||||
InputConfig {
|
InputConfig {
|
||||||
contents: Some(contents),
|
contents: Some(text),
|
||||||
extensions_override: None,
|
extensions_override: None,
|
||||||
additional_system_prompt: None,
|
additional_system_prompt: None,
|
||||||
}
|
},
|
||||||
}
|
None,
|
||||||
(_, Some(text), _, _) => InputConfig {
|
),
|
||||||
contents: Some(text),
|
|
||||||
extensions_override: None,
|
|
||||||
additional_system_prompt: None,
|
|
||||||
},
|
|
||||||
(_, _, Some(recipe_name), explain) => {
|
(_, _, Some(recipe_name), explain) => {
|
||||||
if explain {
|
if explain {
|
||||||
explain_recipe_with_parameters(&recipe_name, params)?;
|
explain_recipe_with_parameters(&recipe_name, params)?;
|
||||||
@@ -718,11 +730,18 @@ pub async fn cli() -> Result<()> {
|
|||||||
eprintln!("{}: {}", console::style("Error").red().bold(), err);
|
eprintln!("{}: {}", console::style("Error").red().bold(), err);
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
});
|
});
|
||||||
InputConfig {
|
(
|
||||||
contents: recipe.prompt,
|
InputConfig {
|
||||||
extensions_override: recipe.extensions,
|
contents: recipe.prompt,
|
||||||
additional_system_prompt: recipe.instructions,
|
extensions_override: recipe.extensions,
|
||||||
}
|
additional_system_prompt: recipe.instructions,
|
||||||
|
},
|
||||||
|
recipe.settings.map(|s| SessionSettings {
|
||||||
|
goose_provider: s.goose_provider,
|
||||||
|
goose_model: s.goose_model,
|
||||||
|
temperature: s.temperature,
|
||||||
|
}),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
(None, None, None, _) => {
|
(None, None, None, _) => {
|
||||||
eprintln!("Error: Must provide either --instructions (-i), --text (-t), or --recipe. Use -i - for stdin.");
|
eprintln!("Error: Must provide either --instructions (-i), --text (-t), or --recipe. Use -i - for stdin.");
|
||||||
@@ -739,6 +758,7 @@ pub async fn cli() -> Result<()> {
|
|||||||
builtins,
|
builtins,
|
||||||
extensions_override: input_config.extensions_override,
|
extensions_override: input_config.extensions_override,
|
||||||
additional_system_prompt: input_config.additional_system_prompt,
|
additional_system_prompt: input_config.additional_system_prompt,
|
||||||
|
settings: session_settings,
|
||||||
debug,
|
debug,
|
||||||
max_tool_repetitions,
|
max_tool_repetitions,
|
||||||
interactive, // Use the interactive flag from the Run command
|
interactive, // Use the interactive flag from the Run command
|
||||||
@@ -854,6 +874,7 @@ pub async fn cli() -> Result<()> {
|
|||||||
builtins: Vec::new(),
|
builtins: Vec::new(),
|
||||||
extensions_override: None,
|
extensions_override: None,
|
||||||
additional_system_prompt: None,
|
additional_system_prompt: None,
|
||||||
|
settings: None::<SessionSettings>,
|
||||||
debug: false,
|
debug: false,
|
||||||
max_tool_repetitions: None,
|
max_tool_repetitions: None,
|
||||||
interactive: true, // Default case is always interactive
|
interactive: true, // Default case is always interactive
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ pub async fn agent_generator(
|
|||||||
builtins: requirements.builtin,
|
builtins: requirements.builtin,
|
||||||
extensions_override: None,
|
extensions_override: None,
|
||||||
additional_system_prompt: None,
|
additional_system_prompt: None,
|
||||||
|
settings: None,
|
||||||
debug: false,
|
debug: false,
|
||||||
max_tool_repetitions: None,
|
max_tool_repetitions: None,
|
||||||
interactive: false, // Benchmarking is non-interactive
|
interactive: false, // Benchmarking is non-interactive
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ pub struct SessionBuilderConfig {
|
|||||||
pub extensions_override: Option<Vec<ExtensionConfig>>,
|
pub extensions_override: Option<Vec<ExtensionConfig>>,
|
||||||
/// Any additional system prompt to append to the default
|
/// Any additional system prompt to append to the default
|
||||||
pub additional_system_prompt: Option<String>,
|
pub additional_system_prompt: Option<String>,
|
||||||
|
/// Settings to override the global Goose settings
|
||||||
|
pub settings: Option<SessionSettings>,
|
||||||
/// Enable debug printing
|
/// Enable debug printing
|
||||||
pub debug: bool,
|
pub debug: bool,
|
||||||
/// Maximum number of consecutive identical tool calls allowed
|
/// Maximum number of consecutive identical tool calls allowed
|
||||||
@@ -136,18 +138,35 @@ async fn offer_extension_debugging_help(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default)]
|
||||||
|
pub struct SessionSettings {
|
||||||
|
pub goose_model: Option<String>,
|
||||||
|
pub goose_provider: Option<String>,
|
||||||
|
pub temperature: Option<f32>,
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn build_session(session_config: SessionBuilderConfig) -> Session {
|
pub async fn build_session(session_config: SessionBuilderConfig) -> Session {
|
||||||
// Load config and get provider/model
|
// Load config and get provider/model
|
||||||
let config = Config::global();
|
let config = Config::global();
|
||||||
|
|
||||||
let provider_name: String = config
|
let provider_name = session_config
|
||||||
.get_param("GOOSE_PROVIDER")
|
.settings
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|s| s.goose_provider.clone())
|
||||||
|
.or_else(|| config.get_param("GOOSE_PROVIDER").ok())
|
||||||
.expect("No provider configured. Run 'goose configure' first");
|
.expect("No provider configured. Run 'goose configure' first");
|
||||||
|
|
||||||
let model: String = config
|
let model_name = session_config
|
||||||
.get_param("GOOSE_MODEL")
|
.settings
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|s| s.goose_model.clone())
|
||||||
|
.or_else(|| config.get_param("GOOSE_MODEL").ok())
|
||||||
.expect("No model configured. Run 'goose configure' first");
|
.expect("No model configured. Run 'goose configure' first");
|
||||||
let model_config = goose::model::ModelConfig::new(model.clone());
|
|
||||||
|
let temperature = session_config.settings.as_ref().and_then(|s| s.temperature);
|
||||||
|
|
||||||
|
let model_config =
|
||||||
|
goose::model::ModelConfig::new(model_name.clone()).with_temperature(temperature);
|
||||||
|
|
||||||
// Create the agent
|
// Create the agent
|
||||||
let agent: Agent = Agent::new();
|
let agent: Agent = Agent::new();
|
||||||
@@ -165,7 +184,7 @@ pub async fn build_session(session_config: SessionBuilderConfig) -> Session {
|
|||||||
worker_model
|
worker_model
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
tracing::info!("🤖 Using model: {}", model);
|
tracing::info!("🤖 Using model: {}", model_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
agent
|
agent
|
||||||
@@ -430,7 +449,7 @@ pub async fn build_session(session_config: SessionBuilderConfig) -> Session {
|
|||||||
output::display_session_info(
|
output::display_session_info(
|
||||||
session_config.resume,
|
session_config.resume,
|
||||||
&provider_name,
|
&provider_name,
|
||||||
&model,
|
&model_name,
|
||||||
&session_file,
|
&session_file,
|
||||||
Some(&provider_for_display),
|
Some(&provider_for_display),
|
||||||
);
|
);
|
||||||
@@ -452,6 +471,7 @@ mod tests {
|
|||||||
builtins: vec!["developer".to_string()],
|
builtins: vec!["developer".to_string()],
|
||||||
extensions_override: None,
|
extensions_override: None,
|
||||||
additional_system_prompt: Some("Test prompt".to_string()),
|
additional_system_prompt: Some("Test prompt".to_string()),
|
||||||
|
settings: None,
|
||||||
debug: true,
|
debug: true,
|
||||||
max_tool_repetitions: Some(5),
|
max_tool_repetitions: Some(5),
|
||||||
interactive: true,
|
interactive: true,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ mod prompt;
|
|||||||
mod thinking;
|
mod thinking;
|
||||||
|
|
||||||
pub use self::export::message_to_markdown;
|
pub use self::export::message_to_markdown;
|
||||||
pub use builder::{build_session, SessionBuilderConfig};
|
pub use builder::{build_session, SessionBuilderConfig, SessionSettings};
|
||||||
use console::Color;
|
use console::Color;
|
||||||
use goose::agents::AgentEvent;
|
use goose::agents::AgentEvent;
|
||||||
use goose::permission::permission_confirmation::PrincipalType;
|
use goose::permission::permission_confirmation::PrincipalType;
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ use crate::permission::permission_judge::check_tool_permissions;
|
|||||||
use crate::permission::PermissionConfirmation;
|
use crate::permission::PermissionConfirmation;
|
||||||
use crate::providers::base::Provider;
|
use crate::providers::base::Provider;
|
||||||
use crate::providers::errors::ProviderError;
|
use crate::providers::errors::ProviderError;
|
||||||
use crate::recipe::{Author, Recipe};
|
use crate::recipe::{Author, Recipe, Settings};
|
||||||
use crate::tool_monitor::{ToolCall, ToolMonitor};
|
use crate::tool_monitor::{ToolCall, ToolMonitor};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
@@ -973,12 +973,26 @@ impl Agent {
|
|||||||
metadata: None,
|
metadata: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Ideally we'd get the name of the provider we are using from the provider itself
|
||||||
|
// but it doesn't know and the plumbing looks complicated.
|
||||||
|
let config = Config::global();
|
||||||
|
let provider_name: String = config
|
||||||
|
.get_param("GOOSE_PROVIDER")
|
||||||
|
.expect("No provider configured. Run 'goose configure' first");
|
||||||
|
|
||||||
|
let settings = Settings {
|
||||||
|
goose_provider: Some(provider_name.clone()),
|
||||||
|
goose_model: Some(model_name.clone()),
|
||||||
|
temperature: Some(model_config.temperature.unwrap_or(0.0)),
|
||||||
|
};
|
||||||
|
|
||||||
let recipe = Recipe::builder()
|
let recipe = Recipe::builder()
|
||||||
.title("Custom recipe from chat")
|
.title("Custom recipe from chat")
|
||||||
.description("a custom recipe instance from this chat session")
|
.description("a custom recipe instance from this chat session")
|
||||||
.instructions(instructions)
|
.instructions(instructions)
|
||||||
.activities(activities)
|
.activities(activities)
|
||||||
.extensions(extension_configs)
|
.extensions(extension_configs)
|
||||||
|
.settings(settings)
|
||||||
.author(author)
|
.author(author)
|
||||||
.build()
|
.build()
|
||||||
.expect("valid recipe");
|
.expect("valid recipe");
|
||||||
|
|||||||
@@ -154,7 +154,6 @@ impl PromptManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the recipe prompt
|
|
||||||
pub async fn get_recipe_prompt(&self) -> String {
|
pub async fn get_recipe_prompt(&self) -> String {
|
||||||
let context: HashMap<&str, Value> = HashMap::new();
|
let context: HashMap<&str, Value> = HashMap::new();
|
||||||
prompt_template::render_global_file("recipe.md", &context).expect("Prompt should render")
|
prompt_template::render_global_file("recipe.md", &context).expect("Prompt should render")
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ fn default_version() -> String {
|
|||||||
/// context: None,
|
/// context: None,
|
||||||
/// activities: None,
|
/// activities: None,
|
||||||
/// author: None,
|
/// author: None,
|
||||||
|
/// settings: None,
|
||||||
/// parameters: None,
|
/// parameters: None,
|
||||||
/// };
|
/// };
|
||||||
///
|
///
|
||||||
@@ -77,6 +78,9 @@ pub struct Recipe {
|
|||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub context: Option<Vec<String>>, // any additional context
|
pub context: Option<Vec<String>>, // any additional context
|
||||||
|
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub settings: Option<Settings>, // settings for the recipe
|
||||||
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub activities: Option<Vec<String>>, // the activity pills that show up when loading the
|
pub activities: Option<Vec<String>>, // the activity pills that show up when loading the
|
||||||
|
|
||||||
@@ -96,6 +100,18 @@ pub struct Author {
|
|||||||
pub metadata: Option<String>, // any additional metadata for the author
|
pub metadata: Option<String>, // any additional metadata for the author
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct Settings {
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub goose_provider: Option<String>,
|
||||||
|
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub goose_model: Option<String>,
|
||||||
|
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub temperature: Option<f32>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum RecipeParameterRequirement {
|
pub enum RecipeParameterRequirement {
|
||||||
@@ -156,6 +172,7 @@ pub struct RecipeBuilder {
|
|||||||
prompt: Option<String>,
|
prompt: Option<String>,
|
||||||
extensions: Option<Vec<ExtensionConfig>>,
|
extensions: Option<Vec<ExtensionConfig>>,
|
||||||
context: Option<Vec<String>>,
|
context: Option<Vec<String>>,
|
||||||
|
settings: Option<Settings>,
|
||||||
activities: Option<Vec<String>>,
|
activities: Option<Vec<String>>,
|
||||||
author: Option<Author>,
|
author: Option<Author>,
|
||||||
parameters: Option<Vec<RecipeParameter>>,
|
parameters: Option<Vec<RecipeParameter>>,
|
||||||
@@ -185,6 +202,7 @@ impl Recipe {
|
|||||||
prompt: None,
|
prompt: None,
|
||||||
extensions: None,
|
extensions: None,
|
||||||
context: None,
|
context: None,
|
||||||
|
settings: None,
|
||||||
activities: None,
|
activities: None,
|
||||||
author: None,
|
author: None,
|
||||||
parameters: None,
|
parameters: None,
|
||||||
@@ -234,6 +252,11 @@ impl RecipeBuilder {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn settings(mut self, settings: Settings) -> Self {
|
||||||
|
self.settings = Some(settings);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Sets the activities for the Recipe
|
/// Sets the activities for the Recipe
|
||||||
pub fn activities(mut self, activities: Vec<String>) -> Self {
|
pub fn activities(mut self, activities: Vec<String>) -> Self {
|
||||||
self.activities = Some(activities);
|
self.activities = Some(activities);
|
||||||
@@ -271,6 +294,7 @@ impl RecipeBuilder {
|
|||||||
prompt: self.prompt,
|
prompt: self.prompt,
|
||||||
extensions: self.extensions,
|
extensions: self.extensions,
|
||||||
context: self.context,
|
context: self.context,
|
||||||
|
settings: self.settings,
|
||||||
activities: self.activities,
|
activities: self.activities,
|
||||||
author: self.author,
|
author: self.author,
|
||||||
parameters: self.parameters,
|
parameters: self.parameters,
|
||||||
|
|||||||
@@ -1300,6 +1300,7 @@ mod tests {
|
|||||||
activities: None,
|
activities: None,
|
||||||
author: None,
|
author: None,
|
||||||
parameters: None,
|
parameters: None,
|
||||||
|
settings: None,
|
||||||
};
|
};
|
||||||
let mut recipe_file = File::create(&recipe_filename)?;
|
let mut recipe_file = File::create(&recipe_filename)?;
|
||||||
writeln!(
|
writeln!(
|
||||||
|
|||||||
Reference in New Issue
Block a user