diff --git a/src/plugin-sdk/provider-catalog-shared.test.ts b/src/plugin-sdk/provider-catalog-shared.test.ts index bcb29e8d9d0..1a39fcfc56a 100644 --- a/src/plugin-sdk/provider-catalog-shared.test.ts +++ b/src/plugin-sdk/provider-catalog-shared.test.ts @@ -217,4 +217,27 @@ describe("provider-catalog-shared manifest provider configs", () => { }), ).toThrow("unsupported runtime input document"); }); + + it("rejects manifest catalogs when normalization drops a model row", () => { + expect(() => + buildManifestModelProviderConfig({ + providerId: "example", + catalog: { + baseUrl: "https://api.example.test/v1", + models: [ + { + id: "valid", + contextWindow: 1024, + maxTokens: 1024, + }, + { + id: "", + contextWindow: 1024, + maxTokens: 1024, + }, + ], + }, + }), + ).toThrow("providers.example.models"); + }); }); diff --git a/src/plugin-sdk/provider-catalog-shared.ts b/src/plugin-sdk/provider-catalog-shared.ts index 97e6b0a6e0d..850178720e6 100644 --- a/src/plugin-sdk/provider-catalog-shared.ts +++ b/src/plugin-sdk/provider-catalog-shared.ts @@ -32,6 +32,14 @@ export type ConfiguredProviderCatalogEntry = { input?: Array<"text" | "image" | "audio" | "video" | "document">; }; +function countRawManifestCatalogModels(catalog: unknown): number | undefined { + if (!catalog || typeof catalog !== "object") { + return undefined; + } + const models = (catalog as { models?: unknown }).models; + return Array.isArray(models) ? models.length : undefined; +} + function cloneManifestCatalogTieredCost( tier: ModelCatalogTieredCost, ): NonNullable[number] { @@ -102,6 +110,10 @@ export function buildManifestModelProviderConfig(params: { if (!catalog.baseUrl) { throw new Error(`Missing modelCatalog.providers.${params.providerId}.baseUrl`); } + const rawModelCount = countRawManifestCatalogModels(params.catalog); + if (rawModelCount !== undefined && rawModelCount !== catalog.models.length) { + throw new Error(`Invalid modelCatalog.providers.${params.providerId}.models`); + } return { baseUrl: catalog.baseUrl, ...(catalog.api ? { api: catalog.api } : {}),