Plugin System Overview
MoFA implements a dual-layer plugin architecture that combines the performance of compile-time plugins with the flexibility of runtime plugins, enabling extreme extensibility without compromising performance.
Architecture
The plugin system consists of two complementary layers:
┌─────────────────────────────────────────────────────────────┐
│ Business Layer │
│ (Your Agents & Workflows) │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ Runtime Plugin Layer (Rhai) │
│ • Hot-reloadable scripts │
│ • Dynamic business logic │
│ • Workflow orchestration │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ Compile-time Plugin Layer (Rust/WASM) │
│ • LLM integration │
│ • Tool execution │
│ • Storage & memory │
│ • Native system integration │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ MoFA Microkernel │
│ • Plugin lifecycle management │
│ • Communication bus │
│ • Metadata system │
└─────────────────────────────────────────────────────────────┘
Plugin Types
MoFA supports multiple plugin types for different use cases:
LLM Plugins Integrate language models for text generation, chat, and embeddings
Tool Plugins Execute custom tools and function calls from agents
Storage Plugins Provide persistent key-value storage backends
Memory Plugins Manage agent memory and retrieval systems
Monitor Plugins Track metrics, alerts, and observability
Custom Plugins Implement domain-specific functionality
Plugin Lifecycle
All plugins follow a standard lifecycle:
Unloaded
Plugin is registered but not yet loaded into memory
Loading
Plugin is being loaded and configured
Loaded
Plugin is loaded but not yet initialized
Running
Plugin is active and processing requests
Paused
Plugin is temporarily stopped but can be resumed
Unloaded
Plugin is shut down and resources are released
Plugin Manager
The PluginManager coordinates all plugin operations:
use mofa_plugins :: {
PluginManager , LLMPlugin , ToolPlugin , StoragePlugin
};
#[tokio :: main]
async fn main () -> Result <(), Box < dyn std :: error :: Error >> {
// Create plugin manager
let manager = PluginManager :: new ( "my_agent" );
// Register plugins
manager . register ( LLMPlugin :: new ( "llm_001" )) . await ? ;
manager . register ( ToolPlugin :: new ( "tools_001" )) . await ? ;
manager . register ( StoragePlugin :: new ( "storage_001" )) . await ? ;
// Initialize all plugins
manager . load_all () . await ? ;
manager . init_all () . await ? ;
manager . start_all () . await ? ;
// Execute plugin
let result = manager . execute (
"llm_001" ,
"What is the capital of France?" . to_string ()
) . await ? ;
println! ( "Result: {}" , result );
// Cleanup
manager . stop_all () . await ? ;
manager . unload_all () . await ? ;
Ok (())
}
Core Plugin Trait
All plugins implement the AgentPlugin trait:
mofa-kernel/src/plugin/mod.rs
#[async_trait :: async_trait]
pub trait AgentPlugin : Send + Sync {
/// Get plugin metadata
fn metadata ( & self ) -> & PluginMetadata ;
/// Get current plugin state
fn state ( & self ) -> PluginState ;
/// Load plugin with context
async fn load ( & mut self , ctx : & PluginContext ) -> PluginResult <()>;
/// Initialize plugin
async fn init_plugin ( & mut self ) -> PluginResult <()>;
/// Start plugin execution
async fn start ( & mut self ) -> PluginResult <()>;
/// Stop plugin execution
async fn stop ( & mut self ) -> PluginResult <()>;
/// Unload plugin and release resources
async fn unload ( & mut self ) -> PluginResult <()>;
/// Execute plugin with input
async fn execute ( & mut self , input : String ) -> PluginResult < String >;
/// Get plugin statistics
fn stats ( & self ) -> HashMap < String , serde_json :: Value >;
/// Type casting support
fn as_any ( & self ) -> & dyn Any ;
fn as_any_mut ( & mut self ) -> & mut dyn Any ;
fn into_any ( self : Box < Self >) -> Box < dyn Any >;
}
Every plugin has associated metadata:
mofa-kernel/src/plugin/mod.rs
pub struct PluginMetadata {
/// Unique plugin identifier
pub id : String ,
/// Human-readable name
pub name : String ,
/// Plugin type
pub plugin_type : PluginType ,
/// Version string
pub version : String ,
/// Description
pub description : String ,
/// Plugin capabilities
pub capabilities : Vec < String >,
/// Execution priority
pub priority : i32 ,
/// Plugin dependencies
pub dependencies : Vec < String >,
}
impl PluginMetadata {
pub fn new ( id : & str , name : & str , plugin_type : PluginType ) -> Self {
Self {
id : id . to_string (),
name : name . to_string (),
plugin_type ,
version : "1.0.0" . to_string (),
description : String :: new (),
capabilities : Vec :: new (),
priority : 0 ,
dependencies : Vec :: new (),
}
}
pub fn with_description ( mut self , desc : & str ) -> Self {
self . description = desc . to_string ();
self
}
pub fn with_capability ( mut self , capability : & str ) -> Self {
self . capabilities . push ( capability . to_string ());
self
}
}
Plugin Context
Plugins receive a shared context for state and configuration:
use mofa_plugins :: { PluginContext , PluginConfig };
// Create context
let ctx = PluginContext :: new ( "my_agent" );
// Set shared state
ctx . set_state ( "counter" , 42 i32 ) . await ;
ctx . set_state ( "session_id" , "abc123" . to_string ()) . await ;
// Get shared state
let counter : Option < i32 > = ctx . get_state ( "counter" ) . await ;
let session : Option < String > = ctx . get_state ( "session_id" ) . await ;
// Configure plugin
let mut config = PluginConfig :: new ();
config . set ( "timeout" , 30 );
config . set ( "enabled" , true );
config . set ( "api_key" , "sk-..." );
The plugin context is thread-safe and can be shared across plugins for inter-plugin communication.
Health Checks
Monitor plugin health:
// Check all plugins
let health = manager . health_check_all () . await ;
for ( id , healthy ) in & health {
println! ( "Plugin {}: {}" , id ,
if * healthy { "✓ Healthy" } else { "✗ Unhealthy" }
);
}
// Get plugin statistics
let stats = manager . stats ( "llm_001" ) . await ;
if let Some ( stats ) = stats {
println! ( "Call count: {}" , stats [ "call_count" ]);
println! ( "Total tokens: {}" , stats [ "total_tokens" ]);
}
Plugin Discovery
List and filter plugins:
// List all plugins
let plugins = manager . list_plugins () . await ;
for plugin in & plugins {
println! ( "- {} ({}): {}" , plugin . name, plugin . id, plugin . description);
}
// Get plugins by type
let llm_plugins = manager . get_by_type ( PluginType :: LLM ) . await ;
let tool_plugins = manager . get_by_type ( PluginType :: Tool ) . await ;
println! ( "LLM plugins: {:?}" , llm_plugins );
println! ( "Tool plugins: {:?}" , tool_plugins );
Next Steps
Compile-time Plugins Build high-performance Rust/WASM plugins
Runtime Plugins Create flexible Rhai runtime plugins
Rhai Scripting Learn the Rhai scripting language
WASM Plugins Develop sandboxed WebAssembly plugins