Skip to main content

adk_plugin/
plugin.rs

1//! Plugin definition
2//!
3//! A Plugin bundles related callbacks together for a specific purpose.
4
5use crate::callbacks::*;
6use adk_core::{
7    AfterAgentCallback, AfterModelCallback, AfterToolCallback, BeforeAgentCallback,
8    BeforeModelCallback, BeforeToolCallback,
9};
10use std::future::Future;
11use std::pin::Pin;
12
13/// Type alias for async cleanup functions.
14pub type CloseFn = Box<dyn Fn() -> Pin<Box<dyn Future<Output = ()> + Send>> + Send + Sync>;
15
16/// Configuration for creating a Plugin.
17///
18/// All callbacks are optional - only set the ones you need.
19///
20/// # Example
21///
22/// ```rust,ignore
23/// let config = PluginConfig {
24///     name: "my-plugin".to_string(),
25///     on_user_message: Some(Box::new(|ctx, content| {
26///         Box::pin(async move {
27///             // Process user message
28///             Ok(None)
29///         })
30///     })),
31///     ..Default::default()
32/// };
33/// ```
34pub struct PluginConfig {
35    /// Unique name for this plugin
36    pub name: String,
37
38    // Run lifecycle callbacks
39    /// Called when a user message is received (can modify)
40    pub on_user_message: Option<OnUserMessageCallback>,
41    /// Called for each event (can modify)
42    pub on_event: Option<OnEventCallback>,
43    /// Called before the run starts (can skip run)
44    pub before_run: Option<BeforeRunCallback>,
45    /// Called after the run completes (cleanup)
46    pub after_run: Option<AfterRunCallback>,
47
48    // Agent callbacks
49    /// Called before agent execution
50    pub before_agent: Option<BeforeAgentCallback>,
51    /// Called after agent execution
52    pub after_agent: Option<AfterAgentCallback>,
53
54    // Model callbacks
55    /// Called before LLM call (can modify request or skip)
56    pub before_model: Option<BeforeModelCallback>,
57    /// Called after LLM call (can modify response)
58    pub after_model: Option<AfterModelCallback>,
59    /// Called when LLM returns an error
60    pub on_model_error: Option<OnModelErrorCallback>,
61
62    // Tool callbacks
63    /// Called before tool execution
64    pub before_tool: Option<BeforeToolCallback>,
65    /// Called after tool execution
66    pub after_tool: Option<AfterToolCallback>,
67    /// Called when tool returns an error
68    pub on_tool_error: Option<OnToolErrorCallback>,
69
70    /// Cleanup function called when plugin is closed
71    pub close_fn: Option<CloseFn>,
72}
73
74impl Default for PluginConfig {
75    fn default() -> Self {
76        Self {
77            name: "unnamed".to_string(),
78            on_user_message: None,
79            on_event: None,
80            before_run: None,
81            after_run: None,
82            before_agent: None,
83            after_agent: None,
84            before_model: None,
85            after_model: None,
86            on_model_error: None,
87            before_tool: None,
88            after_tool: None,
89            on_tool_error: None,
90            close_fn: None,
91        }
92    }
93}
94
95/// A Plugin bundles related callbacks for extending agent behavior.
96///
97/// Plugins are registered with a PluginManager which coordinates
98/// callback execution across all registered plugins.
99///
100/// # Example
101///
102/// ```rust,ignore
103/// use adk_plugin::{Plugin, PluginConfig};
104///
105/// // Create a caching plugin
106/// let cache_plugin = Plugin::new(PluginConfig {
107///     name: "cache".to_string(),
108///     before_model: Some(Box::new(|ctx, request| {
109///         Box::pin(async move {
110///             // Check cache for this request
111///             if let Some(cached) = check_cache(&request).await {
112///                 return Ok(BeforeModelResult::Skip(cached));
113///             }
114///             Ok(BeforeModelResult::Continue(request))
115///         })
116///     })),
117///     after_model: Some(Box::new(|ctx, response| {
118///         Box::pin(async move {
119///             // Store response in cache
120///             store_in_cache(&response).await;
121///             Ok(None)
122///         })
123///     })),
124///     ..Default::default()
125/// });
126/// ```
127pub struct Plugin {
128    config: PluginConfig,
129}
130
131impl Plugin {
132    /// Create a new plugin from configuration.
133    pub fn new(config: PluginConfig) -> Self {
134        Self { config }
135    }
136
137    /// Get the plugin name.
138    pub fn name(&self) -> &str {
139        &self.config.name
140    }
141
142    /// Get the on_user_message callback if set.
143    pub fn on_user_message(&self) -> Option<&OnUserMessageCallback> {
144        self.config.on_user_message.as_ref()
145    }
146
147    /// Get the on_event callback if set.
148    pub fn on_event(&self) -> Option<&OnEventCallback> {
149        self.config.on_event.as_ref()
150    }
151
152    /// Get the before_run callback if set.
153    pub fn before_run(&self) -> Option<&BeforeRunCallback> {
154        self.config.before_run.as_ref()
155    }
156
157    /// Get the after_run callback if set.
158    pub fn after_run(&self) -> Option<&AfterRunCallback> {
159        self.config.after_run.as_ref()
160    }
161
162    /// Get the before_agent callback if set.
163    pub fn before_agent(&self) -> Option<&BeforeAgentCallback> {
164        self.config.before_agent.as_ref()
165    }
166
167    /// Get the after_agent callback if set.
168    pub fn after_agent(&self) -> Option<&AfterAgentCallback> {
169        self.config.after_agent.as_ref()
170    }
171
172    /// Get the before_model callback if set.
173    pub fn before_model(&self) -> Option<&BeforeModelCallback> {
174        self.config.before_model.as_ref()
175    }
176
177    /// Get the after_model callback if set.
178    pub fn after_model(&self) -> Option<&AfterModelCallback> {
179        self.config.after_model.as_ref()
180    }
181
182    /// Get the on_model_error callback if set.
183    pub fn on_model_error(&self) -> Option<&OnModelErrorCallback> {
184        self.config.on_model_error.as_ref()
185    }
186
187    /// Get the before_tool callback if set.
188    pub fn before_tool(&self) -> Option<&BeforeToolCallback> {
189        self.config.before_tool.as_ref()
190    }
191
192    /// Get the after_tool callback if set.
193    pub fn after_tool(&self) -> Option<&AfterToolCallback> {
194        self.config.after_tool.as_ref()
195    }
196
197    /// Get the on_tool_error callback if set.
198    pub fn on_tool_error(&self) -> Option<&OnToolErrorCallback> {
199        self.config.on_tool_error.as_ref()
200    }
201
202    /// Close the plugin, running cleanup if configured.
203    pub async fn close(&self) {
204        if let Some(ref close_fn) = self.config.close_fn {
205            close_fn().await;
206        }
207    }
208}
209
210impl std::fmt::Debug for Plugin {
211    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
212        f.debug_struct("Plugin")
213            .field("name", &self.config.name)
214            .field("has_on_user_message", &self.config.on_user_message.is_some())
215            .field("has_on_event", &self.config.on_event.is_some())
216            .field("has_before_run", &self.config.before_run.is_some())
217            .field("has_after_run", &self.config.after_run.is_some())
218            .field("has_before_agent", &self.config.before_agent.is_some())
219            .field("has_after_agent", &self.config.after_agent.is_some())
220            .field("has_before_model", &self.config.before_model.is_some())
221            .field("has_after_model", &self.config.after_model.is_some())
222            .field("has_before_tool", &self.config.before_tool.is_some())
223            .field("has_after_tool", &self.config.after_tool.is_some())
224            .finish()
225    }
226}
227
228/// Builder for creating plugins with a fluent API.
229///
230/// # Example
231///
232/// ```rust,ignore
233/// let plugin = PluginBuilder::new("my-plugin")
234///     .on_user_message(|ctx, content| Box::pin(async move { Ok(None) }))
235///     .on_event(|ctx, event| Box::pin(async move { Ok(None) }))
236///     .build();
237/// ```
238pub struct PluginBuilder {
239    config: PluginConfig,
240}
241
242impl PluginBuilder {
243    /// Create a new plugin builder with the given name.
244    pub fn new(name: impl Into<String>) -> Self {
245        Self { config: PluginConfig { name: name.into(), ..Default::default() } }
246    }
247
248    /// Set the on_user_message callback.
249    pub fn on_user_message(mut self, callback: OnUserMessageCallback) -> Self {
250        self.config.on_user_message = Some(callback);
251        self
252    }
253
254    /// Set the on_event callback.
255    pub fn on_event(mut self, callback: OnEventCallback) -> Self {
256        self.config.on_event = Some(callback);
257        self
258    }
259
260    /// Set the before_run callback.
261    pub fn before_run(mut self, callback: BeforeRunCallback) -> Self {
262        self.config.before_run = Some(callback);
263        self
264    }
265
266    /// Set the after_run callback.
267    pub fn after_run(mut self, callback: AfterRunCallback) -> Self {
268        self.config.after_run = Some(callback);
269        self
270    }
271
272    /// Set the before_agent callback.
273    pub fn before_agent(mut self, callback: BeforeAgentCallback) -> Self {
274        self.config.before_agent = Some(callback);
275        self
276    }
277
278    /// Set the after_agent callback.
279    pub fn after_agent(mut self, callback: AfterAgentCallback) -> Self {
280        self.config.after_agent = Some(callback);
281        self
282    }
283
284    /// Set the before_model callback.
285    pub fn before_model(mut self, callback: BeforeModelCallback) -> Self {
286        self.config.before_model = Some(callback);
287        self
288    }
289
290    /// Set the after_model callback.
291    pub fn after_model(mut self, callback: AfterModelCallback) -> Self {
292        self.config.after_model = Some(callback);
293        self
294    }
295
296    /// Set the on_model_error callback.
297    pub fn on_model_error(mut self, callback: OnModelErrorCallback) -> Self {
298        self.config.on_model_error = Some(callback);
299        self
300    }
301
302    /// Set the before_tool callback.
303    pub fn before_tool(mut self, callback: BeforeToolCallback) -> Self {
304        self.config.before_tool = Some(callback);
305        self
306    }
307
308    /// Set the after_tool callback.
309    pub fn after_tool(mut self, callback: AfterToolCallback) -> Self {
310        self.config.after_tool = Some(callback);
311        self
312    }
313
314    /// Set the on_tool_error callback.
315    pub fn on_tool_error(mut self, callback: OnToolErrorCallback) -> Self {
316        self.config.on_tool_error = Some(callback);
317        self
318    }
319
320    /// Set the close function.
321    pub fn close_fn(
322        mut self,
323        f: impl Fn() -> Pin<Box<dyn Future<Output = ()> + Send>> + Send + Sync + 'static,
324    ) -> Self {
325        self.config.close_fn = Some(Box::new(f));
326        self
327    }
328
329    /// Build the plugin.
330    pub fn build(self) -> Plugin {
331        Plugin::new(self.config)
332    }
333}