UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

252 lines (251 loc) 12.6 kB
import { r as asNullableRecord } from "./record-coerce-DItp3I4t.js"; import { s as normalizeNullableString } from "./string-coerce-CIXf7egm.js"; import { t as VERSION } from "./version-v1kuAkGj.js"; import { i as normalizeChatChannelId } from "./ids-BVZRYG0I.js"; import { O as resolveOfficialExternalWebProviderContractPluginIdsForEnv, T as resolveOfficialExternalProviderContractPluginIds, i as getOfficialExternalPluginCatalogEntry } from "./official-external-plugin-catalog-Dzu7dwBN.js"; import { t as compareOpenClawVersions } from "./version-BXayNebU.js"; import { t as listDoctorConfiguredChannelIds } from "./configured-channel-ids-BPL8Xd0F.js"; import { n as resolveWebSearchInstallCatalogEntriesForEnv, r as resolveWebSearchInstallCatalogEntry } from "./web-search-install-catalog-mZmYPP1I.js"; import { t as isChannelConfigured } from "./channel-configured-CdbUVGCQ.js"; import "./registry-COqNvmCg.js"; import { t as collectConfiguredAgentHarnessRuntimes } from "./harness-runtimes-BrMGAsrQ.js"; import { t as collectConfiguredSpeechProviderIds } from "./gateway-startup-speech-providers-C1sqNf-9.js"; import { r as detectPluginAutoEnableCandidates } from "./plugin-auto-enable-Tv_C18cS.js"; import { f as shouldDeferConfiguredPluginInstallRepair } from "./update-phase-J3w3q1-f.js"; import { n as repairMissingPluginInstallsForIds, o as collectConfiguredProviderPluginIds } from "./missing-configured-plugin-install-B3eZm5tD.js"; import { a as createDeferredConfiguredPluginRepairDoctorResult } from "./update-doctor-result-D3HkeqjI.js"; //#region src/commands/doctor/shared/release-configured-plugin-installs.ts const CONFIGURED_PLUGIN_INSTALL_RELEASE_VERSION = "2026.5.2-beta.1"; const AGENT_HARNESS_RUNTIME_PLUGIN_IDS = { codex: "codex" }; function isPluginsGloballyDisabled(cfg) { return cfg.plugins?.enabled === false; } function isDenied(cfg, pluginId) { const deny = cfg.plugins?.deny; return Array.isArray(deny) && deny.includes(pluginId); } function collectBlockedPluginIds(cfg) { const ids = /* @__PURE__ */ new Set(); const deny = cfg.plugins?.deny; if (Array.isArray(deny)) for (const pluginId of deny) { const normalized = normalizeNullableString(pluginId); if (normalized) ids.add(normalized); } const entries = asNullableRecord(cfg.plugins?.entries); for (const [pluginId, entry] of Object.entries(entries ?? {})) if (asNullableRecord(entry)?.enabled === false && pluginId.trim()) ids.add(pluginId.trim()); return [...ids].toSorted((left, right) => left.localeCompare(right)); } function isPluginEntryDisabled(cfg, pluginId) { return cfg.plugins?.entries?.[pluginId]?.enabled === false; } function isChannelDisabled(cfg, channelId) { const channels = asNullableRecord(cfg.channels); return asNullableRecord(channels?.[channelId])?.enabled === false; } function isDisabled(cfg, pluginId) { if (isPluginEntryDisabled(cfg, pluginId)) return true; const channelId = normalizeChatChannelId(pluginId); return channelId ? isChannelDisabled(cfg, channelId) : false; } function hasMaterialPluginEntry(entry) { const record = asNullableRecord(entry); if (!record) return false; return record.enabled === true || asNullableRecord(record.config) !== null || asNullableRecord(record.hooks) !== null || asNullableRecord(record.subagent) !== null || record.apiKey !== void 0 || record.env !== void 0; } function collectMaterialPluginEntryIds(cfg) { const entries = asNullableRecord(cfg.plugins?.entries); if (!entries) return []; return Object.entries(entries).filter(([, entry]) => hasMaterialPluginEntry(entry)).map(([pluginId]) => pluginId.trim()).filter((pluginId) => pluginId); } function collectSlotPluginIds(cfg) { const slots = asNullableRecord(cfg.plugins?.slots); return ["memory", "contextEngine"].map((key) => normalizeNullableString(slots?.[key])).filter((pluginId) => typeof pluginId === "string" && pluginId.toLowerCase() !== "none"); } function collectConfiguredChannelIds(cfg, env) { return listDoctorConfiguredChannelIds(cfg, { configEntryPolicy: "enabled-or-meaningful", env, skipWhenPluginsDisabled: true, excludeExplicitlyDisabled: true, mapEnvironmentChannelId: (channelId) => normalizeChatChannelId(channelId) ?? channelId, environmentChannelIsConfigured: (channelId) => !isChannelDisabled(cfg, channelId) && isChannelConfigured(cfg, channelId, env), sort: "locale" }); } function collectAgentHarnessRuntimePluginIds(cfg, _env) { return collectConfiguredAgentHarnessRuntimes(cfg).map((runtime) => AGENT_HARNESS_RUNTIME_PLUGIN_IDS[runtime]).filter((pluginId) => Boolean(pluginId)).toSorted((left, right) => left.localeCompare(right)); } function collectWebSearchPluginIds(cfg) { if (cfg.tools?.web?.search?.enabled === false) return []; const providerId = cfg.tools?.web?.search?.provider; if (typeof providerId !== "string") return []; const entry = resolveWebSearchInstallCatalogEntry({ providerId }); return entry?.pluginId ? [entry.pluginId] : []; } function collectEnvWebSearchPluginIds(cfg, env) { if (cfg.tools?.web?.search?.enabled === false) return []; return resolveWebSearchInstallCatalogEntriesForEnv(env).map((entry) => entry.pluginId); } function collectWebFetchPluginIds(cfg) { const webFetch = cfg.tools?.web?.fetch; if (webFetch?.enabled === false) return []; const providerId = normalizeNullableString(webFetch?.provider)?.toLowerCase(); if (!providerId) return []; return resolveOfficialExternalProviderContractPluginIds({ contract: "webFetchProviders", providerIds: /* @__PURE__ */ new Set([providerId]) }); } function collectEnvWebFetchPluginIds(cfg, env) { if (cfg.tools?.web?.fetch?.enabled === false) return []; return resolveOfficialExternalWebProviderContractPluginIdsForEnv({ contract: "webFetchProviders", env }); } function collectSpeechPluginIds(cfg) { return resolveOfficialExternalProviderContractPluginIds({ contract: "speechProviders", providerIds: collectConfiguredSpeechProviderIds(cfg) }); } function collectAcpRuntimePluginIds(cfg) { const acp = asNullableRecord(cfg.acp); if (!acp) return []; const backend = normalizeNullableString(acp.backend)?.toLowerCase() ?? ""; if (!(acp.enabled === true || asNullableRecord(acp.dispatch)?.enabled === true || backend === "acpx") || backend && backend !== "acpx") return []; return ["acpx"]; } function collectAllowOnlyOfficialPluginIds(cfg) { const allow = cfg.plugins?.allow; if (!Array.isArray(allow) || allow.length === 0) return []; const materialEntryIds = new Set(collectMaterialPluginEntryIds(cfg).map((id) => id.toLowerCase())); const ids = []; for (const rawPluginId of allow) { const pluginId = normalizeNullableString(rawPluginId); if (!pluginId || materialEntryIds.has(pluginId.toLowerCase())) continue; if (getOfficialExternalPluginCatalogEntry(pluginId)) ids.push(pluginId); } return ids; } function addEligiblePluginId(cfg, pluginIds, pluginId) { const normalized = pluginId.trim(); if (!normalized || isDenied(cfg, normalized) || isDisabled(cfg, normalized)) return; pluginIds.add(normalized); } /** Return true when this config has not yet crossed the configured-plugin install release gate. */ function shouldRunConfiguredPluginInstallReleaseStep(params) { const releaseVersion = params.releaseVersion ?? CONFIGURED_PLUGIN_INSTALL_RELEASE_VERSION; const currentComparedToRelease = compareOpenClawVersions(params.currentVersion ?? VERSION, releaseVersion); if (currentComparedToRelease === null || currentComparedToRelease < 0) return false; const touchedComparedToRelease = compareOpenClawVersions(params.touchedVersion, releaseVersion); return touchedComparedToRelease === null || touchedComparedToRelease < 0; } /** Collect plugin/channel ids implied by config for the release install backfill step. */ function collectReleaseConfiguredPluginIds(params) { const env = params.env ?? process.env; const pluginIds = /* @__PURE__ */ new Set(); const channelIds = /* @__PURE__ */ new Set(); if (isPluginsGloballyDisabled(params.cfg)) return { pluginIds: [], channelIds: [] }; for (const candidate of detectPluginAutoEnableCandidates({ config: params.cfg, env })) addEligiblePluginId(params.cfg, pluginIds, candidate.pluginId); for (const pluginId of collectMaterialPluginEntryIds(params.cfg)) addEligiblePluginId(params.cfg, pluginIds, pluginId); for (const pluginId of collectSlotPluginIds(params.cfg)) addEligiblePluginId(params.cfg, pluginIds, pluginId); for (const pluginId of collectConfiguredProviderPluginIds({ cfg: params.cfg, env })) addEligiblePluginId(params.cfg, pluginIds, pluginId); for (const pluginId of collectAgentHarnessRuntimePluginIds(params.cfg, env)) addEligiblePluginId(params.cfg, pluginIds, pluginId); for (const pluginId of collectWebSearchPluginIds(params.cfg)) addEligiblePluginId(params.cfg, pluginIds, pluginId); for (const pluginId of collectEnvWebSearchPluginIds(params.cfg, env)) addEligiblePluginId(params.cfg, pluginIds, pluginId); for (const pluginId of collectWebFetchPluginIds(params.cfg)) addEligiblePluginId(params.cfg, pluginIds, pluginId); for (const pluginId of collectEnvWebFetchPluginIds(params.cfg, env)) addEligiblePluginId(params.cfg, pluginIds, pluginId); for (const pluginId of collectSpeechPluginIds(params.cfg)) addEligiblePluginId(params.cfg, pluginIds, pluginId); for (const pluginId of collectAcpRuntimePluginIds(params.cfg)) addEligiblePluginId(params.cfg, pluginIds, pluginId); for (const pluginId of collectAllowOnlyOfficialPluginIds(params.cfg)) addEligiblePluginId(params.cfg, pluginIds, pluginId); for (const channelId of collectConfiguredChannelIds(params.cfg, env)) if (!isChannelDisabled(params.cfg, channelId) && !isDenied(params.cfg, channelId) && !isPluginEntryDisabled(params.cfg, channelId)) channelIds.add(channelId); return { pluginIds: [...pluginIds].toSorted((left, right) => left.localeCompare(right)), channelIds: [...channelIds].toSorted((left, right) => left.localeCompare(right)) }; } /** Run the configured-plugin install release backfill when the config still needs it. */ async function maybeRunConfiguredPluginInstallReleaseStep(params) { const env = params.env ?? process.env; const updateInProgress = shouldDeferConfiguredPluginInstallRepair(env); const configured = collectReleaseConfiguredPluginIds({ cfg: params.cfg, env }); if (!shouldRunConfiguredPluginInstallReleaseStep({ currentVersion: params.currentVersion, touchedVersion: params.touchedVersion })) { if (configured.pluginIds.length === 0 && configured.channelIds.length === 0) return { changes: [], warnings: [], completed: false, touchedConfig: false }; const repaired = await repairMissingPluginInstallsForIds({ cfg: params.cfg, pluginIds: configured.pluginIds, channelIds: configured.channelIds, blockedPluginIds: collectBlockedPluginIds(params.cfg), env }); const warnings = [...repaired.warnings, ...repaired.notices ?? []]; const postInstallDoctorResult = createPostInstallDoctorResultForDeferredRepair({ updateInProgress, details: repaired.deferredRepairDetails ?? [], warnings: repaired.warnings }); return { changes: repaired.changes, warnings, completed: repaired.warnings.length === 0, touchedConfig: false, ...repaired.pluginInventoryChanged ? { pluginInventoryChanged: true } : {}, ...postInstallDoctorResult ? { postInstallDoctorResult } : {} }; } if (configured.pluginIds.length === 0 && configured.channelIds.length === 0) return { changes: [], warnings: [], completed: true, touchedConfig: !updateInProgress }; const repaired = await repairMissingPluginInstallsForIds({ cfg: params.cfg, pluginIds: configured.pluginIds, channelIds: configured.channelIds, blockedPluginIds: collectBlockedPluginIds(params.cfg), env }); const completed = repaired.warnings.length === 0 && !updateInProgress; const warnings = [...repaired.warnings, ...repaired.notices ?? []]; const postInstallDoctorResult = createPostInstallDoctorResultForDeferredRepair({ updateInProgress, details: repaired.deferredRepairDetails ?? [], warnings: repaired.warnings }); return { changes: repaired.changes, warnings, completed, touchedConfig: completed, ...repaired.pluginInventoryChanged ? { pluginInventoryChanged: true } : {}, ...postInstallDoctorResult ? { postInstallDoctorResult } : {} }; } function createPostInstallDoctorResultForDeferredRepair(params) { if (!params.updateInProgress || params.warnings.length > 0 || params.details.length === 0) return; return createDeferredConfiguredPluginRepairDoctorResult(params.details); } //#endregion export { maybeRunConfiguredPluginInstallReleaseStep };