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:
Douwe Osinga
2025-06-12 21:32:01 -04:00
committed by GitHub
parent 9945e51d73
commit 78afaded33
8 changed files with 110 additions and 30 deletions
+15 -1
View File
@@ -16,7 +16,7 @@ use crate::permission::permission_judge::check_tool_permissions;
use crate::permission::PermissionConfirmation;
use crate::providers::base::Provider;
use crate::providers::errors::ProviderError;
use crate::recipe::{Author, Recipe};
use crate::recipe::{Author, Recipe, Settings};
use crate::tool_monitor::{ToolCall, ToolMonitor};
use regex::Regex;
use serde_json::Value;
@@ -973,12 +973,26 @@ impl Agent {
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()
.title("Custom recipe from chat")
.description("a custom recipe instance from this chat session")
.instructions(instructions)
.activities(activities)
.extensions(extension_configs)
.settings(settings)
.author(author)
.build()
.expect("valid recipe");
@@ -154,7 +154,6 @@ impl PromptManager {
}
}
/// Get the recipe prompt
pub async fn get_recipe_prompt(&self) -> String {
let context: HashMap<&str, Value> = HashMap::new();
prompt_template::render_global_file("recipe.md", &context).expect("Prompt should render")
+24
View File
@@ -50,6 +50,7 @@ fn default_version() -> String {
/// context: None,
/// activities: None,
/// author: None,
/// settings: None,
/// parameters: None,
/// };
///
@@ -77,6 +78,9 @@ pub struct Recipe {
#[serde(skip_serializing_if = "Option::is_none")]
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")]
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
}
#[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)]
#[serde(rename_all = "snake_case")]
pub enum RecipeParameterRequirement {
@@ -156,6 +172,7 @@ pub struct RecipeBuilder {
prompt: Option<String>,
extensions: Option<Vec<ExtensionConfig>>,
context: Option<Vec<String>>,
settings: Option<Settings>,
activities: Option<Vec<String>>,
author: Option<Author>,
parameters: Option<Vec<RecipeParameter>>,
@@ -185,6 +202,7 @@ impl Recipe {
prompt: None,
extensions: None,
context: None,
settings: None,
activities: None,
author: None,
parameters: None,
@@ -234,6 +252,11 @@ impl RecipeBuilder {
self
}
pub fn settings(mut self, settings: Settings) -> Self {
self.settings = Some(settings);
self
}
/// Sets the activities for the Recipe
pub fn activities(mut self, activities: Vec<String>) -> Self {
self.activities = Some(activities);
@@ -271,6 +294,7 @@ impl RecipeBuilder {
prompt: self.prompt,
extensions: self.extensions,
context: self.context,
settings: self.settings,
activities: self.activities,
author: self.author,
parameters: self.parameters,
+1
View File
@@ -1300,6 +1300,7 @@ mod tests {
activities: None,
author: None,
parameters: None,
settings: None,
};
let mut recipe_file = File::create(&recipe_filename)?;
writeln!(