Files
tkmind_go/crates/goose/src/agents/sub_recipe_manager.rs
T
2025-08-12 16:18:41 -04:00

110 lines
3.4 KiB
Rust

use rmcp::model::Tool;
use rmcp::model::{Content, ErrorCode, ErrorData};
use serde_json::Value;
use std::borrow::Cow;
use std::collections::HashMap;
use crate::{
agents::{
recipe_tools::sub_recipe_tools::{
create_sub_recipe_task, create_sub_recipe_task_tool, SUB_RECIPE_TASK_TOOL_NAME_PREFIX,
},
subagent_execution_tool::tasks_manager::TasksManager,
tool_execution::ToolCallResult,
},
recipe::SubRecipe,
};
#[derive(Debug, Clone)]
pub struct SubRecipeManager {
pub sub_recipe_tools: HashMap<String, Tool>,
pub sub_recipes: HashMap<String, SubRecipe>,
}
impl Default for SubRecipeManager {
fn default() -> Self {
Self::new()
}
}
impl SubRecipeManager {
pub fn new() -> Self {
Self {
sub_recipe_tools: HashMap::new(),
sub_recipes: HashMap::new(),
}
}
pub fn add_sub_recipe_tools(&mut self, sub_recipes_to_add: Vec<SubRecipe>) {
for sub_recipe in sub_recipes_to_add {
let sub_recipe_key = format!(
"{}_{}",
SUB_RECIPE_TASK_TOOL_NAME_PREFIX,
sub_recipe.name.clone()
);
let tool = create_sub_recipe_task_tool(&sub_recipe);
self.sub_recipe_tools.insert(sub_recipe_key.clone(), tool);
self.sub_recipes.insert(sub_recipe_key.clone(), sub_recipe);
}
}
pub fn is_sub_recipe_tool(&self, tool_name: &str) -> bool {
self.sub_recipe_tools.contains_key(tool_name)
}
pub async fn dispatch_sub_recipe_tool_call(
&self,
tool_name: &str,
params: Value,
tasks_manager: &TasksManager,
) -> ToolCallResult {
let result = self
.call_sub_recipe_tool(tool_name, params, tasks_manager)
.await;
match result {
Ok(call_result) => ToolCallResult::from(Ok(call_result)),
Err(e) => ToolCallResult::from(Err(ErrorData {
code: ErrorCode::INTERNAL_ERROR,
message: Cow::from(e.to_string()),
data: None,
})),
}
}
async fn call_sub_recipe_tool(
&self,
tool_name: &str,
params: Value,
tasks_manager: &TasksManager,
) -> Result<Vec<Content>, ErrorData> {
let sub_recipe = self.sub_recipes.get(tool_name).ok_or_else(|| {
let sub_recipe_name = tool_name
.strip_prefix(SUB_RECIPE_TASK_TOOL_NAME_PREFIX)
.and_then(|s| s.strip_prefix("_"))
.ok_or_else(|| ErrorData {
code: ErrorCode::INVALID_PARAMS,
message: Cow::from(format!(
"Invalid sub-recipe tool name format: {}",
tool_name
)),
data: None,
})
.unwrap();
ErrorData {
code: ErrorCode::INVALID_PARAMS,
message: Cow::from(format!("Sub-recipe '{}' not found", sub_recipe_name)),
data: None,
}
})?;
let output = create_sub_recipe_task(sub_recipe, params, tasks_manager)
.await
.map_err(|e| ErrorData {
code: ErrorCode::INTERNAL_ERROR,
message: Cow::from(format!("Sub-recipe task creation failed: {}", e)),
data: None,
})?;
Ok(vec![Content::text(output)])
}
}