openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
379 lines (378 loc) • 16.2 kB
JavaScript
import { a as resolveAgentDir, c as resolveDefaultAgentId, n as listAgentIds, o as resolveAgentWorkspaceDir } from "./agent-scope-config-CgCYpZfK.js";
import { n as resolveDefaultAgentWorkspaceDir } from "./workspace-default-B3AjhIK3.js";
import { c as hashRuntimeConfigValue } from "./runtime-snapshot-D93_HOsR.js";
import { i as ensureAuthProfileStoreWithoutExternalProfiles, n as ensureAuthProfileStore, o as getRuntimeAuthProfileStoreSnapshot } from "./store-C8spD0DG.js";
import "./auth-profiles-84rzaGag.js";
import { i as externalCliDiscoveryForProviders, r as externalCliDiscoveryForProviderAuth } from "./external-cli-discovery-Cr-vJMRB.js";
import { n as listProfilesForProvider } from "./profile-list-DI8_o0Rw.js";
import { o as normalizeProviderId } from "./model-selection-normalize-roKDxQ9_.js";
import "./model-selection-CA_65iXi.js";
import { n as loadModelCatalog } from "./model-catalog-0-HKr2yW.js";
import { c as hasRuntimeAvailableProviderAuth, i as createRuntimeProviderAuthLookup, s as hasAvailableAuthForProvider } from "./model-auth-DVfmdW0b.js";
import { a as getCurrentProviderAuthStates, c as setCurrentProviderAuthWarmWorker, i as clearCurrentProviderAuthWarmWorker, n as claimCurrentProviderAuthStateGeneration, o as isCurrentProviderAuthStateGeneration, s as publishProviderAuthWarmSnapshot, t as cancelCurrentProviderAuthWarmWorker } from "./model-provider-auth-state-DW_JYm-o.js";
import "./workspace-B0bmoo98.js";
import { fileURLToPath, pathToFileURL } from "node:url";
import path from "node:path";
import { Worker } from "node:worker_threads";
//#region src/agents/model-provider-auth.ts
/**
* Warms and queries provider-auth availability for model catalogs. The module
* keeps per-agent auth snapshots process-current so model listing can avoid
* repeated env/profile/plugin discovery on hot paths.
*/
const PROVIDER_AUTH_WARM_WORKER_TIMEOUT_MS = 12e4;
const PROVIDER_AUTH_WARM_CANCEL_POLL_MS = 25;
const configFingerprintCache = /* @__PURE__ */ new WeakMap();
function resolvePreparedStateForCaller(params) {
if (!params.states) return null;
if (params.callerAgentId !== void 0) return params.states.get(params.callerAgentId) ?? null;
if (!params.cfg) return null;
return params.states.get(resolveDefaultAgentId(params.cfg)) ?? null;
}
function resolveProviderAuthConfigFingerprint(cfg) {
if (!cfg) return null;
const cached = configFingerprintCache.get(cfg);
if (cached !== void 0) return cached;
const fingerprint = hashRuntimeConfigValue(cfg);
configFingerprintCache.set(cfg, fingerprint);
return fingerprint;
}
/** Resolves whether auth is available for a model provider in the caller's runtime scope. */
async function hasAuthForModelProvider(params) {
const provider = normalizeProviderId(params.provider);
const preparedStates = getCurrentProviderAuthStates();
const workspaceDir = params.workspaceDir ?? resolveDefaultAgentWorkspaceDir();
const configFingerprint = resolveProviderAuthConfigFingerprint(params.cfg);
const preparedState = resolvePreparedStateForCaller({
states: preparedStates,
cfg: params.cfg,
callerAgentId: params.agentId
});
const expectedWorkspaceDir = preparedState !== null && params.cfg ? resolveAgentWorkspaceDir(params.cfg, preparedState.agentId) : null;
const expectedAgentDir = preparedState !== null && params.cfg ? resolveAgentDir(params.cfg, preparedState.agentId) : null;
if (preparedState !== null && configFingerprint === preparedState.configFingerprint && workspaceDir === expectedWorkspaceDir && (params.agentDir === void 0 || params.agentDir === expectedAgentDir) && params.discoverExternalCliAuth !== false && params.allowPluginSyntheticAuth !== false && params.env === void 0 && params.store === void 0 && params.modelApi === void 0) {
const preparedAnswer = preparedState.providers.get(provider);
if (preparedAnswer !== void 0) return preparedAnswer;
}
await new Promise((resolve) => {
setImmediate(resolve);
});
if (hasRuntimeAvailableProviderAuth({
provider,
cfg: params.cfg,
workspaceDir: params.workspaceDir,
env: params.env,
allowPluginSyntheticAuth: params.allowPluginSyntheticAuth,
runtimeLookup: params.runtimeAuthLookup ?? params.resolveRuntimeAuthLookup?.(),
modelApi: params.modelApi
})) return true;
const slowPathAgentDir = params.agentDir ?? (params.agentId && params.cfg ? resolveAgentDir(params.cfg, params.agentId, params.env) : void 0);
const store = params.store ?? (params.discoverExternalCliAuth === false ? ensureAuthProfileStoreWithoutExternalProfiles(slowPathAgentDir, { allowKeychainPrompt: false }) : ensureAuthProfileStore(slowPathAgentDir, { externalCli: externalCliDiscoveryForProviderAuth({
cfg: params.cfg,
provider
}) }));
if (listProfilesForProvider(store, provider).length > 0) return params.modelApi === void 0 ? true : await hasAvailableAuthForProvider({
provider,
modelApi: params.modelApi,
cfg: params.cfg,
workspaceDir: params.workspaceDir,
agentDir: slowPathAgentDir,
store
});
return false;
}
/** Creates a cached provider-auth checker bound to one agent/runtime context. */
function createProviderAuthChecker(params) {
const authCache = /* @__PURE__ */ new Map();
let runtimeAuthLookup;
return async (provider, modelApi) => {
const key = normalizeProviderId(provider);
const cacheKey = modelApi === void 0 ? key : `${key}\0${modelApi}`;
const cached = authCache.get(cacheKey);
if (cached !== void 0) return cached;
const value = await hasAuthForModelProvider({
provider: key,
modelApi,
cfg: params.cfg,
workspaceDir: params.workspaceDir,
agentDir: params.agentDir,
agentId: params.agentId,
env: params.env,
allowPluginSyntheticAuth: params.allowPluginSyntheticAuth,
discoverExternalCliAuth: params.discoverExternalCliAuth,
resolveRuntimeAuthLookup: () => runtimeAuthLookup ??= createRuntimeProviderAuthLookup({
cfg: params.cfg,
workspaceDir: params.workspaceDir,
env: params.env,
includePluginSyntheticAuth: params.allowPluginSyntheticAuth !== false
})
});
authCache.set(cacheKey, value);
return value;
};
}
function serializeProviderAuthStates(states) {
return { agents: [...states.values()].map((state) => ({
agentId: state.agentId,
configFingerprint: state.configFingerprint,
providers: [...state.providers.entries()]
})) };
}
function resolveProviderConfigApi(cfg, provider) {
const providers = cfg?.models?.providers ?? {};
const direct = providers[provider];
if (direct?.api) return direct.api;
const normalized = normalizeProviderId(provider);
return (Object.entries(providers).find(([key]) => normalizeProviderId(key) === normalized)?.[1])?.api;
}
function shouldOmitFalsePreparedAuthForProcessSyntheticProvider(params) {
const syntheticRefs = params.runtimeAuthLookup.syntheticAuthProviderRefs;
if (!syntheticRefs?.length) return false;
const eligibleRefs = new Set(syntheticRefs.map((ref) => normalizeProviderId(ref)));
const providerApi = resolveProviderConfigApi(params.cfg, params.provider);
return [params.provider, providerApi].filter((ref) => typeof ref === "string" && ref.trim().length > 0).some((ref) => eligibleRefs.has(normalizeProviderId(ref)));
}
/** Builds a provider auth snapshot for every configured agent. */
async function buildCurrentProviderAuthStateSnapshot(cfg, options = {}) {
const isWarmStale = () => options.isCancelled?.() === true;
const catalog = await loadModelCatalog({
config: cfg,
readOnly: true
});
if (isWarmStale()) return { agents: [] };
const providers = /* @__PURE__ */ new Set();
for (const entry of catalog) providers.add(normalizeProviderId(entry.provider));
const providerList = [...providers];
const configFingerprint = resolveProviderAuthConfigFingerprint(cfg) ?? "";
const states = /* @__PURE__ */ new Map();
for (const agentId of listAgentIds(cfg)) {
if (isWarmStale()) return { agents: [] };
const workspaceDir = resolveAgentWorkspaceDir(cfg, agentId);
const agentDir = resolveAgentDir(cfg, agentId);
const runtimeAuthLookup = options.runtimeAuthLookups?.get(agentId) ?? createRuntimeProviderAuthLookup({
cfg,
workspaceDir
});
const externalCli = externalCliDiscoveryForProviders({
cfg,
providers: providerList
});
const store = options.readOnlyAuthStore ? ensureAuthProfileStore(agentDir, {
config: cfg,
externalCli,
readOnly: true,
syncExternalCli: false
}) : ensureAuthProfileStore(agentDir, {
config: cfg,
externalCli
});
const state = /* @__PURE__ */ new Map();
for (const provider of providers) {
if (isWarmStale()) return { agents: [] };
const value = await hasAuthForModelProvider({
provider,
cfg,
workspaceDir,
agentId,
store,
runtimeAuthLookup
});
if (!value && (options.omitFalseProviderAuth || shouldOmitFalsePreparedAuthForProcessSyntheticProvider({
cfg,
provider,
runtimeAuthLookup
}))) continue;
state.set(provider, value);
}
states.set(agentId, {
agentId,
configFingerprint,
providers: state
});
}
return serializeProviderAuthStates(states);
}
/** Warms process-current provider auth state on the main thread. */
async function warmCurrentProviderAuthState(cfg, options = {}) {
const ownGeneration = claimCurrentProviderAuthStateGeneration();
const isWarmStale = () => options.isCancelled?.() === true || !isCurrentProviderAuthStateGeneration(ownGeneration);
const snapshot = await buildCurrentProviderAuthStateSnapshot(cfg, { isCancelled: isWarmStale });
if (isWarmStale()) return;
if (options.isCancelled?.() || !isCurrentProviderAuthStateGeneration(ownGeneration)) return;
publishProviderAuthWarmSnapshot(snapshot);
}
function resolveProviderAuthWarmWorkerUrl(currentModuleUrl) {
const currentPath = fileURLToPath(currentModuleUrl);
const distMarker = `${path.sep}dist${path.sep}`;
const distIndex = currentPath.lastIndexOf(distMarker);
if (distIndex >= 0) {
const distRoot = currentPath.slice(0, distIndex + distMarker.length - 1);
return pathToFileURL(path.join(distRoot, "agents", "model-provider-auth.worker.js"));
}
const extension = path.extname(currentPath) || ".js";
return new URL(`./model-provider-auth.worker${extension}`, currentModuleUrl);
}
function isProviderAuthWarmSnapshot(value) {
if (!value || typeof value !== "object" || !Array.isArray(value.agents)) return false;
return value.agents.every((agent) => typeof agent.agentId === "string" && typeof agent.configFingerprint === "string" && Array.isArray(agent.providers) && agent.providers.every((entry) => Array.isArray(entry) && entry.length === 2 && typeof entry[0] === "string" && typeof entry[1] === "boolean"));
}
function isProviderAuthWarmWorkerResult(value) {
if (!value || typeof value !== "object") return false;
const result = value;
if (result.status === "failed") return typeof result.error === "string";
return result.status === "ok" && isProviderAuthWarmSnapshot(result.snapshot);
}
function createProviderAuthWarmPresenceStore(store) {
const profiles = {};
for (const [profileId, credential] of Object.entries(store.profiles)) profiles[profileId] = {
type: "api_key",
provider: credential.provider
};
return {
version: store.version,
profiles
};
}
function collectProviderAuthWarmRuntimeAuthStores(cfg) {
const entries = [];
const seen = /* @__PURE__ */ new Set();
const addStore = (agentDir) => {
if (seen.has(agentDir)) return;
seen.add(agentDir);
const store = getRuntimeAuthProfileStoreSnapshot(agentDir);
if (!store) return;
entries.push({
...agentDir === void 0 ? {} : { agentDir },
store: createProviderAuthWarmPresenceStore(store)
});
};
addStore();
for (const agentId of listAgentIds(cfg)) addStore(resolveAgentDir(cfg, agentId));
return entries;
}
function collectProviderAuthWarmRuntimeAuthLookups(cfg) {
const entries = [];
let omitFalseProviderAuth = false;
for (const agentId of listAgentIds(cfg)) {
const lookup = createRuntimeProviderAuthLookup({
cfg,
workspaceDir: resolveAgentWorkspaceDir(cfg, agentId)
});
if (lookup.syntheticAuthProviderRefsComplete === false) omitFalseProviderAuth = true;
entries.push({
agentId,
lookup
});
}
return {
entries,
omitFalseProviderAuth
};
}
function runProviderAuthWarmWorker(params) {
const worker = new Worker(params.workerUrl ?? resolveProviderAuthWarmWorkerUrl(import.meta.url), { workerData: {
cfg: params.cfg,
...params.runtimeAuthStores?.length ? { runtimeAuthStores: params.runtimeAuthStores } : {},
...params.runtimeAuthLookups?.length ? { runtimeAuthLookups: params.runtimeAuthLookups } : {},
...params.omitFalseProviderAuth ? { omitFalseProviderAuth: true } : {}
} });
worker.unref?.();
const handle = {
worker,
cancelled: false
};
setCurrentProviderAuthWarmWorker(handle);
return new Promise((resolve, reject) => {
let settled = false;
const finish = (complete) => {
if (settled) return;
settled = true;
clearCurrentProviderAuthWarmWorker(handle);
if (timer) clearTimeout(timer);
if (cancelTimer) clearInterval(cancelTimer);
complete();
};
const cancelWorker = () => {
handle.cancelled = true;
worker.terminate();
finish(() => resolve({ agents: [] }));
};
const timer = setTimeout(() => {
handle.cancelled = true;
worker.terminate();
finish(() => reject(/* @__PURE__ */ new Error("provider auth warm worker timed out")));
}, params.timeoutMs);
timer.unref?.();
const cancelTimer = setInterval(() => {
if (params.isCancelled()) cancelWorker();
}, PROVIDER_AUTH_WARM_CANCEL_POLL_MS);
cancelTimer.unref?.();
worker.once("message", (message) => {
worker.terminate();
finish(() => {
if (handle.cancelled) {
resolve({ agents: [] });
return;
}
if (!isProviderAuthWarmWorkerResult(message)) {
reject(/* @__PURE__ */ new Error("invalid provider auth warm worker response"));
return;
}
if (message.status === "failed") {
reject(new Error(message.error));
return;
}
resolve(message.snapshot);
});
});
worker.once("error", (error) => {
finish(() => {
if (handle.cancelled) {
resolve({ agents: [] });
return;
}
reject(toLintErrorObject(error, "Non-Error rejection"));
});
});
worker.once("exit", (code) => {
if (settled || code === 0) return;
finish(() => {
if (handle.cancelled) {
resolve({ agents: [] });
return;
}
reject(/* @__PURE__ */ new Error(`provider auth warm worker exited with code ${code}`));
});
});
if (params.isCancelled()) cancelWorker();
});
}
/** Warms process-current provider auth state in a worker thread. */
async function warmCurrentProviderAuthStateOffMainThread(cfg, options = {}) {
const ownGeneration = claimCurrentProviderAuthStateGeneration();
cancelCurrentProviderAuthWarmWorker();
const isWarmStale = () => options.isCancelled?.() === true || !isCurrentProviderAuthStateGeneration(ownGeneration);
if (isWarmStale()) return;
const runtimeAuthStores = collectProviderAuthWarmRuntimeAuthStores(cfg);
const runtimeAuthLookups = collectProviderAuthWarmRuntimeAuthLookups(cfg);
const snapshot = await (options.runWorker ?? runProviderAuthWarmWorker)({
cfg,
...runtimeAuthStores.length ? { runtimeAuthStores } : {},
...runtimeAuthLookups.entries.length ? { runtimeAuthLookups: runtimeAuthLookups.entries } : {},
...runtimeAuthLookups.omitFalseProviderAuth ? { omitFalseProviderAuth: true } : {},
timeoutMs: options.timeoutMs ?? PROVIDER_AUTH_WARM_WORKER_TIMEOUT_MS,
isCancelled: isWarmStale,
workerUrl: options.workerUrl
});
if (isWarmStale()) return;
publishProviderAuthWarmSnapshot(snapshot);
}
function toLintErrorObject(value, fallbackMessage) {
if (value instanceof Error) return value;
if (typeof value === "string") return new Error(value);
const error = new Error(fallbackMessage, { cause: value });
if (typeof value === "object" && value !== null || typeof value === "function") Object.assign(error, value);
return error;
}
//#endregion
export { warmCurrentProviderAuthStateOffMainThread as a, warmCurrentProviderAuthState as i, createProviderAuthChecker as n, hasAuthForModelProvider as r, buildCurrentProviderAuthStateSnapshot as t };