fix(recipe): auto-inject summon when instructions use delegate()#7360
fix(recipe): auto-inject summon when instructions use delegate()#7360clouatre wants to merge 1 commit intoblock:mainfrom
Conversation
There was a problem hiding this comment.
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_subrecipesto detectdelegate(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
ecd4c76 to
2ebd70e
Compare
There was a problem hiding this comment.
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_subrecipescurrently injectsextensions = Some(vec![summon])whenuses_delegateandextensionsisNone, which turns an implicit "use globally-enabled extensions" recipe into an explicit/exclusive extensions list (seeresolve_extensions_for_new_session), potentially dropping other enabled extensions and changing runtime behavior; consider only auto-injecting when the recipe had an explicitextensions:block (i.e.,self.extensions.is_some()), or mergingsummoninto 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]),
_ => {}
|
Hey @lifeizhou-ap, would you have a chance to look at this? It fixes a regression from #6964 where recipes with an explicit |
|
/goose can you take a look at this? Hi, @clouatre 👋 Recipes that depend on subagents/delegates should probably explicitly include the summon extension going forward. Otherwise, we would probably want to just include all default-enabled platform extensions in recipes instead of making a callout for summon. The exception would be recipes that use subrecipes, in which case we should automatically include the summon extension so that subrecipes work. I figure that's an implicit include of the extension |
|
|
Extend ensure_summon (renamed from ensure_summon_for_subrecipes) to detect delegate() calls in recipe instructions via regex and auto-inject the summon extension with a warning log. Fix the None extensions arm: when extensions is None it means 'use all global extensions' which already includes summon. The previous code from block#6964 incorrectly converted None to Some([summon]), dropping all other global extensions. Addresses regression introduced in block#6964 (v1.24.0) where recipes with explicit extensions blocks silently lost delegate() capability. Signed-off-by: Hugues Clouâtre <[email protected]>
2ebd70e to
5fdc6ed
Compare
|
@tlongwell-block Thanks for the feedback. Agreed that explicit is better, and sub_recipes is the cleanest case for auto-injection. The context here is a silent regression from #6964 (v1.24.0). Recipes with explicit Revised approach:
The warning nudges authors toward explicit declaration while not breaking existing recipes in the meantime. |
|
Closing this PR. The maintainer's position is that recipes using PR #6964 (v1.24.0) moved This cost us several hours of debugging. We initially misattributed the regression to an unrelated change (#7353) because nothing pointed to the Opening a documentation issue so other users do not have to repeat this effort. |
Summary
Recipes with an explicit
extensions:block that omitssummonlose access to thedelegatetool. This was a regression introduced in #6964, which moveddelegatefrom an unconditional builtin into thesummonplatform extension.ensure_summon_for_subrecipesonly checked forsub_recipespresence. It now also scansrecipe.instructionsfor the stringdelegate(and injects thesummonplatform extension when found but absent. Atracing::warnis emitted when auto-injection occurs.Changes
crates/goose/src/recipe/mod.rs: extendensure_summon_for_subrecipesto detectdelegate(in instructions and auto-inject summonTests
Three unit tests added:
test_ensure_summon_injected_when_delegate_in_instructions: recipe with explicit empty extensions anddelegate(in instructions gets summon injectedtest_ensure_summon_not_duplicated_when_already_present: summon already listed + delegate in instructions stays at exactly one summon entrytest_ensure_summon_not_injected_without_delegate: recipe without delegate and empty extensions stays emptyReproduction
Before this fix, a recipe like:
would fail with
delegatetool not found at runtime.After this fix,
summonis auto-injected and the recipe works as expected.Fixes #7355