UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

631 lines (630 loc) 34.5 kB
import { a as normalizeLowercaseStringOrEmpty } from "./string-coerce-mnp54Vah.js"; import { o as isRecord } from "./record-coerce-DHZ4bFlT.js"; import { g as sortUniqueStrings } from "./string-normalization-WNUDCpXX.js"; import { t as discoverOpenClawPlugins } from "./discovery-BDSfxwT6.js"; import { p as tryReadJsonSync } from "./json-files-2umMHm0W.js"; import { i as normalizeProviderId } from "./provider-id-Dq06Bcx6.js"; import { n as PLUGIN_MANIFEST_FILENAME, r as getPackageManifestMetadata } from "./manifest-BcY4wyAU.js"; import { t as loadPluginManifestRegistry } from "./manifest-registry-BywZIeAq.js"; import { a as resolveManifestContractPluginIds } from "./plugin-registry-ChcJPHWl.js"; import { u as resolveLoaderPackageRoot } from "./sdk-alias-ZgondhPg.js"; import { t as loadBundledPluginPublicArtifactModuleSync } from "./public-surface-loader-CqBVRQ-t.js"; import { i as resolveBundledPluginScanDir, r as normalizeBundledPluginStringList } from "./bundled-plugin-metadata-CnZA4QSH.js"; import { t as loadBundledCapabilityRuntimeRegistry } from "./bundled-capability-runtime-cd6lX8t5.js"; import { i as resolveBundledExplicitWebSearchProvidersFromPublicArtifacts } from "./web-provider-public-artifacts.explicit-BNgX1hwM.js"; import { fileURLToPath } from "node:url"; import fs from "node:fs"; import path from "node:path"; //#region src/plugins/provider-contract-public-artifacts.ts function isProviderPlugin(value) { return isRecord(value) && typeof value.id === "string" && typeof value.label === "string" && Array.isArray(value.auth); } function tryLoadProviderContractApi(pluginId) { try { return loadBundledPluginPublicArtifactModuleSync({ dirName: pluginId, artifactBasename: "provider-contract-api.js" }); } catch (error) { if (error instanceof Error && error.message.startsWith("Unable to resolve bundled plugin public surface ")) return null; throw error; } } function collectProviderContractEntries(params) { const providers = []; for (const [name, exported] of Object.entries(params.mod).toSorted(([left], [right]) => left.localeCompare(right))) { if (typeof exported !== "function" || exported.length !== 0 || !name.startsWith("create") || !name.endsWith("Provider")) continue; const candidate = exported(); if (isProviderPlugin(candidate)) providers.push({ pluginId: params.pluginId, provider: candidate }); } return providers; } function resolveBundledExplicitProviderContractsFromPublicArtifacts(params) { const providers = []; for (const pluginId of sortUniqueStrings(params.onlyPluginIds)) { const mod = tryLoadProviderContractApi(pluginId); if (!mod) return null; const entries = collectProviderContractEntries({ pluginId, mod }); if (entries.length === 0) return null; providers.push(...entries); } return providers; } //#endregion //#region src/plugins/contracts/shared.ts /** Returns unique normalized string values while preserving first-seen order. */ function uniqueStrings(values, normalize = (value) => value) { const result = []; const seen = /* @__PURE__ */ new Set(); for (const value of values ?? []) { const normalized = normalize(value); if (!normalized || seen.has(normalized)) continue; seen.add(normalized); result.push(normalized); } return result; } //#endregion //#region src/plugins/contracts/inventory/bundled-capability-metadata.ts const CURRENT_MODULE_PATH = fileURLToPath(import.meta.url); const OPENCLAW_PACKAGE_ROOT = resolveLoaderPackageRoot({ modulePath: CURRENT_MODULE_PATH, moduleUrl: import.meta.url }) ?? fileURLToPath(new URL("../../../..", import.meta.url)); const RUNNING_FROM_BUILT_ARTIFACT = CURRENT_MODULE_PATH.includes(`${path.sep}dist${path.sep}`) || CURRENT_MODULE_PATH.includes(`${path.sep}dist-runtime${path.sep}`); function readJsonRecord(filePath) { const raw = tryReadJsonSync(filePath); return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : void 0; } function readBundledCapabilityManifest(pluginDir) { if (normalizeBundledPluginStringList(getPackageManifestMetadata(readJsonRecord(path.join(pluginDir, "package.json")))?.extensions).length === 0) return; const raw = readJsonRecord(path.join(pluginDir, PLUGIN_MANIFEST_FILENAME)); if (!(typeof raw?.id === "string" ? raw.id.trim() : "")) return; return raw; } function listBundledCapabilityManifests() { const scanDir = resolveBundledPluginScanDir({ packageRoot: OPENCLAW_PACKAGE_ROOT, runningFromBuiltArtifact: RUNNING_FROM_BUILT_ARTIFACT }); if (!scanDir) return []; return fs.readdirSync(scanDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => readBundledCapabilityManifest(path.join(scanDir, entry.name))).filter((manifest) => manifest !== void 0).toSorted((left, right) => left.id.localeCompare(right.id)); } const BUNDLED_CAPABILITY_MANIFESTS = listBundledCapabilityManifests(); function normalizeSetupProviderEnvVars(setup) { return Object.fromEntries((setup?.providers ?? []).map((provider) => [provider.id.trim(), uniqueStrings(provider.envVars ?? [], (value) => typeof value === "string" ? value.trim() : "")]).filter(([key, values]) => key && values.length > 0).toSorted(([left], [right]) => left.localeCompare(right))); } function buildBundledPluginContractSnapshot(manifest) { return { pluginId: manifest.id, cliBackendIds: uniqueStrings(manifest.cliBackends, (value) => value.trim()), providerIds: uniqueStrings(manifest.providers, (value) => value.trim()), providerEnvVars: normalizeSetupProviderEnvVars(manifest.setup), embeddingProviderIds: uniqueStrings(manifest.contracts?.embeddingProviders, (value) => value.trim()), speechProviderIds: uniqueStrings(manifest.contracts?.speechProviders, (value) => value.trim()), realtimeTranscriptionProviderIds: uniqueStrings(manifest.contracts?.realtimeTranscriptionProviders, (value) => value.trim()), realtimeVoiceProviderIds: uniqueStrings(manifest.contracts?.realtimeVoiceProviders, (value) => value.trim()), mediaUnderstandingProviderIds: uniqueStrings(manifest.contracts?.mediaUnderstandingProviders, (value) => value.trim()), transcriptSourceProviderIds: uniqueStrings(manifest.contracts?.transcriptSourceProviders, (value) => value.trim()), documentExtractorIds: uniqueStrings(manifest.contracts?.documentExtractors, (value) => value.trim()), imageGenerationProviderIds: uniqueStrings(manifest.contracts?.imageGenerationProviders, (value) => value.trim()), videoGenerationProviderIds: uniqueStrings(manifest.contracts?.videoGenerationProviders, (value) => value.trim()), musicGenerationProviderIds: uniqueStrings(manifest.contracts?.musicGenerationProviders, (value) => value.trim()), webContentExtractorIds: uniqueStrings(manifest.contracts?.webContentExtractors, (value) => value.trim()), webFetchProviderIds: uniqueStrings(manifest.contracts?.webFetchProviders, (value) => value.trim()), webSearchProviderIds: uniqueStrings(manifest.contracts?.webSearchProviders, (value) => value.trim()), migrationProviderIds: uniqueStrings(manifest.contracts?.migrationProviders, (value) => value.trim()), toolNames: uniqueStrings(manifest.contracts?.tools, (value) => value.trim()) }; } function hasBundledPluginContractSnapshotCapabilities(entry) { return entry.cliBackendIds.length > 0 || entry.providerIds.length > 0 || entry.embeddingProviderIds.length > 0 || entry.speechProviderIds.length > 0 || entry.realtimeTranscriptionProviderIds.length > 0 || entry.realtimeVoiceProviderIds.length > 0 || entry.mediaUnderstandingProviderIds.length > 0 || entry.transcriptSourceProviderIds.length > 0 || entry.documentExtractorIds.length > 0 || entry.imageGenerationProviderIds.length > 0 || entry.videoGenerationProviderIds.length > 0 || entry.musicGenerationProviderIds.length > 0 || entry.webContentExtractorIds.length > 0 || entry.webFetchProviderIds.length > 0 || entry.webSearchProviderIds.length > 0 || entry.migrationProviderIds.length > 0 || entry.toolNames.length > 0; } const BUNDLED_PLUGIN_CONTRACT_SNAPSHOTS = BUNDLED_CAPABILITY_MANIFESTS.map(buildBundledPluginContractSnapshot).filter(hasBundledPluginContractSnapshotCapabilities).toSorted((left, right) => left.pluginId.localeCompare(right.pluginId)); Object.fromEntries(BUNDLED_CAPABILITY_MANIFESTS.flatMap((manifest) => (manifest.legacyPluginIds ?? []).map((legacyPluginId) => [legacyPluginId, manifest.id])).toSorted(([left], [right]) => left.localeCompare(right))); Object.fromEntries(BUNDLED_CAPABILITY_MANIFESTS.flatMap((manifest) => (manifest.autoEnableWhenConfiguredProviders ?? []).map((providerId) => [providerId, manifest.id])).toSorted(([left], [right]) => left.localeCompare(right))); //#endregion //#region src/plugins/contracts/speech-vitest-registry.ts const VITEST_CONTRACT_PLUGIN_IDS = { imageGenerationProviders: BUNDLED_PLUGIN_CONTRACT_SNAPSHOTS.filter((entry) => entry.imageGenerationProviderIds.length > 0).map((entry) => entry.pluginId), speechProviders: BUNDLED_PLUGIN_CONTRACT_SNAPSHOTS.filter((entry) => entry.speechProviderIds.length > 0).map((entry) => entry.pluginId), mediaUnderstandingProviders: BUNDLED_PLUGIN_CONTRACT_SNAPSHOTS.filter((entry) => entry.mediaUnderstandingProviderIds.length > 0).map((entry) => entry.pluginId), transcriptSourceProviders: BUNDLED_PLUGIN_CONTRACT_SNAPSHOTS.filter((entry) => entry.transcriptSourceProviderIds.length > 0).map((entry) => entry.pluginId), realtimeVoiceProviders: BUNDLED_PLUGIN_CONTRACT_SNAPSHOTS.filter((entry) => entry.realtimeVoiceProviderIds.length > 0).map((entry) => entry.pluginId), realtimeTranscriptionProviders: BUNDLED_PLUGIN_CONTRACT_SNAPSHOTS.filter((entry) => entry.realtimeTranscriptionProviderIds.length > 0).map((entry) => entry.pluginId), videoGenerationProviders: BUNDLED_PLUGIN_CONTRACT_SNAPSHOTS.filter((entry) => entry.videoGenerationProviderIds.length > 0).map((entry) => entry.pluginId), musicGenerationProviders: BUNDLED_PLUGIN_CONTRACT_SNAPSHOTS.filter((entry) => entry.musicGenerationProviderIds.length > 0).map((entry) => entry.pluginId) }; function loadVitestVideoGenerationFallbackEntries(pluginIds) { return loadVitestCapabilityContractEntries({ contract: "videoGenerationProviders", pluginSdkResolution: "src", pluginIds, pickEntries: (registry) => registry.videoGenerationProviders.map((entry) => ({ pluginId: entry.pluginId, provider: entry.provider })) }); } function loadVitestMusicGenerationFallbackEntries(pluginIds) { return loadVitestCapabilityContractEntries({ contract: "musicGenerationProviders", pluginSdkResolution: "src", pluginIds, pickEntries: (registry) => registry.musicGenerationProviders.map((entry) => ({ pluginId: entry.pluginId, provider: entry.provider })) }); } function loadVitestSpeechFallbackEntries(pluginIds) { return loadVitestCapabilityContractEntries({ contract: "speechProviders", pluginSdkResolution: "src", pluginIds, pickEntries: (registry) => registry.speechProviders.map((entry) => ({ pluginId: entry.pluginId, provider: entry.provider })) }); } function hasExplicitVideoGenerationModes(provider) { return Boolean(provider.capabilities.generate && provider.capabilities.imageToVideo && provider.capabilities.videoToVideo); } function hasExplicitMusicGenerationModes(provider) { return Boolean(provider.capabilities.generate && provider.capabilities.edit); } function loadVitestCapabilityContractEntries(params) { const pluginIds = [...params.pluginIds ?? VITEST_CONTRACT_PLUGIN_IDS[params.contract]]; if (pluginIds.length === 0) return []; const bulkEntries = params.pickEntries(loadBundledCapabilityRuntimeRegistry({ pluginIds, pluginSdkResolution: params.pluginSdkResolution ?? "dist" })); if (new Set(bulkEntries.map((entry) => entry.pluginId)).size === pluginIds.length) return bulkEntries; return pluginIds.flatMap((pluginId) => params.pickEntries(loadBundledCapabilityRuntimeRegistry({ pluginIds: [pluginId], pluginSdkResolution: params.pluginSdkResolution ?? "dist" })).filter((entry) => entry.pluginId === pluginId)); } function loadVitestSpeechProviderContractRegistry() { const entries = loadVitestCapabilityContractEntries({ contract: "speechProviders", pickEntries: (registry) => registry.speechProviders.map((entry) => ({ pluginId: entry.pluginId, provider: entry.provider })) }); const coveredPluginIds = new Set(entries.map((entry) => entry.pluginId)); const missingPluginIds = VITEST_CONTRACT_PLUGIN_IDS.speechProviders.filter((pluginId) => !coveredPluginIds.has(pluginId)); if (missingPluginIds.length === 0) return entries; const replacementEntries = loadVitestSpeechFallbackEntries(missingPluginIds); const replacedPluginIds = new Set(replacementEntries.map((entry) => entry.pluginId)); return [...entries.filter((entry) => !replacedPluginIds.has(entry.pluginId)), ...replacementEntries]; } function loadVitestMediaUnderstandingProviderContractRegistry() { return loadVitestCapabilityContractEntries({ contract: "mediaUnderstandingProviders", pickEntries: (registry) => registry.mediaUnderstandingProviders.map((entry) => ({ pluginId: entry.pluginId, provider: entry.provider })) }); } function loadVitestTranscriptsSourceProviderContractRegistry() { return loadVitestCapabilityContractEntries({ contract: "transcriptSourceProviders", pluginSdkResolution: "src", pickEntries: (registry) => registry.transcriptSourceProviders.map((entry) => ({ pluginId: entry.pluginId, provider: entry.provider })) }); } function loadVitestRealtimeVoiceProviderContractRegistry() { return loadVitestCapabilityContractEntries({ contract: "realtimeVoiceProviders", pickEntries: (registry) => registry.realtimeVoiceProviders.map((entry) => ({ pluginId: entry.pluginId, provider: entry.provider })) }); } function loadVitestRealtimeTranscriptionProviderContractRegistry() { return loadVitestCapabilityContractEntries({ contract: "realtimeTranscriptionProviders", pickEntries: (registry) => registry.realtimeTranscriptionProviders.map((entry) => ({ pluginId: entry.pluginId, provider: entry.provider })) }); } function loadVitestImageGenerationProviderContractRegistry() { return loadVitestCapabilityContractEntries({ contract: "imageGenerationProviders", pickEntries: (registry) => registry.imageGenerationProviders.map((entry) => ({ pluginId: entry.pluginId, provider: entry.provider })) }); } function loadVitestVideoGenerationProviderContractRegistry() { const entries = loadVitestCapabilityContractEntries({ contract: "videoGenerationProviders", pickEntries: (registry) => registry.videoGenerationProviders.map((entry) => ({ pluginId: entry.pluginId, provider: entry.provider })) }); const coveredPluginIds = new Set(entries.map((entry) => entry.pluginId)); const stalePluginIds = new Set(entries.filter((entry) => !hasExplicitVideoGenerationModes(entry.provider)).map((entry) => entry.pluginId)); const missingPluginIds = VITEST_CONTRACT_PLUGIN_IDS.videoGenerationProviders.filter((pluginId) => !coveredPluginIds.has(pluginId) || stalePluginIds.has(pluginId)); if (missingPluginIds.length === 0) return entries; const replacementEntries = loadVitestVideoGenerationFallbackEntries(missingPluginIds); const replacedPluginIds = new Set(replacementEntries.map((entry) => entry.pluginId)); return [...entries.filter((entry) => !replacedPluginIds.has(entry.pluginId)), ...replacementEntries]; } function loadVitestMusicGenerationProviderContractRegistry() { const entries = loadVitestCapabilityContractEntries({ contract: "musicGenerationProviders", pickEntries: (registry) => registry.musicGenerationProviders.map((entry) => ({ pluginId: entry.pluginId, provider: entry.provider })) }); const coveredPluginIds = new Set(entries.map((entry) => entry.pluginId)); const stalePluginIds = new Set(entries.filter((entry) => !hasExplicitMusicGenerationModes(entry.provider)).map((entry) => entry.pluginId)); const missingPluginIds = VITEST_CONTRACT_PLUGIN_IDS.musicGenerationProviders.filter((pluginId) => !coveredPluginIds.has(pluginId) || stalePluginIds.has(pluginId)); if (missingPluginIds.length === 0) return entries; const replacementEntries = loadVitestMusicGenerationFallbackEntries(missingPluginIds); const replacedPluginIds = new Set(replacementEntries.map((entry) => entry.pluginId)); return [...entries.filter((entry) => !replacedPluginIds.has(entry.pluginId)), ...replacementEntries]; } //#endregion //#region src/plugins/contracts/registry.ts function normalizeProviderEnvVars(providerEnvVars) { return Object.fromEntries(Object.entries(providerEnvVars ?? {}).map(([providerId, envVars]) => [providerId, uniqueStrings(envVars)])); } function resolvePluginProviderEnvVars(plugin) { const envVars = {}; for (const provider of plugin.setup?.providers ?? []) envVars[provider.id] = uniqueStrings(provider.envVars ?? []); for (const [providerId, keys] of Object.entries(plugin.providerAuthEnvVars ?? {})) envVars[providerId] = uniqueStrings([...envVars[providerId] ?? [], ...keys]); return normalizeProviderEnvVars(envVars); } function resolveBundledManifestContracts() { if (process.env.VITEST) return BUNDLED_PLUGIN_CONTRACT_SNAPSHOTS.map((entry) => ({ pluginId: entry.pluginId, cliBackendIds: [...entry.cliBackendIds], providerIds: [...entry.providerIds], providerEnvVars: normalizeProviderEnvVars(entry.providerEnvVars), embeddingProviderIds: [...entry.embeddingProviderIds], speechProviderIds: [...entry.speechProviderIds], realtimeTranscriptionProviderIds: [...entry.realtimeTranscriptionProviderIds], realtimeVoiceProviderIds: [...entry.realtimeVoiceProviderIds], mediaUnderstandingProviderIds: [...entry.mediaUnderstandingProviderIds], transcriptSourceProviderIds: [...entry.transcriptSourceProviderIds], documentExtractorIds: [...entry.documentExtractorIds], imageGenerationProviderIds: [...entry.imageGenerationProviderIds], videoGenerationProviderIds: [...entry.videoGenerationProviderIds], musicGenerationProviderIds: [...entry.musicGenerationProviderIds], webContentExtractorIds: [...entry.webContentExtractorIds], webFetchProviderIds: [...entry.webFetchProviderIds], webSearchProviderIds: [...entry.webSearchProviderIds], migrationProviderIds: [...entry.migrationProviderIds], toolNames: [...entry.toolNames] })); return loadPluginManifestRegistry({}).plugins.filter((plugin) => plugin.origin === "bundled" && (plugin.cliBackends.length > 0 || plugin.providers.length > 0 || (plugin.contracts?.embeddingProviders?.length ?? 0) > 0 || (plugin.contracts?.speechProviders?.length ?? 0) > 0 || (plugin.contracts?.realtimeTranscriptionProviders?.length ?? 0) > 0 || (plugin.contracts?.realtimeVoiceProviders?.length ?? 0) > 0 || (plugin.contracts?.mediaUnderstandingProviders?.length ?? 0) > 0 || (plugin.contracts?.transcriptSourceProviders?.length ?? 0) > 0 || (plugin.contracts?.documentExtractors?.length ?? 0) > 0 || (plugin.contracts?.imageGenerationProviders?.length ?? 0) > 0 || (plugin.contracts?.videoGenerationProviders?.length ?? 0) > 0 || (plugin.contracts?.musicGenerationProviders?.length ?? 0) > 0 || (plugin.contracts?.webContentExtractors?.length ?? 0) > 0 || (plugin.contracts?.webFetchProviders?.length ?? 0) > 0 || (plugin.contracts?.webSearchProviders?.length ?? 0) > 0 || (plugin.contracts?.migrationProviders?.length ?? 0) > 0 || (plugin.contracts?.tools?.length ?? 0) > 0)).map((plugin) => ({ pluginId: plugin.id, cliBackendIds: uniqueStrings(plugin.cliBackends), providerIds: uniqueStrings(plugin.providers), providerEnvVars: resolvePluginProviderEnvVars(plugin), embeddingProviderIds: uniqueStrings(plugin.contracts?.embeddingProviders ?? []), speechProviderIds: uniqueStrings(plugin.contracts?.speechProviders ?? []), realtimeTranscriptionProviderIds: uniqueStrings(plugin.contracts?.realtimeTranscriptionProviders ?? []), realtimeVoiceProviderIds: uniqueStrings(plugin.contracts?.realtimeVoiceProviders ?? []), mediaUnderstandingProviderIds: uniqueStrings(plugin.contracts?.mediaUnderstandingProviders ?? []), transcriptSourceProviderIds: uniqueStrings(plugin.contracts?.transcriptSourceProviders ?? []), documentExtractorIds: uniqueStrings(plugin.contracts?.documentExtractors ?? []), imageGenerationProviderIds: uniqueStrings(plugin.contracts?.imageGenerationProviders ?? []), videoGenerationProviderIds: uniqueStrings(plugin.contracts?.videoGenerationProviders ?? []), musicGenerationProviderIds: uniqueStrings(plugin.contracts?.musicGenerationProviders ?? []), webContentExtractorIds: uniqueStrings(plugin.contracts?.webContentExtractors ?? []), webFetchProviderIds: uniqueStrings(plugin.contracts?.webFetchProviders ?? []), webSearchProviderIds: uniqueStrings(plugin.contracts?.webSearchProviders ?? []), migrationProviderIds: uniqueStrings(plugin.contracts?.migrationProviders ?? []), toolNames: uniqueStrings(plugin.contracts?.tools ?? []) })); } function resolveBundledProviderContractPluginIds() { return uniqueStrings(resolveBundledManifestContracts().filter((entry) => entry.providerIds.length > 0).map((entry) => entry.pluginId)).toSorted((left, right) => left.localeCompare(right)); } function resolveBundledManifestContractPluginIds(contract) { return resolveManifestContractPluginIds({ contract, origin: "bundled" }); } function resolveBundledManifestPluginIdsForContract(contract) { return uniqueStrings(resolveBundledManifestContracts().filter((entry) => { switch (contract) { case "embeddingProviders": return entry.embeddingProviderIds.length > 0; case "speechProviders": return entry.speechProviderIds.length > 0; case "realtimeTranscriptionProviders": return entry.realtimeTranscriptionProviderIds.length > 0; case "realtimeVoiceProviders": return entry.realtimeVoiceProviderIds.length > 0; case "mediaUnderstandingProviders": return entry.mediaUnderstandingProviderIds.length > 0; case "transcriptSourceProviders": return entry.transcriptSourceProviderIds.length > 0; case "documentExtractors": return entry.documentExtractorIds.length > 0; case "imageGenerationProviders": return entry.imageGenerationProviderIds.length > 0; case "videoGenerationProviders": return entry.videoGenerationProviderIds.length > 0; case "musicGenerationProviders": return entry.musicGenerationProviderIds.length > 0; case "webContentExtractors": return entry.webContentExtractorIds.length > 0; case "webFetchProviders": return entry.webFetchProviderIds.length > 0; case "webSearchProviders": return entry.webSearchProviderIds.length > 0; case "migrationProviders": return entry.migrationProviderIds.length > 0; case "tools": return entry.toolNames.length > 0; } throw new Error("Unsupported manifest contract key"); }).map((entry) => entry.pluginId)).toSorted((left, right) => left.localeCompare(right)); } function formatBundledCapabilityPluginLoadError(params) { const plugin = params.registry.plugins.find((entry) => entry.id === params.pluginId); const diagnostics = params.registry.diagnostics.filter((entry) => entry.pluginId === params.pluginId).map((entry) => entry.message); const detailParts = plugin ? [ `status=${plugin.status}`, ...plugin.error ? [`error=${plugin.error}`] : [], `providerIds=[${plugin.providerIds.join(", ")}]`, `webFetchProviderIds=[${plugin.webFetchProviderIds.join(", ")}]`, `webSearchProviderIds=[${plugin.webSearchProviderIds.join(", ")}]` ] : ["plugin record missing"]; if (diagnostics.length > 0) detailParts.push(`diagnostics=${diagnostics.join(" | ")}`); return /* @__PURE__ */ new Error(`bundled ${params.capabilityLabel} contract load failed for ${params.pluginId}: ${detailParts.join("; ")}`); } function loadScopedCapabilityRuntimeRegistryEntries(params) { const discovery = discoverOpenClawPlugins({}); let lastFailure; for (let attempt = 0; attempt < 2; attempt += 1) { const registry = loadBundledCapabilityRuntimeRegistry({ pluginIds: [params.pluginId], pluginSdkResolution: "dist", discovery }); const entries = params.loadEntries(registry); if (entries.length > 0) return entries; const plugin = registry.plugins.find((entry) => entry.id === params.pluginId); lastFailure = formatBundledCapabilityPluginLoadError({ pluginId: params.pluginId, capabilityLabel: params.capabilityLabel, registry }); if (!(attempt === 0 && (!plugin || plugin.status !== "loaded" || params.loadDeclaredIds(plugin).length === 0))) break; } throw lastFailure ?? /* @__PURE__ */ new Error(`bundled ${params.capabilityLabel} contract load failed for ${params.pluginId}: no entries`); } function loadProviderContractEntriesForPluginIds(pluginIds) { return pluginIds.flatMap((pluginId) => loadProviderContractEntriesForPluginId(pluginId)); } function loadProviderContractEntriesForPluginId(pluginId) { const publicArtifactEntries = resolveBundledExplicitProviderContractsFromPublicArtifacts({ onlyPluginIds: [pluginId] }); if (publicArtifactEntries) return publicArtifactEntries; try { return loadScopedCapabilityRuntimeRegistryEntries({ pluginId, capabilityLabel: "provider", loadEntries: (registry) => registry.providers.filter((entry) => entry.pluginId === pluginId).map((entry) => ({ pluginId: entry.pluginId, provider: entry.provider })), loadDeclaredIds: (plugin) => plugin.providerIds }).map((entry) => ({ pluginId: entry.pluginId, provider: entry.provider })); } catch (error) { error instanceof Error || new Error(String(error)); return []; } } function loadProviderContractRegistry() { try { const publicArtifactEntries = resolveBundledProviderContractPluginIds().flatMap((pluginId) => resolveBundledExplicitProviderContractsFromPublicArtifacts({ onlyPluginIds: [pluginId] }) ?? []); const coveredPluginIds = new Set(publicArtifactEntries.map((entry) => entry.pluginId)); const remainingPluginIds = resolveBundledProviderContractPluginIds().filter((pluginId) => !coveredPluginIds.has(pluginId)); const runtimeEntries = remainingPluginIds.length > 0 ? loadBundledCapabilityRuntimeRegistry({ pluginIds: remainingPluginIds, pluginSdkResolution: "dist" }).providers.map((entry) => ({ pluginId: entry.pluginId, provider: entry.provider })) : []; return [...publicArtifactEntries, ...runtimeEntries]; } catch (error) { error instanceof Error || new Error(String(error)); return []; } } function loadUniqueProviderContractProviders() { return [...new Map(loadProviderContractRegistry().map((entry) => [entry.provider.id, entry.provider])).values()]; } function loadProviderContractPluginIds() { return [...resolveBundledProviderContractPluginIds()]; } function loadProviderContractCompatPluginIds() { return loadProviderContractPluginIds(); } function resolveWebSearchCredentialValue(provider) { if (provider.requiresCredential === false) return `${provider.id}-no-key-needed`; const envVar = provider.envVars.find((entry) => entry.trim().length > 0); if (!envVar) return `${provider.id}-test`; if (envVar === "OPENROUTER_API_KEY") return "openrouter-test"; return normalizeLowercaseStringOrEmpty(envVar).includes("api_key") ? `${provider.id}-test` : "sk-test"; } function resolveWebFetchCredentialValue(provider) { if (provider.requiresCredential === false) return `${provider.id}-no-key-needed`; const envVar = provider.envVars.find((entry) => entry.trim().length > 0); if (!envVar) return `${provider.id}-test`; return normalizeLowercaseStringOrEmpty(envVar).includes("api_key") ? `${provider.id}-test` : "sk-test"; } function loadWebFetchProviderContractRegistry() { return loadBundledCapabilityRuntimeRegistry({ pluginIds: resolveBundledManifestContractPluginIds("webFetchProviders"), pluginSdkResolution: "dist" }).webFetchProviders.map((entry) => ({ pluginId: entry.pluginId, provider: entry.provider, credentialValue: resolveWebFetchCredentialValue(entry.provider) })); } function loadWebSearchProviderContractRegistry() { const publicArtifactEntries = resolveBundledManifestContractPluginIds("webSearchProviders").flatMap((pluginId) => (resolveBundledExplicitWebSearchProvidersFromPublicArtifacts({ onlyPluginIds: [pluginId] }) ?? []).map((provider) => ({ pluginId: provider.pluginId, provider, credentialValue: resolveWebSearchCredentialValue(provider) }))); const coveredPluginIds = new Set(publicArtifactEntries.map((entry) => entry.pluginId)); const remainingPluginIds = resolveBundledManifestContractPluginIds("webSearchProviders").filter((pluginId) => !coveredPluginIds.has(pluginId)); const runtimeEntries = remainingPluginIds.length > 0 ? loadBundledCapabilityRuntimeRegistry({ pluginIds: remainingPluginIds, pluginSdkResolution: "dist" }).webSearchProviders.map((entry) => ({ pluginId: entry.pluginId, provider: entry.provider, credentialValue: resolveWebSearchCredentialValue(entry.provider) })) : []; return [...publicArtifactEntries, ...runtimeEntries]; } function loadSpeechProviderContractRegistry() { return process.env.VITEST ? loadVitestSpeechProviderContractRegistry() : loadBundledCapabilityRuntimeRegistry({ pluginIds: resolveBundledManifestPluginIdsForContract("speechProviders"), pluginSdkResolution: "dist" }).speechProviders.map((entry) => ({ pluginId: entry.pluginId, provider: entry.provider })); } function loadRealtimeVoiceProviderContractRegistry() { return process.env.VITEST ? loadVitestRealtimeVoiceProviderContractRegistry() : loadBundledCapabilityRuntimeRegistry({ pluginIds: resolveBundledManifestPluginIdsForContract("realtimeVoiceProviders"), pluginSdkResolution: "dist" }).realtimeVoiceProviders.map((entry) => ({ pluginId: entry.pluginId, provider: entry.provider })); } function loadRealtimeTranscriptionProviderContractRegistry() { return process.env.VITEST ? loadVitestRealtimeTranscriptionProviderContractRegistry() : loadBundledCapabilityRuntimeRegistry({ pluginIds: resolveBundledManifestPluginIdsForContract("realtimeTranscriptionProviders"), pluginSdkResolution: "dist" }).realtimeTranscriptionProviders.map((entry) => ({ pluginId: entry.pluginId, provider: entry.provider })); } function loadMediaUnderstandingProviderContractRegistry() { return process.env.VITEST ? loadVitestMediaUnderstandingProviderContractRegistry() : loadBundledCapabilityRuntimeRegistry({ pluginIds: resolveBundledManifestPluginIdsForContract("mediaUnderstandingProviders"), pluginSdkResolution: "dist" }).mediaUnderstandingProviders.map((entry) => ({ pluginId: entry.pluginId, provider: entry.provider })); } function loadTranscriptsSourceProviderContractRegistry() { return process.env.VITEST ? loadVitestTranscriptsSourceProviderContractRegistry() : loadBundledCapabilityRuntimeRegistry({ pluginIds: resolveBundledManifestPluginIdsForContract("transcriptSourceProviders"), pluginSdkResolution: "dist" }).transcriptSourceProviders.map((entry) => ({ pluginId: entry.pluginId, provider: entry.provider })); } function loadImageGenerationProviderContractRegistry() { return process.env.VITEST ? loadVitestImageGenerationProviderContractRegistry() : loadBundledCapabilityRuntimeRegistry({ pluginIds: resolveBundledManifestPluginIdsForContract("imageGenerationProviders"), pluginSdkResolution: "dist" }).imageGenerationProviders.map((entry) => ({ pluginId: entry.pluginId, provider: entry.provider })); } function loadVideoGenerationProviderContractRegistry() { return process.env.VITEST ? loadVitestVideoGenerationProviderContractRegistry() : loadBundledCapabilityRuntimeRegistry({ pluginIds: resolveBundledManifestPluginIdsForContract("videoGenerationProviders"), pluginSdkResolution: "dist" }).videoGenerationProviders.map((entry) => ({ pluginId: entry.pluginId, provider: entry.provider })); } function loadMusicGenerationProviderContractRegistry() { return process.env.VITEST ? loadVitestMusicGenerationProviderContractRegistry() : loadBundledCapabilityRuntimeRegistry({ pluginIds: resolveBundledManifestPluginIdsForContract("musicGenerationProviders"), pluginSdkResolution: "dist" }).musicGenerationProviders.map((entry) => ({ pluginId: entry.pluginId, provider: entry.provider })); } function createLazyArrayView(load) { return new Proxy([], { get(_target, prop) { const actual = load(); const value = Reflect.get(actual, prop, actual); return typeof value === "function" ? value.bind(actual) : value; }, has(_target, prop) { return Reflect.has(load(), prop); }, ownKeys() { return Reflect.ownKeys(load()); }, getOwnPropertyDescriptor(_target, prop) { const actual = load(); const descriptor = Reflect.getOwnPropertyDescriptor(actual, prop); if (descriptor) return descriptor; if (Reflect.has(actual, prop)) return { configurable: true, enumerable: true, writable: false, value: Reflect.get(actual, prop, actual) }; } }); } createLazyArrayView(loadProviderContractRegistry); createLazyArrayView(loadUniqueProviderContractProviders); createLazyArrayView(loadProviderContractPluginIds); createLazyArrayView(loadProviderContractCompatPluginIds); function resolveProviderContractPluginIdsForProviderAlias(providerId) { const normalizedProvider = normalizeProviderId(providerId); if (!normalizedProvider) return; const pluginIds = uniqueStrings(loadProviderContractEntriesForPluginIds(resolveBundledProviderContractPluginIds()).filter((entry) => { return [ entry.provider.id, ...entry.provider.aliases ?? [], ...entry.provider.hookAliases ?? [] ].some((candidate) => normalizeProviderId(candidate) === normalizedProvider); }).map((entry) => entry.pluginId)).toSorted((left, right) => left.localeCompare(right)); return pluginIds.length > 0 ? pluginIds : void 0; } createLazyArrayView(loadWebSearchProviderContractRegistry); createLazyArrayView(loadWebFetchProviderContractRegistry); createLazyArrayView(loadSpeechProviderContractRegistry); createLazyArrayView(loadRealtimeTranscriptionProviderContractRegistry); createLazyArrayView(loadRealtimeVoiceProviderContractRegistry); createLazyArrayView(loadMediaUnderstandingProviderContractRegistry); createLazyArrayView(loadTranscriptsSourceProviderContractRegistry); createLazyArrayView(loadImageGenerationProviderContractRegistry); createLazyArrayView(loadVideoGenerationProviderContractRegistry); createLazyArrayView(loadMusicGenerationProviderContractRegistry); function loadPluginRegistrationContractRegistry() { return resolveBundledManifestContracts(); } createLazyArrayView(loadPluginRegistrationContractRegistry); //#endregion export { resolveProviderContractPluginIdsForProviderAlias };