Files
openclaw/src/gateway/server-startup-plugins.ts
2026-05-03 18:04:50 +01:00

175 lines
6.5 KiB
TypeScript

import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agents/agent-scope.js";
import { initSubagentRegistry } from "../agents/subagent-registry.js";
import { applyPluginAutoEnable } from "../config/plugin-auto-enable.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { loadPluginLookUpTable } from "../plugins/plugin-lookup-table.js";
import type { PluginMetadataSnapshot } from "../plugins/plugin-metadata-snapshot.js";
import { createEmptyPluginRegistry } from "../plugins/registry.js";
import { getActivePluginRegistry, setActivePluginRegistry } from "../plugins/runtime.js";
import { mergeActivationSectionsIntoRuntimeConfig } from "./plugin-activation-runtime-config.js";
import { listGatewayMethods } from "./server-methods-list.js";
type GatewayPluginBootstrapLog = {
info: (message: string) => void;
warn: (message: string) => void;
error: (message: string) => void;
debug: (message: string) => void;
};
type GatewayStartupTrace = {
detail: (name: string, metrics: ReadonlyArray<readonly [string, number | string]>) => void;
};
export function resolveGatewayStartupMaintenanceConfig(params: {
cfgAtStart: OpenClawConfig;
startupRuntimeConfig: OpenClawConfig;
}): OpenClawConfig {
return params.cfgAtStart.channels === undefined &&
params.startupRuntimeConfig.channels !== undefined
? {
...params.cfgAtStart,
channels: params.startupRuntimeConfig.channels,
}
: params.cfgAtStart;
}
export async function prepareGatewayPluginBootstrap(params: {
cfgAtStart: OpenClawConfig;
activationSourceConfig?: OpenClawConfig;
startupRuntimeConfig: OpenClawConfig;
pluginMetadataSnapshot?: PluginMetadataSnapshot;
minimalTestGateway: boolean;
log: GatewayPluginBootstrapLog;
loadRuntimePlugins?: boolean;
}) {
const activationSourceConfig = params.activationSourceConfig ?? params.cfgAtStart;
const startupMaintenanceConfig = resolveGatewayStartupMaintenanceConfig({
cfgAtStart: params.cfgAtStart,
startupRuntimeConfig: params.startupRuntimeConfig,
});
const shouldRunStartupMaintenance =
!params.minimalTestGateway || startupMaintenanceConfig.channels !== undefined;
if (shouldRunStartupMaintenance) {
const { runChannelPluginStartupMaintenance } =
await import("../channels/plugins/lifecycle-startup.js");
const startupTasks = [
runChannelPluginStartupMaintenance({
cfg: startupMaintenanceConfig,
env: process.env,
log: params.log,
}),
];
if (!params.minimalTestGateway) {
const { runStartupSessionMigration } = await import("./server-startup-session-migration.js");
startupTasks.push(
runStartupSessionMigration({
cfg: params.cfgAtStart,
env: process.env,
log: params.log,
}),
);
}
await Promise.all(startupTasks);
}
initSubagentRegistry();
const gatewayPluginConfig = params.minimalTestGateway
? params.cfgAtStart
: mergeActivationSectionsIntoRuntimeConfig({
runtimeConfig: params.cfgAtStart,
activationConfig: applyPluginAutoEnable({
config: activationSourceConfig,
env: process.env,
...(params.pluginMetadataSnapshot?.manifestRegistry
? { manifestRegistry: params.pluginMetadataSnapshot.manifestRegistry }
: {}),
}).config,
});
const pluginsGloballyDisabled = gatewayPluginConfig.plugins?.enabled === false;
const defaultAgentId = resolveDefaultAgentId(gatewayPluginConfig);
const defaultWorkspaceDir = resolveAgentWorkspaceDir(gatewayPluginConfig, defaultAgentId);
const pluginLookUpTable =
params.minimalTestGateway || pluginsGloballyDisabled
? undefined
: loadPluginLookUpTable({
config: gatewayPluginConfig,
workspaceDir: defaultWorkspaceDir,
env: process.env,
activationSourceConfig,
metadataSnapshot: params.pluginMetadataSnapshot,
});
const deferredConfiguredChannelPluginIds = [
...(pluginLookUpTable?.startup.configuredDeferredChannelPluginIds ?? []),
];
const startupPluginIds = [...(pluginLookUpTable?.startup.pluginIds ?? [])];
const baseMethods = listGatewayMethods();
const emptyPluginRegistry = createEmptyPluginRegistry();
let pluginRegistry = emptyPluginRegistry;
let baseGatewayMethods = baseMethods;
const shouldLoadRuntimePlugins = params.loadRuntimePlugins !== false;
if (!params.minimalTestGateway && shouldLoadRuntimePlugins) {
({ pluginRegistry, gatewayMethods: baseGatewayMethods } = await loadGatewayStartupPluginRuntime(
{
cfg: gatewayPluginConfig,
activationSourceConfig,
workspaceDir: defaultWorkspaceDir,
log: params.log,
baseMethods,
startupPluginIds,
pluginLookUpTable,
preferSetupRuntimeForChannelPlugins: deferredConfiguredChannelPluginIds.length > 0,
suppressPluginInfoLogs: deferredConfiguredChannelPluginIds.length > 0,
},
));
} else {
pluginRegistry = params.minimalTestGateway
? (getActivePluginRegistry() ?? emptyPluginRegistry)
: emptyPluginRegistry;
setActivePluginRegistry(pluginRegistry);
}
return {
gatewayPluginConfigAtStart: gatewayPluginConfig,
defaultWorkspaceDir,
deferredConfiguredChannelPluginIds,
startupPluginIds,
pluginLookUpTable,
baseMethods,
pluginRegistry,
baseGatewayMethods,
runtimePluginsLoaded: !params.minimalTestGateway && shouldLoadRuntimePlugins,
};
}
export async function loadGatewayStartupPluginRuntime(params: {
cfg: OpenClawConfig;
activationSourceConfig?: OpenClawConfig;
workspaceDir: string;
log: GatewayPluginBootstrapLog;
baseMethods: string[];
startupPluginIds: string[];
pluginLookUpTable?: ReturnType<typeof loadPluginLookUpTable>;
preferSetupRuntimeForChannelPlugins?: boolean;
suppressPluginInfoLogs?: boolean;
startupTrace?: GatewayStartupTrace;
}) {
const { loadGatewayStartupPlugins } = await import("./server-plugin-bootstrap.js");
return loadGatewayStartupPlugins({
cfg: params.cfg,
activationSourceConfig: params.activationSourceConfig,
workspaceDir: params.workspaceDir,
log: params.log,
coreGatewayMethodNames: params.baseMethods,
baseMethods: params.baseMethods,
pluginIds: params.startupPluginIds,
pluginLookUpTable: params.pluginLookUpTable,
preferSetupRuntimeForChannelPlugins: params.preferSetupRuntimeForChannelPlugins,
suppressPluginInfoLogs: params.suppressPluginInfoLogs,
startupTrace: params.startupTrace,
});
}