openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
335 lines (334 loc) • 14.8 kB
JavaScript
import { o as normalizeLowercaseStringOrEmpty } from "./string-coerce-CIXf7egm.js";
import { a as writeRuntimeJson, o as writeRuntimeStdout } from "./runtime-CF2WjnNZ.js";
import { n as requestExitAfterOneShotOutput } from "./one-shot-exit-BkFPnjbM.js";
import { t as createLazyImportLoader } from "./lazy-promise-DGqyc4Y4.js";
import { t as formatCliCommand } from "./command-format-C7YfyMTd.js";
import { r as normalizeProviderId } from "./provider-id-DMd-TDFp.js";
import { n as sanitizeTerminalText } from "./safe-text-BGBqp1a4.js";
import "./defaults-CdX9UGcX.js";
import { c as loadManifestMetadataSnapshot } from "./manifest-contract-eligibility-BbV7X6pV.js";
import { n as parseModelRef } from "./model-selection-normalize-D1HuPOqZ.js";
import { r as theme, t as colorize } from "./theme-vjDs9tao.js";
import { t as ExpectedCliError } from "./failure-output-Dc5ce9_F.js";
import { a as resolveLegacyInheritedAuthDir } from "./legacy-inherited-auth-dir-CMGSmv-F.js";
import { s as resolveCliRuntimeExecutionProvider } from "./model-runtime-aliases-BJ2qM8I_.js";
import { n as createModelAuthAvailabilityResolver, t as applyCliRuntimeModelAuthAvailability } from "./model-auth-availability-CRH5-dWY.js";
import { t as resolveConfiguredModelEntries } from "./configured-model-entries-CV1BLgOW.js";
import { i as createModelCatalogProviderAliasCanonicalizer } from "./model-reference-validation-hyAvbbzD.js";
import { d as ensureFlagCompatibility, f as formatTag, g as truncate, h as padTerminalCell, m as isRich, p as formatTokenK, s as resolveModelsTargetAgent } from "./shared-CZFRGTsE.js";
import { n as loadModelsConfigWithSource } from "./load-config-CHI7_3xu.js";
import { t as formatErrorWithStack } from "./list.errors-CvTPa0Ln.js";
//#region src/commands/models/list.auth-index.ts
function listValidatedSyntheticAuthProviderRefs(params) {
if (params.metadataSnapshot.registryDiagnostics.length > 0 || params.metadataSnapshot.registrySource !== "persisted" && params.metadataSnapshot.registrySource !== "provided") return [];
return params.metadataSnapshot.index.plugins.filter((plugin) => plugin.enabled).flatMap((plugin) => plugin.syntheticAuthRefs ?? []);
}
/** Builds one snapshot-scoped command adapter around the shared evaluator. */
function createModelListAuthIndex(params) {
const env = params.env ?? process.env;
const resolver = createModelAuthAvailabilityResolver({
cfg: params.cfg,
authStore: params.authStore,
agentDir: params.agentDir,
workspaceDir: params.workspaceDir,
env,
metadataSnapshot: params.metadataSnapshot,
externalCliProviderIds: params.externalCliProviderIds,
routeResolverFactory: params.routeResolverFactory,
preparedRuntimeAuthModes: params.preparedRuntimeAuthModes,
syntheticAuthProviderRefs: params.syntheticAuthProviderRefs ?? listValidatedSyntheticAuthProviderRefs({ metadataSnapshot: params.metadataSnapshot })
});
return {
providerDiscoveryProviderIds: resolver.providerDiscoveryProviderIds,
evaluateModelAuth: (provider, ref) => {
const evaluation = resolver.evaluateModelAuth(provider, ref);
return applyCliRuntimeModelAuthAvailability({
authResolver: resolver,
evaluation,
cfg: params.cfg,
agentId: params.agentId,
metadataSnapshot: params.metadataSnapshot,
provider,
modelId: ref?.modelId,
preferredProfileId: ref?.preferredProfileId,
pinnedProfileId: ref?.pinnedProfileId
});
}
};
}
//#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) writeRuntimeStdout(runtime, sanitizeTerminalText(row.key));
return;
}
const rich = isRich(opts);
const header = [
padTerminalCell("Model", MODEL_PAD),
padTerminalCell("Input", INPUT_PAD),
padTerminalCell("Ctx", CTX_PAD),
padTerminalCell("Local", LOCAL_PAD),
padTerminalCell("Auth", AUTH_PAD),
"Tags"
].join(" ");
runtime.log(rich ? theme.heading(header) : header);
for (const row of rows) {
const keyLabel = padTerminalCell(truncate(sanitizeTerminalText(row.key), MODEL_PAD), MODEL_PAD);
const inputLabel = padTerminalCell(sanitizeTerminalText(row.input) || "-", INPUT_PAD);
const ctxLabel = padTerminalCell(formatContextLabel(row), CTX_PAD);
const localText = row.local === null ? "-" : row.local ? "yes" : "no";
const localLabel = padTerminalCell(localText, LOCAL_PAD);
const authText = row.available === null ? "-" : row.available ? "yes" : "no";
const authLabel = padTerminalCell(authText, 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 promotionsModuleLoader = createLazyImportLoader(() => import("./list.promotions-BkiUSW2k.js"));
const registryModuleLoader = createLazyImportLoader(() => import("./list.registry-CAzqCql4.js"));
const rowSourcesModuleLoader = createLazyImportLoader(() => import("./list.row-sources-CZ6b8Xh-.js"));
/** Lists configured, catalog, and runtime-discovered models as text, plain, or JSON. */
async function modelsListCommand(opts, runtime) {
ensureFlagCompatibility(opts);
const rawProviderFilter = opts.provider?.trim();
const parsedProviderFilter = (() => {
if (!rawProviderFilter) return;
if (/\s/u.test(rawProviderFilter)) {
const message = `Invalid provider filter "${sanitizeTerminalText(rawProviderFilter)}". Use a provider id such as "moonshot", not a display label.`;
throw new ExpectedCliError({
message,
humanOutput: message,
machineOutput: message
});
}
return parseModelRef(`${rawProviderFilter}/_`, "openai", DISPLAY_MODEL_PARSE_OPTIONS)?.provider ?? normalizeLowercaseStringOrEmpty(rawProviderFilter);
})();
const humanReadable = !opts.json && !opts.plain;
const [{ loadAuthProfileStoreWithoutExternalProfiles }, { resolveAgentWorkspaceDir }, { resolveDefaultAgentWorkspaceDir }] = await Promise.all([
import("./store-DNxWSPNc.js"),
import("./agent-scope-BHLMs19p.js"),
import("./workspace-DYBYNr9B.js")
]);
const { resolvedConfig: cfg } = await loadModelsConfigWithSource({
commandName: "models list",
runtime
});
const { agentId, agentDir } = resolveModelsTargetAgent(cfg, opts.agent, { kind: "read" });
const workspaceDir = resolveAgentWorkspaceDir(cfg, agentId) ?? resolveDefaultAgentWorkspaceDir();
const metadataSnapshot = loadManifestMetadataSnapshot({
config: cfg,
workspaceDir,
env: process.env
});
const providerAliasCanonicalizer = createModelCatalogProviderAliasCanonicalizer({
cfg,
metadataSnapshot
});
const providerFilter = parsedProviderFilter ? providerAliasCanonicalizer.provider(parsedProviderFilter) : void 0;
const { entries } = resolveConfiguredModelEntries({
cfg,
agentId,
...DISPLAY_MODEL_PARSE_OPTIONS,
canonicalizeRef: providerAliasCanonicalizer.ref
});
if (providerFilter) {
if (!new Set([
...metadataSnapshot.owners.providers.keys(),
...metadataSnapshot.owners.modelCatalogProviders.keys(),
...Object.keys(cfg.models?.providers ?? {}),
...entries.map((entry) => entry.ref.provider)
].map((providerId) => providerAliasCanonicalizer.provider(providerId))).has(providerFilter)) {
const message = `Unknown provider filter "${sanitizeTerminalText(rawProviderFilter ?? providerFilter)}" for this installation. Run ${formatCliCommand("openclaw plugins list --json")} to see installed providers, or configure it under models.providers.`;
throw new ExpectedCliError({
message,
humanOutput: message,
machineOutput: message
});
}
}
const inheritedAuthDir = resolveLegacyInheritedAuthDir(cfg);
const authStore = inheritedAuthDir ? loadAuthProfileStoreWithoutExternalProfiles(agentDir, { inheritedAuthDir }) : loadAuthProfileStoreWithoutExternalProfiles(agentDir);
const includePreparedCatalog = Boolean(opts.all || providerFilter);
let preparedRuntimeAuthModes;
let modelRegistry;
let registryModels = [];
let discoveredKeys = /* @__PURE__ */ new Set();
let availableKeys;
let availabilityErrorMessage;
const configuredByKey = new Map(entries.map((entry) => [entry.key, entry]));
const cliRuntimeProviderIds = [...new Set((opts.local ? [] : entries).filter((entry) => !providerFilter || providerAliasCanonicalizer.provider(entry.ref.provider) === providerFilter).map((entry) => resolveCliRuntimeExecutionProvider({
provider: entry.ref.provider,
modelId: entry.ref.model,
cfg,
agentId,
metadataSnapshot
})).map((provider) => normalizeProviderId(provider ?? "")).filter((provider) => provider && provider !== "openai"))];
try {
if (includePreparedCatalog) {
const { loadModelRegistry } = await registryModuleLoader.load();
const loaded = await loadModelRegistry(cfg, {
agentId,
agentDir,
providerFilter,
normalizeModels: Boolean(providerFilter),
workspaceDir
});
modelRegistry = loaded.registry;
registryModels = loaded.models;
discoveredKeys = loaded.discoveredKeys;
availableKeys = loaded.availableKeys;
availabilityErrorMessage = loaded.availabilityErrorMessage;
preparedRuntimeAuthModes = Object.fromEntries(cliRuntimeProviderIds.flatMap((provider) => {
const mode = loaded.authModes[provider];
return mode ? [[provider, mode]] : [];
}));
} else if (!opts.all && opts.local) {
const { loadConfiguredListModelRegistry } = await registryModuleLoader.load();
const loaded = await loadConfiguredListModelRegistry(cfg, entries, {
agentId,
agentDir,
providerFilter,
workspaceDir
});
modelRegistry = loaded.registry;
discoveredKeys = loaded.discoveredKeys;
availableKeys = loaded.availableKeys;
}
} catch (err) {
const message = `Model registry unavailable: ${err instanceof Error ? err.message : String(err)}`;
throw new ExpectedCliError({
message,
humanOutput: `Model registry unavailable:\n${formatErrorWithStack(err)}`,
machineOutput: message
});
}
const unpreparedCliRuntimeProviderIds = includePreparedCatalog ? cliRuntimeProviderIds.filter((provider) => !preparedRuntimeAuthModes?.[provider]) : [];
if (unpreparedCliRuntimeProviderIds.length) try {
const scopedAuthModes = await (await import("./prepared-model-runtime.scoped-catalog-Cg5j61LG.js")).prepareScopedReadOnlyModelAuthModes({
config: cfg,
env: process.env,
workspaceDir
}, unpreparedCliRuntimeProviderIds, metadataSnapshot);
preparedRuntimeAuthModes = {
...preparedRuntimeAuthModes,
...scopedAuthModes
};
} catch (err) {
runtime.error(`CLI runtime auth lookup failed; leaving availability unknown:\n${formatErrorWithStack(err)}`);
}
const authIndex = createModelListAuthIndex({
cfg,
authStore,
agentId,
agentDir,
workspaceDir,
metadataSnapshot,
preparedRuntimeAuthModes,
externalCliProviderIds: ["openai"]
});
const providerDiscoveryProviderIds = (() => {
if (opts.all && !providerFilter) return;
if (providerFilter) return [providerFilter];
return [.../* @__PURE__ */ new Set([
...authIndex.providerDiscoveryProviderIds ?? [],
...entries.map((entry) => entry.ref.provider),
...Object.keys(cfg.models?.providers ?? {})
])].toSorted((left, right) => left.localeCompare(right));
})();
const providerRuntimeDiscoveryProviderIds = providerFilter ? [providerFilter] : opts.all ? void 0 : [];
const providerManifestFallbackProviderIds = !providerFilter && !opts.all ? authIndex.providerDiscoveryProviderIds : void 0;
const promotionsModulePromise = humanReadable ? promotionsModuleLoader.load() : void 0;
const promotionsRefreshPromise = promotionsModulePromise?.then((promotionsModule) => promotionsModule.startPromotionsFeedRefresh()).catch(() => void 0);
const rowContext = {
cfg,
agentId,
agentDir,
...inheritedAuthDir ? { inheritedAuthDir } : {},
authIndex,
canonicalizeProvider: providerAliasCanonicalizer.provider,
providerDiscoveryProviderIds,
providerRuntimeDiscoveryProviderIds,
providerManifestFallbackProviderIds,
availableKeys,
configuredByKey,
discoveredKeys,
filter: {
provider: providerFilter,
local: opts.local
},
metadataSnapshot,
workspaceDir
};
const rows = [];
if (includePreparedCatalog) {
const { appendAllModelRowSources } = await rowSourcesModuleLoader.load();
await appendAllModelRowSources({
rows,
entries,
context: rowContext,
modelRegistry,
registryModels
});
} else {
const { appendConfiguredModelRowSources } = await rowSourcesModuleLoader.load();
await appendConfiguredModelRowSources({
rows,
entries,
modelRegistry,
context: rowContext
});
}
if (availabilityErrorMessage !== void 0) runtime.error(`Model availability lookup failed; falling back to auth heuristics for discovered models: ${availabilityErrorMessage}`);
const promotionsModule = await (promotionsModulePromise ?? promotionsModuleLoader.load());
try {
promotionsModule.applyPromotionClaimTags(rows);
} catch {}
if (rows.length === 0 && !opts.json && !opts.plain) runtime.log("No models found.");
else printModelTable(rows, runtime, opts);
if (promotionsRefreshPromise) try {
const refresh = await promotionsRefreshPromise;
if (refresh) await promotionsModule.printAvailablePromotionsSection({
configuredKeys: new Set(entries.map((entry) => entry.key)),
refresh,
runtime
});
} catch {}
requestExitAfterOneShotOutput(runtime);
}
//#endregion
export { modelsListCommand };