fix: skip broad provider runtime catalog listing

This commit is contained in:
Shakker
2026-04-27 17:46:44 +01:00
parent 9df9bbd243
commit f5439a341b
5 changed files with 98 additions and 3 deletions

View File

@@ -587,6 +587,49 @@ describe("modelsListCommand forward-compat", () => {
]);
});
it("does not load broad provider runtime catalogs for unfiltered all-model lists", async () => {
mocks.resolveConfiguredEntries.mockReturnValueOnce({ entries: [] });
mocks.loadModelRegistry.mockResolvedValueOnce({
models: [{ ...OPENAI_CODEX_MODEL }],
availableKeys: new Set(["openai-codex/gpt-5.4"]),
registry: {
getAll: () => [{ ...OPENAI_CODEX_MODEL }],
},
});
mocks.loadStaticManifestCatalogRowsForList.mockReturnValueOnce([
{
provider: "moonshot",
id: "kimi-k2.6",
ref: "moonshot/kimi-k2.6",
mergeKey: "moonshot::kimi-k2.6",
name: "Kimi K2.6",
source: "manifest",
input: ["text", "image"],
reasoning: false,
status: "available",
baseUrl: "https://api.moonshot.ai/v1",
contextWindow: 262_144,
},
]);
mocks.loadModelCatalog.mockResolvedValueOnce([]);
const runtime = createRuntime();
await modelsListCommand({ all: true, json: true }, runtime as never);
expect(mocks.loadModelRegistry).toHaveBeenCalledWith(mocks.resolvedConfig, {
providerFilter: undefined,
});
expect(mocks.loadProviderCatalogModelsForList).not.toHaveBeenCalled();
expect(lastPrintedRows<{ key: string }>()).toEqual([
expect.objectContaining({
key: "openai-codex/gpt-5.4",
}),
expect.objectContaining({
key: "moonshot/kimi-k2.6",
}),
]);
});
it("falls back to registry-backed rows when the fast-path catalog is empty", async () => {
mocks.resolveConfiguredEntries.mockReturnValueOnce({ entries: [] });
mocks.hasProviderStaticCatalogForFilter.mockResolvedValueOnce(true);

View File

@@ -89,6 +89,24 @@ export async function appendAllModelRowSources(
seenKeys,
});
if (params.sourcePlan.manifestCatalogRows.length > 0) {
await appendManifestCatalogRows({
rows: params.rows,
context: { ...params.context, skipRuntimeModelSuppression: true },
seenKeys,
manifestRows: params.sourcePlan.manifestCatalogRows,
});
}
if (params.sourcePlan.providerIndexCatalogRows.length > 0) {
await appendModelCatalogRows({
rows: params.rows,
context: { ...params.context, skipRuntimeModelSuppression: true },
seenKeys,
catalogRows: params.sourcePlan.providerIndexCatalogRows,
});
}
if (params.modelRegistry) {
await appendCatalogSupplementRows({
rows: params.rows,

View File

@@ -412,7 +412,7 @@ export async function appendCatalogSupplementRows(params: {
});
}
if (params.context.filter.local) {
if (params.context.filter.local || !params.context.filter.provider) {
return;
}

View File

@@ -95,6 +95,27 @@ describe("planAllModelListSources", () => {
});
});
it("keeps broad all-model lists on the registry path with cheap catalog supplements", async () => {
const { planAllModelListSources } = await import("./list.source-plan.js");
const providerIndexRow = { ...catalogRow, source: "provider-index" };
mocks.loadStaticManifestCatalogRowsForList.mockReturnValueOnce([catalogRow]);
mocks.loadProviderIndexCatalogRowsForList.mockReturnValueOnce([providerIndexRow]);
const plan = await planAllModelListSources({
all: true,
cfg: {},
});
expect(plan).toMatchObject({
kind: "registry",
requiresInitialRegistry: true,
skipRuntimeModelSuppression: false,
});
expect(plan.manifestCatalogRows).toEqual([catalogRow]);
expect(plan.providerIndexCatalogRows).toEqual([providerIndexRow]);
expect(mocks.hasProviderStaticCatalogForFilter).not.toHaveBeenCalled();
});
it("falls back to registry only for provider static fast paths that return no rows", async () => {
const { planAllModelListSources } = await import("./list.source-plan.js");
mocks.hasProviderStaticCatalogForFilter.mockResolvedValueOnce(true);

View File

@@ -47,15 +47,28 @@ export async function planAllModelListSources(params: {
providerFilter?: string;
cfg: OpenClawConfig;
}): Promise<ModelListSourcePlan> {
if (!params.all || !params.providerFilter) {
if (!params.all) {
return createRegistryModelListSourcePlan();
}
const { loadStaticManifestCatalogRowsForList } = await import("./list.manifest-catalog.js");
const manifestCatalogRows = loadStaticManifestCatalogRowsForList({
cfg: params.cfg,
providerFilter: params.providerFilter,
...(params.providerFilter ? { providerFilter: params.providerFilter } : {}),
});
if (!params.providerFilter) {
const { loadProviderIndexCatalogRowsForList } =
await import("./list.provider-index-catalog.js");
return createSourcePlan({
kind: "registry",
manifestCatalogRows,
providerIndexCatalogRows: loadProviderIndexCatalogRowsForList({
cfg: params.cfg,
}),
requiresInitialRegistry: true,
});
}
if (manifestCatalogRows.length > 0) {
return createSourcePlan({
kind: "manifest",