perf: generalize provider-filtered catalog fast path

This commit is contained in:
Shakker
2026-04-24 04:19:04 +01:00
committed by Shakker
parent 959dedb7cf
commit a50aef82ba
4 changed files with 64 additions and 12 deletions

View File

@@ -4,6 +4,7 @@ import type { RuntimeEnv } from "../../runtime.js";
import { normalizeLowercaseStringOrEmpty } from "../../shared/string-coerce.js";
import { resolveConfiguredEntries } from "./list.configured.js";
import { formatErrorWithStack } from "./list.errors.js";
import { hasProviderStaticCatalogForFilter } from "./list.provider-catalog.js";
import { loadConfiguredListModelRegistry, loadListModelRegistry } from "./list.registry-load.js";
import {
appendAllModelRowSources,
@@ -58,11 +59,15 @@ export async function modelsListCommand(
let discoveredKeys = new Set<string>();
let availableKeys: Set<string> | undefined;
let availabilityErrorMessage: string | undefined;
const useProviderCatalogFastPath = Boolean(opts.all && providerFilter === "codex");
const { entries } = resolveConfiguredEntries(cfg);
const configuredByKey = new Map(entries.map((entry) => [entry.key, entry]));
const useProviderCatalogFastPath =
opts.all && providerFilter
? await hasProviderStaticCatalogForFilter({ cfg, providerFilter })
: false;
const shouldLoadRegistry = modelRowSourcesRequireRegistry({
all: opts.all,
providerFilter,
useProviderCatalogFastPath,
});
try {

View File

@@ -4,6 +4,7 @@ import type { ModelProviderConfig } from "../../config/types.models.js";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import { formatErrorMessage } from "../../infra/errors.js";
import { createSubsystemLogger } from "../../logging/subsystem.js";
import { loadPluginManifestRegistry } from "../../plugins/manifest-registry.js";
import {
groupPluginDiscoveryProvidersByOrder,
normalizePluginDiscoveryResult,
@@ -45,6 +46,21 @@ export async function resolveProviderCatalogPluginIdsForFilter(params: {
return undefined;
}
export async function hasProviderStaticCatalogForFilter(params: {
cfg: OpenClawConfig;
env?: NodeJS.ProcessEnv;
providerFilter: string;
}): Promise<boolean> {
const pluginIds = await resolveProviderCatalogPluginIdsForFilter(params);
if (!pluginIds || pluginIds.length === 0) {
return false;
}
const pluginIdSet = new Set(pluginIds);
return loadPluginManifestRegistry({ config: params.cfg, env: params.env }).plugins.some(
(plugin) => pluginIdSet.has(plugin.id) && typeof plugin.providerDiscoverySource === "string",
);
}
function modelFromProviderCatalog(params: {
provider: string;
providerConfig: ModelProviderConfig;
@@ -72,6 +88,7 @@ export async function loadProviderCatalogModelsForList(params: {
agentDir: string;
env?: NodeJS.ProcessEnv;
providerFilter?: string;
staticOnly?: boolean;
}): Promise<Model<Api>[]> {
const env = params.env ?? process.env;
const providerFilter = params.providerFilter ? normalizeProviderId(params.providerFilter) : "";
@@ -104,7 +121,7 @@ export async function loadProviderCatalogModelsForList(params: {
env,
onlyPluginIds: scopedPluginIds,
includeUntrustedWorkspacePlugins: false,
requireCompleteDiscoveryEntryCoverage: true,
requireCompleteDiscoveryEntryCoverage: params.staticOnly === true,
})
).filter(
(provider) =>

View File

@@ -18,15 +18,42 @@ type AllModelRowSources = {
export function modelRowSourcesRequireRegistry(params: {
all?: boolean;
providerFilter?: string;
useProviderCatalogFastPath: boolean;
}): boolean {
if (!params.all) {
return false;
}
return !params.useProviderCatalogFastPath;
if (params.providerFilter && params.useProviderCatalogFastPath) {
return false;
}
return true;
}
export async function appendAllModelRowSources(params: AllModelRowSources): Promise<void> {
if (params.context.filter.provider && params.useProviderCatalogFastPath) {
let seenKeys = new Set<string>();
const catalogRows = await appendProviderCatalogRows({
rows: params.rows,
context: params.context,
seenKeys,
staticOnly: true,
});
if (catalogRows === 0) {
seenKeys = appendDiscoveredRows({
rows: params.rows,
models: params.modelRegistry?.getAll() ?? [],
context: params.context,
});
}
appendConfiguredProviderRows({
rows: params.rows,
context: params.context,
seenKeys,
});
return;
}
const seenKeys = appendDiscoveredRows({
rows: params.rows,
models: params.modelRegistry?.getAll() ?? [],
@@ -39,7 +66,7 @@ export async function appendAllModelRowSources(params: AllModelRowSources): Prom
seenKeys,
});
if (params.modelRegistry) {
if (params.modelRegistry && !params.context.filter.provider) {
await appendCatalogSupplementRows({
rows: params.rows,
modelRegistry: params.modelRegistry,
@@ -49,13 +76,11 @@ export async function appendAllModelRowSources(params: AllModelRowSources): Prom
return;
}
if (params.useProviderCatalogFastPath) {
await appendProviderCatalogRows({
rows: params.rows,
context: params.context,
seenKeys,
});
}
await appendProviderCatalogRows({
rows: params.rows,
context: params.context,
seenKeys,
});
}
export function appendConfiguredModelRowSources(params: {

View File

@@ -245,11 +245,14 @@ export async function appendProviderCatalogRows(params: {
rows: ModelRow[];
context: RowBuilderContext;
seenKeys: Set<string>;
}): Promise<void> {
staticOnly?: boolean;
}): Promise<number> {
let appended = 0;
for (const model of await loadProviderCatalogModelsForList({
cfg: params.context.cfg,
agentDir: params.context.agentDir,
providerFilter: params.context.filter.provider,
staticOnly: params.staticOnly,
})) {
if (!matchesRowFilter(params.context.filter, model)) {
continue;
@@ -270,7 +273,9 @@ export async function appendProviderCatalogRows(params: {
}),
);
params.seenKeys.add(key);
appended += 1;
}
return appended;
}
export function appendConfiguredRows(params: {