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}