Files
openclaw/src/plugins/channel-plugin-ids.ts
2026-03-27 17:57:23 +00:00

345 lines
9.6 KiB
TypeScript

import { DEFAULT_PROVIDER } from "../agents/defaults.js";
import {
buildModelAliasIndex,
normalizeProviderId,
resolveModelRefFromString,
} from "../agents/model-selection.js";
import { listPotentialConfiguredChannelIds } from "../channels/config-presence.js";
import type { OpenClawConfig } from "../config/config.js";
import {
resolveAgentModelFallbackValues,
resolveAgentModelPrimaryValue,
} from "../config/model-input.js";
import { normalizePluginsConfig, resolveEffectiveEnableState } from "./config-state.js";
import { loadPluginManifestRegistry } from "./manifest-registry.js";
type ModelListLike = string | { primary?: string; fallbacks?: string[] } | undefined;
function addResolvedActivationId(params: {
raw: string | undefined;
activationIds: Set<string>;
aliasIndex: ReturnType<typeof buildModelAliasIndex>;
}): void {
const raw = params.raw?.trim();
if (!raw) {
return;
}
const resolved = resolveModelRefFromString({
raw,
defaultProvider: DEFAULT_PROVIDER,
aliasIndex: params.aliasIndex,
});
if (!resolved) {
return;
}
params.activationIds.add(normalizeProviderId(resolved.ref.provider));
}
function addModelListActivationIds(params: {
value: ModelListLike;
activationIds: Set<string>;
aliasIndex: ReturnType<typeof buildModelAliasIndex>;
}): void {
addResolvedActivationId({
raw: resolveAgentModelPrimaryValue(params.value),
activationIds: params.activationIds,
aliasIndex: params.aliasIndex,
});
for (const fallback of resolveAgentModelFallbackValues(params.value)) {
addResolvedActivationId({
raw: fallback,
activationIds: params.activationIds,
aliasIndex: params.aliasIndex,
});
}
}
function addProviderModelPairActivationId(params: {
provider: string | undefined;
model: string | undefined;
activationIds: Set<string>;
}): void {
const provider = normalizeProviderId(params.provider ?? "");
const model = params.model?.trim();
if (!provider || !model) {
return;
}
params.activationIds.add(provider);
}
function collectConfiguredActivationIds(config: OpenClawConfig): Set<string> {
const activationIds = new Set<string>();
const aliasIndex = buildModelAliasIndex({
cfg: config,
defaultProvider: DEFAULT_PROVIDER,
});
addModelListActivationIds({ value: config.agents?.defaults?.model, activationIds, aliasIndex });
addModelListActivationIds({
value: config.agents?.defaults?.imageModel,
activationIds,
aliasIndex,
});
addModelListActivationIds({
value: config.agents?.defaults?.imageGenerationModel,
activationIds,
aliasIndex,
});
addModelListActivationIds({
value: config.agents?.defaults?.pdfModel,
activationIds,
aliasIndex,
});
addResolvedActivationId({
raw: config.agents?.defaults?.compaction?.model,
activationIds,
aliasIndex,
});
addResolvedActivationId({
raw: config.agents?.defaults?.heartbeat?.model,
activationIds,
aliasIndex,
});
addModelListActivationIds({
value: config.agents?.defaults?.subagents?.model,
activationIds,
aliasIndex,
});
addResolvedActivationId({
raw: config.messages?.tts?.summaryModel,
activationIds,
aliasIndex,
});
addResolvedActivationId({
raw: config.hooks?.gmail?.model,
activationIds,
aliasIndex,
});
for (const modelRef of Object.keys(config.agents?.defaults?.models ?? {})) {
addResolvedActivationId({
raw: modelRef,
activationIds,
aliasIndex,
});
}
for (const providerId of Object.keys(config.agents?.defaults?.cliBackends ?? {})) {
const normalized = normalizeProviderId(providerId);
if (normalized) {
activationIds.add(normalized);
}
}
for (const providerId of Object.keys(config.models?.providers ?? {})) {
const normalized = normalizeProviderId(providerId);
if (normalized) {
activationIds.add(normalized);
}
}
for (const agent of config.agents?.list ?? []) {
addModelListActivationIds({ value: agent.model, activationIds, aliasIndex });
addModelListActivationIds({ value: agent.subagents?.model, activationIds, aliasIndex });
addResolvedActivationId({
raw: agent.heartbeat?.model,
activationIds,
aliasIndex,
});
}
for (const mapping of config.hooks?.mappings ?? []) {
addResolvedActivationId({
raw: mapping.model,
activationIds,
aliasIndex,
});
}
for (const channelMap of Object.values(config.channels?.modelByChannel ?? {})) {
if (!channelMap || typeof channelMap !== "object") {
continue;
}
for (const raw of Object.values(channelMap)) {
addResolvedActivationId({
raw: typeof raw === "string" ? raw : undefined,
activationIds,
aliasIndex,
});
}
}
addResolvedActivationId({
raw: config.tools?.subagents?.model
? resolveAgentModelPrimaryValue(config.tools?.subagents?.model)
: undefined,
activationIds,
aliasIndex,
});
if (config.tools?.subagents?.model) {
for (const fallback of resolveAgentModelFallbackValues(config.tools.subagents.model)) {
addResolvedActivationId({ raw: fallback, activationIds, aliasIndex });
}
}
addResolvedActivationId({
raw: config.tools?.web?.search?.gemini?.model,
activationIds,
aliasIndex,
});
addResolvedActivationId({
raw: config.tools?.web?.search?.grok?.model,
activationIds,
aliasIndex,
});
addResolvedActivationId({
raw: config.tools?.web?.search?.kimi?.model,
activationIds,
aliasIndex,
});
addResolvedActivationId({
raw: config.tools?.web?.search?.perplexity?.model,
activationIds,
aliasIndex,
});
for (const entry of config.tools?.media?.models ?? []) {
addProviderModelPairActivationId({
provider: entry.provider,
model: entry.model,
activationIds,
});
}
for (const entry of config.tools?.media?.image?.models ?? []) {
addProviderModelPairActivationId({
provider: entry.provider,
model: entry.model,
activationIds,
});
}
for (const entry of config.tools?.media?.audio?.models ?? []) {
addProviderModelPairActivationId({
provider: entry.provider,
model: entry.model,
activationIds,
});
}
for (const entry of config.tools?.media?.video?.models ?? []) {
addProviderModelPairActivationId({
provider: entry.provider,
model: entry.model,
activationIds,
});
}
return activationIds;
}
export function resolveChannelPluginIds(params: {
config: OpenClawConfig;
workspaceDir?: string;
env: NodeJS.ProcessEnv;
}): string[] {
return loadPluginManifestRegistry({
config: params.config,
workspaceDir: params.workspaceDir,
env: params.env,
})
.plugins.filter((plugin) => plugin.channels.length > 0)
.map((plugin) => plugin.id);
}
export function resolveConfiguredChannelPluginIds(params: {
config: OpenClawConfig;
workspaceDir?: string;
env: NodeJS.ProcessEnv;
}): string[] {
const configuredChannelIds = new Set(
listPotentialConfiguredChannelIds(params.config, params.env).map((id) => id.trim()),
);
if (configuredChannelIds.size === 0) {
return [];
}
return resolveChannelPluginIds(params).filter((pluginId) => configuredChannelIds.has(pluginId));
}
export function resolveConfiguredDeferredChannelPluginIds(params: {
config: OpenClawConfig;
workspaceDir?: string;
env: NodeJS.ProcessEnv;
}): string[] {
const configuredChannelIds = new Set(
listPotentialConfiguredChannelIds(params.config, params.env).map((id) => id.trim()),
);
if (configuredChannelIds.size === 0) {
return [];
}
return loadPluginManifestRegistry({
config: params.config,
workspaceDir: params.workspaceDir,
env: params.env,
})
.plugins.filter(
(plugin) =>
plugin.channels.some((channelId) => configuredChannelIds.has(channelId)) &&
plugin.startupDeferConfiguredChannelFullLoadUntilAfterListen === true,
)
.map((plugin) => plugin.id);
}
export function resolveGatewayStartupPluginIds(params: {
config: OpenClawConfig;
workspaceDir?: string;
env: NodeJS.ProcessEnv;
}): string[] {
const configuredChannelIds = new Set(
listPotentialConfiguredChannelIds(params.config, params.env).map((id) => id.trim()),
);
const pluginsConfig = normalizePluginsConfig(params.config.plugins);
const manifestRegistry = loadPluginManifestRegistry({
config: params.config,
workspaceDir: params.workspaceDir,
env: params.env,
});
const configuredActivationIds = collectConfiguredActivationIds(params.config);
return manifestRegistry.plugins
.filter((plugin) => {
if (plugin.channels.some((channelId) => configuredChannelIds.has(channelId))) {
return true;
}
if (plugin.channels.length > 0) {
return false;
}
if (
plugin.origin === "bundled" &&
(plugin.providers.some((providerId) =>
configuredActivationIds.has(normalizeProviderId(providerId)),
) ||
plugin.cliBackends.some((backendId) =>
configuredActivationIds.has(normalizeProviderId(backendId)),
))
) {
return true;
}
const enabled = resolveEffectiveEnableState({
id: plugin.id,
origin: plugin.origin,
config: pluginsConfig,
rootConfig: params.config,
enabledByDefault: plugin.enabledByDefault,
}).enabled;
if (!enabled) {
return false;
}
if (plugin.origin !== "bundled") {
return true;
}
return (
pluginsConfig.allow.includes(plugin.id) ||
pluginsConfig.entries[plugin.id]?.enabled === true ||
pluginsConfig.slots.memory === plugin.id
);
})
.map((plugin) => plugin.id);
}