UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

208 lines (207 loc) 9.39 kB
import { y as uniqueStrings } from "./string-normalization-DsCfAx8q.js"; import { o as safeRealpathSync } from "./boundary-path-DMNeww4q.js"; import { v as resolveDefaultAgentDir } from "./agent-scope-config-DcbEhP0R.js"; import { w as resolveStateDir } from "./paths-D2sRr1a_.js"; import { g as parseEnvTemplateSecretRef, s as coerceSecretRef, t as DEFAULT_SECRET_PROVIDER_ALIAS } from "./types.secrets-kC0nOetj.js"; import { l as isValidSecretRef } from "./ref-contract-D92DqQ-r.js"; import { n as resolveProviderIdForAuth } from "./provider-auth-aliases-DhA9c2am.js"; import { t as getProviderEnvVars } from "./provider-env-vars-B8XgJCSL.js"; import { n as normalizeSecretInput } from "./normalize-secret-input-Df_qhWv_.js"; import { c as upsertAuthProfile, d as upsertAuthProfileWithLock, f as upsertAuthProfileWithLockOrThrow } from "./profiles-DOTqXcYA.js"; import { t as buildAuthProfileId } from "./identity-BamcuBvi.js"; import fs from "node:fs"; import path from "node:path"; //#region src/plugins/provider-auth-helpers.ts const resolveAuthAgentDir = (agentDir, config) => agentDir ?? resolveDefaultAgentDir(config ?? {}); function buildEnvSecretRef(id) { return { source: "env", provider: DEFAULT_SECRET_PROVIDER_ALIAS, id }; } function resolveProviderDefaultEnvSecretRef(provider, config) { const envVar = getProviderEnvVars(provider, { ...config ? { config } : {}, includeUntrustedWorkspacePlugins: false })?.find((candidate) => candidate.trim().length > 0); if (!envVar) throw new Error(`Provider "${provider}" does not have a default env var mapping for secret-input-mode=ref.`); return buildEnvSecretRef(envVar); } function resolveApiKeySecretInput(provider, input, options) { if (input !== null && typeof input === "object") { const coercedRef = coerceSecretRef(input); if (!coercedRef || !isValidSecretRef(coercedRef)) throw new Error("API key SecretRef is invalid."); return coercedRef; } if (options?.secretInputMode === "plaintext") return normalizeSecretInput(input); const coercedRef = coerceSecretRef(input); if (coercedRef) { if (!isValidSecretRef(coercedRef)) throw new Error("API key SecretRef is invalid."); return coercedRef; } const normalized = normalizeSecretInput(input); const inlineEnvRef = parseEnvTemplateSecretRef(normalized, DEFAULT_SECRET_PROVIDER_ALIAS); if (inlineEnvRef) return inlineEnvRef; if (options?.secretInputMode === "ref") return resolveProviderDefaultEnvSecretRef(provider, options.config); return normalized; } function buildApiKeyCredential(provider, input, metadata, options) { const secretInput = resolveApiKeySecretInput(provider, input, options); if (typeof secretInput === "string") return { type: "api_key", provider, key: secretInput, ...metadata ? { metadata } : {} }; return { type: "api_key", provider, keyRef: secretInput, ...metadata ? { metadata } : {} }; } function upsertApiKeyProfile(params) { const profileId = params.profileId ?? buildAuthProfileId({ providerId: params.provider }); upsertAuthProfile({ profileId, credential: buildApiKeyCredential(params.provider, params.input, params.metadata, params.options), agentDir: resolveAuthAgentDir(params.agentDir, params.options?.config) }); return profileId; } function applyAuthProfileConfig(cfg, params) { const profiles = { ...cfg.auth?.profiles, [params.profileId]: { provider: params.provider, mode: params.mode, ...params.email ? { email: params.email } : {}, ...params.displayName ? { displayName: params.displayName } : {} } }; const next = { ...cfg, auth: { ...cfg.auth, profiles } }; const configuredProfiles = Object.entries(cfg.auth?.profiles ?? {}); const orderEntries = Object.entries(cfg.auth?.order ?? {}); const preferProfileFirst = params.preferProfileFirst ?? true; if (orderEntries.length === 0 && (!preferProfileFirst || !configuredProfiles.some(([profileId, profile]) => profileId !== params.profileId && profile.mode !== params.mode))) return next; const normalizedProvider = resolveProviderIdForAuth(params.provider, { config: cfg }); const matchesProvider = (provider) => resolveProviderIdForAuth(provider, { config: cfg }) === normalizedProvider; const matchingOrderEntries = orderEntries.filter(([provider]) => matchesProvider(provider)); let providerOrder; if (matchingOrderEntries.length > 0) { const existingOrder = uniqueStrings(matchingOrderEntries.flatMap(([, order]) => order)); providerOrder = preferProfileFirst ? [params.profileId, ...existingOrder.filter((profileId) => profileId !== params.profileId)] : existingOrder.includes(params.profileId) ? existingOrder : [...existingOrder, params.profileId]; } else if (preferProfileFirst) { const peers = configuredProfiles.filter(([, profile]) => matchesProvider(profile.provider)); if (peers.some(([profileId, profile]) => profileId !== params.profileId && profile.mode !== params.mode)) providerOrder = [params.profileId, ...peers.map(([profileId]) => profileId).filter((profileId) => profileId !== params.profileId)]; } if (providerOrder) next.auth.order = { ...Object.fromEntries(orderEntries.filter(([provider]) => !matchesProvider(provider))), [normalizedProvider]: providerOrder }; return next; } /** Returns true when config still names a removed auth profile. */ function configReferencesAuthProfile(cfg, profileId) { return Boolean(cfg.auth?.profiles?.[profileId]) || Object.values(cfg.auth?.order ?? {}).some((order) => order.includes(profileId)) || Object.values(cfg.models?.providers ?? {}).some((provider) => provider.apiKey === profileId); } /** * Drops a profile from `auth.profiles`, every `auth.order` list, and provider-entry * `apiKey` references. An emptied provider order is deleted rather than left as * `[]`, because an authored empty order is a hard "select no profiles" instruction. */ function removeAuthProfileConfig(cfg, profileId) { if (!configReferencesAuthProfile(cfg, profileId)) return cfg; const authReferencesProfile = Boolean(cfg.auth?.profiles?.[profileId]) || Object.values(cfg.auth?.order ?? {}).some((providerOrder) => providerOrder.includes(profileId)); const profiles = Object.fromEntries(Object.entries(cfg.auth?.profiles ?? {}).filter(([id]) => id !== profileId)); const order = Object.entries(cfg.auth?.order ?? {}).reduce((acc, [providerId, providerOrder]) => { const next = providerOrder.filter((id) => id !== profileId); if (next.length > 0 || next.length === providerOrder.length) acc[providerId] = next; return acc; }, {}); const { order: _droppedOrder, ...auth } = cfg.auth ?? {}; const providers = Object.fromEntries(Object.entries(cfg.models?.providers ?? {}).map(([providerId, provider]) => { if (provider.apiKey !== profileId) return [providerId, provider]; const { apiKey: _droppedApiKey, ...nextProvider } = provider; return [providerId, nextProvider]; })); return { ...cfg, ...authReferencesProfile ? { auth: { ...auth, profiles, ...Object.keys(order).length > 0 ? { order } : {} } } : {}, ...cfg.models?.providers ? { models: { ...cfg.models, providers } } : {} }; } function resolveSiblingAgentDirs(primaryAgentDir) { const normalized = path.resolve(primaryAgentDir); const parentOfAgent = path.dirname(normalized); const candidateAgentsRoot = path.dirname(parentOfAgent); const agentsRoot = path.basename(normalized) === "agent" && path.basename(candidateAgentsRoot) === "agents" ? candidateAgentsRoot : path.join(resolveStateDir(), "agents"); const discovered = (() => { try { return fs.readdirSync(agentsRoot, { withFileTypes: true }); } catch { return []; } })().filter((entry) => entry.isDirectory() || entry.isSymbolicLink()).map((entry) => path.join(agentsRoot, entry.name, "agent")); const seen = /* @__PURE__ */ new Set(); const result = []; for (const dir of [normalized, ...discovered]) { const real = safeRealpathSync(path.resolve(dir)); if (real && !seen.has(real)) { seen.add(real); result.push(real); } } return result; } async function writeOAuthCredentials(provider, creds, agentDir, options) { const email = typeof creds.email === "string" && creds.email.trim() ? creds.email.trim() : "default"; const profileId = buildAuthProfileId({ providerId: provider, profileName: options?.profileName ?? email }); const resolvedAgentDir = path.resolve(resolveAuthAgentDir(agentDir)); const targetAgentDirs = options?.syncSiblingAgents ? resolveSiblingAgentDirs(resolvedAgentDir) : [resolvedAgentDir]; const credential = { type: "oauth", provider, ...creds, ...options?.displayName ? { displayName: options.displayName } : {} }; await upsertAuthProfileWithLockOrThrow({ profileId, credential, agentDir: resolvedAgentDir }); if (options?.syncSiblingAgents) { const primaryReal = safeRealpathSync(path.resolve(resolvedAgentDir)); for (const targetAgentDir of targetAgentDirs) { const targetReal = safeRealpathSync(path.resolve(targetAgentDir)); if (targetReal && primaryReal && targetReal === primaryReal) continue; try { await upsertAuthProfileWithLock({ profileId, credential, agentDir: targetAgentDir }); } catch {} } } return profileId; } //#endregion export { upsertApiKeyProfile as a, removeAuthProfileConfig as i, buildApiKeyCredential as n, writeOAuthCredentials as o, configReferencesAuthProfile as r, applyAuthProfileConfig as t };