fix(look-at): preserve hardcoded multimodal variants

This commit is contained in:
YeonGyu-Kim
2026-03-11 18:02:41 +09:00
parent 3cbff71bd9
commit 605de6ada4
2 changed files with 76 additions and 6 deletions
@@ -0,0 +1,38 @@
describe("buildMultimodalLookerFallbackChain", () => {
it("preserves hardcoded variant metadata when dynamic and hardcoded entries share the same model", async () => {
// given
const { buildMultimodalLookerFallbackChain } = await import("./multimodal-fallback-chain")
const visionCapableModels = [
{ providerID: "openai", modelID: "gpt-5.4" },
{ providerID: "opencode", modelID: "gpt-5.4" },
]
// when
const result = buildMultimodalLookerFallbackChain(visionCapableModels)
const matchingEntries = result.filter((entry) => entry.model === "gpt-5.4")
// then
expect(matchingEntries).toHaveLength(1)
expect(matchingEntries[0]).toEqual({
providers: ["openai", "opencode"],
model: "gpt-5.4",
variant: "medium",
})
})
it("merges missing hardcoded providers into an existing dynamic entry", async () => {
// given
const { buildMultimodalLookerFallbackChain } = await import("./multimodal-fallback-chain")
const visionCapableModels = [{ providerID: "openai", modelID: "gpt-5.4" }]
// when
const result = buildMultimodalLookerFallbackChain(visionCapableModels)
// then
expect(result[0]).toEqual({
providers: ["openai", "opencode"],
model: "gpt-5.4",
variant: "medium",
})
})
})
+38 -6
View File
@@ -19,14 +19,14 @@ export function isHardcodedMultimodalFallbackModel(model: VisionCapableModel): b
export function buildMultimodalLookerFallbackChain(
visionCapableModels: VisionCapableModel[],
): FallbackEntry[] {
const seen = new Set<string>()
const entryIndexByKey = new Map<string, number>()
const fallbackChain: FallbackEntry[] = []
for (const visionCapableModel of visionCapableModels) {
const key = getFullModelKey(visionCapableModel.providerID, visionCapableModel.modelID)
if (seen.has(key)) continue
if (entryIndexByKey.has(key)) continue
seen.add(key)
entryIndexByKey.set(key, fallbackChain.length)
fallbackChain.push({
providers: [visionCapableModel.providerID],
model: visionCapableModel.modelID,
@@ -37,13 +37,45 @@ export function buildMultimodalLookerFallbackChain(
const providerModelKeys = entry.providers.map((providerID) =>
getFullModelKey(providerID, entry.model),
)
if (providerModelKeys.every((key) => seen.has(key))) {
const existingIndexes = [...new Set(
providerModelKeys
.map((key) => entryIndexByKey.get(key))
.filter((index): index is number => index !== undefined),
)]
if (existingIndexes.length > 0) {
const [targetIndex, ...duplicateIndexes] = existingIndexes
const targetEntry = fallbackChain[targetIndex]
const mergedProviders = new Set(targetEntry.providers)
for (const providerID of entry.providers) {
mergedProviders.add(providerID)
}
for (const duplicateIndex of duplicateIndexes) {
const duplicateEntry = fallbackChain[duplicateIndex]
for (const providerID of duplicateEntry.providers) {
mergedProviders.add(providerID)
}
duplicateEntry.providers = []
}
targetEntry.providers = [...mergedProviders]
targetEntry.variant ??= entry.variant
for (const providerID of targetEntry.providers) {
entryIndexByKey.set(getFullModelKey(providerID, targetEntry.model), targetIndex)
}
continue
}
providerModelKeys.forEach((key) => seen.add(key))
providerModelKeys.forEach((key) => {
entryIndexByKey.set(key, fallbackChain.length)
})
fallbackChain.push(entry)
}
return fallbackChain
return fallbackChain.filter((entry) => entry.providers.length > 0)
}