mirror of
https://github.com/block/goose.git
synced 2026-07-17 12:56:20 +02:00
Auto-inject summon extension for recipes with sub_recipes
When a recipe defines sub_recipes, the summon extension is now automatically added to the extensions list. This ensures the delegate tool is available without requiring users to manually specify the summon extension. Changes: - Add ensure_summon_for_subrecipes() helper in Recipe that auto-injects the summon platform extension when sub_recipes are present - Update test assertions to expect summon in extension list - Update test script to look for 'delegate' instead of 'subagent'
This commit is contained in:
@@ -97,7 +97,10 @@ mod tests {
|
||||
input_config.additional_system_prompt,
|
||||
Some("test_instructions my_value".to_string())
|
||||
);
|
||||
assert!(recipe.extensions.is_none());
|
||||
assert!(recipe
|
||||
.extensions
|
||||
.as_ref()
|
||||
.is_none_or(|e| e.iter().all(|ext| ext.name() == "summon")));
|
||||
|
||||
assert!(settings.is_some());
|
||||
let settings = settings.unwrap();
|
||||
@@ -162,7 +165,10 @@ mod tests {
|
||||
input_config.additional_system_prompt,
|
||||
Some("test_instructions my_value".to_string())
|
||||
);
|
||||
assert!(recipe.extensions.is_none());
|
||||
assert!(recipe
|
||||
.extensions
|
||||
.as_ref()
|
||||
.is_none_or(|e| e.iter().all(|ext| ext.name() == "summon")));
|
||||
|
||||
assert!(settings.is_some());
|
||||
let settings = settings.unwrap();
|
||||
|
||||
@@ -226,6 +226,24 @@ pub struct RecipeBuilder {
|
||||
}
|
||||
|
||||
impl Recipe {
|
||||
fn ensure_summon_for_subrecipes(&mut self) {
|
||||
if self.sub_recipes.is_none() {
|
||||
return;
|
||||
}
|
||||
let summon = ExtensionConfig::Platform {
|
||||
name: "summon".to_string(),
|
||||
description: String::new(),
|
||||
display_name: None,
|
||||
bundled: None,
|
||||
available_tools: vec![],
|
||||
};
|
||||
match &mut self.extensions {
|
||||
Some(exts) if !exts.iter().any(|e| e.name() == "summon") => exts.push(summon),
|
||||
None => self.extensions = Some(vec![summon]),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if harmful content is detected in instructions, prompt, or activities fields
|
||||
pub fn check_for_security_warnings(&self) -> bool {
|
||||
if [self.instructions.as_deref(), self.prompt.as_deref()]
|
||||
@@ -277,7 +295,7 @@ impl Recipe {
|
||||
}
|
||||
|
||||
pub fn from_content(content: &str) -> Result<Self> {
|
||||
let recipe: Recipe = match serde_yaml::from_str::<serde_yaml::Value>(content) {
|
||||
let mut recipe: Recipe = match serde_yaml::from_str::<serde_yaml::Value>(content) {
|
||||
Ok(yaml_value) => {
|
||||
if let Some(nested_recipe) = yaml_value.get("recipe") {
|
||||
serde_yaml::from_value(nested_recipe.clone())
|
||||
@@ -291,6 +309,7 @@ impl Recipe {
|
||||
.map_err(|e| anyhow::anyhow!("{}", strip_error_location(&e.to_string())))?,
|
||||
};
|
||||
|
||||
recipe.ensure_summon_for_subrecipes();
|
||||
Ok(recipe)
|
||||
}
|
||||
}
|
||||
@@ -450,8 +469,10 @@ mod tests {
|
||||
assert_eq!(recipe.prompt, Some("Test prompt".to_string()));
|
||||
|
||||
assert!(recipe.extensions.is_some());
|
||||
let extensions = recipe.extensions.unwrap();
|
||||
assert_eq!(extensions.len(), 1);
|
||||
let extensions = recipe.extensions.as_ref().unwrap();
|
||||
assert_eq!(extensions.len(), 2);
|
||||
assert!(extensions.iter().any(|e| e.name() == "test_extension"));
|
||||
assert!(extensions.iter().any(|e| e.name() == "summon"));
|
||||
|
||||
assert!(recipe.parameters.is_some());
|
||||
let parameters = recipe.parameters.unwrap();
|
||||
@@ -533,8 +554,10 @@ sub_recipes:
|
||||
assert_eq!(recipe.prompt, Some("Test prompt".to_string()));
|
||||
|
||||
assert!(recipe.extensions.is_some());
|
||||
let extensions = recipe.extensions.unwrap();
|
||||
assert_eq!(extensions.len(), 1);
|
||||
let extensions = recipe.extensions.as_ref().unwrap();
|
||||
assert_eq!(extensions.len(), 2);
|
||||
assert!(extensions.iter().any(|e| e.name() == "test_extension"));
|
||||
assert!(extensions.iter().any(|e| e.name() == "summon"));
|
||||
|
||||
assert!(recipe.parameters.is_some());
|
||||
let parameters = recipe.parameters.unwrap();
|
||||
|
||||
@@ -17,6 +17,7 @@ prompt: |
|
||||
Run two subrecipes in parallel:
|
||||
- use file_stats subrecipe to gather file statistics for {{ target_directory }}
|
||||
- use code_patterns subrecipe to analyze code patterns in {{ target_directory }}
|
||||
Iteratively `sleep 10` until the delegates complete, then load their output and confirm success
|
||||
extensions:
|
||||
- type: builtin
|
||||
name: developer
|
||||
|
||||
@@ -22,7 +22,7 @@ export PATH="$SCRIPT_DIR/target/release:$PATH"
|
||||
# Set default provider and model if not already set
|
||||
# Use fast model for CI to speed up tests
|
||||
export GOOSE_PROVIDER="${GOOSE_PROVIDER:-anthropic}"
|
||||
export GOOSE_MODEL="${GOOSE_MODEL:-claude-3-5-haiku-20241022}"
|
||||
export GOOSE_MODEL="${GOOSE_MODEL:-claude-haiku-4-5}"
|
||||
|
||||
echo "Using provider: $GOOSE_PROVIDER"
|
||||
echo "Using model: $GOOSE_MODEL"
|
||||
@@ -77,17 +77,17 @@ check_recipe_output() {
|
||||
local tmpfile=$1
|
||||
local mode=$2
|
||||
|
||||
# Check for unified subagent tool invocation (new format: "─── subagent |")
|
||||
if grep -q "─── subagent" "$tmpfile"; then
|
||||
echo "✓ SUCCESS: Subagent tool invoked"
|
||||
RESULTS+=("✓ Subagent tool invocation ($mode)")
|
||||
# Check for delegate tool invocation (new format: "─── delegate |")
|
||||
if grep -q "─── delegate" "$tmpfile"; then
|
||||
echo "✓ SUCCESS: Delegate tool invoked"
|
||||
RESULTS+=("✓ Delegate tool invocation ($mode)")
|
||||
else
|
||||
echo "✗ FAILED: No evidence of subagent tool invocation"
|
||||
RESULTS+=("✗ Subagent tool invocation ($mode)")
|
||||
echo "✗ FAILED: No evidence of delegate tool invocation"
|
||||
RESULTS+=("✗ Delegate tool invocation ($mode)")
|
||||
fi
|
||||
|
||||
# Check that both subrecipes were called (shown as "subrecipe: <name>" in output)
|
||||
if grep -q "subrecipe:.*file_stats\|file_stats.*subrecipe" "$tmpfile" && grep -q "subrecipe:.*code_patterns\|code_patterns.*subrecipe" "$tmpfile"; then
|
||||
# Check that both subrecipes were called (shown as "source: <name>" in delegate output)
|
||||
if grep -q "source:.*file_stats\|source.*file_stats" "$tmpfile" && grep -q "source:.*code_patterns\|source.*code_patterns" "$tmpfile"; then
|
||||
echo "✓ SUCCESS: Both subrecipes (file_stats, code_patterns) found in output"
|
||||
RESULTS+=("✓ Both subrecipes present ($mode)")
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user