systemprompt_agent/services/a2a_server/processing/artifact/
mod.rs1use anyhow::Result;
2use async_trait::async_trait;
3use std::sync::Arc;
4use systemprompt_identifiers::AgentName;
5use systemprompt_models::{AiProvider, CallToolResult, McpTool, RequestContext, ToolCall};
6
7use crate::models::a2a::Artifact;
8use crate::services::mcp::McpToA2aTransformer;
9
10#[async_trait]
11pub trait ToolProvider: Send + Sync {
12 async fn list_available_tools_for_agent(
13 &self,
14 agent_name: &AgentName,
15 context: &RequestContext,
16 ) -> Result<Vec<McpTool>>;
17}
18
19pub struct AiServiceToolProvider {
20 ai_service: Arc<dyn AiProvider>,
21}
22
23impl std::fmt::Debug for AiServiceToolProvider {
24 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25 f.debug_struct("AiServiceToolProvider")
26 .field("ai_service", &"<AiProvider>")
27 .finish()
28 }
29}
30
31impl AiServiceToolProvider {
32 pub fn new(ai_service: Arc<dyn AiProvider>) -> Self {
33 Self { ai_service }
34 }
35}
36
37#[async_trait]
38impl ToolProvider for AiServiceToolProvider {
39 async fn list_available_tools_for_agent(
40 &self,
41 agent_name: &AgentName,
42 context: &RequestContext,
43 ) -> Result<Vec<McpTool>> {
44 self.ai_service
45 .list_available_tools_for_agent(agent_name, context)
46 .await
47 }
48}
49
50#[derive(Debug)]
51pub struct ArtifactBuilder {
52 tool_calls: Vec<ToolCall>,
53 tool_results: Vec<CallToolResult>,
54 tools: Vec<McpTool>,
55 context_id: String,
56 task_id: String,
57}
58
59impl ArtifactBuilder {
60 pub fn new(
61 tool_calls: Vec<ToolCall>,
62 tool_results: Vec<CallToolResult>,
63 tools: Vec<McpTool>,
64 context_id: String,
65 task_id: String,
66 ) -> Self {
67 Self {
68 tool_calls,
69 tool_results,
70 tools,
71 context_id,
72 task_id,
73 }
74 }
75
76 fn get_output_schema(&self, tool_name: &str) -> Option<&serde_json::Value> {
77 self.tools
78 .iter()
79 .find(|t| t.name == tool_name)
80 .and_then(|t| t.output_schema.as_ref())
81 }
82
83 pub fn build_artifacts(&self) -> Result<Vec<Artifact>> {
84 let mut artifacts = Vec::new();
85
86 for (index, result) in self.tool_results.iter().enumerate() {
87 if let Some(structured_content) =
88 result.structured_content.as_ref().filter(|v| !v.is_null())
89 {
90 if let Some(tool_call) = self.tool_calls.get(index) {
91 let output_schema = self.get_output_schema(&tool_call.name);
92
93 let mut artifact = McpToA2aTransformer::transform_from_json(
94 &tool_call.name,
95 structured_content,
96 output_schema,
97 &self.context_id,
98 &self.task_id,
99 Some(&tool_call.arguments),
100 )
101 .map_err(|e| {
102 anyhow::anyhow!("Tool '{}' artifact transform failed: {e}", tool_call.name)
103 })?;
104
105 artifact.metadata = artifact.metadata.with_execution_index(index);
106
107 artifacts.push(artifact);
108 }
109 }
110 }
111
112 Ok(artifacts)
113 }
114}