fix(opencode-plugin): stop warning when an auto combo replaces its expected /v1/models twin (#8983) (#9042)

* test(opencode): cover expected auto-combo twin

* fix(opencode): suppress expected auto-combo twin warning

---------

Co-authored-by: 千乘妍 (Xiaoyaner) <xiaoyaner0201@users.noreply.github.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
This commit is contained in:
小妍儿 ✨
2026-08-13 18:54:33 +08:00
committed by GitHub
parent 4ff9f0df0a
commit 62fd7f7c20
2 changed files with 43 additions and 5 deletions

View File

@@ -4256,6 +4256,7 @@ export function buildStaticProviderEntry(
rawAutoCombos?: OmniRouteRawAutoCombo[]
): OmniRouteStaticProviderEntry {
const models: Record<string, OmniRouteStaticModelEntry> = {};
const rawModelKeys = new Set<string>();
// 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 (`<providerId>/<raw-id>`) 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/<slug>`), 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);
}
}

View File

@@ -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)
// ────────────────────────────────────────────────────────────────────────────