systemprompt_agent/services/a2a_server/processing/strategies/
tool_executor.rs1use anyhow::Result;
2use async_trait::async_trait;
3use serde_json::Value;
4use systemprompt_identifiers::AiToolCallId;
5use systemprompt_models::{McpTool, RequestContext, ToolCall};
6
7use super::plan_executor::ToolExecutorTrait;
8use super::ExecutionContext;
9
10#[derive(Debug)]
11pub struct ContextToolExecutor {
12 pub context: ExecutionContext,
13}
14
15#[async_trait]
16impl ToolExecutorTrait for ContextToolExecutor {
17 async fn execute_tool(
18 &self,
19 tool_name: &str,
20 arguments: Value,
21 tools: &[McpTool],
22 ctx: &RequestContext,
23 ) -> Result<Value> {
24 let tool_call = ToolCall {
25 ai_tool_call_id: AiToolCallId::new(format!("call_{}", tool_name)),
26 name: tool_name.to_string(),
27 arguments,
28 };
29
30 let (_, results) = self
31 .context
32 .ai_service
33 .execute_tools(
34 vec![tool_call],
35 tools,
36 ctx,
37 Some(&self.context.agent_runtime.tool_model_overrides),
38 )
39 .await;
40
41 let result = results
42 .into_iter()
43 .next()
44 .ok_or_else(|| anyhow::anyhow!("Tool {} returned no result", tool_name))?;
45
46 if result.is_error.unwrap_or(false) {
47 let error_msg = result
48 .content
49 .into_iter()
50 .next()
51 .and_then(|c| {
52 if let rmcp::model::RawContent::Text(text_content) = c.raw {
53 Some(text_content.text)
54 } else {
55 None
56 }
57 })
58 .unwrap_or_else(|| "Unknown error".to_string());
59 return Err(anyhow::anyhow!("Tool {} failed: {}", tool_name, error_msg));
60 }
61
62 result
63 .structured_content
64 .ok_or_else(|| anyhow::anyhow!("Tool {} returned no structured_content", tool_name))
65 }
66}