systemprompt_agent/services/a2a_server/processing/strategies/
tool_executor.rs1use crate::services::shared::{AgentServiceError, Result};
2use async_trait::async_trait;
3use serde_json::Value;
4use systemprompt_identifiers::AiToolCallId;
5use systemprompt_models::{McpTool, RequestContext, ToolCall};
6
7use super::ExecutionContext;
8use super::plan_executor::ToolExecutorTrait;
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_owned(),
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.into_iter().next().ok_or_else(|| {
42 AgentServiceError::Internal(format!("Tool {} returned no result", tool_name))
43 })?;
44
45 if result.is_error.unwrap_or(false) {
46 let error_msg = result
47 .content
48 .into_iter()
49 .next()
50 .and_then(|c| {
51 if let rmcp::model::RawContent::Text(text_content) = c.raw {
52 Some(text_content.text)
53 } else {
54 None
55 }
56 })
57 .unwrap_or_else(|| "Unknown error".to_owned());
58 return Err(AgentServiceError::Internal(format!(
59 "Tool {tool_name} failed: {error_msg}"
60 )));
61 }
62
63 result.structured_content.ok_or_else(|| {
64 AgentServiceError::Internal(format!("Tool {tool_name} returned no structured_content"))
65 })
66 }
67}