fix(providers): refresh OpenCode (oc) free-tier model catalog (#6998) (#7188)

The oc registry entry (opencode.ai/zen/v1) hardcoded 6 free-tier model
IDs (minimax-m3-free, minimax-m2.5-free, ling-2.6-1t-free,
trinity-large-preview-free, nemotron-3-super-free, qwen3.6-plus-free)
that were delisted upstream and now return 401 "Model X is not
supported". Live upstream instead offers 4 different free models
(mimo-v2.5-free, hy3-free, nemotron-3-ultra-free, north-mini-code-free)
that were never added to our static catalog.

Swap the 6 delisted IDs for the 4 currently-live ones, confirmed
against https://opencode.ai/zen/v1/chat/completions on 2026-07-14.

Updates two existing tests (minimax-m3-model-registry,
provider-registry-qwen-vision) that asserted the now-delisted
minimax-m3-free was present in the oc catalog — they now assert its
absence, matching the corrected contract.
This commit is contained in:
Diego Rodrigues de Sa e Souza
2026-07-14 21:21:44 -03:00
committed by GitHub
parent de2b464c3f
commit 39293bda5b
5 changed files with 63 additions and 37 deletions

View File

@@ -0,0 +1 @@
- fix(providers): refresh OpenCode (`oc`) free-tier model catalog — 6 delisted IDs replaced with the 4 currently-live free models (#6998)

View File

@@ -23,29 +23,15 @@ export const opencodeProvider: RegistryEntry = {
interleavedField: "reasoning_content",
},
{ id: "deepseek-v4-flash-free", name: "DeepSeek V4 Flash Free", supportsReasoning: true },
// #3110: MiniMax M3 free tier via OpenCode
// #3328: MiniMax M3 is multimodal (verified: describes base64 images via the
// opencode upstream) — flag it so vision requests aren't gated/stripped.
{
id: "minimax-m3-free",
name: "MiniMax M3 Free",
contextLength: 1048576,
supportsVision: true,
},
{ id: "minimax-m2.5-free", name: "MiniMax M2.5 Free", contextLength: 204800 },
{ id: "ling-2.6-1t-free", name: "Ling 2.6 Free", contextLength: 262000 },
{
id: "trinity-large-preview-free",
name: "Trinity Large Preview Free",
contextLength: 131000,
},
{ id: "nemotron-3-super-free", name: "Nemotron 3 Super Free", contextLength: 1000000 },
{
id: "qwen3.6-plus-free",
name: "Qwen3.6 Plus Free",
targetFormat: "claude",
supportsVision: false,
contextLength: 200000,
},
// #6998: 2026-07-14 refresh — the upstream free tier rotated its lineup;
// minimax-m3-free, minimax-m2.5-free, ling-2.6-1t-free,
// trinity-large-preview-free, nemotron-3-super-free and qwen3.6-plus-free
// were delisted (401 "Model X is not supported") and replaced by the 4
// entries below, confirmed live against
// https://opencode.ai/zen/v1/chat/completions.
{ id: "mimo-v2.5-free", name: "MiMo V2.5 Free", contextLength: 131000 },
{ id: "hy3-free", name: "HY3 Free", contextLength: 131000 },
{ id: "nemotron-3-ultra-free", name: "Nemotron 3 Ultra Free", contextLength: 1000000 },
{ id: "north-mini-code-free", name: "North Mini Code Free", contextLength: 131000 },
],
};

View File

@@ -29,13 +29,11 @@ describe("MiniMax M3 model registration (#3110)", () => {
assert.equal(m3.contextLength, 1_048_576);
});
it("opencode provider has minimax-m3-free with 1M context", () => {
it("opencode provider does NOT list minimax-m3-free (#6998 — delisted upstream, 401)", () => {
const entry = REGISTRY.opencode;
assert.ok(entry, "opencode registry entry must exist");
const m3 = entry.models.find((m) => m.id === "minimax-m3-free");
assert.ok(m3, "minimax-m3-free must be in opencode models");
assert.equal(m3.name, "MiniMax M3 Free");
assert.equal(m3.contextLength, 1_048_576);
assert.equal(m3, undefined, "minimax-m3-free was delisted from OpenCode Zen's free tier (#6998)");
});
it("opencode-go provider has minimax-m3 with Claude targetFormat", () => {

View File

@@ -0,0 +1,40 @@
import test from "node:test";
import assert from "node:assert/strict";
const { opencodeProvider } = await import(
"../../open-sse/config/providers/registry/opencode/index.ts"
);
function modelIds(): string[] {
return (opencodeProvider.models ?? []).map((m) => m.id);
}
const DELISTED_FREE_MODELS = [
"minimax-m3-free",
"minimax-m2.5-free",
"ling-2.6-1t-free",
"trinity-large-preview-free",
"nemotron-3-super-free",
"qwen3.6-plus-free",
];
const LIVE_FREE_MODELS_MISSING_FROM_CATALOG = [
"mimo-v2.5-free",
"hy3-free",
"nemotron-3-ultra-free",
"north-mini-code-free",
];
test("issue #6998: oc registry does not advertise delisted free-tier models", () => {
const ids = modelIds();
for (const delisted of DELISTED_FREE_MODELS) {
assert.ok(!ids.includes(delisted), `oc registry still advertises delisted upstream model "${delisted}"`);
}
});
test("issue #6998: oc registry advertises the current live free-tier models", () => {
const ids = modelIds();
for (const live of LIVE_FREE_MODELS_MISSING_FROM_CATALOG) {
assert.ok(ids.includes(live), `oc registry is missing live upstream free-tier model "${live}"`);
}
});

View File

@@ -63,16 +63,17 @@ test("#2822 opencode-go/qwen3.6-plus deve ter supportsVision !== true", () => {
);
});
// #3328 — o oposto do #2822: MiniMax M3 (opencode) É multimodal (verificado
// empiricamente: descreve imagens base64 via o upstream opencode). Deve ter
// supportsVision: true para não ser barrado/strippado em requests com imagem.
test("#3328 opencode/minimax-m3-free deve ter supportsVision: true", () => {
// #3328 — o oposto do #2822: MiniMax M3 (opencode) era multimodal (verificado
// empiricamente: descrevia imagens base64 via o upstream opencode). #6998:
// minimax-m3-free foi deslistado do free tier da OpenCode Zen (401 "not
// supported") em 2026-07-14 e removido do catálogo estático — este teste
// agora confirma a remoção.
test("#6998 opencode/minimax-m3-free não deve mais estar registrado (deslistado upstream)", () => {
const model = getModel("opencode", "minimax-m3-free");
assert.ok(model, "minimax-m3-free deve estar registrado em opencode");
assert.strictEqual(
model.supportsVision,
true,
"opencode/minimax-m3-free é multimodal — supportsVision deve ser true"
assert.equal(
model,
undefined,
"opencode/minimax-m3-free foi deslistado do free tier da OpenCode Zen (#6998)"
);
});