fix(deepseek): align V4 reasoning efforts across DeepSeek and OpenCode Go (#10540)

* fix(deepseek): align V4 reasoning efforts

* docs(changelog): note DeepSeek effort fix

* fix(deepseek): align OpenCode V4 effort aliases

* test(deepseek): align effort alias expectation

* fix(deepseek): scope low effort to v4

* fix(opencode-go): route DeepSeek V4 through Responses
This commit is contained in:
Ke Jin
2026-08-18 21:51:52 +08:00
committed by GitHub
parent 276b3dffa3
commit f92075bb63
12 changed files with 267 additions and 189 deletions

View File

@@ -0,0 +1 @@
- **fix(deepseek):** Advertise `none`, `low`, `high`, and `max` for V4 Pro and Flash, derive OpenCode Go effort aliases from base-model metadata, and route those models through native Responses ([#10540](https://github.com/diegosouzapw/OmniRoute/pull/10540)) — thanks @jackjinke

View File

@@ -24,7 +24,7 @@ export const deepseekProvider: RegistryEntry = {
contextLength: 1_000_000,
maxOutputTokens: 384_000,
supportsReasoning: true,
supportedThinkingEfforts: ["none", "high", "max"],
supportedThinkingEfforts: ["none", "low", "high", "max"],
toolCalling: true,
},
{

View File

@@ -131,27 +131,19 @@ export const opencode_goProvider: RegistryEntry = {
{ id: "grok-4.5-low", name: "Grok 4.5 (low effort)", supportsReasoning: true },
{ id: "grok-4.5-medium", name: "Grok 4.5 (medium effort)", supportsReasoning: true },
{ id: "grok-4.5-high", name: "Grok 4.5 (high effort)", supportsReasoning: true },
{ id: "deepseek-v4-pro", name: "DeepSeek V4 Pro", supportsReasoning: true },
// OpencodeExecutor rewrites these aliases to the canonical upstream id and injects reasoning_effort.
{ id: "deepseek-v4-pro-low", name: "DeepSeek V4 Pro (low effort)", supportsReasoning: true },
{
id: "deepseek-v4-pro-medium",
name: "DeepSeek V4 Pro (medium effort)",
supportsReasoning: true,
},
{ id: "deepseek-v4-pro-high", name: "DeepSeek V4 Pro (high effort)", supportsReasoning: true },
{ id: "deepseek-v4-pro-max", name: "DeepSeek V4 Pro (max effort)", supportsReasoning: true },
{ id: "deepseek-v4-flash", name: "DeepSeek V4 Flash", supportsReasoning: true },
// #8353: DeepSeek V4 Flash effort tiers from the OpenCode Go registry.
{
id: "deepseek-v4-flash-high",
name: "DeepSeek V4 Flash (high effort)",
id: "deepseek-v4-pro",
name: "DeepSeek V4 Pro",
supportsReasoning: true,
supportedThinkingEfforts: ["none", "low", "high", "max"],
targetFormat: "openai-responses",
},
{
id: "deepseek-v4-flash-max",
name: "DeepSeek V4 Flash (max effort)",
id: "deepseek-v4-flash",
name: "DeepSeek V4 Flash",
supportsReasoning: true,
supportedThinkingEfforts: ["none", "low", "high", "max"],
targetFormat: "openai-responses",
},
],
};

View File

@@ -297,23 +297,17 @@ export function sanitizeReasoningEffortForProvider(
return writeEffortValue(b, "max", c);
}
// Native DeepSeek (api.deepseek.com) — V4 thinking mode uses the native
// {low, high, max} vocabulary on Flash and {high, max} on Pro. OmniRoute's
// internal top tier xhigh maps to DeepSeek's literal max. Pro's unsupported
// low/medium values still clamp to high; Flash's documented low tier passes
// through. This is the INVERSE of the OpenRouter-DeepSeek path, whose
// normalized API expects xhigh, not max (pi#4055). `none` is already the
// OpenAI no-thinking carrier and passes through unchanged.
// Native DeepSeek (api.deepseek.com) — V4 Pro and Flash use the native
// {low, high, max} vocabulary, while other model ids retain the {high, max}
// floor. OmniRoute's internal top tier xhigh maps to DeepSeek's literal max,
// while compatibility-only medium maps to high. `none` is already the OpenAI
// no-thinking carrier and passes through unchanged.
if (provider === "deepseek") {
// Match the Flash family even when the sanitizer sees a suffixed or prefixed
// id — exact-match would silently clamp Flash `low → high` if a future route
// forwards the raw catalog id (`deepseek-v4-flash-low`) before resolution
// (#9485 review).
const isFlash = modelStr.toLowerCase().startsWith("deepseek-v4-flash");
const isV4 = modelStr.toLowerCase().startsWith("deepseek-v4-");
const mapped =
effortStr === "xhigh"
? "max"
: effortStr === "medium" || (effortStr === "low" && !isFlash)
: effortStr === "medium" || (effortStr === "low" && !isV4)
? "high"
: null;
if (mapped && mapped !== effortStr) {

View File

@@ -31,7 +31,7 @@ interface OpencodeAccountState extends RotatableAccount {
fingerprint: string;
}
const EFFORT_LEVELS = ["low", "medium", "high", "max"] as const;
const EFFORT_LEVELS = ["none", "low", "high", "max"] as const;
/**
* Models that work WITHOUT any API key on the free/noauth opencode tier.
@@ -62,7 +62,7 @@ const OPENCODE_FREE_MODELS = new Set([
* Models on opencode-go that support effort-tier aliases. Each entry maps the
* canonical base id to the set of effort suffixes the upstream supports.
*
* - deepseek-v4-pro: all four tiers (low/medium/high/max)
* - DeepSeek V4 Pro and Flash: none/low/high/max
* - glm-5.2: high/max only (Z.AI maps these through the reasoning plane;
* low/medium are not supported on the OpenAI transport)
* - mimo-v2.5: high/max only (same reasoning; Xiaomi MiMo does not document
@@ -70,12 +70,12 @@ const OPENCODE_FREE_MODELS = new Set([
* - #8353 OpenCode Go registry effort variants (exact suffix sets from
* `opencode models opencode-go --verbose`; MiniMax M3 excluded — different
* thinking-mode mapping):
* deepseek-v4-flash high/max; grok-4.5 low/medium/high; hy3 none/low/high;
* kimi-k3 max; qwen3.6-plus / qwen3.7-max / qwen3.7-plus high/max
* grok-4.5 low/medium/high; hy3 none/low/high; kimi-k3 max;
* qwen3.6-plus / qwen3.7-max / qwen3.7-plus high/max
*/
const EFFORT_TIERS: Record<string, readonly string[]> = {
"deepseek-v4-pro": EFFORT_LEVELS,
"deepseek-v4-flash": ["high", "max"],
"deepseek-v4-flash": EFFORT_LEVELS,
"glm-5.2": ["high", "max"],
"mimo-v2.5": ["high", "max"],
"grok-4.5": ["low", "medium", "high"],

View File

@@ -676,11 +676,9 @@ test("sanitizeReasoningEffortForProvider: NVIDIA GLM-5.2 mapping is narrowly sco
});
// ── Native DeepSeek (api.deepseek.com) ───────────────────────────────────────
// DeepSeek V4 thinking mode accepts reasoning_effort ONLY as {high, max}. The
// internal OmniRoute scale (low|medium|high|xhigh, xhigh = top) must be mapped
// onto DeepSeek's native vocabulary so the client's requested effort is honored
// instead of silently dropped to the default. This is the INVERSE of the
// OpenRouter-DeepSeek path, whose normalized API expects xhigh, not max.
// DeepSeek V4 thinking mode accepts reasoning_effort as {low, high, max}.
// The internal OmniRoute scale maps mediumhigh and xhigh → max so the client's
// requested effort is honored instead of silently dropped to the default.
test("sanitizeReasoningEffortForProvider: native deepseek maps xhigh → max", () => {
const log = makeLog();
@@ -716,19 +714,25 @@ test("sanitizeReasoningEffortForProvider: native deepseek preserves max", () =>
assert.equal(log.messages.length, 0);
});
test("sanitizeReasoningEffortForProvider: native deepseek clamps low → high", () => {
test("sanitizeReasoningEffortForProvider: native deepseek preserves low", () => {
const body = {
model: "deepseek-v4-pro",
reasoning_effort: "low",
messages: [{ role: "user", content: "hi" }],
};
const result = sanitizeReasoningEffortForProvider(body, "deepseek", "deepseek-v4-pro", null);
assert.equal(result, body, "low is already valid — passes through unchanged");
});
test("sanitizeReasoningEffortForProvider: native non-V4 deepseek clamps low → high", () => {
const body = {
model: "deepseek-chat",
reasoning_effort: "low",
messages: [{ role: "user", content: "hi" }],
};
const result = sanitizeReasoningEffortForProvider(body, "deepseek", "deepseek-chat", null);
assert.notEqual(result, body, "must return a new object when mutating");
assert.equal(
(result as Record<string, unknown>).reasoning_effort,
"high",
"below the {high, max} floor → high"
);
assert.equal((result as Record<string, unknown>).reasoning_effort, "high");
});
test("sanitizeReasoningEffortForProvider: native deepseek clamps medium → high", () => {
@@ -786,11 +790,10 @@ test("sanitizeReasoningEffortForProvider: OpenRouter DeepSeek still preserves xh
assert.equal((result as Record<string, unknown>).reasoning_effort, "xhigh");
});
// ── opencode-go DeepSeek V4 Pro effort variants (#4647) ──────────────────────
// opencode-go proxies DeepSeek with the native DeepSeek API contract, which
// accepts {high, max} literally. The OpencodeExecutor's transformRequest sets
// reasoning_effort to the variant suffix (low|medium|high|max), and the
// sanitizer must NOT rewrite `max` → `xhigh` for this provider+model combo.
// ── opencode-go DeepSeek V4 effort variants (#4647) ──────────────────────────
// opencode-go proxies DeepSeek with the native DeepSeek API contract. Both V4
// models advertise none/low/high/max, and the sanitizer must preserve those
// literal values rather than rewriting `max` to `xhigh`.
test("sanitizeReasoningEffortForProvider: opencode-go DeepSeek V4 Pro preserves max", () => {
const body = {
@@ -803,24 +806,26 @@ test("sanitizeReasoningEffortForProvider: opencode-go DeepSeek V4 Pro preserves
assert.equal((result as Record<string, unknown>).reasoning_effort, "max");
});
test("sanitizeReasoningEffortForProvider: opencode-go DeepSeek V4 Pro preserves variant suffix levels", () => {
for (const level of ["low", "medium", "high", "max"]) {
const body = {
model: `deepseek-v4-pro-${level}`,
reasoning_effort: level,
messages: [],
};
const result = sanitizeReasoningEffortForProvider(
body,
"opencode-go",
`deepseek-v4-pro-${level}`,
null
);
assert.equal(
(result as Record<string, unknown>).reasoning_effort,
level,
`opencode-go deepseek-v4-pro-${level} preserves reasoning_effort=${level}`
);
test("sanitizeReasoningEffortForProvider: opencode-go preserves both V4 models' tiers", () => {
for (const model of ["deepseek-v4-pro", "deepseek-v4-flash"]) {
for (const level of ["none", "low", "high", "max"]) {
const body = {
model: `${model}-${level}`,
reasoning_effort: level,
messages: [],
};
const result = sanitizeReasoningEffortForProvider(
body,
"opencode-go",
`${model}-${level}`,
null
);
assert.equal(
(result as Record<string, unknown>).reasoning_effort,
level,
`opencode-go ${model}-${level} preserves reasoning_effort=${level}`
);
}
}
});

View File

@@ -141,6 +141,7 @@ test("#9485 static DeepSeek effort aliases appear when synced rows omit supporte
`${flashId}-high`,
`${flashId}-max`,
`${proId}-none`,
`${proId}-low`,
`${proId}-high`,
`${proId}-max`,
]);
@@ -150,10 +151,6 @@ test("#9485 static DeepSeek effort aliases appear when synced rows omit supporte
.filter((id) => id.startsWith(`${flashId}-`) || id.startsWith(`${proId}-`))
);
assert.deepEqual(deepSeekAliases, expectedAliases);
assert.equal(
provider!.models.some((model) => model.id === `${proId}-low`),
false
);
assert.equal(
provider!.models.some((model) => model.id === `${proId}-medium`),
false

View File

@@ -29,20 +29,21 @@ test.after(() => {
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
test("DeepSeek registry declares the documented per-model thinking efforts", () => {
const models = new Map((REGISTRY.deepseek?.models || []).map((model) => [model.id, model]));
assert.deepEqual(models.get("deepseek-v4-flash")?.supportedThinkingEfforts, [
"none",
"low",
"high",
"max",
]);
assert.deepEqual(models.get("deepseek-v4-pro")?.supportedThinkingEfforts, [
"none",
"high",
"max",
]);
test("DeepSeek registries declare none/low/high/max on both V4 models", () => {
const expectedEfforts = ["none", "low", "high", "max"];
for (const providerId of ["deepseek", "opencode-go"]) {
const models = new Map((REGISTRY[providerId]?.models || []).map((model) => [model.id, model]));
for (const modelId of ["deepseek-v4-flash", "deepseek-v4-pro"]) {
assert.deepEqual(models.get(modelId)?.supportedThinkingEfforts, expectedEfforts);
for (const effort of expectedEfforts) {
assert.equal(
models.has(`${modelId}-${effort}`),
false,
`${providerId} should derive ${modelId}-${effort} from the base model metadata`
);
}
}
}
});
test("DeepSeek catalog exposes only the declared effort aliases", async () => {
@@ -66,13 +67,38 @@ test("DeepSeek catalog exposes only the declared effort aliases", async () => {
assert.ok([...ids].some((id) => id.endsWith("deepseek-v4-flash-high")));
assert.ok([...ids].some((id) => id.endsWith("deepseek-v4-flash-max")));
assert.ok([...ids].some((id) => id.endsWith("deepseek-v4-pro-none")));
assert.ok([...ids].some((id) => id.endsWith("deepseek-v4-pro-low")));
assert.ok([...ids].some((id) => id.endsWith("deepseek-v4-pro-high")));
assert.ok([...ids].some((id) => id.endsWith("deepseek-v4-pro-max")));
assert.equal(
[...ids].some((id) => id.endsWith("deepseek-v4-pro-low")),
false,
"Pro does not advertise low"
});
test("OpenCode Go catalog derives the declared V4 effort aliases from base models", async () => {
await providersDb.createProviderConnection({
provider: "opencode-go",
authType: "apikey",
name: "opencode-go-deepseek-efforts",
apiKey: "opencode-go-test-key",
isActive: true,
testStatus: "active",
});
const response = await v1ModelsCatalog.getUnifiedModelsResponse(
new Request("http://localhost/api/v1/models")
);
const body = (await response.json()) as {
data: Array<{ id: string; capabilities?: { effort_tiers?: string[] } }>;
};
const models = new Map(body.data.map((model) => [model.id, model]));
const expectedEfforts = ["none", "low", "high", "max"];
for (const modelId of ["deepseek-v4-flash", "deepseek-v4-pro"]) {
const baseId = `opencode-go/${modelId}`;
assert.deepEqual(models.get(baseId)?.capabilities?.effort_tiers, expectedEfforts);
for (const effort of expectedEfforts) {
assert.ok(models.has(`${baseId}-${effort}`), `${baseId}-${effort} must be advertised`);
}
assert.equal(models.has(`${baseId}-medium`), false);
}
});
test("Crof synced reasoning metadata exposes exactly none/low/medium/high/max aliases", async () => {
const connection = await providersDb.createProviderConnection({
@@ -181,25 +207,31 @@ test("hardcoded DeepSeek effort suffixes resolve through the static registry", a
assert.equal(flashNone.model, "deepseek-v4-flash");
assert.equal(flashNone.resolvedThinkingEffort, "none");
const unsupportedProLow = await getModelInfo("ds/deepseek-v4-pro-low");
assert.equal(unsupportedProLow.model, "deepseek-v4-pro-low");
assert.equal(unsupportedProLow.resolvedThinkingEffort, undefined);
const proLow = await getModelInfo("ds/deepseek-v4-pro-low");
assert.equal(proLow.model, "deepseek-v4-pro");
assert.equal(proLow.resolvedThinkingEffort, "low");
});
test("native DeepSeek preserves Flash low while clamping unsupported Pro low", () => {
const flash = sanitizeReasoningEffortForProvider(
{ model: "deepseek-v4-flash", reasoning_effort: "low" },
"deepseek",
"deepseek-v4-flash"
) as Record<string, unknown>;
assert.equal(flash.reasoning_effort, "low");
test("OpenCode Go V4 suffixes resolve from base-model effort metadata", async () => {
for (const modelId of ["deepseek-v4-flash", "deepseek-v4-pro"]) {
for (const effort of ["none", "low", "high", "max"]) {
const info = await getModelInfo(`opencode-go/${modelId}-${effort}`);
assert.equal(info.provider, "opencode-go");
assert.equal(info.model, modelId);
assert.equal(info.resolvedThinkingEffort, effort);
}
}
});
const pro = sanitizeReasoningEffortForProvider(
{ model: "deepseek-v4-pro", reasoning_effort: "low" },
"deepseek",
"deepseek-v4-pro"
) as Record<string, unknown>;
assert.equal(pro.reasoning_effort, "high");
test("native DeepSeek preserves the documented low effort for Flash and Pro", () => {
for (const model of ["deepseek-v4-flash", "deepseek-v4-pro"]) {
const body = { model, reasoning_effort: "low" };
assert.equal(
sanitizeReasoningEffortForProvider(body, "deepseek", model),
body,
`${model} must pass low through unchanged`
);
}
});
test("non-DeepSeek static reasoning models do not advertise unresolvable effort aliases", async () => {
@@ -266,9 +298,9 @@ test("custom model named deepseek-v4-flash-low is not rewritten by registry suff
assert.equal(info.resolvedThinkingEffort, undefined);
});
test("none effort resolves and passes through the native DeepSeek sanitizer unchanged", async () => {
// The -none suffix resolves to base + effort "none", which reaches the native
// DeepSeek endpoint as reasoning_effort: "none" unchanged (#9485 review #8).
test("none effort resolves and stays explicit through provider sanitation", async () => {
// The format translator subsequently carries this as reasoning.effort:"none"
// on DeepSeek's default Responses route, which disables thinking.
const flashNone = await getModelInfo("ds/deepseek-v4-flash-none");
assert.equal(flashNone.model, "deepseek-v4-flash");
assert.equal(flashNone.resolvedThinkingEffort, "none");
@@ -281,9 +313,9 @@ test("none effort resolves and passes through the native DeepSeek sanitizer unch
assert.equal(sanitized.reasoning_effort, "none");
});
test("isFlash check is robust to suffixed model ids", () => {
// A suffixed id like deepseek-v4-flash-low must still be recognized as Flash
// so its low effort is preserved, not clamped to high (#9485 review #5).
test("suffixed Flash low remains valid before alias resolution", () => {
// Preserve low even if a future route sanitizes the raw suffixed id before
// resolving it to the registered base model.
const sanitizedSuffixed = sanitizeReasoningEffortForProvider(
{ model: "deepseek-v4-flash-low", reasoning_effort: "low" },
"deepseek",

View File

@@ -155,3 +155,46 @@ test("single-target combo reflects unblocked Antigravity Gemini reasoning", asyn
assert.equal(capabilities.supportsThinking, true);
assert.equal(Object.hasOwn(capabilities, "effort_tiers"), true);
});
test("mixed DeepSeek combos advertise the efforts accepted by every V4 target", async () => {
await providersDb.createProviderConnection({
provider: "deepseek",
authType: "apikey",
name: "deepseek-v4-combos",
apiKey: "deepseek-test-key",
isActive: true,
testStatus: "active",
});
await providersDb.createProviderConnection({
provider: "opencode-go",
authType: "apikey",
name: "opencode-go-deepseek-v4-combos",
apiKey: "opencode-go-test-key",
isActive: true,
testStatus: "active",
});
for (const modelId of ["deepseek-v4-flash", "deepseek-v4-pro"]) {
await combosDb.createCombo({
name: `${modelId}-combo`,
strategy: "auto",
models: [`deepseek/${modelId}`, `opencode-go/${modelId}`],
});
}
const response = await catalog.getUnifiedModelsResponse(
new Request("http://localhost/api/v1/models")
);
const body = (await response.json()) as { data: Array<Record<string, unknown>> };
assert.equal(response.status, 200);
for (const modelId of ["deepseek-v4-flash", "deepseek-v4-pro"]) {
const combo = body.data.find((item) => item.id === `${modelId}-combo`);
assert.ok(combo);
assert.deepEqual((combo.capabilities as Record<string, unknown>).effort_tiers, [
"none",
"low",
"high",
"max",
]);
}
});

View File

@@ -78,19 +78,25 @@ describe("OpencodeExecutor", () => {
assert.equal(model.supportsReasoning, true);
});
it("exposes DeepSeek V4 Pro effort variants on opencode-go only", () => {
it("declares V4 effort tiers on OpenCode Go base models only", () => {
const goModels = PROVIDER_MODELS["opencode-go"] || [];
const zenModels = PROVIDER_MODELS["opencode-zen"] || [];
const variants = ["low", "medium", "high", "max"].map((level) => `deepseek-v4-pro-${level}`);
for (const variant of variants) {
const model = goModels.find((m) => m.id === variant);
assert.ok(model, `${variant} should be in opencode-go model list`);
assert.equal(model?.supportsReasoning, true);
assert.equal(
zenModels.some((m) => m.id === variant),
false,
`${variant} should not be exposed on opencode-zen`
);
const efforts = ["none", "low", "high", "max"];
for (const modelId of ["deepseek-v4-pro", "deepseek-v4-flash"]) {
const base = goModels.find((model) => model.id === modelId);
assert.deepEqual(base?.supportedThinkingEfforts, efforts);
for (const effort of efforts) {
const variant = `${modelId}-${effort}`;
assert.equal(
goModels.some((model) => model.id === variant),
false
);
assert.equal(
zenModels.some((model) => model.id === variant),
false
);
}
}
});
@@ -137,6 +143,16 @@ describe("OpencodeExecutor", () => {
assert.equal(fetchCalls[0].url, "https://opencode.ai/zen/v1/responses");
});
it("routes OpenCode Go DeepSeek V4 models to the responses endpoint", async () => {
const models = ["deepseek-v4-pro", "deepseek-v4-flash"];
for (const [index, model] of models.entries()) {
const result = await goExecutor.execute(createInput(model));
assert.equal(result.url, "https://opencode.ai/zen/go/v1/responses");
assert.equal(fetchCalls[index].url, "https://opencode.ai/zen/go/v1/responses");
}
});
it("routes gemini streaming requests to streamGenerateContent", async () => {
registerModel("opencode-zen", {
id: "gemini-2.5-pro",
@@ -544,7 +560,7 @@ describe("OpencodeExecutor", () => {
});
});
describe("DeepSeek V4 Pro reasoning-effort variants", () => {
describe("DeepSeek V4 reasoning-effort variants", () => {
function baseBody(model) {
return {
model,
@@ -554,17 +570,19 @@ describe("OpencodeExecutor", () => {
};
}
const levels = ["low", "medium", "high", "max"];
for (const level of levels) {
it(`maps deepseek-v4-pro-${level} to base id + reasoning_effort=${level}`, () => {
const variant = `deepseek-v4-pro-${level}`;
const out = goExecutor.transformRequest(variant, baseBody(variant), false, {
apiKey: "test-key",
const levels = ["none", "low", "high", "max"];
for (const model of ["deepseek-v4-pro", "deepseek-v4-flash"]) {
for (const level of levels) {
it(`maps ${model}-${level} to base id + reasoning_effort=${level}`, () => {
const variant = `${model}-${level}`;
const out = goExecutor.transformRequest(variant, baseBody(variant), false, {
apiKey: "test-key",
});
assert.equal(out.model, model);
assert.equal(out.reasoning_effort, level);
assert.ok(!String(out.model).endsWith(`-${level}`));
});
assert.equal(out.model, "deepseek-v4-pro");
assert.equal(out.reasoning_effort, level);
assert.ok(!String(out.model).endsWith(`-${level}`));
});
}
}
it("preserves explicit reasoning_effort over the variant suffix", () => {

View File

@@ -19,41 +19,29 @@ import assert from "node:assert/strict";
// node:test process without triggering side effects (DB init, fetch,
// etc.). We only need parseEffortLevel, which is a pure function. ───
const { parseEffortLevel, OpencodeExecutor } = (await import(
"../../open-sse/executors/opencode.ts"
)) as {
parseEffortLevel: (model: string) => { baseModel: string; effort: string } | null;
OpencodeExecutor: new (provider: string) => {
transformRequest: (
model: string,
body: Record<string, unknown>,
stream: boolean,
credentials: unknown
) => Record<string, unknown>;
const { parseEffortLevel, OpencodeExecutor } =
(await import("../../open-sse/executors/opencode.ts")) as {
parseEffortLevel: (model: string) => { baseModel: string; effort: string } | null;
OpencodeExecutor: new (provider: string) => {
transformRequest: (
model: string,
body: Record<string, unknown>,
stream: boolean,
credentials: unknown
) => Record<string, unknown>;
};
};
};
// ─── DeepSeek v4-pro: all 4 tiers ─────────────────────────────────────────
// ─── DeepSeek V4 Pro: none/low/high/max ───────────────────────────────────
test("#6922 parseEffortLevel: deepseek-v4-pro-low → low", () => {
const result = parseEffortLevel("deepseek-v4-pro-low");
assert.deepEqual(result, { baseModel: "deepseek-v4-pro", effort: "low" });
});
test("#6922 parseEffortLevel: deepseek-v4-pro-medium → medium", () => {
const result = parseEffortLevel("deepseek-v4-pro-medium");
assert.deepEqual(result, { baseModel: "deepseek-v4-pro", effort: "medium" });
});
test("#6922 parseEffortLevel: deepseek-v4-pro-high → high", () => {
const result = parseEffortLevel("deepseek-v4-pro-high");
assert.deepEqual(result, { baseModel: "deepseek-v4-pro", effort: "high" });
});
test("#6922 parseEffortLevel: deepseek-v4-pro-max → max", () => {
const result = parseEffortLevel("deepseek-v4-pro-max");
assert.deepEqual(result, { baseModel: "deepseek-v4-pro", effort: "max" });
});
for (const effort of ["none", "low", "high", "max"]) {
test(`#6922 parseEffortLevel: deepseek-v4-pro-${effort}${effort}`, () => {
assert.deepEqual(parseEffortLevel(`deepseek-v4-pro-${effort}`), {
baseModel: "deepseek-v4-pro",
effort,
});
});
}
// ─── GLM-5.2: high + max only ────────────────────────────────────────────
@@ -81,6 +69,10 @@ test("#6922 parseEffortLevel: mimo-v2.5-max → max", () => {
// ─── Negative cases ────────────────────────────────────────────────────────
test("#6922 parseEffortLevel: deepseek-v4-pro-medium → null (unsupported tier)", () => {
assert.strictEqual(parseEffortLevel("deepseek-v4-pro-medium"), null);
});
test("#6922 parseEffortLevel: unknown model → null", () => {
const result = parseEffortLevel("nonexistent-model-high");
assert.strictEqual(result, null);
@@ -160,5 +152,9 @@ test("#6922 transformRequest: unaliased model passes through unchanged", () => {
const out = executor.transformRequest("gpt-4o-mini", body, true, CREDENTIALS);
assert.equal(out.model, "gpt-4o-mini", "unaliased model id is left untouched");
assert.equal(out.reasoning_effort, undefined, "no reasoning_effort is injected for a non-tier model");
assert.equal(
out.reasoning_effort,
undefined,
"no reasoning_effort is injected for a non-tier model"
);
});

View File

@@ -1,9 +1,8 @@
/**
* Issue #8353 — Missing OpenCode Go reasoning variants.
*
* OpenCode's local Go registry exposes effort-tier aliases that OmniRoute did
* not register or resolve. These tests cover:
* 1. Catalog exposure on opencode-go (and absence on opencode-zen)
* These tests cover:
* 1. Static registry metadata for aliases that have not migrated to derived variants
* 2. parseEffortLevel → base + effort for every listed alias
* 3. transformRequest rewrite + reasoning_effort injection
* 4. MiniMax M3 stays out of the effort-alias path
@@ -12,19 +11,18 @@
import test from "node:test";
import assert from "node:assert/strict";
const { parseEffortLevel, OpencodeExecutor } = (await import(
"../../open-sse/executors/opencode.ts"
)) as {
parseEffortLevel: (model: string) => { baseModel: string; effort: string } | null;
OpencodeExecutor: new (provider: string) => {
transformRequest: (
model: string,
body: Record<string, unknown>,
stream: boolean,
credentials: unknown
) => Record<string, unknown>;
const { parseEffortLevel, OpencodeExecutor } =
(await import("../../open-sse/executors/opencode.ts")) as {
parseEffortLevel: (model: string) => { baseModel: string; effort: string } | null;
OpencodeExecutor: new (provider: string) => {
transformRequest: (
model: string,
body: Record<string, unknown>,
stream: boolean,
credentials: unknown
) => Record<string, unknown>;
};
};
};
const { REGISTRY } = (await import("../../open-sse/config/providerRegistry.ts")) as {
REGISTRY: Record<
@@ -33,8 +31,10 @@ const { REGISTRY } = (await import("../../open-sse/config/providerRegistry.ts"))
>;
};
/** Exact alias set from #8353 (MiniMax M3 intentionally excluded). */
/** Exact alias set from #8353, plus the newly declared DeepSeek tiers. */
const ISSUE_ALIASES: ReadonlyArray<{ alias: string; base: string; effort: string }> = [
{ alias: "deepseek-v4-flash-none", base: "deepseek-v4-flash", effort: "none" },
{ alias: "deepseek-v4-flash-low", base: "deepseek-v4-flash", effort: "low" },
{ alias: "deepseek-v4-flash-high", base: "deepseek-v4-flash", effort: "high" },
{ alias: "deepseek-v4-flash-max", base: "deepseek-v4-flash", effort: "max" },
{ alias: "grok-4.5-low", base: "grok-4.5", effort: "low" },
@@ -68,10 +68,10 @@ function zenModelIds(): string[] {
// ─── Catalog exposure ──────────────────────────────────────────────────────
test("#8353 catalog: every listed alias is registered on opencode-go", () => {
test("#8353 catalog: DeepSeek aliases are derived instead of registered as duplicate rows", () => {
const ids = new Set(goModelIds());
for (const { alias } of ISSUE_ALIASES) {
assert.ok(ids.has(alias), `opencode-go must expose ${alias}`);
for (const { alias, base } of ISSUE_ALIASES) {
assert.equal(ids.has(alias), base !== "deepseek-v4-flash", alias);
}
});
@@ -128,7 +128,7 @@ for (const { alias, base, effort } of ISSUE_ALIASES) {
}
test("#8353 parseEffortLevel: unsupported tiers stay null", () => {
assert.equal(parseEffortLevel("deepseek-v4-flash-low"), null);
assert.equal(parseEffortLevel("deepseek-v4-flash-medium"), null);
assert.equal(parseEffortLevel("grok-4.5-max"), null);
assert.equal(parseEffortLevel("hy3-max"), null);
assert.equal(parseEffortLevel("kimi-k3-high"), null);
@@ -155,7 +155,7 @@ test("#8353 parseEffortLevel: MiniMax M3 has no effort-tier aliases", () => {
const CREDENTIALS = { apiKey: "k" } as Record<string, unknown>;
const TRANSFORM_SAMPLES = [
{ alias: "deepseek-v4-flash-high", base: "deepseek-v4-flash", effort: "high" },
{ alias: "deepseek-v4-flash-low", base: "deepseek-v4-flash", effort: "low" },
{ alias: "grok-4.5-medium", base: "grok-4.5", effort: "medium" },
{ alias: "hy3-none", base: "hy3", effort: "none" },
{ alias: "kimi-k3-max", base: "kimi-k3", effort: "max" },