openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
269 lines (268 loc) • 11.2 kB
JavaScript
import { u as resolveAgentDir } from "./agent-scope-config-DcbEhP0R.js";
import { t as createSubsystemLogger } from "./subsystem-Dy2tqXOS.js";
import { f as getActivePluginRegistryVersion } from "./runtime-BL4wZfTq.js";
import { i as trackAsyncWork } from "./async-work-scope-CMQS2uTf.js";
import { l as getRuntimeAuthProfileStoreSnapshotRevision } from "./runtime-snapshots-CHAErv1O.js";
import { r as ensureAuthProfileStore } from "./store-F1B2duCT.js";
import { a as resolveAuthProfileOrder } from "./order-CC2RBzI5.js";
import { i as resolveLegacyInheritedAuthAgentId } from "./legacy-inherited-auth-dir-CMGSmv-F.js";
import { n as PROVIDER_USAGE_TIMEOUT_MS } from "./provider-usage.shared-BKgwfwAS.js";
import { l as listProviderUsagePluginDescriptors } from "./provider-runtime-BRJDPNgk.js";
import { t as resolveEnvApiKey } from "./model-auth-env-Dq9W4xg9.js";
import { t as externalCliDiscoveryForConfigStatus } from "./external-cli-discovery-CbeZXk1q.js";
import { S as resolveUsableCustomProviderApiKey } from "./model-auth-provider-config-C_kr_q2g.js";
import "./auth-profiles-BdUEhE7u.js";
import "./model-auth-C48_DZ-I.js";
import { n as fingerprintAuthProfileOwnerShape, o as fingerprintResolvedProviderAuth, t as fingerprintAuthProfileCredential } from "./execution-auth-binding-CmucNoqo.js";
import { t as formatForLog } from "./ws-log-Dkg9wKNU.js";
import { t as loadProviderUsageSummary } from "./provider-usage.load-xP5nsGGG.js";
//#region src/gateway/server-methods/provider-usage-runtime.ts
let current;
function sortedRecordEntries(value) {
return Object.entries(value ?? {}).toSorted(([left], [right]) => left.localeCompare(right));
}
function fingerprintProviderUsageCredentials(params) {
const profiles = Object.entries(params.store.profiles).toSorted(([left], [right]) => left.localeCompare(right)).map(([profileId, credential]) => {
return fingerprintAuthProfileCredential({
profileId,
credential
}) ?? fingerprintAuthProfileOwnerShape({
profileId,
credential
}) ?? `${profileId}:${credential.type}:${credential.provider}`;
});
const direct = [...params.directApiKeys].toSorted(([left], [right]) => left.localeCompare(right)).map(([provider, resolved]) => [provider, fingerprintResolvedProviderAuth({
...resolved,
mode: "api-key"
}) ?? null]);
const selectedProfiles = params.providerIds.map((provider) => [provider, resolveAuthProfileOrder({
cfg: params.cfg,
store: params.store,
provider
})]);
return JSON.stringify({
profiles,
direct,
order: sortedRecordEntries(params.store.order),
lastGood: sortedRecordEntries(params.store.lastGood),
selectedProfiles
});
}
function resolveDirectApiKeys(config, providerIds) {
const directApiKeys = /* @__PURE__ */ new Map();
for (const provider of providerIds) {
const resolved = resolveUsableCustomProviderApiKey({
cfg: config,
provider,
env: process.env
}) ?? resolveEnvApiKey(provider, process.env, { config });
if (!resolved) continue;
directApiKeys.set(provider, resolved);
}
return directApiKeys;
}
function clearProviderUsageRuntimeSnapshot() {
current = void 0;
}
function getProviderUsageRuntimeSnapshot(params) {
const agentId = params.agentId ?? resolveLegacyInheritedAuthAgentId(params.config);
const agentDir = params.agentDir ?? resolveAgentDir(params.config, agentId);
const configRef = params.config;
const pluginRegistryGeneration = getActivePluginRegistryVersion();
const authStoreGeneration = getRuntimeAuthProfileStoreSnapshotRevision(agentDir);
if (current?.configRef === configRef && (params.store === void 0 || current.store === params.store) && current.agentDir === agentDir && current.agentId === agentId && current.pluginRegistryGeneration === pluginRegistryGeneration && current.authStoreGeneration === authStoreGeneration) return current;
const store = params.store ?? ensureAuthProfileStore(agentDir, { externalCli: externalCliDiscoveryForConfigStatus({ cfg: configRef }) });
const descriptors = listProviderUsagePluginDescriptors({
config: configRef,
env: process.env
});
const providerIds = descriptors.map((descriptor) => descriptor.provider);
const directApiKeys = resolveDirectApiKeys(configRef, providerIds);
current = {
agentDir,
agentId,
configRef,
credentialKey: fingerprintProviderUsageCredentials({
cfg: configRef,
directApiKeys,
providerIds,
store
}),
descriptors,
directApiKeys,
providerIds,
store,
authStoreGeneration: getRuntimeAuthProfileStoreSnapshotRevision(agentDir),
pluginRegistryGeneration
};
return current;
}
//#endregion
//#region src/gateway/server-methods/models-auth-status-usage-cache.ts
const log = createSubsystemLogger("provider-usage-cache");
const USAGE_CACHE_TTL_MS = 6e4;
const usageCacheByAgentId = /* @__PURE__ */ new Map();
const usageRefreshByAgentId = /* @__PURE__ */ new Map();
let cacheGeneration = 0;
function clearModelAuthStatusUsageCache() {
cacheGeneration += 1;
usageCacheByAgentId.clear();
usageRefreshByAgentId.clear();
clearProviderUsageRuntimeSnapshot();
}
function providerUsageCacheKey(providerIds) {
return providerIds.toSorted().join("\0");
}
function scopeProviderUsageCredentialKey(credentialKey, providerIds) {
try {
const parsed = JSON.parse(credentialKey);
if (!Array.isArray(parsed.direct)) return credentialKey;
const providers = new Set(providerIds);
return JSON.stringify({
...parsed,
direct: parsed.direct.filter(([provider, fingerprint]) => providers.has(provider) && fingerprint !== null)
});
} catch {
return credentialKey;
}
}
function mapProviderUsage(usage) {
const usageByProvider = /* @__PURE__ */ new Map();
for (const snap of usage.providers) usageByProvider.set(snap.provider, {
windows: snap.windows,
...snap.summary ? { summary: snap.summary } : {},
...snap.plan ? { plan: snap.plan } : {},
...snap.billing?.length ? { billing: snap.billing } : {},
...snap.accountEmail ? { accountEmail: snap.accountEmail } : {}
});
return usageByProvider;
}
function retainLastGoodOnTimeout(summary, lastGood) {
if (!lastGood) return summary;
const lastGoodByProvider = new Map(lastGood.providers.filter((provider) => provider.error === void 0).map((provider) => [provider.provider, provider]));
const retainedLastGood = summary.providers.some((provider) => provider.error === "Timeout" && lastGoodByProvider.has(provider.provider));
return {
...summary,
updatedAt: retainedLastGood ? lastGood.updatedAt : summary.updatedAt,
providers: summary.providers.map((provider) => provider.error === "Timeout" ? lastGoodByProvider.get(provider.provider) ?? provider : provider)
};
}
function scheduleProviderUsageRefresh(params) {
const active = usageRefreshByAgentId.get(params.agentId);
if (active?.agentDir === params.agentDir && active.configRef === params.configRef && active.credentialKey === params.credentialKey && active.providerKey === params.providerKey) return active.promise;
const publishGeneration = cacheGeneration;
const promise = trackAsyncWork(() => loadProviderUsageSummary({
providers: params.providerIds,
agentDir: params.agentDir,
authStore: params.authStore,
config: params.configRef,
timeoutMs: PROVIDER_USAGE_TIMEOUT_MS
}).then((freshUsage) => {
const usage = retainLastGoodOnTimeout(freshUsage, params.lastGood);
if (publishGeneration === cacheGeneration && usageRefreshByAgentId.get(params.agentId) === refresh) usageCacheByAgentId.set(params.agentId, {
agentDir: params.agentDir,
configRef: params.configRef,
credentialKey: params.credentialKey,
providerKey: params.providerKey,
refreshedAt: Date.now(),
summary: usage,
usageByProvider: mapProviderUsage(usage)
});
return usage;
}).catch((err) => {
log.debug(`usage refresh failed: providers=${params.providerIds.join(",")} error=${formatForLog(err)}`);
throw err;
}).finally(() => {
if (usageRefreshByAgentId.get(params.agentId) === refresh) usageRefreshByAgentId.delete(params.agentId);
}));
const refresh = {
agentDir: params.agentDir,
configRef: params.configRef,
credentialKey: params.credentialKey,
providerKey: params.providerKey,
promise
};
usageRefreshByAgentId.set(params.agentId, refresh);
return promise;
}
function resolveProviderUsageCacheRead(params) {
const providerIds = params.providerIds.toSorted();
const providerKey = providerUsageCacheKey(providerIds);
const credentialKey = scopeProviderUsageCredentialKey(params.credentialKey, providerIds);
const cached = usageCacheByAgentId.get(params.agentId);
const matching = cached?.agentDir === params.agentDir && cached.configRef === params.configRef && cached.credentialKey === credentialKey && cached.providerKey === providerKey ? cached : void 0;
return {
credentialKey,
matching,
needsRefresh: params.forceRefresh === true || !matching || params.now - matching.refreshedAt >= USAGE_CACHE_TTL_MS,
providerIds,
providerKey
};
}
function readProviderUsageStaleWhileRevalidate(params) {
if (params.providerIds.length === 0) {
usageCacheByAgentId.delete(params.agentId);
return /* @__PURE__ */ new Map();
}
const { credentialKey, matching, needsRefresh, providerIds, providerKey } = resolveProviderUsageCacheRead(params);
if (needsRefresh) scheduleProviderUsageRefresh({
agentId: params.agentId,
agentDir: params.agentDir,
authStore: params.authStore,
configRef: params.configRef,
credentialKey,
providerIds,
providerKey,
lastGood: matching?.summary
}).catch(() => {});
return matching?.usageByProvider ?? /* @__PURE__ */ new Map();
}
/** Returns cached provider usage while network refreshes run in the background for capable clients. */
async function loadProviderUsageSummaryStaleWhileRevalidate(params) {
if (params.providerIds.length === 0) {
usageCacheByAgentId.delete(params.agentId);
return {
updatedAt: params.now,
providers: []
};
}
const { credentialKey, matching, needsRefresh, providerIds, providerKey } = resolveProviderUsageCacheRead(params);
if (matching && !needsRefresh) return matching.summary;
const refresh = scheduleProviderUsageRefresh({
agentId: params.agentId,
agentDir: params.agentDir,
authStore: params.authStore,
configRef: params.configRef,
credentialKey,
providerIds,
providerKey,
lastGood: matching?.summary
});
if (matching) {
refresh.catch(() => {});
return matching.summary;
}
if (params.coldRead !== "refresh-marker") return await refresh;
refresh.catch(() => {});
return {
updatedAt: params.now,
providers: [],
refreshing: true
};
}
/** Shares the models.authStatus cache contract with the unscoped usage.status RPC. */
async function loadUsageStatusStaleWhileRevalidate(params) {
const snapshot = getProviderUsageRuntimeSnapshot({ config: params.config });
return await loadProviderUsageSummaryStaleWhileRevalidate({
agentId: snapshot.agentId,
agentDir: snapshot.agentDir,
authStore: snapshot.store,
configRef: snapshot.configRef,
credentialKey: snapshot.credentialKey,
providerIds: snapshot.providerIds,
coldRead: params.coldRead,
now: params.now ?? Date.now()
});
}
//#endregion
export { getProviderUsageRuntimeSnapshot as i, loadUsageStatusStaleWhileRevalidate as n, readProviderUsageStaleWhileRevalidate as r, clearModelAuthStatusUsageCache as t };