openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
281 lines (280 loc) • 12.6 kB
JavaScript
import { i as formatErrorMessage } from "./errors-BXgSefBE.js";
import { g as sortUniqueStrings } from "./string-normalization-WNUDCpXX.js";
import { t as createSubsystemLogger } from "./subsystem-BzXSmsuh.js";
import { i as normalizeProviderId } from "./provider-id-Dq06Bcx6.js";
import { c as resolveProviderOwners, m as loadPluginRegistrySnapshotWithMetadata, s as resolvePluginContributionOwners } from "./plugin-registry-ChcJPHWl.js";
import { u as loadAuthProfileStoreWithoutExternalProfiles } from "./store-C8spD0DG.js";
import { g as resolveOwningPluginIdsForProviderRef, s as resolveBundledProviderCompatPluginIds } from "./plugin-auto-enable-pAtqig-B.js";
import { n as readCachedAgentModelCatalog, r as writeCachedAgentModelCatalog, t as buildAgentModelCatalogCacheKey } from "./model-catalog-state-cache-BMVIG9NR.js";
import { t as buildModelsJsonSourceFingerprint } from "./models-config-SUxEzcTF.js";
import { a as runProviderStaticCatalog, i as runProviderCatalog, n as normalizePluginDiscoveryResult, r as resolveRuntimePluginDiscoveryProviders, t as groupPluginDiscoveryProvidersByOrder } from "./provider-discovery-Cuk49qKB.js";
import { n as createProviderAuthResolver, t as createProviderApiKeyResolver } from "./models-config.providers.secrets-CK7mTB4U.js";
import { createHash } from "node:crypto";
//#region src/commands/models/list.provider-catalog.ts
/** Provider plugin catalog loading for model-list output. */
const DISCOVERY_ORDERS = [
"simple",
"profile",
"paired",
"late"
];
const SELF_HOSTED_DISCOVERY_PROVIDER_IDS = new Set([
"lmstudio",
"ollama",
"sglang",
"vllm"
]);
const log = createSubsystemLogger("models/list-provider-catalog");
function buildProviderCatalogEnvCacheFingerprint(env) {
const entries = Object.entries(env).filter((entry) => entry[1] !== void 0).map(([key, value]) => [key, createHash("sha256").update(value).digest("hex")]).toSorted(([left], [right]) => left.localeCompare(right));
return createHash("sha256").update(JSON.stringify(entries)).digest("hex");
}
function providerMatchesFilter(params) {
return [
params.provider.id,
...params.provider.aliases ?? [],
...params.provider.hookAliases ?? []
].some((providerId) => normalizeProviderId(providerId) === params.providerFilter);
}
function collectMatchingContributionOwners(index, contribution, providerFilter, cfg, options = {}) {
if (contribution === "providers") return [...resolveProviderOwners({
index,
providerId: providerFilter,
includeDisabled: options.includeDisabled,
config: cfg
})];
return [...resolvePluginContributionOwners({
index,
contribution: "cliBackends",
matches: (contributionId) => normalizeProviderId(contributionId) === providerFilter,
includeDisabled: options.includeDisabled,
config: cfg
})];
}
function resolveInstalledIndexPluginIdsForProviderFilter(params) {
const snapshot = loadPluginRegistrySnapshotWithMetadata({
config: params.cfg,
env: params.env,
index: params.registryIndex
});
if (snapshot.source !== "persisted" && snapshot.source !== "provided") return;
const index = snapshot.snapshot;
const pluginIds = [...collectMatchingContributionOwners(index, "providers", params.providerFilter, params.cfg), ...collectMatchingContributionOwners(index, "cliBackends", params.providerFilter, params.cfg)];
if (pluginIds.length > 0) return sortUniqueStrings(pluginIds);
return [...collectMatchingContributionOwners(index, "providers", params.providerFilter, params.cfg, { includeDisabled: true }), ...collectMatchingContributionOwners(index, "cliBackends", params.providerFilter, params.cfg, { includeDisabled: true })].length > 0 ? [] : void 0;
}
/** Resolves plugin ids that can provide catalog rows for a provider filter. */
async function resolveProviderCatalogPluginIdsForFilter(params) {
const providerFilter = normalizeProviderId(params.providerFilter);
if (!providerFilter) return;
const installedIndexPluginIds = resolveInstalledIndexPluginIdsForProviderFilter({
cfg: params.cfg,
env: params.env,
providerFilter,
registryIndex: params.metadataSnapshot?.index ?? params.registryIndex
});
if (installedIndexPluginIds) return installedIndexPluginIds;
const manifestPluginIds = resolveOwningPluginIdsForProviderRef({
provider: providerFilter,
config: params.cfg,
env: params.env,
manifestRegistry: params.metadataSnapshot?.manifestRegistry
});
if (manifestPluginIds) return manifestPluginIds;
const { resolveProviderContractPluginIdsForProviderAlias } = await import("./registry-DxqynoV1.js");
const bundledAliasPluginIds = resolveProviderContractPluginIdsForProviderAlias(providerFilter);
if (bundledAliasPluginIds) return bundledAliasPluginIds;
}
/** Returns true when a provider filter can be satisfied by a static bundled catalog. */
async function hasProviderStaticCatalogForFilter(params) {
return await hasProviderCatalogForFilter(params, (provider) => typeof provider.staticCatalog?.run === "function", { discoveryEntriesOnly: true });
}
async function hasProviderRuntimeCatalogForFilter(params) {
return await hasProviderCatalogForFilter(params, (provider) => typeof provider.catalog?.run === "function" || typeof provider.discovery?.run === "function", { discoveryEntriesOnly: false });
}
async function hasProviderCatalogForFilter(params, predicate, options) {
const env = params.env ?? process.env;
const providerFilter = normalizeProviderId(params.providerFilter);
if (!providerFilter) return false;
const pluginIds = await resolveProviderCatalogPluginIdsForFilter({
...params,
env,
registryIndex: params.metadataSnapshot?.index ?? params.registryIndex
});
if (!pluginIds || pluginIds.length === 0) return false;
const bundledPluginIds = resolveBundledProviderCompatPluginIds({
config: params.cfg,
env,
manifestRegistry: params.metadataSnapshot?.manifestRegistry
});
const bundledPluginIdSet = new Set(bundledPluginIds);
const scopedPluginIds = pluginIds.filter((pluginId) => bundledPluginIdSet.has(pluginId));
if (scopedPluginIds.length === 0) return false;
return (await resolveRuntimePluginDiscoveryProviders({
config: params.cfg,
env,
onlyPluginIds: scopedPluginIds,
includeUntrustedWorkspacePlugins: false,
requireCompleteDiscoveryEntryCoverage: options.discoveryEntriesOnly,
discoveryEntriesOnly: options.discoveryEntriesOnly,
pluginMetadataSnapshot: params.metadataSnapshot
})).some((provider) => predicate(provider) && providerMatchesFilter({
provider,
providerFilter
}));
}
function modelFromProviderCatalog(params) {
return {
id: params.model.id,
name: params.model.name || params.model.id,
provider: params.provider,
api: params.model.api ?? params.providerConfig.api ?? "openai-responses",
baseUrl: params.model.baseUrl ?? params.providerConfig.baseUrl,
reasoning: params.model.reasoning,
input: params.model.input ?? ["text"],
cost: params.model.cost,
contextWindow: params.model.contextWindow,
contextTokens: params.model.contextTokens,
maxTokens: params.model.maxTokens,
headers: params.model.headers,
compat: params.model.compat
};
}
async function runProviderCatalogForList(params) {
if (params.staticOnly === true) return await runProviderStaticCatalog({
provider: params.provider,
config: params.cfg,
agentDir: params.agentDir,
env: params.env
}) ?? null;
if (typeof params.provider.catalog?.run === "function" || typeof params.provider.discovery?.run === "function") {
const authStore = loadAuthProfileStoreWithoutExternalProfiles(params.agentDir);
const resolveProviderApiKey = createProviderApiKeyResolver(params.env, authStore, params.cfg);
const resolveProviderAuth = createProviderAuthResolver(params.env, authStore, params.cfg);
try {
const runtimeResult = await runProviderCatalog({
provider: params.provider,
config: params.cfg,
agentDir: params.agentDir,
env: params.env,
resolveProviderApiKey: (providerId) => resolveProviderApiKey(providerId?.trim() || params.provider.id),
resolveProviderAuth: (providerId, options) => resolveProviderAuth(providerId?.trim() || params.provider.id, options)
});
if (runtimeResult) return runtimeResult;
} catch (error) {
log.warn(`provider runtime catalog failed for ${params.provider.id}: ${formatErrorMessage(error)}`);
}
}
if (typeof params.provider.staticCatalog?.run !== "function") return null;
return await runProviderStaticCatalog({
provider: params.provider,
config: params.cfg,
agentDir: params.agentDir,
env: params.env
}) ?? null;
}
/** Loads model rows from provider static/runtime catalog hooks for model-list output. */
async function loadProviderCatalogModelsForList(params) {
const env = params.env ?? process.env;
const providerFilter = params.providerFilter ? normalizeProviderId(params.providerFilter) : "";
const onlyPluginIds = providerFilter ? await resolveProviderCatalogPluginIdsForFilter({
cfg: params.cfg,
env,
providerFilter,
registryIndex: params.metadataSnapshot?.index ?? params.registryIndex,
metadataSnapshot: params.metadataSnapshot
}) : void 0;
if (providerFilter && !onlyPluginIds) return [];
const bundledPluginIds = resolveBundledProviderCompatPluginIds({
config: params.cfg,
env,
manifestRegistry: params.metadataSnapshot?.manifestRegistry
});
const bundledPluginIdSet = new Set(bundledPluginIds);
const scopedPluginIds = onlyPluginIds ? onlyPluginIds.filter((pluginId) => bundledPluginIdSet.has(pluginId)) : bundledPluginIds;
if (scopedPluginIds.length === 0) return [];
const sourceFingerprint = await buildModelsJsonSourceFingerprint(params.cfg, params.agentDir, {
pluginMetadataSnapshot: params.metadataSnapshot,
providerDiscoveryEntriesOnly: params.staticOnly === true,
providerDiscoveryProviderIds: scopedPluginIds,
workspaceDir: params.metadataSnapshot?.workspaceDir
});
const catalogKey = buildAgentModelCatalogCacheKey({
agentDir: params.agentDir,
cacheScope: {
envFingerprint: buildProviderCatalogEnvCacheFingerprint(env),
source: "models-list-provider-catalog",
providerFilter,
scopedPluginIds,
sourceFingerprint: sourceFingerprint.fingerprint,
staticOnly: params.staticOnly === true
},
config: params.cfg,
metadataSnapshot: params.metadataSnapshot,
workspaceDir: params.metadataSnapshot?.workspaceDir
});
const cached = readCachedAgentModelCatalog({
agentDir: params.agentDir,
catalogKey
});
if (cached?.length) return cached;
const byOrder = groupPluginDiscoveryProvidersByOrder((await resolveRuntimePluginDiscoveryProviders({
config: params.cfg,
env,
onlyPluginIds: scopedPluginIds,
includeUntrustedWorkspacePlugins: false,
requireCompleteDiscoveryEntryCoverage: params.staticOnly === true,
discoveryEntriesOnly: params.staticOnly === true,
pluginMetadataSnapshot: params.metadataSnapshot
})).filter((provider) => typeof provider.pluginId === "string" && bundledPluginIdSet.has(provider.pluginId)));
const rows = [];
const seen = /* @__PURE__ */ new Set();
for (const order of DISCOVERY_ORDERS) for (const provider of byOrder[order] ?? []) {
if (!providerFilter && SELF_HOSTED_DISCOVERY_PROVIDER_IDS.has(provider.id)) continue;
let result;
try {
result = await runProviderCatalogForList({
provider,
cfg: params.cfg,
agentDir: params.agentDir,
env,
staticOnly: params.staticOnly
});
} catch (error) {
log.warn(`provider catalog failed for ${provider.id}: ${formatErrorMessage(error)}`);
result = null;
}
const normalized = normalizePluginDiscoveryResult({
provider,
result
});
for (const [providerIdRaw, providerConfig] of Object.entries(normalized)) {
const providerId = normalizeProviderId(providerIdRaw);
if (providerFilter && providerId !== providerFilter) continue;
if (!providerId || !Array.isArray(providerConfig.models)) continue;
for (const model of providerConfig.models) {
const key = `${providerId}/${model.id}`;
if (seen.has(key)) continue;
seen.add(key);
rows.push(modelFromProviderCatalog({
provider: providerId,
providerConfig,
model
}));
}
}
}
const sorted = rows.toSorted((left, right) => {
const provider = left.provider.localeCompare(right.provider);
if (provider !== 0) return provider;
return left.id.localeCompare(right.id);
});
writeCachedAgentModelCatalog({
agentDir: params.agentDir,
catalogKey,
entries: sorted
});
return sorted;
}
//#endregion
export { resolveProviderCatalogPluginIdsForFilter as i, hasProviderStaticCatalogForFilter as n, loadProviderCatalogModelsForList as r, hasProviderRuntimeCatalogForFilter as t };