diff --git a/crates/goose/src/recipe/build_recipe/mod.rs b/crates/goose/src/recipe/build_recipe/mod.rs index ddd7be58..b14d322c 100644 --- a/crates/goose/src/recipe/build_recipe/mod.rs +++ b/crates/goose/src/recipe/build_recipe/mod.rs @@ -131,23 +131,28 @@ where ); let mut missing_params: Vec = Vec::new(); for param in recipe_parameters.unwrap_or_default() { - if !param_map.contains_key(¶m.key) { + let raw_value = if let Some(v) = param_map.get(¶m.key) { + Some(v.clone()) + } else { match (¶m.default, ¶m.requirement) { - (Some(default), _) => param_map.insert(param.key.clone(), default.clone()), - (None, RecipeParameterRequirement::UserPrompt) if user_prompt_fn.is_some() => { - let input_value = - user_prompt_fn.as_ref().unwrap()(¶m.key, ¶m.description)?; - param_map.insert(param.key.clone(), input_value) - } - _ => { - missing_params.push(param.key.clone()); - None - } - }; - } else if matches!(param.input_type, RecipeParameterInputType::File) { - let file_path = param_map.get(¶m.key).unwrap(); - let file_content = read_parameter_file_content(file_path)?; - param_map.insert(param.key.clone(), file_content); + (Some(default), _) => Some(default.clone()), + (None, RecipeParameterRequirement::UserPrompt) if user_prompt_fn.is_some() => Some( + user_prompt_fn.as_ref().unwrap()(¶m.key, ¶m.description)?, + ), + _ => None, + } + }; + + match raw_value { + Some(value) => { + let final_value = if matches!(param.input_type, RecipeParameterInputType::File) { + read_parameter_file_content(&value)? + } else { + value + }; + param_map.insert(param.key.clone(), final_value); + } + None => missing_params.push(param.key.clone()), } } Ok((param_map, missing_params)) diff --git a/crates/goose/src/recipe/build_recipe/tests.rs b/crates/goose/src/recipe/build_recipe/tests.rs index c486938a..de602260 100644 --- a/crates/goose/src/recipe/build_recipe/tests.rs +++ b/crates/goose/src/recipe/build_recipe/tests.rs @@ -578,6 +578,40 @@ parameters: assert!(instructions.contains("Test file content:")); } + #[test] + fn test_build_recipe_user_prompt_file_parameter_reads_file_content() { + let instructions_and_parameters = r#"instructions: "Test file content: {{ FILE_PARAM }}" +parameters: + - key: FILE_PARAM + input_type: file + requirement: user_prompt + description: A file parameter"#; + + let (temp_dir, recipe_file) = setup_yaml_recipe_file(instructions_and_parameters); + + let test_content = "Hello from prompted file!\nThis is line 2"; + let test_file_path = setup_test_file(&temp_dir, "prompted_file.txt", test_content); + let user_prompt = |key: &str, description: &str| -> Result { + assert_eq!(key, "FILE_PARAM"); + assert_eq!(description, "A file parameter"); + Ok(test_file_path.to_string_lossy().to_string()) + }; + + let result = build_recipe_from_template( + recipe_file.content, + &recipe_file.parent_dir, + Vec::new(), + Some(user_prompt), + ); + + assert!(result.is_ok()); + let recipe = result.unwrap(); + + let instructions = recipe.instructions.as_ref().unwrap(); + assert!(instructions.contains("Hello from prompted file!")); + assert!(!instructions.contains("prompted_file.txt")); + } + #[test] fn test_build_recipe_file_parameter_nonexistent_file() { let instructions_and_parameters = r#"instructions: "Test file content: {{ FILE_PARAM }}"