openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
254 lines (253 loc) • 11.7 kB
JavaScript
import { a as normalizeLowercaseStringOrEmpty } from "./string-coerce-mnp54Vah.js";
import { t as createLazyImportLoader } from "./lazy-promise-BONnzNfb.js";
import "./agent-scope-MrLta7Pq.js";
import { c as resolveDefaultAgentId, o as resolveAgentWorkspaceDir, s as resolveDefaultAgentDir } from "./agent-scope-config-CgCYpZfK.js";
import { i as getRuntimeConfig } from "./io-Gi7-pyU-.js";
import "./config-C9RxTsn1.js";
import { o as normalizeProviderId } from "./model-selection-normalize-roKDxQ9_.js";
import "./model-selection-CA_65iXi.js";
import { t as computeBackoff } from "./backoff-S1yazmy1.js";
import { n as discoverModels, t as discoverAuthStorage } from "./agent-model-discovery-BSvavgs4.js";
//#region src/agents/context-cache.ts
/** Process-local model context window cache keyed by model id. */
const MODEL_CONTEXT_TOKEN_CACHE = /* @__PURE__ */ new Map();
/** Looks up cached context-token count for a model id. */
function lookupCachedContextTokens(modelId) {
if (!modelId) return;
return MODEL_CONTEXT_TOKEN_CACHE.get(modelId);
}
//#endregion
//#region src/agents/context-runtime-state.ts
const CONTEXT_WINDOW_RUNTIME_STATE_KEY = Symbol.for("openclaw.contextWindowRuntimeState");
/** Shared mutable state for context-window resolution and model config loading. */
const CONTEXT_WINDOW_RUNTIME_STATE = (() => {
const globalState = globalThis;
if (!globalState[CONTEXT_WINDOW_RUNTIME_STATE_KEY]) globalState[CONTEXT_WINDOW_RUNTIME_STATE_KEY] = {
loadPromise: null,
configuredConfig: void 0,
configLoadFailures: 0,
nextConfigLoadAttemptAtMs: 0,
modelsConfigRuntimeLoader: createLazyImportLoader(() => import("./agents/models-config.runtime.js"))
};
return globalState[CONTEXT_WINDOW_RUNTIME_STATE_KEY];
})();
/** Reset context-window runtime state and token cache for isolated tests. */
function resetContextWindowCacheForTest() {
CONTEXT_WINDOW_RUNTIME_STATE.loadPromise = null;
CONTEXT_WINDOW_RUNTIME_STATE.configuredConfig = void 0;
CONTEXT_WINDOW_RUNTIME_STATE.configLoadFailures = 0;
CONTEXT_WINDOW_RUNTIME_STATE.nextConfigLoadAttemptAtMs = 0;
CONTEXT_WINDOW_RUNTIME_STATE.modelsConfigRuntimeLoader.clear();
MODEL_CONTEXT_TOKEN_CACHE.clear();
}
//#endregion
//#region src/agents/context.ts
const ANTHROPIC_GA_1M_MODEL_PREFIXES = [
"claude-opus-4-8",
"claude-opus-4.8",
"claude-opus-4-6",
"claude-opus-4.6",
"claude-opus-4-7",
"claude-opus-4.7",
"claude-sonnet-4-6",
"claude-sonnet-4.6"
];
const ANTHROPIC_CONTEXT_1M_TOKENS = 1048576;
const ANTHROPIC_FABLE_CONTEXT_TOKENS = 1e6;
const CONFIG_LOAD_RETRY_POLICY = {
initialMs: 1e3,
maxMs: 6e4,
factor: 2,
jitter: 0
};
function applyDiscoveredContextWindows(params) {
for (const model of params.models) {
if (!model?.id) continue;
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) continue;
const existing = params.cache.get(model.id);
if (existing === void 0 || contextTokens < existing) params.cache.set(model.id, contextTokens);
}
}
function applyConfiguredContextWindows(params) {
const providers = params.modelsConfig?.providers;
if (!providers || typeof providers !== "object") return;
for (const provider of Object.values(providers)) {
if (!Array.isArray(provider?.models)) continue;
for (const model of provider.models) {
const modelId = typeof model?.id === "string" ? model.id : void 0;
const contextTokens = typeof model?.contextTokens === "number" ? model.contextTokens : typeof model?.contextWindow === "number" ? model.contextWindow : typeof provider?.contextTokens === "number" ? provider.contextTokens : typeof provider?.contextWindow === "number" ? provider.contextWindow : void 0;
if (!modelId || !contextTokens || contextTokens <= 0) continue;
params.cache.set(modelId, contextTokens);
}
}
}
function loadModelsConfigRuntime() {
return CONTEXT_WINDOW_RUNTIME_STATE.modelsConfigRuntimeLoader.load();
}
function primeConfiguredContextWindows() {
if (CONTEXT_WINDOW_RUNTIME_STATE.configuredConfig) {
applyConfiguredContextWindows({
cache: MODEL_CONTEXT_TOKEN_CACHE,
modelsConfig: CONTEXT_WINDOW_RUNTIME_STATE.configuredConfig.models
});
return CONTEXT_WINDOW_RUNTIME_STATE.configuredConfig;
}
if (Date.now() < CONTEXT_WINDOW_RUNTIME_STATE.nextConfigLoadAttemptAtMs) return;
try {
const cfg = getRuntimeConfig();
applyConfiguredContextWindows({
cache: MODEL_CONTEXT_TOKEN_CACHE,
modelsConfig: cfg.models
});
CONTEXT_WINDOW_RUNTIME_STATE.configuredConfig = cfg;
CONTEXT_WINDOW_RUNTIME_STATE.configLoadFailures = 0;
CONTEXT_WINDOW_RUNTIME_STATE.nextConfigLoadAttemptAtMs = 0;
return cfg;
} 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() {
if (CONTEXT_WINDOW_RUNTIME_STATE.loadPromise) return CONTEXT_WINDOW_RUNTIME_STATE.loadPromise;
const cfg = primeConfiguredContextWindows();
if (!cfg) return Promise.resolve();
CONTEXT_WINDOW_RUNTIME_STATE.loadPromise = (async () => {
const agentDir = resolveDefaultAgentDir(cfg);
const workspaceDir = resolveAgentWorkspaceDir(cfg, resolveDefaultAgentId(cfg));
try {
await (await loadModelsConfigRuntime()).ensureOpenClawModelsJson(cfg, agentDir, { workspaceDir });
} catch {}
try {
const modelRegistry = discoverModels(discoverAuthStorage(agentDir), agentDir, {
normalizeModels: false,
workspaceDir
});
applyDiscoveredContextWindows({
cache: MODEL_CONTEXT_TOKEN_CACHE,
models: typeof modelRegistry.getAvailable === "function" ? modelRegistry.getAvailable() : modelRegistry.getAll()
});
} catch {}
applyConfiguredContextWindows({
cache: MODEL_CONTEXT_TOKEN_CACHE,
modelsConfig: cfg.models
});
})().catch(() => {});
return CONTEXT_WINDOW_RUNTIME_STATE.loadPromise;
}
function lookupContextTokens(modelId, options) {
if (!modelId) return;
if (options?.skipRuntimeConfigLoad) return lookupCachedContextTokens(modelId);
if (options?.allowAsyncLoad === false) primeConfiguredContextWindows();
else ensureContextWindowCacheLoaded();
return lookupCachedContextTokens(modelId);
}
function resolveProviderModelRef(params) {
const modelRaw = params.model?.trim();
if (!modelRaw) return;
const providerRaw = params.provider?.trim();
if (providerRaw) {
const provider = normalizeProviderId(providerRaw);
if (!provider) return;
return {
provider,
model: modelRaw
};
}
const slash = modelRaw.indexOf("/");
if (slash <= 0) return;
const provider = normalizeProviderId(modelRaw.slice(0, slash));
const model = modelRaw.slice(slash + 1).trim();
if (!provider || !model) return;
return {
provider,
model
};
}
function resolveConfiguredProviderContextTokens(cfg, provider, model) {
const providers = (cfg?.models)?.providers;
if (!providers) return;
function readProviderContextTokens(providerConfig) {
return typeof providerConfig?.contextTokens === "number" ? providerConfig.contextTokens : typeof providerConfig?.contextWindow === "number" ? providerConfig.contextWindow : void 0;
}
function findContextTokens(matchProviderId) {
for (const [providerId, providerConfig] of Object.entries(providers)) {
if (!matchProviderId(providerId)) continue;
if (Array.isArray(providerConfig?.models)) for (const m of providerConfig.models) {
const contextTokens = typeof m?.contextTokens === "number" ? m.contextTokens : typeof m?.contextWindow === "number" ? m.contextWindow : void 0;
if (typeof m?.id === "string" && m.id === model && typeof contextTokens === "number" && contextTokens > 0) return contextTokens;
}
const providerContextTokens = readProviderContextTokens(providerConfig);
if (typeof providerContextTokens === "number" && providerContextTokens > 0) return providerContextTokens;
}
}
const exactResult = findContextTokens((id) => normalizeLowercaseStringOrEmpty(id) === normalizeLowercaseStringOrEmpty(provider));
if (exactResult !== void 0) return exactResult;
const normalizedProvider = normalizeProviderId(provider);
return findContextTokens((id) => normalizeProviderId(id) === normalizedProvider);
}
function resolveAnthropicFixedContextWindow(provider, model) {
const modelId = resolveModelFamilyId(model);
if ((provider === "anthropic" || provider === "anthropic-vertex") && modelId.startsWith("claude-fable-5")) return ANTHROPIC_FABLE_CONTEXT_TOKENS;
if (provider !== "anthropic" && provider !== "claude-cli") return;
return ANTHROPIC_GA_1M_MODEL_PREFIXES.some((prefix) => modelId.startsWith(prefix)) ? ANTHROPIC_CONTEXT_1M_TOKENS : void 0;
}
function resolveDiscoveredAnthropicFixedContextWindow(model) {
const provider = typeof model.provider === "string" ? normalizeProviderId(model.provider) : void 0;
const modelId = model.id;
if (provider) return resolveAnthropicFixedContextWindow(provider, modelId);
const normalized = normalizeLowercaseStringOrEmpty(modelId);
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;
}
function resolveModelFamilyId(modelId) {
const normalized = normalizeLowercaseStringOrEmpty(modelId);
return normalized.includes("/") ? normalized.split("/").at(-1) ?? normalized : normalized;
}
function resolveContextTokensForModel(params) {
if (typeof params.contextTokensOverride === "number" && params.contextTokensOverride > 0) return params.contextTokensOverride;
const ref = resolveProviderModelRef({
provider: params.provider,
model: params.model
});
const explicitProvider = params.provider?.trim();
if (ref) {
if (explicitProvider) {
const fixedContextWindow = resolveAnthropicFixedContextWindow(ref.provider, ref.model);
if (fixedContextWindow !== void 0) return fixedContextWindow;
}
if (explicitProvider) {
const configuredWindow = resolveConfiguredProviderContextTokens(params.cfg, explicitProvider, ref.model);
if (configuredWindow !== void 0) return configuredWindow;
}
}
if (params.provider && ref && !ref.model.includes("/")) {
const qualifiedResult = lookupContextTokens(`${normalizeProviderId(ref.provider)}/${ref.model}`, {
allowAsyncLoad: params.allowAsyncLoad,
skipRuntimeConfigLoad: Boolean(params.cfg)
});
if (qualifiedResult !== void 0) return qualifiedResult;
}
const bareResult = lookupContextTokens(params.model, {
allowAsyncLoad: params.allowAsyncLoad,
skipRuntimeConfigLoad: Boolean(params.cfg)
});
if (bareResult !== void 0) return bareResult;
if (!params.provider && ref && !ref.model.includes("/")) {
const qualifiedResult = lookupContextTokens(`${normalizeProviderId(ref.provider)}/${ref.model}`, {
allowAsyncLoad: params.allowAsyncLoad,
skipRuntimeConfigLoad: Boolean(params.cfg)
});
if (qualifiedResult !== void 0) return qualifiedResult;
}
return params.fallbackContextTokens;
}
//#endregion
export { ensureContextWindowCacheLoaded as a, resetContextWindowCacheForTest as c, applyDiscoveredContextWindows as i, ANTHROPIC_FABLE_CONTEXT_TOKENS as n, lookupContextTokens as o, applyConfiguredContextWindows as r, resolveContextTokensForModel as s, ANTHROPIC_CONTEXT_1M_TOKENS as t };