Skip to main content

saorsa_agent/extension/
mod.rs

1//! Extension system for saorsa-agent.
2//!
3//! The extension system allows dynamically loading plugins that can:
4//! - Register custom tools, commands, and keybindings
5//! - Add custom UI widgets and overlays
6//! - Hook into agent lifecycle events (tool calls, messages, turns)
7//!
8//! Extensions are trait-based and use dynamic dispatch, allowing for future
9//! WASM-backed implementations without adding heavy dependencies now.
10
11pub mod command_registry;
12pub mod keybinding_registry;
13pub mod package_manager;
14pub mod registry;
15#[cfg(test)]
16mod tests;
17pub mod tool_registry;
18pub mod widget_registry;
19
20use crate::error::Result;
21
22pub use command_registry::{CommandDefinition, CommandHandler, CommandRegistry};
23pub use keybinding_registry::{KeybindingDefinition, KeybindingHandler, KeybindingRegistry};
24pub use package_manager::{ExtensionPackage, PackageManager};
25pub use registry::{ExtensionRegistry, SharedExtensionRegistry, shared_registry};
26pub use tool_registry::{ToolDefinition, ToolHandler, ToolParameter, ToolRegistry};
27pub use widget_registry::{OverlayConfig, WidgetFactory, WidgetRegistry};
28
29/// Extension trait defining the lifecycle and capabilities of a plugin.
30///
31/// Extensions can hook into agent events and provide custom functionality
32/// without modifying the core agent runtime.
33pub trait Extension: Send + Sync {
34    /// Returns the unique name of this extension.
35    fn name(&self) -> &str;
36
37    /// Returns the semantic version of this extension.
38    fn version(&self) -> &str;
39
40    /// Called when the extension is loaded into the runtime.
41    ///
42    /// Use this to initialize resources, register tools/commands, etc.
43    fn on_load(&mut self) -> Result<()> {
44        Ok(())
45    }
46
47    /// Called when the extension is unloaded from the runtime.
48    ///
49    /// Use this to clean up resources, unregister handlers, etc.
50    fn on_unload(&mut self) -> Result<()> {
51        Ok(())
52    }
53
54    /// Called when a tool is invoked by the agent.
55    ///
56    /// Return `Some(output)` to intercept and handle the tool call,
57    /// or `None` to allow normal processing.
58    fn on_tool_call(&mut self, _tool: &str, _args: &str) -> Result<Option<String>> {
59        Ok(None)
60    }
61
62    /// Called when a message is received by the agent.
63    ///
64    /// Return `Some(response)` to intercept and handle the message,
65    /// or `None` to allow normal processing.
66    fn on_message(&mut self, _message: &str) -> Result<Option<String>> {
67        Ok(None)
68    }
69
70    /// Called at the start of each agent turn.
71    fn on_turn_start(&mut self) -> Result<()> {
72        Ok(())
73    }
74
75    /// Called at the end of each agent turn.
76    fn on_turn_end(&mut self) -> Result<()> {
77        Ok(())
78    }
79}
80
81/// Metadata describing an extension.
82#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
83pub struct ExtensionMetadata {
84    /// Unique extension name.
85    pub name: String,
86    /// Semantic version.
87    pub version: String,
88    /// Human-readable description.
89    pub description: String,
90    /// Author name or organization.
91    pub author: String,
92}
93
94impl ExtensionMetadata {
95    /// Creates new extension metadata.
96    pub fn new(name: String, version: String, description: String, author: String) -> Self {
97        Self {
98            name,
99            version,
100            description,
101            author,
102        }
103    }
104}