diff --git a/crates/goose-cli/src/recipes/extract_from_cli.rs b/crates/goose-cli/src/recipes/extract_from_cli.rs index 0550ee26fef4..199c7091e3a6 100644 --- a/crates/goose-cli/src/recipes/extract_from_cli.rs +++ b/crates/goose-cli/src/recipes/extract_from_cli.rs @@ -47,7 +47,7 @@ pub fn extract_recipe_info_from_cli( } Ok(( InputConfig { - contents: recipe.prompt, + contents: recipe.prompt.filter(|s| !s.trim().is_empty()), extensions_override: recipe.extensions, additional_system_prompt: recipe.instructions, }, diff --git a/crates/goose-cli/src/recipes/recipe.rs b/crates/goose-cli/src/recipes/recipe.rs index a7c99e041419..49b0e6bf7210 100644 --- a/crates/goose-cli/src/recipes/recipe.rs +++ b/crates/goose-cli/src/recipes/recipe.rs @@ -37,7 +37,6 @@ pub fn load_recipe_content_as_template( missing_parameters_command_line(missing_params) )); } - render_recipe_content_with_params(&recipe_file_content, ¶ms_for_template) } diff --git a/crates/goose-cli/src/recipes/search_recipe.rs b/crates/goose-cli/src/recipes/search_recipe.rs index d87c30e97cc5..e78dfe223b36 100644 --- a/crates/goose-cli/src/recipes/search_recipe.rs +++ b/crates/goose-cli/src/recipes/search_recipe.rs @@ -117,7 +117,6 @@ fn read_recipe_file>(recipe_path: P) -> Result { let content = fs::read_to_string(&path) .map_err(|e| anyhow!("Failed to read recipe file {}: {}", path.display(), e))?; - let canonical = path.canonicalize().map_err(|e| { anyhow!( "Failed to resolve absolute path for {}: {}", diff --git a/crates/goose-cli/src/recipes/template_recipe.rs b/crates/goose-cli/src/recipes/template_recipe.rs index 2792f20ba662..43a04e08bd33 100644 --- a/crates/goose-cli/src/recipes/template_recipe.rs +++ b/crates/goose-cli/src/recipes/template_recipe.rs @@ -6,6 +6,7 @@ use std::{ use anyhow::Result; use goose::recipe::Recipe; use minijinja::{Environment, UndefinedBehavior}; +use regex::Regex; use crate::recipes::recipe::BUILT_IN_RECIPE_DIR_PARAM; @@ -15,8 +16,13 @@ pub fn render_recipe_content_with_params( content: &str, params: &HashMap, ) -> Result { + // Pre-process content to replace empty double quotes with single quotes + // This prevents MiniJinja from escaping "" to "\"\"" which would break YAML parsing + let re = Regex::new(r#":\s*"""#).unwrap(); + let processed_content = re.replace_all(content, ": ''"); + let env = add_template_in_env( - content, + &processed_content, params.get(BUILT_IN_RECIPE_DIR_PARAM).unwrap().clone(), UndefinedBehavior::Strict, )?; @@ -168,5 +174,21 @@ mod tests { let err = render_recipe_content_with_params(content, ¶ms).unwrap_err(); assert!(err.to_string().contains("unexpected end of input")); } + + #[test] + fn test_empty_prompt() { + let content = r#" +prompt: "" +name: "Simple Recipe" +description: "A test recipe" +"#; + let params = HashMap::from([("recipe_dir".to_string(), "test_dir".to_string())]); + let result = render_recipe_content_with_params(content, ¶ms).unwrap(); + + assert!(result.contains("prompt: ''")); + assert!(!result.contains(r#"prompt: "\"\"""#)); // Should not contain escaped quotes + + assert!(result.contains(r#"name: "Simple Recipe""#)); + } } }