goose icon indicating copy to clipboard operation
goose copied to clipboard

Replace TaskParameter with Recipe in Dynamic Task Tools

Open tlongwell-block opened this issue 1 month ago • 1 comments

Problem

The TaskParameter struct in dynamic_task_tools.rs is essentially a duplicate of the Recipe struct. We manually convert from one to the other, which is unnecessary and error-prone.

Current State

// We define this duplicate structure:
pub struct TaskParameter {
    pub instructions: Option<String>,
    pub prompt: Option<String>,
    pub title: Option<String>,
    pub description: Option<String>,
    pub extensions: Option<Vec<JsonObject>>,
    pub settings: Option<JsonObject>,
    pub parameters: Option<Vec<JsonObject>>,
    pub response: Option<JsonObject>,
    pub retry: Option<JsonObject>,
    pub activities: Option<Vec<String>>,
    pub return_last_only: Option<bool>,
}

// Then manually convert it to Recipe with ~100 lines of code:
pub fn task_params_to_inline_recipe(task_param: &Value, ...) -> Result<Recipe> {
    // ... lots of manual field mapping ...
}

Proposed Solution

Just use Recipe directly:

#[derive(Debug, Serialize, Deserialize, JsonSchema)]
pub struct CreateDynamicTaskParams {
    pub task_parameters: Vec<Recipe>,
    pub execution_mode: Option<ExecutionModeParam>,
}

For the one field that doesn't belong in Recipe (return_last_only), we can handle it separately or create a thin wrapper.

Benefits

  • Removes ~200 lines of duplicate code
  • Single source of truth for recipe structure
  • Fixes #5241 - LLMs work with actual Recipe schema
  • Eliminates .expect() calls that can crash the server
  • Better validation - Recipe validation happens automatically

Implementation

  1. Add JsonSchema derive to Recipe and its nested types
  2. Update CreateDynamicTaskParams to use Vec<Recipe>
  3. Delete TaskParameter struct
  4. Delete task_params_to_inline_recipe() function
  5. Update tests

Notes

  • The return_last_only field (which exists in TaskParameter but not Recipe) can be handled as a separate parameter or wrapper. Or, better, add it to recipe and subrecipes spec.
  • This aligns with PR #5082's goal of unifying recipe execution
  • Suggested by @DOsinga in PR #5082

tlongwell-block avatar Nov 06 '25 23:11 tlongwell-block

this seems to be the same thing as: https://github.com/block/goose/issues/5241

we can close the other one though, this one has more detail

DOsinga avatar Nov 06 '25 23:11 DOsinga