openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
86 lines (85 loc) • 4.54 kB
JavaScript
import { i as normalizeProviderId } from "./provider-id-Dq06Bcx6.js";
import { existsSync, readdirSync } from "node:fs";
import path from "node:path";
//#region src/agents/plugin-model-catalog.ts
/**
* Generated plugin model catalog discovery.
*
* Catalog files live under agent profiles and let provider discovery reuse plugin-owned catalogs without loading runtimes.
*/
const PLUGIN_MODEL_CATALOG_FILE = "catalog.json";
const PLUGIN_MODEL_CATALOG_GENERATED_BY = "openclaw-plugin-model-catalog-v1";
/** Encodes the profile-relative path for a plugin-owned generated model catalog. */
function encodePluginModelCatalogRelativePath(pluginId) {
return `plugins/${encodeURIComponent(pluginId)}/${PLUGIN_MODEL_CATALOG_FILE}`;
}
/** Returns true only for canonical profile-relative generated catalog paths. */
function isPluginModelCatalogRelativePath(relativePath) {
const parts = relativePath.split(/[\\/]/);
return !path.isAbsolute(relativePath) && parts.length === 3 && parts[0] === "plugins" && parts[1] !== "" && parts[1] !== "." && parts[1] !== ".." && parts[2] === "catalog.json";
}
/** Decodes the plugin id from a canonical generated catalog path. */
function decodePluginModelCatalogRelativePathPluginId(relativePath) {
if (!isPluginModelCatalogRelativePath(relativePath)) return;
const encodedPluginId = relativePath.split(/[\\/]/)[1];
try {
return decodeURIComponent(encodedPluginId);
} catch {
return;
}
}
/** Lists deterministic generated catalog paths present in an agent profile. */
function listPluginModelCatalogRelativePaths(agentDir) {
const pluginsDir = path.join(agentDir, "plugins");
let pluginDirs;
try {
pluginDirs = readdirSync(pluginsDir, { withFileTypes: true });
} catch {
return [];
}
return pluginDirs.filter((entry) => entry.isDirectory()).map((entry) => path.join("plugins", entry.name, PLUGIN_MODEL_CATALOG_FILE)).filter(isPluginModelCatalogRelativePath).toSorted((left, right) => left.localeCompare(right));
}
/** Lists existing generated catalog files with decoded plugin ownership. */
function listPluginModelCatalogFiles(agentDir) {
return listPluginModelCatalogRelativePaths(agentDir).map((relativePath) => {
const pluginId = decodePluginModelCatalogRelativePathPluginId(relativePath);
return pluginId ? {
path: path.join(agentDir, relativePath),
pluginId,
relativePath
} : void 0;
}).filter((entry) => entry !== void 0).filter((entry) => existsSync(entry.path));
}
/** Detects model catalogs generated by OpenClaw rather than user-authored JSON. */
function isGeneratedPluginModelCatalog(value) {
return typeof value === "object" && value !== null && !Array.isArray(value) && value.generatedBy === "openclaw-plugin-model-catalog-v1";
}
/** Resolves the sole enabled plugin that owns a provider's model catalog. */
function resolvePluginModelCatalogOwnerPluginId(params) {
const snapshot = params.pluginMetadataSnapshot;
const owners = snapshot?.owners;
if (!owners) return;
const providerId = normalizeProviderId(params.providerId);
const candidates = [
owners.modelCatalogProviders.get(providerId),
owners.providers.get(providerId),
owners.setupProviders.get(providerId)
].find((entry) => Array.isArray(entry) && entry.length > 0);
const pluginId = candidates?.length === 1 ? candidates[0] : void 0;
if (!pluginId) return;
if (!snapshot?.index) return pluginId;
const normalizedPluginId = snapshot.normalizePluginId?.(pluginId) ?? pluginId;
return snapshot.index.plugins.some((plugin) => plugin.pluginId === normalizedPluginId && plugin.enabled) ? normalizedPluginId : void 0;
}
/** Keeps generated catalog providers only when the catalog plugin still owns them. */
function filterGeneratedPluginModelCatalogProviders(params) {
if (!params.catalogPluginId || !params.pluginMetadataSnapshot || params.parsedCatalog !== void 0 && !isGeneratedPluginModelCatalog(params.parsedCatalog)) return {};
return Object.fromEntries(Object.entries(params.providers).filter(([providerId]) => {
return resolvePluginModelCatalogOwnerPluginId({
providerId,
pluginMetadataSnapshot: params.pluginMetadataSnapshot
}) === params.catalogPluginId;
}));
}
//#endregion
export { isGeneratedPluginModelCatalog as a, listPluginModelCatalogRelativePaths as c, filterGeneratedPluginModelCatalogProviders as i, resolvePluginModelCatalogOwnerPluginId as l, decodePluginModelCatalogRelativePathPluginId as n, isPluginModelCatalogRelativePath as o, encodePluginModelCatalogRelativePath as r, listPluginModelCatalogFiles as s, PLUGIN_MODEL_CATALOG_GENERATED_BY as t };