UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

512 lines (511 loc) 23.2 kB
import { o as asDateTimestampMs } from "./number-coercion-CLj0HTDM.js"; import { c as isRecord } from "./record-coerce-DItp3I4t.js"; import { l as normalizeOptionalString } from "./string-coerce-CIXf7egm.js"; import "./utils-P__uGsPB.js"; import { n as findNormalizedProviderValue, r as normalizeProviderId } from "./provider-id-DMd-TDFp.js"; import { t as buildModelCatalogMergeKey } from "./model-catalog-refs-BdjEHOKQ.js"; import { s as coerceSecretRef } from "./types.secrets-kC0nOetj.js"; import { i as isAmbientCredentialAllowedByProviderAuthPin } from "./external-auth-D5zyqyNH.js"; import { a as registryContainsRuntimePluginIds } from "./active-runtime-registry-C5SJbS7x.js"; import { n as withPluginRuntimeGenerationScope } from "./generation-scope-Cf83d_iq.js"; import { o as resolveLoadedProviderRuntimePlugin } from "./provider-hook-runtime-DgKv_Z8O.js"; import { a as ensureAuthProfileStoreWithoutExternalProfiles, r as ensureAuthProfileStore } from "./store-F1B2duCT.js"; import { a as resolveAuthProfileOrder } from "./order-CC2RBzI5.js"; import { t as buildPreparedModelCatalogSnapshot } from "./model-catalog-DOgUhUHe.js"; import { i as normalizeModelCompat } from "./provider-model-compat-BNXu5bti.js"; import { g as resolveProviderEnvAuthLookupMaps, h as listProviderEnvAuthLookupKeys } from "./model-auth-markers-jBKQn38x.js"; import { O as resolveProviderSyntheticAuthWithPlugin, p as normalizeProviderResolvedModelWithPlugin, t as applyProviderResolvedTransportWithPlugin, y as prepareProviderSyntheticAuthWithPlugin } from "./provider-runtime-BRJDPNgk.js"; import { i as resolveRuntimeSyntheticAuthProviderRefs } from "./synthetic-auth.runtime.js"; import { t as resolveEnvApiKey } from "./model-auth-env-Dq9W4xg9.js"; import { Lt as resolveModelPluginMetadataSnapshot, dt as ModelRegistry, xt as AuthStorage } from "./sessions-BdNAJTEP.js"; import { o as toStaticCatalogEntry } from "./prepared-model-runtime.configured-fNJibGQY.js"; import { n as augmentPreparedModelCatalogWithAgentHarness } from "./model-catalog-BPCzXkGj.js"; import { i as resolveAgentRuntimePluginLoadPlan } from "./runtime-plugin-load-plan-bSDzapSx.js"; import path from "node:path"; //#region src/agents/agent-auth-credentials.ts /** Converts auth-profile credentials into agent runtime credential maps. */ const AGENT_SECRET_REF_CONFIGURED_MARKER = "openclaw-secret-ref-configured"; /** Records only credential modes whose secret material is usable by a prepared runtime owner. */ function resolveUsableAgentCredentialModes(credentials) { const modes = {}; for (const [rawProvider, credential] of Object.entries(credentials)) { const provider = normalizeProviderId(rawProvider); if (!provider) continue; if (credential.type === "api_key" && credential.key && credential.key !== AGENT_SECRET_REF_CONFIGURED_MARKER) modes[provider] = "api_key"; else if (credential.type === "token" && credential.token && (credential.expires === void 0 || credential.expires > Date.now())) modes[provider] = "token"; else if (credential.type === "oauth" && credential.access && credential.refresh && credential.expires > 0) modes[provider] = "oauth"; } return Object.freeze(modes); } function hasConfiguredSecretRef(value) { return coerceSecretRef(value) !== null; } function secretRefPlaceholder(options) { if (options?.includeSecretRefPlaceholders === true) return { type: "api_key", key: AGENT_SECRET_REF_CONFIGURED_MARKER }; return null; } function convertAuthProfileCredentialToAgent(cred, options) { if (cred.type === "api_key") { const key = normalizeOptionalString(cred.key) ?? ""; if (!key) return hasConfiguredSecretRef(cred.keyRef) ? secretRefPlaceholder(options) : null; return { type: "api_key", key }; } if (cred.type === "token") { if (cred.expires !== void 0) { const expires = asDateTimestampMs(cred.expires); if (expires === void 0 || Date.now() >= expires) return null; } const token = normalizeOptionalString(cred.token) ?? ""; if (!token) return hasConfiguredSecretRef(cred.tokenRef) ? secretRefPlaceholder(options) : null; return { type: "api_key", key: token }; } if (cred.type === "oauth") { const access = normalizeOptionalString(cred.access) ?? ""; const refresh = normalizeOptionalString(cred.refresh) ?? ""; const expires = asDateTimestampMs(cred.expires); if (!access || !refresh || expires === void 0 || expires <= 0) return null; return { type: "oauth", access, refresh, expires }; } return null; } /** Build one canonically selected credential per normalized provider. */ function resolveAgentCredentialMapFromStore(store, options) { const credentials = {}; for (const credential of Object.values(store.profiles)) { const provider = normalizeProviderId(credential.provider ?? ""); if (!provider) continue; if (credentials[provider]) continue; const profileIds = resolveAuthProfileOrder({ cfg: options?.config, store, provider, ...options?.includeSecretRefPlaceholders === true ? { readinessMode: "read-only" } : {} }); for (const profileId of profileIds) { const profile = store.profiles[profileId]; if (!profile) continue; const converted = convertAuthProfileCredentialToAgent(profile, options); if (converted) { credentials[provider] = converted; break; } } } return credentials; } //#endregion //#region src/agents/agent-auth-discovery-core.ts /** Adds provider credentials resolvable from env/config without mutating existing credentials. */ function addEnvBackedAgentCredentials(credentials, options = {}) { const env = options.env ?? process.env; const lookupParams = { config: options.config, workspaceDir: options.workspaceDir, env }; const { aliasMap, envCandidateMap: candidateMap, authEvidenceMap } = resolveProviderEnvAuthLookupMaps(lookupParams); const next = { ...credentials }; for (const provider of listProviderEnvAuthLookupKeys({ envCandidateMap: candidateMap, authEvidenceMap })) { if (next[provider]) continue; const resolved = resolveEnvApiKey(provider, env, { config: options.config, workspaceDir: options.workspaceDir, aliasMap, candidateMap, authEvidenceMap }); if (!resolved?.apiKey) continue; next[provider] = { type: "api_key", key: resolved.apiKey }; } return next; } //#endregion //#region src/agents/agent-auth-discovery.ts /** Discovers agent runtime credentials from auth profiles, env, and synthetic providers. */ function resolveAmbientCredentialInputs(options) { const credentials = addEnvBackedAgentCredentials({}, options); const syntheticAuthProviderRefs = options.syntheticAuthProviderRefs ?? resolveRuntimeSyntheticAuthProviderRefs(); const authoritativeSyntheticAuthProviderRefs = new Set([...options.authoritativeSyntheticAuthProviderRefs ?? []].map(normalizeProviderId).filter(Boolean)); for (const provider of authoritativeSyntheticAuthProviderRefs) delete credentials[provider]; const providers = []; for (const provider of syntheticAuthProviderRefs) { const normalizedProvider = normalizeProviderId(provider); if (!authoritativeSyntheticAuthProviderRefs.has(normalizedProvider) && credentials[provider]) continue; if (!isAmbientCredentialAllowedByProviderAuthPin({ config: options.config, authAliasLookupParams: { ...options.env ? { env: options.env } : {}, ...options.workspaceDir ? { workspaceDir: options.workspaceDir } : {} }, provider, type: "api_key" })) continue; providers.push(provider); } return { credentials, providers }; } function syntheticAuthParams(options, provider) { return { config: options.config, workspaceDir: options.workspaceDir, env: options.env, provider, context: { config: options.config, provider, providerConfig: options.config?.models?.providers?.[provider] } }; } function addSyntheticCredential(credentials, provider, resolved) { const apiKey = resolved?.apiKey?.trim(); if (apiKey) credentials[normalizeProviderId(provider) || provider] = { type: "api_key", key: apiKey }; } /** Reads prepared workspace/config/env credentials independently of agent-local profiles. */ function resolveAmbientAgentCredentialsForDiscovery(options = {}) { const { credentials, providers } = resolveAmbientCredentialInputs(options); for (const provider of providers) addSyntheticCredential(credentials, provider, options.resolveSyntheticAuth ? options.resolveSyntheticAuth(provider) : resolveProviderSyntheticAuthWithPlugin(syntheticAuthParams(options, provider))); return credentials; } /** Prepares external availability before publishing a generation's synchronous auth facts. */ async function prepareAmbientAgentCredentialsForDiscovery(options = {}) { const { credentials, providers } = resolveAmbientCredentialInputs(options); for (const provider of providers) { options.signal?.throwIfAborted(); const resolved = options.resolveSyntheticAuth ? await options.resolveSyntheticAuth(provider) : await prepareProviderSyntheticAuthWithPlugin({ ...syntheticAuthParams(options, provider), signal: options.signal }); options.signal?.throwIfAborted(); addSyntheticCredential(credentials, provider, resolved); } return credentials; } /** Resolves the effective auth store and provider credentials for one discovery generation. */ function resolveAgentDiscoveryAuthFacts(agentDir, options) { const storeOptions = { allowKeychainPrompt: false, ...options?.config ? { config: options.config } : {}, ...options?.externalCli ? { externalCli: options.externalCli } : {}, ...options?.inheritedAuthDir ? { inheritedAuthDir: options.inheritedAuthDir } : {} }; const store = options?.preparedStore ? options.preparedStore : options?.skipExternalAuthProfiles === true ? ensureAuthProfileStoreWithoutExternalProfiles(agentDir, { allowKeychainPrompt: false, ...options?.inheritedAuthDir ? { inheritedAuthDir: options.inheritedAuthDir } : {}, ...options?.readOnly === true ? { readOnly: true } : {} }) : ensureAuthProfileStore(agentDir, { ...storeOptions, ...options?.readOnly === true ? { readOnly: true } : {} }); const credentials = resolveAgentCredentialMapFromStore(store, { includeSecretRefPlaceholders: options?.readOnly === true, config: options?.config }); const ambientCredentials = options?.ambientCredentials ?? resolveAmbientAgentCredentialsForDiscovery({ config: options?.config, workspaceDir: options?.workspaceDir, env: options?.env, syntheticAuthProviderRefs: options?.syntheticAuthProviderRefs }); for (const [provider, credential] of Object.entries(ambientCredentials)) { if (credentials[provider]) continue; credentials[provider] = credential; } return { store, credentials }; } //#endregion //#region src/agents/agent-model-discovery.ts /** Discovers agent models and auth storage with provider/plugin normalization hooks. */ const CAPTURED_MODELS_JSON_SOURCE_PATH = "captured:models.json"; /** Applies plugin model normalization and transport hooks to discovered agent models. */ function normalizeDiscoveredAgentModel(value, agentDir, options) { if (!isRecord(value)) return value; if (typeof value.id !== "string" || typeof value.name !== "string" || typeof value.provider !== "string") return value; const model = value; const runtimeContext = { ...options?.config !== void 0 ? { config: options.config } : {}, ...options?.workspaceDir !== void 0 ? { workspaceDir: options.workspaceDir } : {} }; const pluginNormalized = normalizeProviderResolvedModelWithPlugin({ provider: model.provider, modelId: model.id, ...runtimeContext, context: { provider: model.provider, modelId: model.id, model, agentDir } }) ?? model; const transportNormalized = applyProviderResolvedTransportWithPlugin({ provider: model.provider, modelId: model.id, ...runtimeContext, context: { provider: model.provider, modelId: model.id, model: pluginNormalized, agentDir } }) ?? pluginNormalized; if (!isRecord(transportNormalized) || typeof transportNormalized.id !== "string" || typeof transportNormalized.name !== "string" || typeof transportNormalized.provider !== "string" || typeof transportNormalized.api !== "string") return value; return normalizeModelCompat(transportNormalized, options?.providerMetadataOwners); } function createOpenClawModelRegistry(authStorage, modelsJsonPath, agentDir, options) { const pluginMetadataSnapshot = resolveModelPluginMetadataSnapshot({ ...options?.config ? { config: options.config } : {}, ...options?.pluginMetadataSnapshot ? { pluginMetadataSnapshot: options.pluginMetadataSnapshot } : {}, ...options?.workspaceDir ? { workspaceDir: options.workspaceDir } : {}, allowWorkspaceScopedCurrent: options?.workspaceDir === void 0, useRuntimeConfig: options?.config === void 0 }); const registryOptions = { ...pluginMetadataSnapshot ? { pluginMetadataSnapshot } : {}, ...options?.includePluginCatalogs !== void 0 ? { includePluginCatalogs: options.includePluginCatalogs } : {}, ...options?.modelsJsonContents !== void 0 ? { modelsJsonContents: options.modelsJsonContents } : {}, ...options?.pluginCatalogs !== void 0 ? { pluginCatalogs: options.pluginCatalogs } : {} }; const registry = ModelRegistry.create(authStorage, modelsJsonPath, registryOptions); const getAll = registry.getAll.bind(registry); const getAvailable = registry.getAvailable.bind(registry); const find = registry.find.bind(registry); const refresh = registry.refresh.bind(registry); const providerFilter = options?.providerFilter ? normalizeProviderId(options.providerFilter) : ""; const matchesProviderFilter = (entry) => !providerFilter || normalizeProviderId(entry.provider) === providerFilter; const shouldNormalize = options?.normalizeModels !== false; const findCache = /* @__PURE__ */ new Map(); const normalizeEntry = (entry) => { if (!shouldNormalize) return entry; if (!agentDir) throw new Error("agent directory is required for model normalization"); return normalizeDiscoveredAgentModel(entry, agentDir, { ...options, ...pluginMetadataSnapshot?.owners ? { providerMetadataOwners: pluginMetadataSnapshot.owners } : {} }); }; registry.getAll = () => { const entries = getAll().filter((entry) => matchesProviderFilter(entry)); return shouldNormalize ? entries.map(normalizeEntry) : entries; }; registry.getAvailable = () => { const entries = getAvailable().filter((entry) => matchesProviderFilter(entry)); return shouldNormalize ? entries.map(normalizeEntry) : entries; }; registry.find = (provider, modelId) => { const key = `${normalizeProviderId(provider)}\0${modelId}`; if (findCache.has(key)) return findCache.get(key); const fallbackEntry = find(provider, modelId); const resolved = fallbackEntry ? normalizeEntry(fallbackEntry) : void 0; findCache.set(key, resolved); return resolved; }; registry.refresh = () => { findCache.clear(); return refresh(); }; return registry; } /** Captures the effective profile store and its AuthStorage projection as one generation. */ function discoverAuthStorageFacts(agentDir, options) { const facts = options?.skipCredentials === true ? { store: { version: 1, profiles: {} }, credentials: {} } : resolveAgentDiscoveryAuthFacts(agentDir, options); return { ...facts, authStorage: AuthStorage.inMemory(facts.credentials) }; } /** Creates the model registry used by agent model discovery. */ /** Creates a model registry for one agent directory, optionally filtered and plugin-normalized. */ function discoverModels(authStorage, agentDir, options) { return createOpenClawModelRegistry(authStorage, path.join(agentDir, "models.json"), agentDir, options); } /** * Parses complete lifecycle-captured sources without retaining an agent-directory dependency. * Callers may share the resulting immutable catalog snapshot across exact source generations. */ function discoverModelsFromCapturedSources(authStorage, options) { return createOpenClawModelRegistry(authStorage, CAPTURED_MODELS_JSON_SOURCE_PATH, void 0, { ...options, normalizeModels: false }); } //#endregion //#region src/agents/prepared-model-runtime.configured-catalog.ts function modelCatalogEntryKey(entry) { return `${normalizeProviderId(entry.provider)}\0${entry.id.trim().toLowerCase()}`; } function createConfiguredModelCatalogSnapshot(params) { const entries = /* @__PURE__ */ new Map(); const addEntry = (entry) => { const key = modelCatalogEntryKey(entry); if (!entries.has(key)) entries.set(key, entry); }; for (const entry of params.workspaceFacts.configuredCatalogEntries) addEntry(entry); for (const configured of params.configuredRuntimeModels) addEntry(toStaticCatalogEntry(configured.model)); for (const { provider, modelId } of params.agentFacts.configuredModelRefs) { const model = params.templateModelRegistry.find(provider, modelId); if (model) addEntry(toStaticCatalogEntry(model)); } const configuredEntries = [...entries.values()]; const staticEntries = params.configuredRuntimeModels.map(({ model }) => toStaticCatalogEntry(model)); return { entries: configuredEntries, routeVariants: configuredEntries, ...staticEntries.length > 0 ? { staticEntries } : {} }; } function prepareConfiguredRuntimeFacts(params) { return { templateModelRegistry: params.templateModelRegistry, modelCatalog: createConfiguredModelCatalogSnapshot(params), configuredRuntimeModels: params.configuredRuntimeModels, inlineProviderModels: params.workspaceFacts.inlineProviderModels }; } //#endregion //#region src/agents/prepared-model-runtime.configured-completion.ts function completeConfiguredRuntimeModels(agentFacts, pluginGeneration, modelRegistry) { if (!pluginGeneration.pluginRegistry) return agentFacts.configuredRuntimeModels; const { input, configuredModelRefs, configuredRuntimeModels, env } = agentFacts; const { config, agentDir, workspaceDir } = input; return withPluginRuntimeGenerationScope({ metadataSnapshot: pluginGeneration.pluginMetadataSnapshot, pluginRegistry: pluginGeneration.pluginRegistry }, () => { const existing = new Map(configuredRuntimeModels.map((configured) => [buildModelCatalogMergeKey(configured.provider, configured.modelId), configured])); const completed = []; const seen = /* @__PURE__ */ new Set(); for (const ref of configuredModelRefs) { const { provider, modelId } = ref; const key = buildModelCatalogMergeKey(provider, modelId); if (seen.has(key)) continue; seen.add(key); const model = existing.get(key)?.model ?? resolveLoadedProviderRuntimePlugin({ provider, modelId, config, workspaceDir, env })?.resolveDynamicModel?.({ config, agentDir, workspaceDir, provider, modelId, modelRegistry, providerConfig: config.models?.providers?.[provider] ?? findNormalizedProviderValue(config.models?.providers, provider) }); if (model) completed.push({ ...ref, model }); } return completed; }); } //#endregion //#region src/agents/prepared-model-runtime.plugin-generation.ts const derivedGenerationBases = /* @__PURE__ */ new WeakMap(); /** Borrowing may narrow a prepared selection, but cannot acquire a different plugin owner. */ function preparedPluginGenerationSupportsSelections(generation, input) { if (!input.runtimePluginSelections) return true; const registry = generation.pluginRegistry; const plan = resolveAgentRuntimePluginLoadPlan({ config: input.config, workspaceDir: generation.pluginMetadataSnapshot.workspaceDir ?? input.workspaceDir ?? process.cwd(), selections: input.runtimePluginSelections, metadataSnapshot: generation.pluginMetadataSnapshot }); return registry !== void 0 && (plan.pluginIds ?? []).every((id) => registry.plugins.some((plugin) => plugin.id === id && plugin.status === "error") || registryContainsRuntimePluginIds(registry, [id])); } function preparedPluginGenerationReusesBase(generation, base) { return generation === base || generation !== void 0 && derivedGenerationBases.get(generation) === base; } function createPreparedPluginGeneration(params) { const reusable = params.reusablePluginGeneration; if (reusable) { if (params.pluginMetadataSnapshot === reusable.pluginMetadataSnapshot && params.runtimePluginRegistry === reusable.pluginRegistry) return reusable; const derived = Object.freeze({ ...reusable, pluginMetadataSnapshot: params.pluginMetadataSnapshot, pluginRegistry: params.runtimePluginRegistry, mediaCapabilityProviders: params.mediaCapabilityProviders, messageToolCatalog: params.messageToolCatalog, preparedStaticProviderCatalog: params.preparedStaticProviderCatalog }); if (params.pluginMetadataSnapshot === reusable.pluginMetadataSnapshot) derivedGenerationBases.set(derived, reusable); return derived; } return Object.freeze({ pluginMetadataSnapshot: params.pluginMetadataSnapshot, inlineProviderModels: Object.freeze([...params.inlineProviderModels]), configuredCatalogEntries: Object.freeze([...params.configuredCatalogEntries]), ...params.messageToolCatalog ? { messageToolCatalog: params.messageToolCatalog } : {}, ...params.runtimePluginRegistry ? { pluginRegistry: params.runtimePluginRegistry } : {}, ...params.inboundPluginRegistry ? { inboundPluginRegistry: params.inboundPluginRegistry } : {}, ...params.preferBuiltPluginArtifacts ? { preferBuiltPluginArtifacts: true } : {}, ...params.mediaCapabilityProviders ? { mediaCapabilityProviders: params.mediaCapabilityProviders } : {}, ...params.preparedStaticProviderCatalog ? { preparedStaticProviderCatalog: params.preparedStaticProviderCatalog } : {}, ...params.catalogMode === "live" ? { providerStaticModels: Object.freeze([...params.providerStaticModels ?? []]) } : {} }); } async function buildPreparedPluginModelCatalog(params) { const { credentials, input } = params.agentFacts; const { pluginMetadataSnapshot: metadataSnapshot, pluginRegistry } = params.pluginGeneration; return await withPluginRuntimeGenerationScope({ metadataSnapshot, pluginRegistry }, async () => { const snapshot = await buildPreparedModelCatalogSnapshot({ agentDir: input.agentDir, authCredentials: credentials, config: input.config, modelRegistry: params.modelRegistry, metadataSnapshot, includeProviderPluginAugmentation: params.catalogMode === "live", ...input.env ? { env: input.env } : {}, ...input.readOnly ? { readOnly: true } : {}, ...input.workspaceDir ? { workspaceDir: input.workspaceDir } : {} }); return params.catalogMode === "live" ? await augmentPreparedModelCatalogWithAgentHarness({ input, snapshot, pluginRegistry }) : snapshot; }); } //#endregion export { completeConfiguredRuntimeModels as a, discoverAuthStorageFacts as c, normalizeDiscoveredAgentModel as d, prepareAmbientAgentCredentialsForDiscovery as f, resolveUsableAgentCredentialModes as h, preparedPluginGenerationSupportsSelections as i, discoverModels as l, resolveAgentCredentialMapFromStore as m, createPreparedPluginGeneration as n, modelCatalogEntryKey as o, resolveAmbientAgentCredentialsForDiscovery as p, preparedPluginGenerationReusesBase as r, prepareConfiguredRuntimeFacts as s, buildPreparedPluginModelCatalog as t, discoverModelsFromCapturedSources as u };