22. Plugin Development SDK
Chapter 22 of 24 · 20 min
OpenCLaw supports extensibility through plugins. The plugin SDK provides interfaces for extending core functionality while maintaining system stability and security.
Plugin Architecture
Plugins register capabilities during initialization and communicate with the core through defined interfaces.
# plugin_sdk.py
from abc import ABC, abstractmethod
from dataclasses import dataclass
from typing import Dict, Any, List, Optional
import importlib.util
import os
@dataclass
class PluginMetadata:
name: str
version: str
author: str
description: str
dependencies: List[str] = None
class PluginInterface(ABC):
@abstractmethod
def get_metadata(self) -> PluginMetadata:
pass
@abstractmethod
def initialize(self, context: PluginContext) -> bool:
pass
@abstractmethod
def shutdown(self):
pass
class PluginContext:
def __init__(self, core_api: 'CoreAPI'):
self.api = core_api
self.config = {}
self.logger = core_api.get_logger()
class CoreAPI:
def send_message(self, message: str, channel: str = 'default') -> str:
pass
def register_capability(self, plugin_name: str, capability: Capability):
pass
def get_logger(self):
pass
class PluginManager:
def __init__(self, plugin_directory: str, core_api: CoreAPI):
self.directory = plugin_directory
self.api = core_api
self.loaded_plugins: Dict[str, PluginInterface] = {}
def discover_plugins(self) -> List[str]:
plugin_specs = []
for filename in os.listdir(self.directory):
if filename.endswith('.py') and not filename.startswith('_'):
plugin_specs.append(os.path.join(self.directory, filename))
return plugin_specs
def load_plugin(self, plugin_path: str) -> Optional[PluginInterface]:
spec = importlib.util.spec_from_file_location("plugin", plugin_path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
plugin_class = getattr(module, 'Plugin')
plugin_instance = plugin_class()
context = PluginContext(self.api)
if plugin_instance.initialize(context):
metadata = plugin_instance.get_metadata()
self.loaded_plugins[metadata.name] = plugin_instance
return plugin_instance
return None
def unload_plugin(self, plugin_name: str):
plugin = self.loaded_plugins.get(plugin_name)
if plugin:
plugin.shutdown()
del self.loaded_plugins[plugin_name]
Capability Registration
Plugins declare capabilities that integrate with OpenCLaw's processing pipeline.
from enum import Enum
class CapabilityType(Enum):
MESSAGE_PROCESSOR = "message_processor"
CONTEXT_ENHANCER = "context_enhancer"
ACTION_HANDLER = "action_handler"
OUTPUT_FORMATTER = "output_formatter"
@dataclass
class Capability:
name: str
ctype: CapabilityType
priority: int
handler: Any
class MessageProcessorPlugin(PluginInterface):
def process_message(self, message: str, context: Dict) -> Dict:
pass
class CapabilityRegistry:
def __init__(self):
self.capabilities: Dict[CapabilityType, List[Capability]] = {
ct: [] for ct in CapabilityType
}
def register(self, capability: Capability):
self.capabilities[capability.ctype].append(capability)
self.capabilities[capability.ctype].sort(key=lambda c: c.priority)
def get_capabilities(self, ctype: CapabilityType) -> List[Capability]:
return self.capabilities.get(ctype, [])
def unregister(self, capability_name: str):
for capabilities in self.capabilities.values():
capabilities[:] = [c for c in capabilities if c.name != capability_name]
Plugin Security
Plugins execute with elevated access and require sandboxing. The SDK provides capability限制了 that prevent plugins from accessing unauthorized resources.
class PluginSandbox:
def __init__(self):
self.allowed_modules = ['json', 'datetime', 'math', 're']
self.denied_paths = ['/etc', '/root', '/home']
def validate_plugin(self, plugin_code: str) -> bool:
if 'import os' in plugin_code:
return False
if 'subprocess' in plugin_code:
return False
if 'open(' in plugin_code:
return False
return True
EXERCISE
Create a sample plugin that integrates with an external API (weather, news, or calendar). Implement the full plugin lifecycle including initialization, capability registration, message processing, and graceful shutdown.