|
| 1 | +use schemars::{ |
| 2 | + JsonSchema, |
| 3 | + schema_for, |
| 4 | +}; |
| 5 | +use serde::{ |
| 6 | + Deserialize, |
| 7 | + Serialize, |
| 8 | +}; |
| 9 | +use tokio::sync::broadcast; |
| 10 | + |
| 11 | +use super::{ |
| 12 | + BuiltInToolName, |
| 13 | + BuiltInToolTrait, |
| 14 | + ToolExecutionError, |
| 15 | + ToolExecutionOutput, |
| 16 | + ToolExecutionResult, |
| 17 | +}; |
| 18 | +use crate::protocol::AgentEvent; |
| 19 | + |
| 20 | +/// A tool for conveying information from subagent to its main agent |
| 21 | +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] |
| 22 | +/// A tool for conveying information from subagent to its main agent |
| 23 | +pub struct Summary { |
| 24 | + /// Description of the task that was assigned to the subagent |
| 25 | + pub task_description: String, |
| 26 | + /// Relevant context and information gathered during task execution |
| 27 | + pub context_summary: Option<String>, |
| 28 | + /// The final result or outcome of the completed task |
| 29 | + pub task_result: String, |
| 30 | +} |
| 31 | + |
| 32 | +const SUMMARY_TOOL_DESCRIPTION: &str = r#" |
| 33 | +A tool for conveying task summary and results from subagent to main agent. |
| 34 | +
|
| 35 | +WHEN TO USE THIS TOOL: |
| 36 | +- As a subagent, when a task is completed, use this tool to send the findings / conclusions to the main agent |
| 37 | +
|
| 38 | +HOW TO USE: |
| 39 | +- Provide the description of the task given |
| 40 | +- Optionally provide any context summary that compliments the consumer of the results. This is to aid subsequent actions to be performed with the result being sent |
| 41 | +- Provide the result of the task performed |
| 42 | +"#; |
| 43 | + |
| 44 | +impl BuiltInToolTrait for Summary { |
| 45 | + fn name() -> super::BuiltInToolName { |
| 46 | + BuiltInToolName::Ls |
| 47 | + } |
| 48 | + |
| 49 | + fn description() -> std::borrow::Cow<'static, str> { |
| 50 | + SUMMARY_TOOL_DESCRIPTION.into() |
| 51 | + } |
| 52 | + |
| 53 | + fn input_schema() -> std::borrow::Cow<'static, str> { |
| 54 | + serde_json::to_string(&Self::tool_schema()) |
| 55 | + .expect("serializing schema should not fail") |
| 56 | + .into() |
| 57 | + } |
| 58 | +} |
| 59 | + |
| 60 | +impl Summary { |
| 61 | + pub fn tool_schema() -> serde_json::Value { |
| 62 | + let schema = schema_for!(Self); |
| 63 | + serde_json::to_value(schema).expect("creating tool schema should not fail") |
| 64 | + } |
| 65 | + |
| 66 | + pub async fn execute(&self, result_tx: broadcast::Sender<AgentEvent>) -> ToolExecutionResult { |
| 67 | + result_tx |
| 68 | + .send(self.into()) |
| 69 | + .map(|_res| ToolExecutionOutput::default()) |
| 70 | + .map_err(|e| ToolExecutionError::Custom(e.to_string())) |
| 71 | + } |
| 72 | +} |
| 73 | + |
| 74 | +#[cfg(test)] |
| 75 | +mod tests { |
| 76 | + use super::*; |
| 77 | + |
| 78 | + #[tokio::test] |
| 79 | + async fn test_summary_tool_execute() { |
| 80 | + let (tx, mut rx) = broadcast::channel(10); |
| 81 | + let summary = Summary { |
| 82 | + task_description: "test task".to_string(), |
| 83 | + context_summary: Some("test context".to_string()), |
| 84 | + task_result: "test result".to_string(), |
| 85 | + }; |
| 86 | + let result = summary.execute(tx).await; |
| 87 | + assert!(result.is_ok()); |
| 88 | + |
| 89 | + let event = rx.recv().await.unwrap(); |
| 90 | + |
| 91 | + if let AgentEvent::SubagentSummary(Summary { |
| 92 | + task_description, |
| 93 | + context_summary, |
| 94 | + task_result, |
| 95 | + }) = event |
| 96 | + { |
| 97 | + assert_eq!(task_description, "test task"); |
| 98 | + assert_eq!(context_summary, Some("test context".to_string())); |
| 99 | + assert_eq!(task_result, "test result"); |
| 100 | + } else { |
| 101 | + panic!("Expected AgentEvent::Summary"); |
| 102 | + } |
| 103 | + } |
| 104 | +} |
0 commit comments