use anyhow::Result;
use async_trait::async_trait;
use serde_json::Value;
use crate::spec_ai_plugin::{PluginToolRef, PluginToolResult as PluginResult};
use super::{Tool, ToolResult};
pub struct PluginToolAdapter {
tool_ref: PluginToolRef,
name: String,
description: String,
parameters: Value,
plugin_name: String,
}
impl PluginToolAdapter {
pub fn new(tool_ref: PluginToolRef, plugin_name: impl Into<String>) -> Result<Self> {
let info = (tool_ref.info)();
let parameters: Value = serde_json::from_str(info.parameters_json.as_str())
.map_err(|e| anyhow::anyhow!("Invalid parameters JSON from plugin: {}", e))?;
Ok(Self {
tool_ref,
name: info.name.to_string(),
description: info.description.to_string(),
parameters,
plugin_name: plugin_name.into(),
})
}
pub fn plugin_name(&self) -> &str {
&self.plugin_name
}
}
#[async_trait]
impl Tool for PluginToolAdapter {
fn name(&self) -> &str {
&self.name
}
fn description(&self) -> &str {
&self.description
}
fn parameters(&self) -> Value {
self.parameters.clone()
}
async fn execute(&self, args: Value) -> Result<ToolResult> {
let args_json = serde_json::to_string(&args)?;
let result: PluginResult = (self.tool_ref.execute)(args_json.as_str().into());
Ok(ToolResult {
success: result.success,
output: result.output.to_string(),
error: result.error.map(|e| e.to_string()).into_option(),
})
}
}
impl std::fmt::Debug for PluginToolAdapter {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("PluginToolAdapter")
.field("name", &self.name)
.field("plugin_name", &self.plugin_name)
.field("description", &self.description)
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_tool_result_conversion() {
let plugin_result = PluginResult::success("test output");
let result = ToolResult {
success: plugin_result.success,
output: plugin_result.output.to_string(),
error: plugin_result.error.map(|e| e.to_string()).into_option(),
};
assert!(result.success);
assert_eq!(result.output, "test output");
assert!(result.error.is_none());
let plugin_result = PluginResult::failure("test error");
let result = ToolResult {
success: plugin_result.success,
output: plugin_result.output.to_string(),
error: plugin_result.error.map(|e| e.to_string()).into_option(),
};
assert!(!result.success);
assert_eq!(result.error, Some("test error".to_string()));
}
}