Skip to main content

mofa_plugins/tool/
adapter.rs

1//! Tool to Plugin Adapter
2//!
3//! Provides an adapter that converts Tool implementations to AgentPlugin implementations.
4//! This allows tools to be registered and managed through the plugin system.
5
6use async_trait::async_trait;
7use mofa_kernel::agent::components::tool::{Tool, ToolInput};
8use mofa_kernel::{
9    AgentPlugin, PluginContext, PluginMetadata, PluginResult, PluginState, PluginType,
10};
11use std::any::Any;
12use std::sync::Arc;
13
14/// Adapter that converts a Tool to an AgentPlugin
15///
16/// This allows any Tool implementation to be registered as a plugin,
17/// enabling centralized management through the plugin system.
18///
19/// # Example
20///
21/// ```rust,ignore
22/// use mofa_plugins::tool::adapter::ToolPluginAdapter;
23/// use mofa_kernel::agent::components::tool::Tool;
24/// use std::sync::Arc;
25///
26/// let tool = Arc::new(MyTool::new());
27/// let plugin = ToolPluginAdapter::new(tool);
28///
29/// // Now can be registered with PluginManager
30/// plugin_manager.register(plugin).await?;
31/// ```
32pub struct ToolPluginAdapter {
33    /// The underlying tool
34    tool: Arc<dyn Tool>,
35    /// Plugin metadata
36    metadata: PluginMetadata,
37    /// Current plugin state
38    state: PluginState,
39    /// Number of times the tool has been called
40    call_count: u64,
41}
42
43impl ToolPluginAdapter {
44    /// Create a new ToolPluginAdapter from a Tool
45    pub fn new(tool: Arc<dyn Tool>) -> Self {
46        let tool_name = tool.name();
47        let metadata = PluginMetadata::new(
48            &format!("tool-{}", tool_name),
49            &format!("Tool: {}", tool_name),
50            PluginType::Tool,
51        )
52        .with_description(tool.description());
53
54        Self {
55            tool,
56            metadata,
57            state: PluginState::Unloaded,
58            call_count: 0,
59        }
60    }
61
62    /// Get the number of times this tool has been called
63    pub fn call_count(&self) -> u64 {
64        self.call_count
65    }
66
67    /// Get a reference to the underlying tool
68    pub fn tool(&self) -> &Arc<dyn Tool> {
69        &self.tool
70    }
71}
72
73#[async_trait]
74impl AgentPlugin for ToolPluginAdapter {
75    fn metadata(&self) -> &PluginMetadata {
76        &self.metadata
77    }
78
79    fn state(&self) -> PluginState {
80        self.state.clone()
81    }
82
83    async fn load(&mut self, _ctx: &PluginContext) -> PluginResult<()> {
84        self.state = PluginState::Loaded;
85        Ok(())
86    }
87
88    async fn init_plugin(&mut self) -> PluginResult<()> {
89        self.state = PluginState::Loaded;
90        Ok(())
91    }
92
93    async fn start(&mut self) -> PluginResult<()> {
94        self.state = PluginState::Running;
95        Ok(())
96    }
97
98    async fn stop(&mut self) -> PluginResult<()> {
99        self.state = PluginState::Paused;
100        Ok(())
101    }
102
103    async fn unload(&mut self) -> PluginResult<()> {
104        self.state = PluginState::Unloaded;
105        Ok(())
106    }
107
108    async fn execute(&mut self, input: String) -> PluginResult<String> {
109        // Parse the input as ToolInput
110        let tool_input: ToolInput = serde_json::from_str(&input)
111            .map_err(|e| anyhow::anyhow!("Failed to parse tool input: {}", e))?;
112
113        // Execute the tool with a minimal context
114        let ctx = mofa_kernel::agent::context::AgentContext::new("tool-execution");
115        let result = self.tool.execute(tool_input, &ctx).await;
116
117        self.call_count += 1;
118
119        // Return the result as a string
120        Ok(result.to_string_output())
121    }
122
123    fn as_any(&self) -> &dyn Any {
124        self
125    }
126
127    fn as_any_mut(&mut self) -> &mut dyn Any {
128        self
129    }
130
131    fn into_any(self: Box<Self>) -> Box<dyn Any> {
132        self
133    }
134}
135
136/// Create a ToolPluginAdapter from a Tool
137///
138/// Convenience function for creating adapters.
139///
140/// # Example
141///
142/// ```rust,ignore
143/// use mofa_plugins::tool::adapter::adapt_tool;
144/// use std::sync::Arc;
145///
146/// let tool = Arc::new(MyTool::new());
147/// let plugin = adapt_tool(tool);
148/// ```
149pub fn adapt_tool(tool: Arc<dyn Tool>) -> ToolPluginAdapter {
150    ToolPluginAdapter::new(tool)
151}