fix(models): guard manifest model id metadata

This commit is contained in:
Vincent Koc
2026-06-03 19:05:45 +02:00
parent 286e5ffe07
commit 01499da3cf
2 changed files with 59 additions and 1 deletions
@@ -6,6 +6,24 @@ import {
stripSelfProviderModelPrefix,
} from "./provider-model-id-normalization.js";
function poisonedModelIdNormalizationRecord() {
return Object.defineProperty({}, "modelIdNormalization", {
get() {
throw new Error("model id normalization metadata exploded");
},
});
}
function poisonedModelIdNormalizationProvidersRecord() {
return {
modelIdNormalization: Object.defineProperty({}, "providers", {
get() {
throw new Error("model id normalization providers exploded");
},
}),
};
}
describe("provider model id policy normalization", () => {
it("applies manifest policies before built-in provider normalization", () => {
const policies = collectManifestModelIdNormalizationPolicies([
@@ -27,6 +45,40 @@ describe("provider model id policy normalization", () => {
);
});
it("skips unreadable manifest model id normalization records", () => {
const policies = collectManifestModelIdNormalizationPolicies([
{
modelIdNormalization: {
providers: {
custom: {
prefixWhenBare: "vendor",
},
},
},
},
poisonedModelIdNormalizationRecord(),
poisonedModelIdNormalizationProvidersRecord(),
{
modelIdNormalization: {
providers: {
"Google-Vertex": {
aliases: {
pro: "gemini-3-pro",
},
},
},
},
},
]);
expect(normalizeStaticProviderModelIdWithPolicies("custom", "latest", policies)).toBe(
"vendor/latest",
);
expect(normalizeStaticProviderModelIdWithPolicies("google-vertex", "pro", policies)).toBe(
"gemini-3.1-pro-preview",
);
});
it("normalizes provider-prefixed Google catalog refs behind gateway prefixes", () => {
expect(
normalizeConfiguredProviderCatalogModelId(
@@ -29,7 +29,13 @@ export function collectManifestModelIdNormalizationPolicies(
): Map<string, ManifestModelIdNormalizationProvider> {
const policies = new Map<string, ManifestModelIdNormalizationProvider>();
for (const plugin of plugins) {
for (const [provider, policy] of Object.entries(plugin.modelIdNormalization?.providers ?? {})) {
let providers: Record<string, ManifestModelIdNormalizationProvider> | undefined;
try {
providers = plugin.modelIdNormalization?.providers;
} catch {
continue;
}
for (const [provider, policy] of Object.entries(providers ?? {})) {
policies.set(normalizeLowercaseStringOrEmpty(provider), policy);
}
}