fix(plugins): split registry type surface

This commit is contained in:
Vincent Koc
2026-04-09 09:05:11 +01:00
parent 7d6af7e154
commit c87994bc9a
3 changed files with 343 additions and 253 deletions

View File

@@ -1,4 +1,4 @@
import type { PluginRegistry } from "./registry.js";
import type { PluginRegistry } from "./registry-types.js";
export function createEmptyPluginRegistry(): PluginRegistry {
return {

View File

@@ -0,0 +1,289 @@
import type { ChannelPlugin } from "../channels/plugins/types.js";
import type { OperatorScope } from "../gateway/method-scopes.js";
import type { GatewayRequestHandlers } from "../gateway/server-methods/types.js";
import type { HookEntry } from "../hooks/types.js";
import type { PluginActivationSource } from "./config-state.js";
import type { PluginManifestContracts } from "./manifest.js";
import type { MemoryEmbeddingProviderAdapter } from "./memory-embedding-providers.js";
import type { PluginRuntime } from "./runtime/types.js";
import type {
CliBackendPlugin,
ImageGenerationProviderPlugin,
MediaUnderstandingProviderPlugin,
MusicGenerationProviderPlugin,
OpenClawPluginChannelRegistration,
OpenClawPluginCliCommandDescriptor,
OpenClawPluginCliRegistrar,
OpenClawPluginCommandDefinition,
OpenClawPluginHttpRouteAuth,
OpenClawPluginHttpRouteHandler,
OpenClawPluginHttpRouteMatch,
OpenClawPluginReloadRegistration,
OpenClawPluginSecurityAuditCollector,
OpenClawPluginService,
OpenClawPluginToolFactory,
PluginBundleFormat,
PluginConfigUiHint,
PluginConversationBindingResolvedEvent,
PluginDiagnostic,
PluginFormat,
PluginHookRegistration as TypedPluginHookRegistration,
PluginKind,
PluginLogger,
PluginOrigin,
ProviderPlugin,
RealtimeTranscriptionProviderPlugin,
RealtimeVoiceProviderPlugin,
SpeechProviderPlugin,
VideoGenerationProviderPlugin,
WebFetchProviderPlugin,
WebSearchProviderPlugin,
} from "./types.js";
export type PluginToolRegistration = {
pluginId: string;
pluginName?: string;
factory: OpenClawPluginToolFactory;
names: string[];
optional: boolean;
source: string;
rootDir?: string;
};
export type PluginCliRegistration = {
pluginId: string;
pluginName?: string;
register: OpenClawPluginCliRegistrar;
commands: string[];
descriptors: OpenClawPluginCliCommandDescriptor[];
source: string;
rootDir?: string;
};
export type PluginHttpRouteRegistration = {
pluginId?: string;
path: string;
handler: OpenClawPluginHttpRouteHandler;
auth: OpenClawPluginHttpRouteAuth;
match: OpenClawPluginHttpRouteMatch;
source?: string;
};
export type PluginChannelRegistration = {
pluginId: string;
pluginName?: string;
plugin: ChannelPlugin;
source: string;
rootDir?: string;
};
export type PluginChannelSetupRegistration = {
pluginId: string;
pluginName?: string;
plugin: ChannelPlugin;
source: string;
enabled: boolean;
rootDir?: string;
};
export type PluginProviderRegistration = {
pluginId: string;
pluginName?: string;
provider: ProviderPlugin;
source: string;
rootDir?: string;
};
export type PluginCliBackendRegistration = {
pluginId: string;
pluginName?: string;
backend: CliBackendPlugin;
source: string;
rootDir?: string;
};
type PluginOwnedProviderRegistration<T extends { id: string }> = {
pluginId: string;
pluginName?: string;
provider: T;
source: string;
rootDir?: string;
};
export type PluginSpeechProviderRegistration =
PluginOwnedProviderRegistration<SpeechProviderPlugin>;
export type PluginRealtimeTranscriptionProviderRegistration =
PluginOwnedProviderRegistration<RealtimeTranscriptionProviderPlugin>;
export type PluginRealtimeVoiceProviderRegistration =
PluginOwnedProviderRegistration<RealtimeVoiceProviderPlugin>;
export type PluginMediaUnderstandingProviderRegistration =
PluginOwnedProviderRegistration<MediaUnderstandingProviderPlugin>;
export type PluginImageGenerationProviderRegistration =
PluginOwnedProviderRegistration<ImageGenerationProviderPlugin>;
export type PluginVideoGenerationProviderRegistration =
PluginOwnedProviderRegistration<VideoGenerationProviderPlugin>;
export type PluginMusicGenerationProviderRegistration =
PluginOwnedProviderRegistration<MusicGenerationProviderPlugin>;
export type PluginWebFetchProviderRegistration =
PluginOwnedProviderRegistration<WebFetchProviderPlugin>;
export type PluginWebSearchProviderRegistration =
PluginOwnedProviderRegistration<WebSearchProviderPlugin>;
export type PluginMemoryEmbeddingProviderRegistration =
PluginOwnedProviderRegistration<MemoryEmbeddingProviderAdapter>;
export type PluginHookRegistration = {
pluginId: string;
entry: HookEntry;
events: string[];
source: string;
rootDir?: string;
};
export type PluginServiceRegistration = {
pluginId: string;
pluginName?: string;
service: OpenClawPluginService;
source: string;
rootDir?: string;
};
export type PluginReloadRegistration = {
pluginId: string;
pluginName?: string;
registration: OpenClawPluginReloadRegistration;
source: string;
rootDir?: string;
};
export type PluginNodeHostCommandRegistration = {
pluginId: string;
pluginName?: string;
command: import("./types.js").OpenClawPluginNodeHostCommand;
source: string;
rootDir?: string;
};
export type PluginSecurityAuditCollectorRegistration = {
pluginId: string;
pluginName?: string;
collector: OpenClawPluginSecurityAuditCollector;
source: string;
rootDir?: string;
};
export type PluginCommandRegistration = {
pluginId: string;
pluginName?: string;
command: OpenClawPluginCommandDefinition;
source: string;
rootDir?: string;
};
export type PluginConversationBindingResolvedHandlerRegistration = {
pluginId: string;
pluginName?: string;
pluginRoot?: string;
handler: (event: PluginConversationBindingResolvedEvent) => void | Promise<void>;
source: string;
rootDir?: string;
};
export type PluginRecord = {
id: string;
name: string;
version?: string;
description?: string;
format?: PluginFormat;
bundleFormat?: PluginBundleFormat;
bundleCapabilities?: string[];
kind?: PluginKind | PluginKind[];
source: string;
rootDir?: string;
origin: PluginOrigin;
workspaceDir?: string;
enabled: boolean;
explicitlyEnabled?: boolean;
activated?: boolean;
imported?: boolean;
activationSource?: PluginActivationSource;
activationReason?: string;
status: "loaded" | "disabled" | "error";
error?: string;
failedAt?: Date;
failurePhase?: "validation" | "load" | "register";
toolNames: string[];
hookNames: string[];
channelIds: string[];
cliBackendIds: string[];
providerIds: string[];
speechProviderIds: string[];
realtimeTranscriptionProviderIds: string[];
realtimeVoiceProviderIds: string[];
mediaUnderstandingProviderIds: string[];
imageGenerationProviderIds: string[];
videoGenerationProviderIds: string[];
musicGenerationProviderIds: string[];
webFetchProviderIds: string[];
webSearchProviderIds: string[];
memoryEmbeddingProviderIds: string[];
gatewayMethods: string[];
cliCommands: string[];
services: string[];
commands: string[];
httpRoutes: number;
hookCount: number;
configSchema: boolean;
configUiHints?: Record<string, PluginConfigUiHint>;
configJsonSchema?: Record<string, unknown>;
contracts?: PluginManifestContracts;
memorySlotSelected?: boolean;
};
export type PluginRegistry = {
plugins: PluginRecord[];
tools: PluginToolRegistration[];
hooks: PluginHookRegistration[];
typedHooks: TypedPluginHookRegistration[];
channels: PluginChannelRegistration[];
channelSetups: PluginChannelSetupRegistration[];
providers: PluginProviderRegistration[];
cliBackends?: PluginCliBackendRegistration[];
speechProviders: PluginSpeechProviderRegistration[];
realtimeTranscriptionProviders: PluginRealtimeTranscriptionProviderRegistration[];
realtimeVoiceProviders: PluginRealtimeVoiceProviderRegistration[];
mediaUnderstandingProviders: PluginMediaUnderstandingProviderRegistration[];
imageGenerationProviders: PluginImageGenerationProviderRegistration[];
videoGenerationProviders: PluginVideoGenerationProviderRegistration[];
musicGenerationProviders: PluginMusicGenerationProviderRegistration[];
webFetchProviders: PluginWebFetchProviderRegistration[];
webSearchProviders: PluginWebSearchProviderRegistration[];
memoryEmbeddingProviders: PluginMemoryEmbeddingProviderRegistration[];
gatewayHandlers: GatewayRequestHandlers;
gatewayMethodScopes?: Partial<Record<string, OperatorScope>>;
httpRoutes: PluginHttpRouteRegistration[];
cliRegistrars: PluginCliRegistration[];
reloads?: PluginReloadRegistration[];
nodeHostCommands?: PluginNodeHostCommandRegistration[];
securityAuditCollectors?: PluginSecurityAuditCollectorRegistration[];
services: PluginServiceRegistration[];
commands: PluginCommandRegistration[];
conversationBindingResolvedHandlers: PluginConversationBindingResolvedHandlerRegistration[];
diagnostics: PluginDiagnostic[];
};
export type PluginRegistryParams = {
logger: PluginLogger;
coreGatewayHandlers?: GatewayRequestHandlers;
runtime: PluginRuntime;
activateGlobalSideEffects?: boolean;
};
export type PluginRegistrationMode = import("./types.js").PluginRegistrationMode;
export type OpenClawPluginNodeHostCommand = import("./types.js").OpenClawPluginNodeHostCommand;
export type OpenClawPluginToolContext = import("./types.js").OpenClawPluginToolContext;
export type OpenClawPluginHttpRouteParams = import("./types.js").OpenClawPluginHttpRouteParams;
export type OpenClawPluginHookOptions = import("./types.js").OpenClawPluginHookOptions;
export type PluginHookHandlerMap = import("./types.js").PluginHookHandlerMap;
export type OpenClawPluginApi = import("./types.js").OpenClawPluginApi;
export type TypedPluginHook = TypedPluginHookRegistration;
export type OpenClawPluginChannelReg = OpenClawPluginChannelRegistration;

View File

@@ -3,10 +3,7 @@ import type { AnyAgentTool } from "../agents/tools/common.js";
import type { ChannelPlugin } from "../channels/plugins/types.js";
import { registerContextEngineForOwner } from "../context-engine/registry.js";
import type { OperatorScope } from "../gateway/method-scopes.js";
import type {
GatewayRequestHandler,
GatewayRequestHandlers,
} from "../gateway/server-methods/types.js";
import type { GatewayRequestHandler } from "../gateway/server-methods/types.js";
import { registerInternalHook } from "../hooks/internal-hooks.js";
import type { HookEntry } from "../hooks/types.js";
import {
@@ -26,14 +23,11 @@ import {
getRegisteredCompactionProvider,
registerCompactionProvider,
} from "./compaction-provider.js";
import type { PluginActivationSource } from "./config-state.js";
import { normalizePluginHttpPath } from "./http-path.js";
import { findOverlappingPluginHttpRoute } from "./http-route-overlap.js";
import { registerPluginInteractiveHandler } from "./interactive-registry.js";
import type { PluginManifestContracts } from "./manifest.js";
import {
getRegisteredMemoryEmbeddingProvider,
type MemoryEmbeddingProviderAdapter,
registerMemoryEmbeddingProvider,
} from "./memory-embedding-providers.js";
import {
@@ -46,6 +40,23 @@ import {
} from "./memory-state.js";
import { normalizeRegisteredProvider } from "./provider-validation.js";
import { createEmptyPluginRegistry } from "./registry-empty.js";
import type {
PluginCliBackendRegistration,
PluginCliRegistration,
PluginCommandRegistration,
PluginConversationBindingResolvedHandlerRegistration,
PluginHookRegistration,
PluginHttpRouteRegistration,
PluginMemoryEmbeddingProviderRegistration,
PluginNodeHostCommandRegistration,
PluginProviderRegistration,
PluginRecord,
PluginRegistry,
PluginRegistryParams,
PluginReloadRegistration,
PluginSecurityAuditCollectorRegistration,
PluginServiceRegistration,
} from "./registry-types.js";
import { withPluginRuntimePluginIdScope } from "./runtime/gateway-request-scope.js";
import type { PluginRuntime } from "./runtime/types.js";
import { defaultSlotIdForKey, hasKind } from "./slots.js";
@@ -58,106 +69,36 @@ import type {
CliBackendPlugin,
ImageGenerationProviderPlugin,
MusicGenerationProviderPlugin,
RealtimeTranscriptionProviderPlugin,
OpenClawPluginApi,
OpenClawPluginChannelRegistration,
OpenClawPluginCliCommandDescriptor,
OpenClawPluginCliRegistrar,
OpenClawPluginCommandDefinition,
PluginConversationBindingResolvedEvent,
OpenClawPluginHttpRouteAuth,
OpenClawPluginHttpRouteMatch,
OpenClawPluginHttpRouteHandler,
OpenClawPluginHttpRouteParams,
OpenClawPluginHookOptions,
OpenClawPluginNodeHostCommand,
OpenClawPluginReloadRegistration,
OpenClawPluginSecurityAuditCollector,
MediaUnderstandingProviderPlugin,
ProviderPlugin,
RealtimeVoiceProviderPlugin,
OpenClawPluginService,
OpenClawPluginToolContext,
OpenClawPluginToolFactory,
PluginConfigUiHint,
PluginDiagnostic,
PluginBundleFormat,
PluginFormat,
PluginLogger,
PluginOrigin,
PluginKind,
PluginRegistrationMode,
PluginHookName,
PluginHookHandlerMap,
PluginHookName,
PluginHookRegistration as TypedPluginHookRegistration,
PluginLogger,
PluginRegistrationMode,
ProviderPlugin,
RealtimeTranscriptionProviderPlugin,
RealtimeVoiceProviderPlugin,
SpeechProviderPlugin,
VideoGenerationProviderPlugin,
WebFetchProviderPlugin,
WebSearchProviderPlugin,
} from "./types.js";
export type PluginToolRegistration = {
pluginId: string;
pluginName?: string;
factory: OpenClawPluginToolFactory;
names: string[];
optional: boolean;
source: string;
rootDir?: string;
};
export type PluginCliRegistration = {
pluginId: string;
pluginName?: string;
register: OpenClawPluginCliRegistrar;
commands: string[];
descriptors: OpenClawPluginCliCommandDescriptor[];
source: string;
rootDir?: string;
};
export type PluginHttpRouteRegistration = {
pluginId?: string;
path: string;
handler: OpenClawPluginHttpRouteHandler;
auth: OpenClawPluginHttpRouteAuth;
match: OpenClawPluginHttpRouteMatch;
source?: string;
};
export type PluginChannelRegistration = {
pluginId: string;
pluginName?: string;
plugin: ChannelPlugin;
source: string;
rootDir?: string;
};
export type PluginChannelSetupRegistration = {
pluginId: string;
pluginName?: string;
plugin: ChannelPlugin;
source: string;
enabled: boolean;
rootDir?: string;
};
export type PluginProviderRegistration = {
pluginId: string;
pluginName?: string;
provider: ProviderPlugin;
source: string;
rootDir?: string;
};
export type PluginCliBackendRegistration = {
pluginId: string;
pluginName?: string;
backend: CliBackendPlugin;
source: string;
rootDir?: string;
};
type PluginOwnedProviderRegistration<T extends { id: string }> = {
pluginId: string;
pluginName?: string;
@@ -166,175 +107,35 @@ type PluginOwnedProviderRegistration<T extends { id: string }> = {
rootDir?: string;
};
export type PluginSpeechProviderRegistration =
PluginOwnedProviderRegistration<SpeechProviderPlugin>;
export type PluginRealtimeTranscriptionProviderRegistration =
PluginOwnedProviderRegistration<RealtimeTranscriptionProviderPlugin>;
export type PluginRealtimeVoiceProviderRegistration =
PluginOwnedProviderRegistration<RealtimeVoiceProviderPlugin>;
export type PluginMediaUnderstandingProviderRegistration =
PluginOwnedProviderRegistration<MediaUnderstandingProviderPlugin>;
export type PluginImageGenerationProviderRegistration =
PluginOwnedProviderRegistration<ImageGenerationProviderPlugin>;
export type PluginVideoGenerationProviderRegistration =
PluginOwnedProviderRegistration<VideoGenerationProviderPlugin>;
export type PluginMusicGenerationProviderRegistration =
PluginOwnedProviderRegistration<MusicGenerationProviderPlugin>;
export type PluginWebFetchProviderRegistration =
PluginOwnedProviderRegistration<WebFetchProviderPlugin>;
export type PluginWebSearchProviderRegistration =
PluginOwnedProviderRegistration<WebSearchProviderPlugin>;
export type PluginMemoryEmbeddingProviderRegistration =
PluginOwnedProviderRegistration<MemoryEmbeddingProviderAdapter>;
export type PluginHookRegistration = {
pluginId: string;
entry: HookEntry;
events: string[];
source: string;
rootDir?: string;
};
export type PluginServiceRegistration = {
pluginId: string;
pluginName?: string;
service: OpenClawPluginService;
source: string;
rootDir?: string;
};
export type PluginReloadRegistration = {
pluginId: string;
pluginName?: string;
registration: OpenClawPluginReloadRegistration;
source: string;
rootDir?: string;
};
export type PluginNodeHostCommandRegistration = {
pluginId: string;
pluginName?: string;
command: OpenClawPluginNodeHostCommand;
source: string;
rootDir?: string;
};
export type PluginSecurityAuditCollectorRegistration = {
pluginId: string;
pluginName?: string;
collector: OpenClawPluginSecurityAuditCollector;
source: string;
rootDir?: string;
};
export type PluginCommandRegistration = {
pluginId: string;
pluginName?: string;
command: OpenClawPluginCommandDefinition;
source: string;
rootDir?: string;
};
export type PluginConversationBindingResolvedHandlerRegistration = {
pluginId: string;
pluginName?: string;
pluginRoot?: string;
handler: (event: PluginConversationBindingResolvedEvent) => void | Promise<void>;
source: string;
rootDir?: string;
};
export type PluginRecord = {
id: string;
name: string;
version?: string;
description?: string;
format?: PluginFormat;
bundleFormat?: PluginBundleFormat;
bundleCapabilities?: string[];
kind?: PluginKind | PluginKind[];
source: string;
rootDir?: string;
origin: PluginOrigin;
workspaceDir?: string;
enabled: boolean;
explicitlyEnabled?: boolean;
activated?: boolean;
imported?: boolean;
activationSource?: PluginActivationSource;
activationReason?: string;
status: "loaded" | "disabled" | "error";
error?: string;
failedAt?: Date;
failurePhase?: "validation" | "load" | "register";
toolNames: string[];
hookNames: string[];
channelIds: string[];
cliBackendIds: string[];
providerIds: string[];
speechProviderIds: string[];
realtimeTranscriptionProviderIds: string[];
realtimeVoiceProviderIds: string[];
mediaUnderstandingProviderIds: string[];
imageGenerationProviderIds: string[];
videoGenerationProviderIds: string[];
musicGenerationProviderIds: string[];
webFetchProviderIds: string[];
webSearchProviderIds: string[];
memoryEmbeddingProviderIds: string[];
gatewayMethods: string[];
cliCommands: string[];
services: string[];
commands: string[];
httpRoutes: number;
hookCount: number;
configSchema: boolean;
configUiHints?: Record<string, PluginConfigUiHint>;
configJsonSchema?: Record<string, unknown>;
contracts?: PluginManifestContracts;
memorySlotSelected?: boolean;
};
export type PluginRegistry = {
plugins: PluginRecord[];
tools: PluginToolRegistration[];
hooks: PluginHookRegistration[];
typedHooks: TypedPluginHookRegistration[];
channels: PluginChannelRegistration[];
channelSetups: PluginChannelSetupRegistration[];
providers: PluginProviderRegistration[];
cliBackends?: PluginCliBackendRegistration[];
speechProviders: PluginSpeechProviderRegistration[];
realtimeTranscriptionProviders: PluginRealtimeTranscriptionProviderRegistration[];
realtimeVoiceProviders: PluginRealtimeVoiceProviderRegistration[];
mediaUnderstandingProviders: PluginMediaUnderstandingProviderRegistration[];
imageGenerationProviders: PluginImageGenerationProviderRegistration[];
videoGenerationProviders: PluginVideoGenerationProviderRegistration[];
musicGenerationProviders: PluginMusicGenerationProviderRegistration[];
webFetchProviders: PluginWebFetchProviderRegistration[];
webSearchProviders: PluginWebSearchProviderRegistration[];
memoryEmbeddingProviders: PluginMemoryEmbeddingProviderRegistration[];
gatewayHandlers: GatewayRequestHandlers;
gatewayMethodScopes?: Partial<Record<string, OperatorScope>>;
httpRoutes: PluginHttpRouteRegistration[];
cliRegistrars: PluginCliRegistration[];
reloads?: PluginReloadRegistration[];
nodeHostCommands?: PluginNodeHostCommandRegistration[];
securityAuditCollectors?: PluginSecurityAuditCollectorRegistration[];
services: PluginServiceRegistration[];
commands: PluginCommandRegistration[];
conversationBindingResolvedHandlers: PluginConversationBindingResolvedHandlerRegistration[];
diagnostics: PluginDiagnostic[];
};
export type PluginRegistryParams = {
logger: PluginLogger;
coreGatewayHandlers?: GatewayRequestHandlers;
runtime: PluginRuntime;
// When false, keep registration local to the returned registry and avoid mutating
// process-global command/hook state during non-activating snapshot loads.
activateGlobalSideEffects?: boolean;
};
export type {
PluginChannelRegistration,
PluginChannelSetupRegistration,
PluginCliBackendRegistration,
PluginCliRegistration,
PluginCommandRegistration,
PluginConversationBindingResolvedHandlerRegistration,
PluginHookRegistration,
PluginHttpRouteRegistration,
PluginMemoryEmbeddingProviderRegistration,
PluginNodeHostCommandRegistration,
PluginProviderRegistration,
PluginRecord,
PluginRegistry,
PluginRegistryParams,
PluginReloadRegistration,
PluginSecurityAuditCollectorRegistration,
PluginServiceRegistration,
PluginToolRegistration,
PluginSpeechProviderRegistration,
PluginRealtimeTranscriptionProviderRegistration,
PluginRealtimeVoiceProviderRegistration,
PluginMediaUnderstandingProviderRegistration,
PluginImageGenerationProviderRegistration,
PluginVideoGenerationProviderRegistration,
PluginMusicGenerationProviderRegistration,
PluginWebFetchProviderRegistration,
PluginWebSearchProviderRegistration,
} from "./registry-types.js";
type PluginTypedHookPolicy = {
allowPromptInjection?: boolean;