From 62fd7f7c2066e100269b49db70d5094cbd883ede Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E5=A6=8D=E5=84=BF=20=E2=9C=A8?= Date: Thu, 13 Aug 2026 18:54:33 +0800 Subject: [PATCH] fix(opencode-plugin): stop warning when an auto combo replaces its expected /v1/models twin (#8983) (#9042) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * test(opencode): cover expected auto-combo twin * fix(opencode): suppress expected auto-combo twin warning --------- Co-authored-by: 千乘妍 (Xiaoyaner) Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> --- @omniroute/opencode-plugin/src/index.ts | 17 +++++++--- .../opencode-plugin/tests/config-shim.test.ts | 31 +++++++++++++++++++ 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/@omniroute/opencode-plugin/src/index.ts b/@omniroute/opencode-plugin/src/index.ts index 747c57beeb..ef07b3c112 100644 --- a/@omniroute/opencode-plugin/src/index.ts +++ b/@omniroute/opencode-plugin/src/index.ts @@ -4256,6 +4256,7 @@ export function buildStaticProviderEntry( rawAutoCombos?: OmniRouteRawAutoCombo[] ): OmniRouteStaticProviderEntry { const models: Record = {}; + const rawModelKeys = new Set(); // usableOnly filter — compute once when feature enabled AND we have // connection data to filter against. Soft-fail (empty connections list) @@ -4412,7 +4413,9 @@ export function buildStaticProviderEntry( // provider prefix (`/`) is unreachable. Keys are the // raw id verbatim; ids that already contain `/` (e.g. `cc/claude-opus-4-7`) // keep it because the slash is part of the upstream model id itself. - models[raw.id] = entry; + const key = raw.id; + models[key] = entry; + rawModelKeys.add(key); } // Combo entries → stripped LCD shape. Each combo is keyed as @@ -4609,8 +4612,9 @@ export function buildStaticProviderEntry( // (`opencode-omniroute/opencode-omniroute/`), and `parseModel()` // resolves credentials for the nonexistent provider `opencode-omniroute` // instead of `omniroute`. See #7976. - models[buildComboKey(combo, usedComboKeys, opts.omnirouteProviderId).split("/").pop()!] = - entry; + const key = buildComboKey(combo, usedComboKeys, opts.omnirouteProviderId).split("/").pop()!; + models[key] = entry; + rawModelKeys.delete(key); // Make this combo's resolved entry available to parent combos // that reference it via combo-ref. Use the friendly name since @@ -4645,8 +4649,10 @@ export function buildStaticProviderEntry( // Use the variant as the key: "auto", "auto/coding", etc. const key = autoComboModelId(autoCombo.variant); if (models[key]) { - // Collision with a raw model or DB combo — auto combo wins (log once) - if (!reportedCollisions.has(key)) { + // `/v1/models` mirrors auto combos under the same stable id. Replacing + // that expected raw twin is silent; every other collision still warns. + const isExpectedRawTwin = autoCombo.id === key && rawModelKeys.has(key); + if (!isExpectedRawTwin && !reportedCollisions.has(key)) { reportedCollisions.add(key); console.warn( `[omniroute-plugin] auto combo key "${key}" collides with an existing model; auto combo wins.` @@ -4654,6 +4660,7 @@ export function buildStaticProviderEntry( } } models[key] = entry; + rawModelKeys.delete(key); } } diff --git a/@omniroute/opencode-plugin/tests/config-shim.test.ts b/@omniroute/opencode-plugin/tests/config-shim.test.ts index f439656416..7072341398 100644 --- a/@omniroute/opencode-plugin/tests/config-shim.test.ts +++ b/@omniroute/opencode-plugin/tests/config-shim.test.ts @@ -763,6 +763,37 @@ test("buildStaticProviderEntry: hidden combos are excluded", () => { assert.ok(block.models["claude-sonnet-4-6"]); }); +test("buildStaticProviderEntry: expected raw auto twin does not warn and auto combo wins", () => { + const resolved = resolveOmniRoutePluginOptions({ providerId: "omniroute" }); + const warnings: string[] = []; + const originalWarn = console.warn; + console.warn = (...args: unknown[]) => warnings.push(args.map(String).join(" ")); + + let block: OmniRouteStaticProviderEntry; + try { + block = buildStaticProviderEntry( + [{ id: "auto/coding" }], + [], + resolved, + "https://or.example/v1", + "sk-test", + undefined, + undefined, + undefined, + [{ id: "auto/coding", name: "Auto Coding", variant: "coding", candidateCount: 5 }] + ); + } finally { + console.warn = originalWarn; + } + + assert.equal(Object.keys(block.models).filter((key) => key === "auto/coding").length, 1); + assert.equal(block.models["auto/coding"].tool_call, true, "auto-combo entry wins over raw twin"); + assert.deepEqual( + warnings.filter((warning) => warning.includes("collides with an existing model")), + [] + ); +}); + // ──────────────────────────────────────────────────────────────────────────── // Schema parity (modalities / cost / release_date / limit cleanup) // ────────────────────────────────────────────────────────────────────────────