spec_ai_core/tools/
plugin_adapter.rs1use anyhow::Result;
4use async_trait::async_trait;
5use serde_json::Value;
6use spec_ai_plugin::{PluginToolRef, PluginToolResult as PluginResult};
7
8use super::{Tool, ToolResult};
9
10pub struct PluginToolAdapter {
12 tool_ref: PluginToolRef,
13 name: String,
15 description: String,
17 parameters: Value,
19 plugin_name: String,
21}
22
23impl PluginToolAdapter {
24 pub fn new(tool_ref: PluginToolRef, plugin_name: impl Into<String>) -> Result<Self> {
33 let info = (tool_ref.info)();
34
35 let parameters: Value = serde_json::from_str(info.parameters_json.as_str())
36 .map_err(|e| anyhow::anyhow!("Invalid parameters JSON from plugin: {}", e))?;
37
38 Ok(Self {
39 tool_ref,
40 name: info.name.to_string(),
41 description: info.description.to_string(),
42 parameters,
43 plugin_name: plugin_name.into(),
44 })
45 }
46
47 pub fn plugin_name(&self) -> &str {
49 &self.plugin_name
50 }
51}
52
53#[async_trait]
54impl Tool for PluginToolAdapter {
55 fn name(&self) -> &str {
56 &self.name
57 }
58
59 fn description(&self) -> &str {
60 &self.description
61 }
62
63 fn parameters(&self) -> Value {
64 self.parameters.clone()
65 }
66
67 async fn execute(&self, args: Value) -> Result<ToolResult> {
68 let args_json = serde_json::to_string(&args)?;
70
71 let result: PluginResult = (self.tool_ref.execute)(args_json.as_str().into());
73
74 Ok(ToolResult {
76 success: result.success,
77 output: result.output.to_string(),
78 error: result.error.map(|e| e.to_string()).into_option(),
79 })
80 }
81}
82
83impl std::fmt::Debug for PluginToolAdapter {
84 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85 f.debug_struct("PluginToolAdapter")
86 .field("name", &self.name)
87 .field("plugin_name", &self.plugin_name)
88 .field("description", &self.description)
89 .finish()
90 }
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96
97 #[test]
101 fn test_tool_result_conversion() {
102 let plugin_result = PluginResult::success("test output");
104 let result = ToolResult {
105 success: plugin_result.success,
106 output: plugin_result.output.to_string(),
107 error: plugin_result.error.map(|e| e.to_string()).into_option(),
108 };
109 assert!(result.success);
110 assert_eq!(result.output, "test output");
111 assert!(result.error.is_none());
112
113 let plugin_result = PluginResult::failure("test error");
115 let result = ToolResult {
116 success: plugin_result.success,
117 output: plugin_result.output.to_string(),
118 error: plugin_result.error.map(|e| e.to_string()).into_option(),
119 };
120 assert!(!result.success);
121 assert_eq!(result.error, Some("test error".to_string()));
122 }
123}