Skip to content

fix(recipe): auto-inject summon when instructions use delegate()#7360

Open
clouatre wants to merge 1 commit intoblock:mainfrom
clouatre:feat/delegate-summon-injection
Open

fix(recipe): auto-inject summon when instructions use delegate()#7360
clouatre wants to merge 1 commit intoblock:mainfrom
clouatre:feat/delegate-summon-injection

Conversation

@clouatre
Copy link
Contributor

Summary

Recipes with an explicit extensions: block that omits summon lose access to the delegate tool. This was a regression introduced in #6964, which moved delegate from an unconditional builtin into the summon platform extension.

ensure_summon_for_subrecipes only checked for sub_recipes presence. It now also scans recipe.instructions for the string delegate( and injects the summon platform extension when found but absent. A tracing::warn is emitted when auto-injection occurs.

Changes

  • crates/goose/src/recipe/mod.rs: extend ensure_summon_for_subrecipes to detect delegate( in instructions and auto-inject summon

Tests

Three unit tests added:

  • test_ensure_summon_injected_when_delegate_in_instructions: recipe with explicit empty extensions and delegate( in instructions gets summon injected
  • test_ensure_summon_not_duplicated_when_already_present: summon already listed + delegate in instructions stays at exactly one summon entry
  • test_ensure_summon_not_injected_without_delegate: recipe without delegate and empty extensions stays empty

Reproduction

Before this fix, a recipe like:

extensions:
  - type: builtin
    name: developer
instructions: |
  Use delegate() to spawn subagents.

would fail with delegate tool not found at runtime.

After this fix, summon is auto-injected and the recipe works as expected.

Fixes #7355

Copilot AI review requested due to automatic review settings February 19, 2026 17:02
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a regression from #6964 where recipes with explicit extensions: blocks that omit summon lose access to the delegate() tool. The fix extends the ensure_summon_for_subrecipes function to detect delegate( usage in recipe instructions and auto-inject the summon extension when needed.

Changes:

  • Extended ensure_summon_for_subrecipes to detect delegate( in instructions and auto-inject summon platform extension
  • Added warning when auto-injection occurs due to delegate usage
  • Added three unit tests for delegate detection and summon injection scenarios

@clouatre clouatre force-pushed the feat/delegate-summon-injection branch from 4ea343f to ecd4c76 Compare February 19, 2026 17:12
Recipes with an explicit extensions block that omits summon lose access
to the delegate tool. ensure_summon_for_subrecipes only checked for
sub_recipes presence; it now also scans recipe.instructions for the
string 'delegate(' and injects the summon platform extension when found
but absent. A tracing warning is emitted when auto-injection occurs.

Three unit tests cover: injection when delegate is used without summon,
no duplication when summon is already listed, and no injection when
delegate is not used.

Fixes block#7355

Signed-off-by: Hugues Clouâtre <hugues@linux.com>
@clouatre clouatre force-pushed the feat/delegate-summon-injection branch from ecd4c76 to 2ebd70e Compare February 19, 2026 17:13
Copilot AI review requested due to automatic review settings February 19, 2026 17:13
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

crates/goose/src/recipe/mod.rs:267

  • ensure_summon_for_subrecipes currently injects extensions = Some(vec![summon]) when uses_delegate and extensions is None, which turns an implicit "use globally-enabled extensions" recipe into an explicit/exclusive extensions list (see resolve_extensions_for_new_session), potentially dropping other enabled extensions and changing runtime behavior; consider only auto-injecting when the recipe had an explicit extensions: block (i.e., self.extensions.is_some()), or merging summon into the resolved enabled extensions instead of replacing them.
        let summon_present = self
            .extensions
            .as_ref()
            .map(|exts| exts.iter().any(|e| e.name() == "summon"))
            .unwrap_or(false);

        if uses_delegate && !summon_present {
            warn!("recipe instructions use 'delegate' but 'summon' extension is not listed; auto-injecting summon");
        }

        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]),
            _ => {}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Recipe sessions lose delegate tool when extensions block omits summon

1 participant

Comments