Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 28 additions & 4 deletions crates/goose-server/src/routes/recipe_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ use crate::state::AppState;
use anyhow::Result;
use axum::http::StatusCode;
use goose::agents::Agent;
use goose::recipe::build_recipe::{build_recipe_from_template, RecipeError};
use goose::recipe::build_recipe::{
build_recipe_from_template, resolve_sub_recipe_path, RecipeError,
};
use goose::recipe::local_recipes::{get_recipe_library_dir, list_local_recipes};
use goose::recipe::validate_recipe::validate_recipe_template_from_content;
use goose::recipe::Recipe;
Expand Down Expand Up @@ -44,13 +46,23 @@ pub fn short_id_from_path(path: &str) -> String {
pub fn get_all_recipes_manifests() -> Result<Vec<RecipeManifest>> {
let recipes_with_path = list_local_recipes()?;
let mut recipe_manifests_with_path = Vec::new();
for (file_path, recipe) in recipes_with_path {
for (file_path, mut recipe) in recipes_with_path {
let Ok(last_modified) = fs::metadata(file_path.clone())
.map(|m| chrono::DateTime::<chrono::Utc>::from(m.modified().unwrap()).to_rfc3339())
else {
continue;
};

if let Some(recipe_dir) = file_path.parent() {
if let Some(ref mut sub_recipes) = recipe.sub_recipes {
for sr in sub_recipes.iter_mut() {
if let Ok(resolved) = resolve_sub_recipe_path(&sr.path, recipe_dir) {
sr.path = resolved;
}
Comment on lines +59 to +61
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

Silent error handling: when resolve_sub_recipe_path fails, the error is silently ignored. This could hide issues like missing sub-recipe files. Consider logging a warning when path resolution fails so issues are visible during debugging.

Copilot uses AI. Check for mistakes.
Copy link
Collaborator

Choose a reason for hiding this comment

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

probably ok in this case

}
}
}
Comment on lines +56 to +64
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

This path resolution logic is duplicated in load_recipe_by_id (lines 144-152). Consider extracting it into a helper function to avoid duplication and ensure consistent behavior across both functions.

Copilot uses AI. Check for mistakes.

let manifest_with_path = RecipeManifest {
id: short_id_from_path(file_path.to_string_lossy().as_ref()),
recipe,
Expand Down Expand Up @@ -126,10 +138,22 @@ pub async fn get_recipe_file_path_by_id(
pub async fn load_recipe_by_id(state: &AppState, id: &str) -> Result<Recipe, ErrorResponse> {
let path = get_recipe_file_path_by_id(state, id).await?;

Recipe::from_file_path(&path).map_err(|err| ErrorResponse {
let mut recipe = Recipe::from_file_path(&path).map_err(|err| ErrorResponse {
message: format!("Failed to load recipe: {}", err),
status: StatusCode::INTERNAL_SERVER_ERROR,
})
})?;

if let Some(recipe_dir) = path.parent() {
if let Some(ref mut sub_recipes) = recipe.sub_recipes {
for sr in sub_recipes.iter_mut() {
if let Ok(resolved) = resolve_sub_recipe_path(&sr.path, recipe_dir) {
sr.path = resolved;
Comment on lines +149 to +150
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

Silent error handling: when resolve_sub_recipe_path fails, the error is silently ignored. This could hide issues like missing sub-recipe files. Consider logging a warning when path resolution fails so issues are visible during debugging.

Suggested change
if let Ok(resolved) = resolve_sub_recipe_path(&sr.path, recipe_dir) {
sr.path = resolved;
match resolve_sub_recipe_path(&sr.path, recipe_dir) {
Ok(resolved) => {
sr.path = resolved;
}
Err(err) => {
eprintln!(
"Warning: failed to resolve sub-recipe path '{}' relative to '{}': {err}",
sr.path.display(),
recipe_dir.display()
);
}

Copilot uses AI. Check for mistakes.
}
}
}
}

Ok(recipe)
}

pub async fn build_recipe_with_parameter_values(
Expand Down
2 changes: 1 addition & 1 deletion crates/goose/src/recipe/build_recipe/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ where
Ok((param_map, missing_params))
}

fn resolve_sub_recipe_path(
pub fn resolve_sub_recipe_path(
sub_recipe_path: &str,
parent_recipe_dir: &Path,
) -> Result<String, RecipeError> {
Expand Down
Loading