UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

448 lines (447 loc) 18.6 kB
import { a as normalizeLowercaseStringOrEmpty } from "./string-coerce-mnp54Vah.js"; import { r as theme, t as colorize } from "./theme-vjDs9tao.js"; import { t as createLazyImportLoader } from "./lazy-promise-BONnzNfb.js"; import { r as writeRuntimeJson } from "./runtime-B4lgFmsS.js"; import { a as normalizeProviderIdForAuth } from "./provider-id-Dq06Bcx6.js"; import { i as resolveAgentModelPrimaryValue, r as resolveAgentModelFallbackValues } from "./model-input-B2zxl6MM.js"; import { m as loadPluginRegistrySnapshotWithMetadata } from "./plugin-registry-ChcJPHWl.js"; import { t as sanitizeTerminalText } from "./safe-text-BkQYdJi1.js"; import { o as openAIProviderUsesCodexRuntimeByDefault } from "./openai-routing-DXJmS9CT.js"; import { n as DEFAULT_MODEL, r as DEFAULT_PROVIDER } from "./defaults-mDjiWzE5.js"; import { s as loadManifestMetadataSnapshot } from "./manifest-contract-eligibility-DEeoLRlM.js"; import { g as resolveConfiguredModelRef, i as buildModelAliasIndex, y as resolveModelRefFromString } from "./model-selection-shared-b32cUYts.js"; import { c as parseModelRef, i as modelKey } from "./model-selection-normalize-roKDxQ9_.js"; import { b as resolveProviderEnvAuthLookupMaps, y as listProviderEnvAuthLookupKeys } from "./model-auth-markers-Sq8HdQFX.js"; import "./model-selection-CA_65iXi.js"; import { t as resolveEnvApiKey } from "./model-auth-env-O5hF4UJr.js"; import { s as resolveAwsSdkEnvVarName } from "./model-auth-runtime-shared-ZF0jyHxm.js"; import { l as hasSyntheticLocalProviderAuthConfig, u as hasUsableCustomProviderApiKey } from "./model-auth-DVfmdW0b.js"; import { a as formatTokenK, h as createModelCatalogProviderAliasCanonicalizer, m as canonicalizeModelCatalogProviderAlias, r as ensureFlagCompatibility } from "./shared-B3B7qn2l.js"; import { n as loadModelsConfigWithSource } from "./load-config-BBaPFZx-.js"; import { n as formatErrorWithStack } from "./list.errors-DDA-CnZS.js"; import { i as truncate, n as isRich, r as pad, t as formatTag } from "./list.format-Dm4sqBw2.js"; //#region src/commands/models/list.auth-index.ts /** Auth availability index for `openclaw models list` rows. */ function normalizeAuthProvider(provider, aliasMap) { const normalized = normalizeProviderIdForAuth(provider); return aliasMap[normalized] ?? normalized; } function normalizeStoredAuthProvider(provider, aliasMap) { const normalized = normalizeProviderIdForAuth(provider); if (normalized === "openai") return normalized; return aliasMap[normalized] ?? normalized; } function listValidatedSyntheticAuthProviderRefs(params) { if (params.metadataSnapshot && (params.metadataSnapshot.registryDiagnostics?.length ?? 0) > 0) return []; const result = loadPluginRegistrySnapshotWithMetadata({ config: params.cfg, workspaceDir: params.workspaceDir, env: params.env, index: params.metadataSnapshot?.index }); if (result.source !== "persisted" && result.source !== "provided") return []; return result.snapshot.plugins.filter((plugin) => plugin.enabled).flatMap((plugin) => plugin.syntheticAuthRefs ?? []); } /** Builds a provider-auth lookup from profiles, env, config, and synthetic plugin refs. */ function createModelListAuthIndex(params) { const env = params.env ?? process.env; const { aliasMap, envCandidateMap, authEvidenceMap } = resolveProviderEnvAuthLookupMaps({ config: params.cfg, workspaceDir: params.workspaceDir, env, metadataSnapshot: params.metadataSnapshot }); const skipSetupProviderFallback = params.metadataSnapshot !== void 0; const authenticatedProviders = /* @__PURE__ */ new Set(); const syntheticAuthProviders = /* @__PURE__ */ new Set(); const envProviderAuthCache = /* @__PURE__ */ new Map(); const credentialAuthsProvider = (credential) => { const normalizedProvider = normalizeStoredAuthProvider(credential.provider, aliasMap); if (normalizedProvider !== "openai") return true; if (credential.type === "api_key") return true; if (credential.type !== "oauth" && credential.type !== "token") return false; return openAIProviderUsesCodexRuntimeByDefault({ provider: normalizedProvider, config: params.cfg }); }; const addProvider = (provider) => { if (!provider?.trim()) return; authenticatedProviders.add(normalizeStoredAuthProvider(provider, aliasMap)); }; const addSyntheticProvider = (provider) => { const normalized = provider?.trim() ? normalizeProviderIdForAuth(provider) : ""; if (!normalized) return; syntheticAuthProviders.add(normalized); }; for (const credential of Object.values(params.authStore.profiles ?? {})) if (credentialAuthsProvider(credential)) addProvider(credential.provider); for (const provider of listProviderEnvAuthLookupKeys({ envCandidateMap, authEvidenceMap })) if (resolveEnvApiKey(provider, env, { aliasMap, candidateMap: envCandidateMap, authEvidenceMap, skipSetupProviderFallback, config: params.cfg, workspaceDir: params.workspaceDir })) addProvider(provider); if (resolveAwsSdkEnvVarName(env)) addProvider("amazon-bedrock"); for (const provider of Object.keys(params.cfg.models?.providers ?? {})) if (hasUsableCustomProviderApiKey(params.cfg, provider, env) || hasSyntheticLocalProviderAuthConfig({ cfg: params.cfg, provider })) addProvider(provider); if (resolveAgentModelPrimaryValue(params.cfg.agents?.defaults?.model)?.split("/", 1)[0] === "codex") addSyntheticProvider("codex"); for (const provider of params.syntheticAuthProviderRefs ?? listValidatedSyntheticAuthProviderRefs({ cfg: params.cfg, workspaceDir: params.workspaceDir, env, metadataSnapshot: params.metadataSnapshot })) addSyntheticProvider(provider); const hasEnvProviderAuth = (provider) => { const normalized = normalizeAuthProvider(provider, aliasMap); const cached = envProviderAuthCache.get(normalized); if (cached !== void 0) return cached; const hasAuth = Boolean(resolveEnvApiKey(provider, env, { aliasMap, candidateMap: skipSetupProviderFallback || Object.hasOwn(envCandidateMap, normalized) ? envCandidateMap : void 0, authEvidenceMap: skipSetupProviderFallback || Object.hasOwn(authEvidenceMap, normalized) ? authEvidenceMap : void 0, skipSetupProviderFallback, config: params.cfg, workspaceDir: params.workspaceDir })); envProviderAuthCache.set(normalized, hasAuth); if (hasAuth) authenticatedProviders.add(normalized); return hasAuth; }; const hasOpenAICodexRuntimeAuth = (provider) => { return openAIProviderUsesCodexRuntimeByDefault({ provider: normalizeAuthProvider(provider, aliasMap), config: params.cfg }) && (authenticatedProviders.has("openai") || authenticatedProviders.has("openai")); }; return { hasProviderAuth(provider) { const normalizedProvider = normalizeAuthProvider(provider, aliasMap); if (authenticatedProviders.has(normalizedProvider) || syntheticAuthProviders.has(normalizeProviderIdForAuth(provider)) || hasEnvProviderAuth(provider)) return true; return hasOpenAICodexRuntimeAuth(normalizedProvider); }, allowsProviderAuthAvailabilityFallback(provider) { return hasOpenAICodexRuntimeAuth(provider); } }; } //#endregion //#region src/commands/models/list.configured.ts /** Resolves configured model refs and tags for model-list rows. */ const DISPLAY_MODEL_PARSE_OPTIONS$1 = { allowPluginNormalization: false }; /** Returns canonical configured model entries with default/fallback/image/configured tags. */ function resolveConfiguredEntries(cfg, metadataSnapshot) { const resolvedDefault = resolveConfiguredModelRef({ cfg, defaultProvider: DEFAULT_PROVIDER, defaultModel: DEFAULT_MODEL, ...DISPLAY_MODEL_PARSE_OPTIONS$1 }); const aliasIndex = buildModelAliasIndex({ cfg, defaultProvider: DEFAULT_PROVIDER, ...DISPLAY_MODEL_PARSE_OPTIONS$1 }); const order = []; const tagsByKey = /* @__PURE__ */ new Map(); const aliasesByKey = /* @__PURE__ */ new Map(); const canonicalizeProviderAlias = createModelCatalogProviderAliasCanonicalizer({ cfg, metadataSnapshot }); for (const [key, aliases] of aliasIndex.byKey.entries()) aliasesByKey.set(key, aliases); const addEntry = (ref, tag) => { const canonicalRef = canonicalizeProviderAlias.ref(ref); const key = modelKey(canonicalRef.provider, canonicalRef.model); const originalKey = modelKey(ref.provider, ref.model); if (originalKey !== key) { const aliases = aliasesByKey.get(originalKey); if (aliases) aliasesByKey.set(key, [...new Set([...aliasesByKey.get(key) ?? [], ...aliases])]); } if (!tagsByKey.has(key)) { tagsByKey.set(key, /* @__PURE__ */ new Set()); order.push(key); } tagsByKey.get(key)?.add(tag); }; const addResolvedModelRef = (raw, tag) => { const resolved = resolveModelRefFromString({ raw, defaultProvider: DEFAULT_PROVIDER, aliasIndex, ...DISPLAY_MODEL_PARSE_OPTIONS$1 }); if (resolved) addEntry(resolved.ref, tag); }; addEntry(resolvedDefault, "default"); const modelFallbacks = resolveAgentModelFallbackValues(cfg.agents?.defaults?.model); const imageFallbacks = resolveAgentModelFallbackValues(cfg.agents?.defaults?.imageModel); const imagePrimary = resolveAgentModelPrimaryValue(cfg.agents?.defaults?.imageModel) ?? ""; modelFallbacks.forEach((raw, idx) => { addResolvedModelRef(raw, `fallback#${idx + 1}`); }); if (imagePrimary) addResolvedModelRef(imagePrimary, "image"); imageFallbacks.forEach((raw, idx) => { addResolvedModelRef(raw, `img-fallback#${idx + 1}`); }); for (const key of Object.keys(cfg.agents?.defaults?.models ?? {})) { if (key.trim().endsWith("/*")) continue; const resolved = resolveModelRefFromString({ cfg, raw: key, defaultProvider: DEFAULT_PROVIDER, aliasIndex, ...DISPLAY_MODEL_PARSE_OPTIONS$1 }); if (!resolved) continue; addEntry(resolved.ref, "configured"); } return { entries: order.map((key) => { const slash = key.indexOf("/"); return { key, ref: { provider: slash === -1 ? key : key.slice(0, slash), model: slash === -1 ? "" : key.slice(slash + 1) }, tags: tagsByKey.get(key) ?? /* @__PURE__ */ new Set(), aliases: aliasesByKey.get(key) ?? [] }; }) }; } //#endregion //#region src/commands/models/list.table.ts /** Terminal/JSON/plain table renderer for model-list rows. */ const MODEL_PAD = 42; const INPUT_PAD = 10; const CTX_PAD = 11; const LOCAL_PAD = 5; const AUTH_PAD = 5; function formatContextLabel(row) { if (typeof row.contextTokens === "number" && Number.isFinite(row.contextTokens) && row.contextTokens > 0 && row.contextTokens !== row.contextWindow) return `${formatTokenK(row.contextTokens)}/${formatTokenK(row.contextWindow)}`; return formatTokenK(row.contextWindow); } /** Prints model-list rows in JSON, plain, or fixed-width terminal form. */ function printModelTable(rows, runtime, opts = {}) { if (opts.json) { writeRuntimeJson(runtime, { count: rows.length, models: rows }); return; } if (opts.plain) { for (const row of rows) runtime.log(sanitizeTerminalText(row.key)); return; } const rich = isRich(opts); const header = [ pad("Model", MODEL_PAD), pad("Input", INPUT_PAD), pad("Ctx", CTX_PAD), pad("Local", LOCAL_PAD), pad("Auth", AUTH_PAD), "Tags" ].join(" "); runtime.log(rich ? theme.heading(header) : header); for (const row of rows) { const keyLabel = pad(truncate(sanitizeTerminalText(row.key), MODEL_PAD), MODEL_PAD); const inputLabel = pad(sanitizeTerminalText(row.input) || "-", INPUT_PAD); const ctxLabel = pad(formatContextLabel(row), CTX_PAD); const localLabel = pad(row.local === null ? "-" : row.local ? "yes" : "no", LOCAL_PAD); const authLabel = pad(row.available === null ? "-" : row.available ? "yes" : "no", AUTH_PAD); const tags = row.tags.map(sanitizeTerminalText); const tagsLabel = tags.length > 0 ? rich ? tags.map((tag) => formatTag(tag, rich)).join(",") : tags.join(",") : ""; const coloredInput = colorize(rich, row.input.includes("image") ? theme.accentBright : theme.info, inputLabel); const coloredLocal = colorize(rich, row.local === null ? theme.muted : row.local ? theme.success : theme.muted, localLabel); const coloredAuth = colorize(rich, row.available === null ? theme.muted : row.available ? theme.success : theme.error, authLabel); const line = [ rich ? theme.accent(keyLabel) : keyLabel, coloredInput, ctxLabel, coloredLocal, coloredAuth, tagsLabel ].join(" "); runtime.log(line); } } //#endregion //#region src/commands/models/list.list-command.ts /** Implementation of `openclaw models list`. */ const DISPLAY_MODEL_PARSE_OPTIONS = { allowPluginNormalization: false }; const registryLoadModuleLoader = createLazyImportLoader(() => import("./list.registry-load-Adz6qZBb.js")); const rowSourcesModuleLoader = createLazyImportLoader(() => import("./list.row-sources-Cq7WM88z.js")); const sourcePlanModuleLoader = createLazyImportLoader(() => import("./list.source-plan-BoHeZG39.js")); function loadRegistryLoadModule() { return registryLoadModuleLoader.load(); } function loadRowSourcesModule() { return rowSourcesModuleLoader.load(); } function loadSourcePlanModule() { return sourcePlanModuleLoader.load(); } /** Lists configured, catalog, and runtime-discovered models as text, plain, or JSON. */ async function modelsListCommand(opts, runtime) { ensureFlagCompatibility(opts); const parsedProviderFilter = (() => { const raw = opts.provider?.trim(); if (!raw) return; if (/\s/u.test(raw)) { runtime.error(`Invalid provider filter "${raw}". Use a provider id such as "moonshot", not a display label.`); process.exitCode = 1; return null; } return parseModelRef(`${raw}/_`, "openai", DISPLAY_MODEL_PARSE_OPTIONS)?.provider ?? normalizeLowercaseStringOrEmpty(raw); })(); if (parsedProviderFilter === null) return; const [{ loadAuthProfileStoreWithoutExternalProfiles }, { resolveAgentWorkspaceDir, resolveDefaultAgentDir, resolveDefaultAgentId }, { resolveDefaultAgentWorkspaceDir }] = await Promise.all([ import("./store-DVS-q9q9.js"), import("./agent-scope-Do4dPjL6.js"), import("./workspace-BJPdELaN.js") ]); const { resolvedConfig: cfg } = await loadModelsConfigWithSource({ commandName: "models list", runtime }); const agentDir = resolveDefaultAgentDir(cfg); const authStore = loadAuthProfileStoreWithoutExternalProfiles(agentDir); const workspaceDir = resolveAgentWorkspaceDir(cfg, resolveDefaultAgentId(cfg)) ?? resolveDefaultAgentWorkspaceDir(); const metadataSnapshot = loadManifestMetadataSnapshot({ config: cfg, workspaceDir, env: process.env }); const providerFilter = parsedProviderFilter ? canonicalizeModelCatalogProviderAlias(parsedProviderFilter, { cfg, metadataSnapshot }) : void 0; const authIndex = createModelListAuthIndex({ cfg, authStore, workspaceDir, metadataSnapshot }); let modelRegistry; let registryModels = []; let discoveredKeys = /* @__PURE__ */ new Set(); let availableKeys; let availabilityErrorMessage; const { entries } = resolveConfiguredEntries(cfg, metadataSnapshot); const configuredByKey = new Map(entries.map((entry) => [entry.key, entry])); const enableSourcePlanCascade = Boolean(opts.all) || Boolean(providerFilter); const sourcePlanModule = enableSourcePlanCascade ? await loadSourcePlanModule() : void 0; const sourcePlan = sourcePlanModule ? await sourcePlanModule.planAllModelListSources({ all: opts.all, enableCascade: enableSourcePlanCascade, providerFilter, cfg, metadataSnapshot }) : void 0; const shouldLoadRegistry = sourcePlan?.requiresInitialRegistry ?? false; const loadRegistryState = async (optsLocal) => { const { loadListModelRegistry } = await loadRegistryLoadModule(); const loaded = await loadListModelRegistry(cfg, { providerFilter, normalizeModels: optsLocal?.normalizeModels ?? Boolean(providerFilter), loadAvailability: optsLocal?.loadAvailability, workspaceDir }); modelRegistry = loaded.registry; registryModels = loaded.models; discoveredKeys = loaded.discoveredKeys; availableKeys = loaded.availableKeys; availabilityErrorMessage = loaded.availabilityErrorMessage; }; try { if (shouldLoadRegistry) await loadRegistryState(); else if (!opts.all && opts.local) { const { loadConfiguredListModelRegistry } = await loadRegistryLoadModule(); const loaded = loadConfiguredListModelRegistry(cfg, entries, { providerFilter, workspaceDir }); modelRegistry = loaded.registry; discoveredKeys = loaded.discoveredKeys; availableKeys = loaded.availableKeys; } } catch (err) { runtime.error(`Model registry unavailable:\n${formatErrorWithStack(err)}`); process.exitCode = 1; return; } const buildRowContext = (skipRuntimeModelSuppression) => ({ cfg, agentDir, authIndex, availableKeys, configuredByKey, discoveredKeys, filter: { provider: providerFilter, local: opts.local }, skipRuntimeModelSuppression, metadataSnapshot, workspaceDir }); const rows = []; if (enableSourcePlanCascade) { const { appendAllModelRowSources } = await loadRowSourcesModule(); if (!sourcePlan || !sourcePlanModule) throw new Error("models list source plan was not initialized"); let rowContext = buildRowContext(sourcePlan.skipRuntimeModelSuppression); if ((await appendAllModelRowSources({ rows, entries, context: rowContext, modelRegistry, registryModels, sourcePlan })).requiresRegistryFallback) { const useScopedRegistryFallback = sourcePlan.kind === "provider-runtime-scoped"; try { await loadRegistryState(useScopedRegistryFallback ? { normalizeModels: false, loadAvailability: false } : void 0); } catch (err) { runtime.error(`Model registry unavailable:\n${formatErrorWithStack(err)}`); process.exitCode = 1; return; } rows.length = 0; rowContext = buildRowContext(useScopedRegistryFallback); await appendAllModelRowSources({ rows, entries, context: rowContext, modelRegistry, registryModels, sourcePlan: useScopedRegistryFallback ? sourcePlan : sourcePlanModule.createRegistryModelListSourcePlan() }); } } else { const { appendConfiguredModelRowSources } = await loadRowSourcesModule(); await appendConfiguredModelRowSources({ rows, entries, modelRegistry, context: buildRowContext(!modelRegistry) }); } if (availabilityErrorMessage !== void 0) runtime.error(`Model availability lookup failed; falling back to auth heuristics for discovered models: ${availabilityErrorMessage}`); if (rows.length === 0) { runtime.log("No models found."); return; } printModelTable(rows, runtime, opts); } //#endregion export { modelsListCommand };