Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions open-sse/config/providers/registry/opencode/go/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,18 @@ export const opencode_goProvider: RegistryEntry = {
supportsVision: false,
supportsReasoning: true,
},
// #14181: OpenCode Go now serves a GA `qwen3.8-max` alongside the preview.
// Without this row the provider-aware exemption in resolveModelAlias could not
// see it, and the stale built-in rewrite to `qwen3.8-max-preview` (which the
// upstream rejects with a 401) fired before dispatch. Base id only — no
// effort-tier variants are advertised upstream yet.
{
id: "qwen3.8-max",
name: "Qwen3.8 Max",
targetFormat: "claude",
supportsVision: false,
supportsReasoning: true,
},
// qwen3.6-plus / qwen3.5-plus base ids declared identically on opencode-zen — see
// OPENCODE_ZEN_GO_SHARED_MODELS.
{
Expand Down
11 changes: 6 additions & 5 deletions open-sse/services/modelDeprecation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,12 @@ const BUILT_IN_ALIASES: Record<string, string> = {
"fireworks/accounts/fireworks/models/kimi-k2": "moonshotai/Kimi-K2",
"kimi-k2": "moonshotai/Kimi-K2",

// Qwen — the model ships only under the `-preview` id (bailian-coding-plan, qoder,
// qwen-cloud-token-plan). Without this, the bare id missed MODEL_SPECS and
// the context preflight fell back to contextManager's `default: 128000`, rejecting
// prompts the model's real 1M window accepts. Drop this line if Alibaba ever ships a
// distinct GA `qwen3.8-max` — it would no longer be the same model.
// Qwen — preview-only providers (bailian-coding-plan, qoder, qwen-cloud-token-plan)
// still serve the model solely under the `-preview` id; without this rewrite the
// bare id missed MODEL_SPECS there and the context preflight fell back to
// contextManager's `default: 128000`. Providers that list the GA id as-is
// (alibaba, qwen-cloud, kilocode, clinepass, xkiro, opencode-go — #14181) are
// exempted by the provider-aware check in resolveModelAlias.
"qwen3.8-max": "qwen3.8-max-preview",

// Mistral short aliases
Expand Down
12 changes: 11 additions & 1 deletion src/shared/constants/modelSpecs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -576,14 +576,24 @@ export const MODEL_SPECS: Record<string, ModelSpec> = {
supportsVision: true,
aliases: ["qwen3.7-max", "qwen3-max-2026-01-23"],
},
// #14181: the GA `qwen3.8-max` is a distinct model served by opencode-go (and
// listed bare by alibaba/qwen-cloud/kilocode/clinepass/xkiro) — it gets its own
// spec row instead of aliasing to the preview, which remains a separate model.
"qwen3.8-max": {
maxOutputTokens: 65536,
contextWindow: 1000000,
thinkingBudgetCap: 38912,
supportsThinking: true,
supportsTools: true,
supportsVision: true,
},
"qwen3.8-max-preview": {
maxOutputTokens: 65536,
contextWindow: 1000000,
thinkingBudgetCap: 38912,
supportsThinking: true,
supportsTools: true,
supportsVision: true,
aliases: ["qwen3.8-max"],
},
"qwen3.6-plus": {
maxOutputTokens: 65536,
Expand Down
58 changes: 58 additions & 0 deletions tests/unit/14181-opencode-go-qwen-ga-alias.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import assert from "node:assert/strict";
import { test } from "node:test";
import { resolveModelAlias } from "../../open-sse/services/modelDeprecation.ts";
import { opencode_goProvider } from "../../open-sse/config/providers/registry/opencode/go/index.ts";
import {
findModelSpecIdByExactOrAlias,
getModelSpec,
} from "../../src/shared/constants/modelSpecs.ts";

/**
* #14181 — OpenCode Go now serves a GA `qwen3.8-max`, but OmniRoute's built-in
* deprecation table (`qwen3.8-max` → `qwen3.8-max-preview`, written when the model
* shipped only under the `-preview` id) rewrote the id before dispatch, and the
* upstream rejects the preview id with `401 Model qwen3.8-max-preview is not
* supported`.
*
* The rewrite is skipped only when `hasKnownProviderModel(provider, id)` finds the
* id in the provider's static registry — and the opencode-go registry never
* declared `qwen3.8-max`, so the exemption never fired for it (alibaba/qwen-cloud/
* kilocode/clinepass/xkiro already declare the bare GA id and were unaffected).
*
* Fix: declare the GA id in the opencode-go registry (qwen family on opencode-go
* is text-only and routes through the Claude translator per #2292), and give the
* GA model its own MODEL_SPECS entry instead of aliasing it to the preview spec.
*/
test("opencode-go registry declares the GA qwen3.8-max id (#14181)", () => {
const entry = (opencode_goProvider.models || []).find((m) => m.id === "qwen3.8-max");
assert.ok(
entry,
"opencode-go registry must list qwen3.8-max so the provider-aware alias exemption fires"
);
assert.equal(
entry.targetFormat,
"claude",
"qwen models on opencode-go reject oa-compat (#2292) — the GA id must route through the Claude translator like its qwen3.7-max sibling"
);
assert.equal(entry.supportsVision, false, "text-only on opencode-go (#2822)");
});

test("resolveModelAlias leaves qwen3.8-max untouched for opencode-go (#14181)", () => {
assert.equal(resolveModelAlias("qwen3.8-max", "opencode-go"), "qwen3.8-max");
});

test("resolveModelAlias still rewrites qwen3.8-max for preview-only providers (#14181)", () => {
// qoder / bailian-coding-plan serve only the -preview id: the built-in rewrite
// remains the correct behaviour there (and for callers with no provider in hand).
assert.equal(resolveModelAlias("qwen3.8-max", "qoder"), "qwen3.8-max-preview");
assert.equal(resolveModelAlias("qwen3.8-max"), "qwen3.8-max-preview");
});

test("GA qwen3.8-max resolves to its own MODEL_SPECS entry, not the preview alias (#14181)", () => {
assert.equal(findModelSpecIdByExactOrAlias("qwen3.8-max"), "qwen3.8-max");
const ga = getModelSpec("qwen3.8-max");
const preview = getModelSpec("qwen3.8-max-preview");
assert.ok(ga && preview, "both GA and preview specs must exist");
assert.equal(ga.contextWindow, preview.contextWindow);
assert.equal(ga.maxOutputTokens, preview.maxOutputTokens);
});
Loading