openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
558 lines (557 loc) • 22.9 kB
JavaScript
import { o as normalizeLowercaseStringOrEmpty } from "./string-coerce-CIXf7egm.js";
import { t as createLazyImportLoader } from "./lazy-promise-DGqyc4Y4.js";
import { i as normalizeProviderIdForAuth } from "./provider-id-DMd-TDFp.js";
import { c as stripSelfProviderModelPrefix } from "./provider-model-id-normalization-BFjPahr6.js";
import { o as normalizeConfiguredProviderCatalogModelId } from "./model-ref-shared-Dz7QU0Lx.js";
import { t as modelKey } from "./model-key-CMdQNkZf.js";
import { d as modelCatalogLogicalKey } from "./model-selection-shared-BlLyx1r2.js";
import "./defaults-CdX9UGcX.js";
import { n as openAIModelCatalogRoutePolicy } from "./openai-model-routes-Bte2KVl5.js";
import { r as resolveBundledProviderPolicySurface } from "./provider-public-artifacts-Bone7gkJ.js";
import { f as isLoopbackIpAddress, i as isCanonicalDottedDecimalIPv4 } from "./ip-BkT2Is0E.js";
import { r as shouldSuppressBuiltInModelCore } from "./model-suppression-BNPeKW4_.js";
import { n as projectModelCatalogEntryForRoute, r as resolveConfiguredModelCatalogOverrides } from "./model-catalog-route-DKbERkez.js";
//#region src/commands/models/list.local-url.ts
/** Local URL classifier for model provider status/list output. */
/** Returns true for loopback, wildcard, and mDNS local base URLs. */
const isLocalBaseUrl = (baseUrl) => {
try {
const url = new URL(baseUrl);
const host = normalizeLowercaseStringOrEmpty(url.hostname).replace(/^\[|\]$/g, "");
return host === "localhost" || isCanonicalDottedDecimalIPv4(host) && isLoopbackIpAddress(host) || host === "0.0.0.0" || host === "::" || host === "::1" || host.endsWith(".local");
} catch {
return false;
}
};
//#endregion
//#region src/commands/models/list.model-row.ts
/** Converts registry/catalog models into printable model-list rows. */
function toListRowInput(input) {
const parsed = input?.filter((item) => item === "text" || item === "image" || item === "document");
return parsed?.length ? parsed : ["text"];
}
/** Builds a display row, preserving configured tags and alias metadata. */
function toModelRow(params) {
const { model, key, tags, aliases = [], availableKeys, authAvailability, authAvailabilityAuthoritative = false } = params;
if (!model) return {
key,
name: key,
input: "-",
contextWindow: null,
local: null,
available: null,
tags: [...tags, "missing"],
missing: true
};
const input = model.input?.join("+") || "-";
const local = isLocalBaseUrl(model.baseUrl ?? "");
const modelIsAvailable = local || (availableKeys?.has(modelKey(model.provider, model.id)) ?? false);
const available = authAvailabilityAuthoritative ? authAvailability ?? null : availableKeys !== void 0 ? modelIsAvailable : authAvailability ?? (modelIsAvailable ? true : null);
const aliasTags = aliases.length > 0 ? [`alias:${aliases.join(",")}`] : [];
const mergedTags = new Set(tags);
if (aliasTags.length > 0) {
for (const tag of mergedTags) if (tag === "alias" || tag.startsWith("alias:")) mergedTags.delete(tag);
for (const tag of aliasTags) mergedTags.add(tag);
}
return {
key,
name: model.name || model.id,
input,
contextWindow: model.contextWindow ?? null,
...typeof model.contextTokens === "number" ? { contextTokens: model.contextTokens } : {},
local,
available,
tags: Array.from(mergedTags),
missing: false
};
}
//#endregion
//#region src/commands/models/list.model-projection.ts
const providerRuntimeModuleLoader = createLazyImportLoader(() => import("./provider-runtime-Bq0N6145.js"));
function mergeNormalizedListRow(model, normalized) {
return {
...model,
id: normalized.id,
name: normalized.name,
provider: normalized.provider,
api: normalized.api ?? model.api,
baseUrl: normalized.baseUrl ?? model.baseUrl,
input: toListRowInput(normalized.input),
contextWindow: normalized.contextWindow,
contextTokens: normalized.contextTokens
};
}
/** Projects one authored provider row while keeping full runtime loading optional. */
async function normalizeConfiguredProviderListRow(params) {
const normalizationContext = {
config: params.context.cfg,
agentDir: params.context.agentDir,
workspaceDir: params.context.workspaceDir,
provider: params.model.provider,
modelId: params.model.id,
model: params.model
};
const policySurface = resolveBundledProviderPolicySurface(params.model.provider, { manifestRegistry: params.context.metadataSnapshot?.manifestRegistry });
if (policySurface?.projectConfiguredModelRow) {
const projected = policySurface.projectConfiguredModelRow(normalizationContext);
if (projected === null) return params.model;
if (projected !== void 0) return mergeNormalizedListRow(params.model, projected);
}
const { normalizeProviderResolvedModelWithPlugin } = await providerRuntimeModuleLoader.load();
const normalized = normalizeProviderResolvedModelWithPlugin({
provider: params.model.provider,
config: params.context.cfg,
workspaceDir: params.context.workspaceDir,
pluginMetadataSnapshot: params.context.metadataSnapshot,
context: normalizationContext
});
return normalized ? mergeNormalizedListRow(params.model, normalized) : params.model;
}
//#endregion
//#region src/commands/models/list.rows.ts
/** Row builders used by `openclaw models list` source orchestration. */
const modelCatalogModuleLoader = createLazyImportLoader(() => import("./prepared-model-catalog-BH7NC_p8.js"));
const scopedModelCatalogModuleLoader = createLazyImportLoader(() => import("./list.scoped-catalog-BIJ9hkKP.js"));
const modelResolverModuleLoader = createLazyImportLoader(() => import("./model-CokXeqgU.js"));
function matchesProviderFilter(context, provider) {
const providerFilter = context.filter.provider;
if (!providerFilter) return true;
return context.canonicalizeProvider(provider) === providerFilter;
}
function matchesRowFilter(context, model) {
if (!matchesProviderFilter(context, model.provider)) return false;
if (context.filter.local && !isLocalBaseUrl(model.baseUrl ?? "")) return false;
return true;
}
function resolveCatalogLogicalKey(model) {
return openAIModelCatalogRoutePolicy.resolveIdentity(model)?.key ?? modelCatalogLogicalKey(model);
}
function createModelCatalogLogicalRouteIndex(catalog) {
const index = /* @__PURE__ */ new Map();
for (const entry of catalog) {
const key = resolveCatalogLogicalKey(entry);
const variants = index.get(key) ?? [];
variants.push(entry);
index.set(key, variants);
}
return index;
}
function resolveCatalogLogicalRoutes(model, routeIndex) {
return routeIndex?.get(resolveCatalogLogicalKey(model));
}
function toModelAuthRef(model, routeIndex) {
const identity = openAIModelCatalogRoutePolicy.resolveIdentity(model);
const observedRoutes = resolveCatalogLogicalRoutes(model, routeIndex)?.map((entry) => ({
api: entry.api,
baseUrl: entry.baseUrl
}));
return {
modelId: identity?.id ?? model.id,
...observedRoutes && observedRoutes.length > 0 ? { observedRoutes } : {
api: model.api,
baseUrl: model.baseUrl
}
};
}
function toCatalogProjectionEntry(model) {
return {
id: model.id,
name: model.name,
provider: model.provider,
...typeof model.api === "string" ? { api: model.api } : {},
...model.baseUrl !== void 0 ? { baseUrl: model.baseUrl } : {},
...typeof model.contextWindow === "number" ? { contextWindow: model.contextWindow } : {},
...typeof model.contextTokens === "number" ? { contextTokens: model.contextTokens } : {},
...model.input !== void 0 ? { input: model.input } : {}
};
}
function hasSameCatalogRoute(left, right) {
return left.api === right.api && left.baseUrl === right.baseUrl;
}
function projectListRowModel(params) {
const projection = params.evaluation.routeResolution === null ? { kind: "unmanaged" } : params.evaluation.selectedRoute ? {
kind: "selected",
route: params.evaluation.selectedRoute,
policy: openAIModelCatalogRoutePolicy
} : {
kind: "unresolved",
policy: openAIModelCatalogRoutePolicy
};
const entry = toCatalogProjectionEntry(params.model);
const overrides = resolveConfiguredModelCatalogOverrides({
cfg: params.cfg,
entry,
policy: openAIModelCatalogRoutePolicy
});
const routeVariants = resolveCatalogLogicalRoutes(entry, params.routeIndex);
const projected = projectModelCatalogEntryForRoute({
entry,
projection,
...routeVariants ? { catalog: routeVariants } : {},
...overrides ? { overrides } : {}
});
return {
...params.model,
name: projected.name,
api: projected.api,
baseUrl: projected.baseUrl,
input: projected.input?.filter((item) => item === "text" || item === "image" || item === "document"),
contextWindow: projected.contextWindow,
contextTokens: projected.contextTokens
};
}
function buildRow(params) {
const configured = params.configuredEntry ?? params.context.configuredByKey.get(params.key);
return toModelRow({
model: params.model,
key: params.key,
tags: configured ? Array.from(configured.tags) : [],
aliases: configured?.aliases ?? [],
availableKeys: params.context.availableKeys,
authAvailability: params.authEvaluation.availability,
authAvailabilityAuthoritative: params.allowAuthAvailabilityOverride === true || normalizeProviderIdForAuth(params.model.provider) === "openai" || params.authEvaluation.routeResolution !== null
});
}
function shouldSuppressListModel(params) {
return shouldSuppressBuiltInModelCore({
provider: params.model.provider,
id: params.model.id,
baseUrl: params.model.baseUrl,
config: params.context.cfg
});
}
async function appendVisibleRow(params) {
if (params.seenKeys?.has(params.key)) return false;
const model = params.normalizeWithProviderPlugin ? await normalizeConfiguredProviderListRow({
model: params.model,
context: params.context
}) : params.model;
const authEvaluation = params.authEvaluation ?? params.context.authIndex.evaluateModelAuth(model.provider, toModelAuthRef(model, params.routeIndex));
const projectedModel = projectListRowModel({
model,
evaluation: authEvaluation,
cfg: params.context.cfg,
...params.routeIndex ? { routeIndex: params.routeIndex } : {}
});
if (!matchesRowFilter(params.context, projectedModel)) return false;
if (!params.skipSuppression && shouldSuppressListModel({
model: projectedModel,
context: params.context
})) return false;
params.rows.push(buildRow({
model: projectedModel,
key: params.key,
context: params.context,
authEvaluation,
allowAuthAvailabilityOverride: params.allowAuthAvailabilityOverride,
...params.configuredEntry ? { configuredEntry: params.configuredEntry } : {}
}));
params.seenKeys?.add(params.key);
return true;
}
function resolveConfiguredModelInput(params) {
const input = Array.isArray(params.model.input) ? params.model.input.filter((item) => item === "text" || item === "image") : [];
return input.length > 0 ? input : ["text"];
}
function toConfiguredProviderListModel(params) {
return {
provider: params.provider,
id: params.model.id,
name: params.model.name ?? params.model.id,
api: params.model.api ?? params.providerConfig.api,
baseUrl: params.model.baseUrl ?? params.providerConfig.baseUrl,
input: resolveConfiguredModelInput({ model: params.model }),
contextWindow: params.model.contextWindow ?? 2e5,
contextTokens: params.model.contextTokens
};
}
function toPreparedCatalogListModel(row) {
return {
provider: row.provider,
id: row.id,
name: row.name,
api: row.api,
baseUrl: row.baseUrl,
input: toListRowInput(row.input),
contextWindow: row.contextWindow ?? 2e5,
contextTokens: row.contextTokens
};
}
function shouldListConfiguredProviderModel(params) {
return params.providerConfig.api !== void 0 || params.model.api !== void 0;
}
function findConfiguredProviderModel(params) {
const providerConfig = params.cfg.models?.providers?.[params.provider];
const configuredModel = providerConfig?.models?.find((model) => model.id === params.modelId);
if (!providerConfig || !configuredModel) return;
return toConfiguredProviderListModel({
provider: params.provider,
providerConfig,
model: configuredModel
});
}
function toFallbackConfiguredListModel(entry, cfg, catalogEntry) {
return findConfiguredProviderModel({
cfg,
provider: entry.ref.provider,
modelId: entry.ref.model
}) ?? (catalogEntry ? toPreparedCatalogListModel(catalogEntry) : void 0) ?? {
provider: entry.ref.provider,
id: entry.ref.model,
name: entry.ref.model,
input: ["text"],
contextWindow: 2e5
};
}
/** Loads the committed catalog generation shared by every model-list row source. */
async function loadListModelCatalogSnapshot(context) {
const workspaceDir = context.workspaceDir ?? context.metadataSnapshot?.workspaceDir;
if (context.providerDiscoveryProviderIds) {
const { loadScopedListModelCatalogSnapshot } = await scopedModelCatalogModuleLoader.load();
return loadScopedListModelCatalogSnapshot({
cfg: context.cfg,
...context.agentId ? { agentId: context.agentId } : {},
agentDir: context.agentDir,
...context.inheritedAuthDir ? { inheritedAuthDir: context.inheritedAuthDir } : {},
...workspaceDir ? { workspaceDir } : {},
providerIds: context.providerDiscoveryProviderIds,
runtimeProviderIds: context.providerRuntimeDiscoveryProviderIds,
manifestFallbackProviderIds: context.providerManifestFallbackProviderIds,
configuredKeys: [...context.configuredByKey.keys()],
...context.metadataSnapshot ? { metadataSnapshot: context.metadataSnapshot } : {}
});
}
const { loadPreparedModelCatalogSnapshot } = await modelCatalogModuleLoader.load();
return loadPreparedModelCatalogSnapshot({
config: context.cfg,
...context.agentId ? { agentId: context.agentId } : {},
agentDir: context.agentDir,
...workspaceDir ? { workspaceDir } : {},
readOnly: true,
refreshFullCatalog: "stale"
});
}
/** Indexes a catalog generation by model key so configured refs can reuse its metadata. */
function indexModelCatalogEntriesByKey(snapshot) {
const byKey = /* @__PURE__ */ new Map();
for (const entry of [...snapshot.entries, ...snapshot.staticEntries ?? []]) {
const key = modelKey(entry.provider, entry.id);
if (!byKey.has(key)) byKey.set(key, entry);
}
return byKey;
}
/** Appends rows discovered from the loaded model registry. */
async function appendDiscoveredRows(params) {
const seenKeys = /* @__PURE__ */ new Set();
const modelResolver = params.modelRegistry && params.resolveWithRegistry !== false ? (await modelResolverModuleLoader.load()).resolveModelWithRegistry : void 0;
const preparedModels = [...params.models].toSorted((a, b) => {
const providerCompare = a.provider.localeCompare(b.provider);
if (providerCompare !== 0) return providerCompare;
return a.id.localeCompare(b.id);
}).map((model) => {
const key = modelKey(model.provider, model.id);
const resolvedModel = params.modelRegistry && modelResolver ? modelResolver({
provider: model.provider,
modelId: model.id,
modelRegistry: params.modelRegistry,
cfg: params.context.cfg,
agentDir: params.context.agentDir
}) : void 0;
return {
key,
model,
rowModel: resolvedModel && modelKey(resolvedModel.provider, resolvedModel.id) === key ? resolvedModel : model
};
});
const routeIndex = createModelCatalogLogicalRouteIndex(preparedModels.map(({ model, rowModel }) => toCatalogProjectionEntry(hasSameCatalogRoute(model, rowModel) ? rowModel : model)));
for (const { key, rowModel } of preparedModels) await appendVisibleRow({
rows: params.rows,
model: rowModel,
key,
context: params.context,
seenKeys,
routeIndex,
skipSuppression: params.skipSuppression
});
return seenKeys;
}
/** Appends models explicitly configured under models.providers. */
async function appendConfiguredProviderRows(params) {
const replaceMode = params.context.cfg.models?.mode === "replace";
for (const [provider, providerConfig] of Object.entries(params.context.cfg.models?.providers ?? {})) for (const configuredModel of providerConfig.models ?? []) {
if (!replaceMode && !shouldListConfiguredProviderModel({
providerConfig,
model: configuredModel
})) continue;
const modelId = replaceMode ? normalizeConfiguredProviderCatalogModelId(provider, stripSelfProviderModelPrefix(provider, configuredModel.id), { manifestPlugins: params.context.metadataSnapshot }) : configuredModel.id;
const displayProvider = replaceMode ? params.context.canonicalizeProvider(provider) : provider;
const key = modelKey(displayProvider, modelId);
const model = toConfiguredProviderListModel({
provider,
providerConfig,
model: {
...configuredModel,
id: modelId
}
});
const authEvaluation = replaceMode ? params.context.authIndex.evaluateModelAuth(provider, toModelAuthRef(model)) : void 0;
await appendVisibleRow({
rows: params.rows,
model,
key,
context: params.context,
seenKeys: params.seenKeys,
...authEvaluation ? { authEvaluation } : {},
allowAuthAvailabilityOverride: true,
normalizeWithProviderPlugin: true
});
}
}
/** Appends catalog models for providers that have configured auth. */
async function appendAuthenticatedCatalogRows(params) {
if (params.context.cfg.models?.mode === "replace") return;
const { entries: catalog, routeVariants } = params.catalogSnapshot ?? await loadListModelCatalogSnapshot(params.context);
const routeIndex = createModelCatalogLogicalRouteIndex(routeVariants);
for (const entry of catalog) {
const model = toPreparedCatalogListModel(entry);
const authEvaluation = params.context.authIndex.evaluateModelAuth(entry.provider, toModelAuthRef(model, routeIndex));
const hasRunnableSyntheticAuth = authEvaluation.availability === void 0 && authEvaluation.evidence === "synthetic";
if (authEvaluation.availability !== true && !hasRunnableSyntheticAuth) continue;
const key = modelKey(entry.provider, entry.id);
await appendVisibleRow({
rows: params.rows,
model,
key,
context: params.context,
seenKeys: params.seenKeys,
routeIndex,
authEvaluation,
allowAuthAvailabilityOverride: !hasRunnableSyntheticAuth
});
}
}
/** Projects every model from the same lifecycle generation used by the Gateway. */
async function appendPreparedModelCatalogRows(params) {
const catalogSnapshot = params.catalogSnapshot ?? await loadListModelCatalogSnapshot(params.context);
const staticEntries = catalogSnapshot.staticEntries ?? [];
const routeVariants = [...catalogSnapshot.routeVariants];
const seenRouteVariants = new Set(routeVariants.map((entry) => `${resolveCatalogLogicalKey(entry)}\0${entry.api ?? ""}\0${entry.baseUrl ?? ""}`));
for (const entry of staticEntries) {
const routeKey = `${resolveCatalogLogicalKey(entry)}\0${entry.api ?? ""}\0${entry.baseUrl ?? ""}`;
if (!seenRouteVariants.has(routeKey)) {
routeVariants.push(entry);
seenRouteVariants.add(routeKey);
}
}
const routeIndex = createModelCatalogLogicalRouteIndex(routeVariants);
for (const entry of [...catalogSnapshot.entries, ...staticEntries]) await appendVisibleRow({
rows: params.rows,
model: toPreparedCatalogListModel(entry),
key: modelKey(entry.provider, entry.id),
context: params.context,
seenKeys: params.seenKeys,
routeIndex,
allowAuthAvailabilityOverride: !params.context.discoveredKeys.has(modelKey(entry.provider, entry.id))
});
}
/** Appends rows from default/fallback/configured model references. */
async function appendConfiguredRows(params) {
const resolveModelWithRegistry = params.modelRegistry ? (await modelResolverModuleLoader.load()).resolveModelWithRegistry : void 0;
const catalogByKey = params.catalogSnapshot ? indexModelCatalogEntriesByKey(params.catalogSnapshot) : void 0;
const routeIndex = params.catalogSnapshot ? createModelCatalogLogicalRouteIndex(params.catalogSnapshot.routeVariants) : void 0;
for (const entry of params.entries) {
if (!matchesProviderFilter(params.context, entry.ref.provider)) continue;
const resolvedModel = params.modelRegistry && resolveModelWithRegistry ? resolveModelWithRegistry({
provider: entry.ref.provider,
modelId: entry.ref.model,
modelRegistry: params.modelRegistry,
cfg: params.context.cfg
}) : toFallbackConfiguredListModel(entry, params.context.cfg, catalogByKey?.get(entry.key));
if (!resolvedModel) {
if (!params.context.filter.local) params.rows.push(toModelRow({
key: entry.key,
tags: Array.from(entry.tags),
aliases: entry.aliases,
availableKeys: params.context.availableKeys,
authAvailability: void 0
}));
continue;
}
await appendVisibleRow({
rows: params.rows,
model: resolvedModel,
key: entry.key,
context: params.context,
...routeIndex ? { routeIndex } : {},
configuredEntry: entry,
normalizeWithProviderPlugin: true,
allowAuthAvailabilityOverride: !params.context.discoveredKeys.has(modelKey(resolvedModel.provider, resolvedModel.id))
});
}
}
//#endregion
//#region src/commands/models/list.row-sources.ts
/** Appends all rows requested by `models list --all` or a provider-filtered list. */
async function appendAllModelRowSources(params) {
const seenKeys = await appendDiscoveredRows({
rows: params.rows,
models: params.registryModels ?? params.modelRegistry?.getAll() ?? [],
modelRegistry: params.modelRegistry,
context: params.context,
resolveWithRegistry: Boolean(params.context.filter.provider),
skipSuppression: Boolean(params.modelRegistry)
});
await appendPreparedModelCatalogRows({
rows: params.rows,
context: params.context,
seenKeys
});
await appendConfiguredProviderRows({
rows: params.rows,
context: params.context,
seenKeys
});
if (params.context.filter.provider && params.entries && params.entries.length > 0) {
const missingEntries = params.entries.filter((entry) => !seenKeys.has(entry.key));
if (missingEntries.length > 0) {
const appendedRowsStart = params.rows.length;
await appendConfiguredRows({
rows: params.rows,
entries: missingEntries,
modelRegistry: params.modelRegistry,
context: params.context
});
for (const row of params.rows.slice(appendedRowsStart)) seenKeys.add(row.key);
}
}
}
/** Appends the configured/default rows used by the cheap default list path. */
async function appendConfiguredModelRowSources(params) {
if (params.context.cfg.models?.mode === "replace") {
await appendConfiguredProviderRows({
rows: params.rows,
context: params.context,
seenKeys: /* @__PURE__ */ new Set()
});
return;
}
const catalogSnapshot = await loadListModelCatalogSnapshot(params.context);
await appendConfiguredRows({
...params,
catalogSnapshot
});
const seenKeys = new Set(params.rows.map((row) => row.key));
await appendConfiguredProviderRows({
rows: params.rows,
context: params.context,
seenKeys
});
await appendAuthenticatedCatalogRows({
rows: params.rows,
context: params.context,
seenKeys,
catalogSnapshot
});
}
//#endregion
export { appendAllModelRowSources, appendConfiguredModelRowSources };