Include Luna AI Assistant design docs covering channels, configuration, core architecture, memory, scheduler, and skills. Add reference docs from OpenClaw and ZeroClaw projects, plus Mistral and OpenAI API specs.
6.2 KiB
Plugin Architecture
OpenClaw employs a multi-tiered plugin architecture designed for high extensibility across model providers, messaging channels, and agent capabilities. The system is built on a massive type system that allows plugins to hook into almost every stage of the AI lifecycle, from initial message receipt to final inference and tool execution.
Plugin Type System
The core of the architecture is defined in src/plugins/types.ts. It provides a unified contract for different plugin flavors: ProviderPlugin, WebSearchProviderPlugin, SpeechProviderPlugin, and the general OpenClawPluginDefinition.
Provider Plugin Hooks
The ProviderPlugin is the most complex type, featuring over 40 hooks for deep integration with LLM providers. These are categorized into distinct functional areas:
- Catalog & Discovery: Hooks like
catalogandaugmentModelCatalogallow plugins to publish model definitions dynamically. - Auth & Credentials:
prepareRuntimeAuthandresolveSyntheticAuthhandle the exchange of source credentials for runtime tokens. - Model Resolution:
resolveDynamicModelandnormalizeResolvedModelprovide last-mile control over how model IDs are mapped to API endpoints. - Streaming & Transport:
createStreamFnandwrapStreamFnallow plugins to replace or wrap the default transport layer with provider-specific logic. - Usage & Billing:
resolveUsageAuthandfetchUsageSnapshotenable integrated quota tracking.
export type ProviderPlugin = {
id: string;
label: string;
auth: ProviderAuthMethod[];
catalog?: ProviderPluginCatalog;
resolveDynamicModel?: (ctx: ProviderResolveDynamicModelContext) => ProviderRuntimeModel | null | undefined;
prepareRuntimeAuth?: (ctx: ProviderPrepareRuntimeAuthContext) => Promise<ProviderPreparedRuntimeAuth | null | undefined>;
createStreamFn?: (ctx: ProviderCreateStreamFnContext) => StreamFn | null | undefined;
fetchUsageSnapshot?: (ctx: ProviderFetchUsageSnapshotContext) => Promise<ProviderUsageSnapshot | null | undefined>;
// ... and 30+ more hooks
};
Tool Factories
Plugins expose agent-level capabilities through OpenClawPluginToolFactory. This pattern allows tools to be instantiated with a trusted execution context that includes workspace paths, session identifiers, and security boundaries.
export type OpenClawPluginToolContext = {
config?: OpenClawConfig;
workspaceDir?: string;
agentId?: string;
sessionId?: string;
deliveryContext?: DeliveryContext;
senderIsOwner?: boolean;
};
export type OpenClawPluginToolFactory = (
ctx: OpenClawPluginToolContext,
) => AnyAgentTool | AnyAgentTool[] | null | undefined;
Config Schema
Plugins declare their configuration requirements using a Zod-like validation system. The OpenClawPluginConfigSchema allows the host to validate plugin settings, generate UI forms, and provide help text without loading the plugin's full implementation.
export type OpenClawPluginConfigSchema = {
safeParse?: (value: unknown) => {
success: boolean;
data?: unknown;
error?: { issues?: Array<{ path: Array<string | number>; message: string }> };
};
uiHints?: Record<string, PluginConfigUiHint>;
jsonSchema?: Record<string, unknown>;
};
Channel Handlers
Interactive platform support (Telegram, Discord, Slack) is handled via specialized interactive handlers. These allow plugins to respond to platform-specific events like button clicks or modal submissions through a unified context.
export type PluginInteractiveTelegramHandlerContext = {
channel: "telegram";
callback: { data: string; namespace: string; payload: string };
respond: {
reply: (params: { text: string; buttons?: PluginInteractiveButtons }) => Promise<void>;
editMessage: (params: { text: string; buttons?: PluginInteractiveButtons }) => Promise<void>;
};
};
Conversation Bindings
Plugins can request "Conversation Bindings" to take over the message flow for a specific thread or user. This is used for interactive wizards or stateful interactions that bypass the general LLM dispatcher.
requestConversationBinding: Attaches a plugin to the current conversation.detachConversationBinding: Releases the conversation back to the general agent.getCurrentConversationBinding: Checks if the conversation is currently owned by a plugin.
Plugin Lifecycle
The lifecycle is managed through several stages, primarily defined in the OpenClawPluginApi provided during registration:
- Discovery: Plugins are found in
bundled,global, orworkspacedirectories. - Registration:
register(api)is called. The plugin registers its tools, hooks, and services. - Activation:
activate(api)is called when the plugin is enabled and ready for service. - Runtime: The plugin responds to lifecycle hooks such as
before_agent_start,llm_input, andagent_end. - Uninstallation: Managed via the
ClawHubregistry or local file deletion.
Specialized Plugin Types
Web Search Providers
WebSearchProviderPlugin defines how the agent interacts with search engines. It requires specific credential resolution logic and a createTool factory that returns a standardized search tool definition.
Speech Providers
SpeechProviderPlugin handles text-to-speech (TTS) capabilities. It includes hooks for voice listing, directive parsing (e.g., for custom SSML or tokens), and synthesis for both standard and telephony audio formats.
Relevance to Luna
While Luna does not require the full overhead of OpenClaw's provider ecosystem, it can adopt several key patterns:
- Manifest-Based Registration: Luna could use a simplified version of
OpenClawPluginDefinitionto allow for Skills that declare their dependencies and config schemas upfront. - Hook Interceptors: Adopting the
before_prompt_buildandllm_outputhook patterns would allow Luna's Core to support middleware for logging, safety filtering, or memory injection. - Trusted Contexts: Passing a
ToolContextsimilar to OpenClaw's would ensure that Luna's tools have consistent access to session and workspace state without relying on global variables.