UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

285 lines (284 loc) • 12.6 kB
import { o as normalizeLowercaseStringOrEmpty } from "./string-coerce-1VuiLaaR.mjs"; import { n as computeBackoff } from "./src-D1BHGNTj.mjs"; import { r as normalizeProviderId } from "./provider-id-D1VImdKk.mjs"; import "./backoff-BrzXG7iD.mjs"; import { r as getRuntimeConfig } from "./io.runtime-B134MOMz.mjs"; import "./config-VnHbY_QV.mjs"; import "./model-selection-Cpoq0B2R.mjs"; import { a as resolveModelContextTokenProjectionFromCache, c as providerContextTokenCacheKey, l as replaceContextWindowCaches, o as REUSED_CONTEXT_WINDOW_CACHE_STATE, s as getContextWindowCaches, t as resolveAnthropicFixedContextWindow, u as replaceDiscoveredContextTokenCache } from "./context-resolution-B-tr3K6X.mjs"; import { setImmediate } from "node:timers/promises"; //#region src/agents/context-cache-projection.ts const CONTEXT_PROJECTION_BATCH_SIZE = 512; function cacheMinimum(cache, key, contextTokens) { const existing = cache.get(key); if (existing === void 0 || contextTokens < existing) cache.set(key, contextTokens); } function contextModelKeys(modelId, provider) { const keys = [modelId]; if (provider === void 0) return keys; keys.push(providerContextTokenCacheKey(provider, modelId)); const slash = modelId.indexOf("/"); const prefixedProvider = slash > 0 ? normalizeProviderId(modelId.slice(0, slash)) : ""; const bareModelId = slash > 0 ? modelId.slice(slash + 1).trim() : ""; if (provider && prefixedProvider === provider && bareModelId) keys.push(providerContextTokenCacheKey(provider, bareModelId)); return keys; } function applyDiscoveredContextWindow(cache, model) { if (!model?.id) return; const discoveredContextTokens = typeof model.contextTokens === "number" ? Math.trunc(model.contextTokens) : typeof model.contextWindow === "number" ? Math.trunc(model.contextWindow) : void 0; const contextTokens = resolveDiscoveredAnthropicFixedContextWindow(model) ?? discoveredContextTokens; if (!contextTokens || contextTokens <= 0) return; const provider = typeof model.provider === "string" ? normalizeProviderId(model.provider) : ""; for (const key of contextModelKeys(model.id, provider || void 0)) cacheMinimum(cache, key, contextTokens); } function applyConfiguredContextWindows(params) { const providers = params.modelsConfig?.providers; if (!providers || typeof providers !== "object") return; for (const [providerId, provider] of Object.entries(providers)) { if (!Array.isArray(provider?.models)) continue; for (const model of provider.models) applyConfiguredContextWindow({ cache: params.cache, windowCache: params.windowCache, providerId, model }); } } function applyConfiguredContextWindow(params) { const modelId = typeof params.model?.id === "string" ? params.model.id : void 0; const contextTokens = typeof params.model?.contextTokens === "number" ? params.model.contextTokens : void 0; const contextWindow = typeof params.model?.contextWindow === "number" ? params.model.contextWindow : void 0; const configuredValue = contextTokens && contextTokens > 0 ? { cache: params.cache, value: contextTokens } : contextWindow && contextWindow > 0 ? { cache: params.windowCache, value: contextWindow } : void 0; if (!modelId || !configuredValue) return; for (const key of contextModelKeys(modelId, normalizeProviderId(params.providerId))) configuredValue.cache.set(key, configuredValue.value); } function resolveDiscoveredAnthropicFixedContextWindow(model) { const provider = typeof model.provider === "string" ? normalizeProviderId(model.provider) : void 0; if (provider) return resolveAnthropicFixedContextWindow(provider, model.id); const normalized = normalizeLowercaseStringOrEmpty(model.id); const slash = normalized.indexOf("/"); if (slash < 0) return; const inferredProvider = normalizeProviderId(normalized.slice(0, slash)); const inferredModel = normalized.slice(slash + 1); return inferredProvider === "claude-cli" ? resolveAnthropicFixedContextWindow(inferredProvider, inferredModel) : void 0; } async function projectModels(params) { let processed = params.processed; for (const models of [params.modelCatalog.entries, params.modelCatalog.staticEntries ?? []]) for (const model of models) { applyDiscoveredContextWindow(params.cache, model); processed += 1; if (processed % CONTEXT_PROJECTION_BATCH_SIZE === 0) { await setImmediate(); params.assertCurrent?.(); } } } async function prepareContextWindowCaches(params) { const caches = { configuredTokenCache: /* @__PURE__ */ new Map(), discoveredTokenCache: /* @__PURE__ */ new Map(), contextWindowCache: /* @__PURE__ */ new Map() }; let processed = 0; const providers = params.config.models?.providers; if (providers && typeof providers === "object") for (const [providerId, provider] of Object.entries(providers)) { if (!Array.isArray(provider?.models)) continue; for (const model of provider.models) { applyConfiguredContextWindow({ cache: caches.configuredTokenCache, windowCache: caches.contextWindowCache, providerId, model }); processed += 1; if (processed % CONTEXT_PROJECTION_BATCH_SIZE === 0) { await setImmediate(); params.assertCurrent?.(); } } } await projectModels({ cache: caches.discoveredTokenCache, modelCatalog: params.modelCatalog, processed, assertCurrent: params.assertCurrent }); params.assertCurrent?.(); return caches; } async function prepareDiscoveredContextTokenCache(params) { const cache = /* @__PURE__ */ new Map(); await projectModels({ cache, modelCatalog: params.modelCatalog, processed: 0, assertCurrent: params.assertCurrent }); params.assertCurrent?.(); return cache; } //#endregion //#region src/agents/context-runtime-state.ts const CONTEXT_WINDOW_RUNTIME_STATE_KEY = Symbol.for("openclaw.contextWindowRuntimeState"); const globalState = globalThis; /** Shared mutable state for context-window resolution and model discovery. */ const CONTEXT_WINDOW_RUNTIME_STATE = globalState[CONTEXT_WINDOW_RUNTIME_STATE_KEY] ||= { generation: 0, loadPromise: null, loadGeneration: null, configuredConfig: void 0, configLoadFailures: 0, nextConfigLoadAttemptAtMs: 0 }; if (!REUSED_CONTEXT_WINDOW_CACHE_STATE) { CONTEXT_WINDOW_RUNTIME_STATE.loadPromise = null; CONTEXT_WINDOW_RUNTIME_STATE.loadGeneration = null; } /** Invalidate prepared context metadata while a replacement load is staged. */ function beginContextWindowCacheRefresh() { CONTEXT_WINDOW_RUNTIME_STATE.generation += 1; CONTEXT_WINDOW_RUNTIME_STATE.configuredConfig = void 0; CONTEXT_WINDOW_RUNTIME_STATE.configLoadFailures = 0; CONTEXT_WINDOW_RUNTIME_STATE.nextConfigLoadAttemptAtMs = 0; } //#endregion //#region src/agents/context.ts const CONFIG_LOAD_RETRY_POLICY = { initialMs: 1e3, maxMs: 6e4, factor: 2, jitter: 0 }; const loadPreparedModelCatalogRuntime = () => import("./prepared-model-catalog-lJotEjrx.mjs"); function primeConfiguredContextWindowsFromConfig(cfg) { const caches = getContextWindowCaches(); applyConfiguredContextWindows({ cache: caches.configuredTokenCache, windowCache: caches.contextWindowCache, modelsConfig: cfg.models }); CONTEXT_WINDOW_RUNTIME_STATE.configuredConfig = cfg; CONTEXT_WINDOW_RUNTIME_STATE.configLoadFailures = 0; CONTEXT_WINDOW_RUNTIME_STATE.nextConfigLoadAttemptAtMs = 0; return cfg; } function primeConfiguredContextWindows() { if (CONTEXT_WINDOW_RUNTIME_STATE.configuredConfig) return primeConfiguredContextWindowsFromConfig(CONTEXT_WINDOW_RUNTIME_STATE.configuredConfig); if (Date.now() < CONTEXT_WINDOW_RUNTIME_STATE.nextConfigLoadAttemptAtMs) return; try { return primeConfiguredContextWindowsFromConfig(getRuntimeConfig()); } catch { CONTEXT_WINDOW_RUNTIME_STATE.configLoadFailures += 1; const backoffMs = computeBackoff(CONFIG_LOAD_RETRY_POLICY, CONTEXT_WINDOW_RUNTIME_STATE.configLoadFailures); CONTEXT_WINDOW_RUNTIME_STATE.nextConfigLoadAttemptAtMs = Date.now() + backoffMs; return; } } function ensureContextWindowCacheLoaded(cfgOverride) { const generation = CONTEXT_WINDOW_RUNTIME_STATE.generation; if (CONTEXT_WINDOW_RUNTIME_STATE.loadPromise && CONTEXT_WINDOW_RUNTIME_STATE.loadGeneration === generation) return CONTEXT_WINDOW_RUNTIME_STATE.loadPromise; const cfg = cfgOverride ? primeConfiguredContextWindowsFromConfig(cfgOverride) : primeConfiguredContextWindows(); if (!cfg) return Promise.resolve(); CONTEXT_WINDOW_RUNTIME_STATE.loadPromise = Promise.resolve().then(async () => { if (CONTEXT_WINDOW_RUNTIME_STATE.generation !== generation) return; let stagedTokenCache = /* @__PURE__ */ new Map(); try { const { loadPreparedModelCatalogOwnerSnapshot } = await loadPreparedModelCatalogRuntime(); const owner = await loadPreparedModelCatalogOwnerSnapshot({ config: cfg, readOnly: true }); if (CONTEXT_WINDOW_RUNTIME_STATE.generation !== generation) return; stagedTokenCache = await prepareDiscoveredContextTokenCache({ modelCatalog: owner.modelCatalog, assertCurrent: () => { if (CONTEXT_WINDOW_RUNTIME_STATE.generation !== generation) throw new Error("context window cache generation was superseded"); } }); } catch {} if (CONTEXT_WINDOW_RUNTIME_STATE.generation === generation) replaceDiscoveredContextTokenCache(stagedTokenCache); }).catch(() => {}); CONTEXT_WINDOW_RUNTIME_STATE.loadGeneration = generation; return CONTEXT_WINDOW_RUNTIME_STATE.loadPromise; } /** * Reuse the Gateway's published catalog generation. Omitting the Gateway binding * falls through to a read-only owner whose key hashes the full model config. */ async function prewarmContextWindowCacheAfterReady(params) { beginContextWindowCacheRefresh(); const generation = CONTEXT_WINDOW_RUNTIME_STATE.generation; const shouldStop = () => CONTEXT_WINDOW_RUNTIME_STATE.generation !== generation || params.isCancelled?.() === true; if (shouldStop()) return; let published = false; const loadPromise = (async () => { const { getPublishedPreparedModelCatalogOwnerSnapshot } = await loadPreparedModelCatalogRuntime(); if (shouldStop()) return; const owner = getPublishedPreparedModelCatalogOwnerSnapshot({ config: params.config, allowGatewaySubagentBinding: true }); if (!owner) throw new Error("published Gateway model catalog owner is unavailable"); if (shouldStop()) return; const caches = await prepareContextWindowCaches({ config: owner.config, modelCatalog: owner.modelCatalog, assertCurrent: () => { if (shouldStop()) throw new Error("context window cache prewarm cancelled"); } }); if (shouldStop()) return; replaceContextWindowCaches(caches); CONTEXT_WINDOW_RUNTIME_STATE.configuredConfig = owner.config; CONTEXT_WINDOW_RUNTIME_STATE.configLoadFailures = 0; CONTEXT_WINDOW_RUNTIME_STATE.nextConfigLoadAttemptAtMs = 0; published = true; })(); const trackedLoadPromise = loadPromise.catch(() => {}); CONTEXT_WINDOW_RUNTIME_STATE.loadPromise = trackedLoadPromise; CONTEXT_WINDOW_RUNTIME_STATE.loadGeneration = generation; try { await loadPromise; } catch {} finally { if (!published && CONTEXT_WINDOW_RUNTIME_STATE.generation === generation && CONTEXT_WINDOW_RUNTIME_STATE.loadPromise === trackedLoadPromise) { CONTEXT_WINDOW_RUNTIME_STATE.loadPromise = null; CONTEXT_WINDOW_RUNTIME_STATE.loadGeneration = null; } } } /** Restore configured context limits without acquiring a model catalog. */ function resetContextWindowCache(cfg) { beginContextWindowCacheRefresh(); const caches = getContextWindowCaches(); caches.configuredTokenCache.clear(); caches.contextWindowCache.clear(); primeConfiguredContextWindowsFromConfig(cfg); } /** Replace cached model context metadata for the active runtime configuration. */ async function refreshContextWindowCache(cfg) { resetContextWindowCache(cfg); await ensureContextWindowCacheLoaded(); } function prepareContextWindowCache(options) { if (options?.skipRuntimeConfigLoad) return; if (options?.allowAsyncLoad === false) primeConfiguredContextWindows(); else ensureContextWindowCacheLoaded(); } function resolveContextTokensForModel(params) { return resolveModelContextTokenProjection(params).contextTokens; } function resolveModelContextTokenProjection(params) { prepareContextWindowCache({ allowAsyncLoad: params.allowAsyncLoad, skipRuntimeConfigLoad: Boolean(params.cfg) || params.allowCacheLookup === false }); return resolveModelContextTokenProjectionFromCache(params); } //#endregion export { resolveContextTokensForModel as a, resetContextWindowCache as i, prewarmContextWindowCacheAfterReady as n, resolveModelContextTokenProjection as o, refreshContextWindowCache as r, ensureContextWindowCacheLoaded as t };