UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

130 lines (129 loc) 5.19 kB
import { D as resolveExpiresAtMsFromDurationMs, g as isFutureDateTimestampMs } from "./number-coercion-CLj0HTDM.js"; import { t as findNormalizedProviderKey } from "./provider-id-DMd-TDFp.js"; import { t as pruneMapToMaxSize } from "./map-size-CNcWiFKu.js"; import { o as normalizeConfiguredProviderCatalogModelId } from "./model-ref-shared-Dz7QU0Lx.js"; import { r as resolveProviderRequestCapabilities } from "./provider-attribution-CDS-94hQ.js"; import "./provider-catalog-8ARoyQkL.js"; import { createHash } from "node:crypto"; //#region src/plugin-sdk/provider-catalog-shared.ts const liveCatalogCache = /* @__PURE__ */ new Map(); function buildLiveCatalogCacheKey(parts) { return createHash("sha256").update(JSON.stringify(parts)).digest("hex"); } /** * Caches one live catalog load promise by stable key parts for a short TTL. */ async function getCachedLiveCatalogValue(params) { const rawNow = params.now?.() ?? Date.now(); const expiresAt = resolveExpiresAtMsFromDurationMs(params.ttlMs ?? 3e4, { nowMs: rawNow }); if (expiresAt === void 0) return await params.load(); const key = buildLiveCatalogCacheKey(params.keyParts); const existing = liveCatalogCache.get(key); if (existing) { if (isFutureDateTimestampMs(existing.expiresAt, { nowMs: rawNow })) return await existing.value; liveCatalogCache.delete(key); } const entry = { expiresAt, value: params.load() }; pruneMapToMaxSize(liveCatalogCache, 99); liveCatalogCache.set(key, entry); let retain = false; try { const resolved = await entry.value; retain = params.shouldCache?.(resolved) ?? true; return resolved; } finally { if (!retain && liveCatalogCache.get(key) === entry) liveCatalogCache.delete(key); } } /** * Clears the process-local live catalog cache for tests and isolated plugin probes. */ function clearLiveCatalogCacheForTests() { liveCatalogCache.clear(); } function normalizeConfiguredCatalogModelInput(input) { if (!Array.isArray(input)) return; const normalized = input.filter((item) => item === "text" || item === "image" || item === "audio" || item === "video" || item === "document"); return normalized.length > 0 ? normalized : void 0; } function resolveConfiguredProviderModels(config, providerId) { const providers = config?.models?.providers; if (!providers || typeof providers !== "object") return []; const providerKey = findNormalizedProviderKey(providers, providerId); if (!providerKey) return []; const providerConfig = providers[providerKey]; if (!providerConfig || typeof providerConfig !== "object") return []; return Array.isArray(providerConfig.models) ? providerConfig.models : []; } /** * Reads user-configured provider models as catalog entries for plugin discovery output. */ function readConfiguredProviderCatalogEntries(params) { const provider = params.publishedProviderId ?? params.providerId; const models = resolveConfiguredProviderModels(params.config, params.providerId); const entries = []; for (const model of models) { if (!model || typeof model !== "object") continue; const id = typeof model.id === "string" ? model.id.trim() : ""; if (!id) continue; const normalizedId = normalizeConfiguredProviderCatalogModelId(provider, id); const name = (typeof model.name === "string" ? model.name : normalizedId).trim() || normalizedId; const contextWindow = typeof model.contextWindow === "number" && model.contextWindow > 0 ? model.contextWindow : void 0; const reasoning = typeof model.reasoning === "boolean" ? model.reasoning : void 0; const input = normalizeConfiguredCatalogModelInput(model.input); entries.push({ provider, id: normalizedId, name, ...contextWindow ? { contextWindow } : {}, ...reasoning !== void 0 ? { reasoning } : {}, ...input ? { input } : {} }); } return entries; } function withStreamingUsageCompat(provider) { if (!Array.isArray(provider.models) || provider.models.length === 0) return provider; let changed = false; const models = provider.models.map((model) => { if (model.compat?.supportsUsageInStreaming !== void 0) return model; changed = true; return { ...model, compat: { ...model.compat, supportsUsageInStreaming: true } }; }); return changed ? { ...provider, models } : provider; } /** * Returns whether a provider transport can report native usage while streaming. */ function supportsNativeStreamingUsageCompat(params) { return resolveProviderRequestCapabilities({ provider: params.providerId, api: "openai-completions", baseUrl: params.baseUrl, capability: "llm", transport: "stream" }).supportsNativeStreamingUsageCompat; } /** * Marks models as streaming-usage compatible when provider transport capabilities allow it. */ function applyProviderNativeStreamingUsageCompat(params) { return supportsNativeStreamingUsageCompat({ providerId: params.providerId, baseUrl: params.providerConfig.baseUrl }) ? withStreamingUsageCompat(params.providerConfig) : params.providerConfig; } //#endregion export { supportsNativeStreamingUsageCompat as a, readConfiguredProviderCatalogEntries as i, clearLiveCatalogCacheForTests as n, getCachedLiveCatalogValue as r, applyProviderNativeStreamingUsageCompat as t };