From 88180d069a786158f07fa9d1da5a887c08ba3cd9 Mon Sep 17 00:00:00 2001 From: Prudhvi Vuda <53619858+Prudhvivuda@users.noreply.github.com> Date: Sat, 25 Jul 2026 01:51:56 -0400 Subject: [PATCH] feat(providers): add missing opencode-go reasoning effort variants (#8441) Register OpenCode Go registry effort aliases and EFFORT_TIERS rewrites so clients can select declared reasoning levels through OmniRoute. Closes #8353 --- .../providers/registry/opencode/go/index.ts | 73 +++++++ open-sse/executors/opencode.ts | 12 ++ .../opencode-go-effort-aliases-8353.test.ts | 190 ++++++++++++++++++ 3 files changed, 275 insertions(+) create mode 100644 tests/unit/opencode-go-effort-aliases-8353.test.ts diff --git a/open-sse/config/providers/registry/opencode/go/index.ts b/open-sse/config/providers/registry/opencode/go/index.ts index e3dd4b4d80..4ead5d8823 100644 --- a/open-sse/config/providers/registry/opencode/go/index.ts +++ b/open-sse/config/providers/registry/opencode/go/index.ts @@ -28,6 +28,9 @@ export const opencode_goProvider: RegistryEntry = { { id: "kimi-k2.7-code", name: "Kimi K2.7 Code" }, { id: "kimi-k2.6", name: "Kimi K2.6" }, { id: "kimi-k2.5", name: "Kimi K2.5" }, + // #8353: Kimi K3 base + max-effort alias from the OpenCode Go registry. + { id: "kimi-k3", name: "Kimi K3", supportsReasoning: true }, + { id: "kimi-k3-max", name: "Kimi K3 (max effort)", supportsReasoning: true }, // MiMo-V2.5 — base model + effort-tier aliases (#6922). { id: "mimo-v2.5-pro", name: "MiMo-V2.5-Pro", supportsReasoning: true }, { id: "mimo-v2.5", name: "MiMo-V2.5", supportsReasoning: true }, @@ -50,10 +53,69 @@ export const opencode_goProvider: RegistryEntry = { // Issue #2822: These models are text-only — mark supportsVision: false // so combo routing skips them when the request contains image blocks, // preventing image content from reaching a vision-incapable upstream. + // #8353: effort-tier aliases from the OpenCode Go registry. { id: "qwen3.7-max", name: "Qwen3.7 Max", targetFormat: "claude", supportsVision: false }, + { + id: "qwen3.7-max-high", + name: "Qwen3.7 Max (high effort)", + targetFormat: "claude", + supportsVision: false, + supportsReasoning: true, + }, + { + id: "qwen3.7-max-max", + name: "Qwen3.7 Max (max effort)", + targetFormat: "claude", + supportsVision: false, + supportsReasoning: true, + }, + { + id: "qwen3.7-plus", + name: "Qwen3.7 Plus", + targetFormat: "claude", + supportsVision: false, + }, + { + id: "qwen3.7-plus-high", + name: "Qwen3.7 Plus (high effort)", + targetFormat: "claude", + supportsVision: false, + supportsReasoning: true, + }, + { + id: "qwen3.7-plus-max", + name: "Qwen3.7 Plus (max effort)", + targetFormat: "claude", + supportsVision: false, + supportsReasoning: true, + }, { id: "qwen3.6-plus", name: "Qwen3.6 Plus", targetFormat: "claude", supportsVision: false }, + { + id: "qwen3.6-plus-high", + name: "Qwen3.6 Plus (high effort)", + targetFormat: "claude", + supportsVision: false, + supportsReasoning: true, + }, + { + id: "qwen3.6-plus-max", + name: "Qwen3.6 Plus (max effort)", + targetFormat: "claude", + supportsVision: false, + supportsReasoning: true, + }, { id: "qwen3.5-plus", name: "Qwen3.5 Plus", targetFormat: "claude", supportsVision: false }, + // #8353: hy3 is the Go-tier base id (distinct from hy3-preview / hy3-free). + { id: "hy3", name: "Hunyuan3", supportsReasoning: true }, + { id: "hy3-none", name: "Hunyuan3 (none effort)", supportsReasoning: true }, + { id: "hy3-low", name: "Hunyuan3 (low effort)", supportsReasoning: true }, + { id: "hy3-high", name: "Hunyuan3 (high effort)", supportsReasoning: true }, { id: "hy3-preview", name: "Hunyuan3 Preview" }, + // #8353: Grok 4.5 + effort tiers from the OpenCode Go registry. + { id: "grok-4.5", name: "Grok 4.5", supportsReasoning: true }, + { 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 }, @@ -65,5 +127,16 @@ export const opencode_goProvider: RegistryEntry = { { 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)", + supportsReasoning: true, + }, + { + id: "deepseek-v4-flash-max", + name: "DeepSeek V4 Flash (max effort)", + supportsReasoning: true, + }, ], }; diff --git a/open-sse/executors/opencode.ts b/open-sse/executors/opencode.ts index babae8a710..8180d43afe 100644 --- a/open-sse/executors/opencode.ts +++ b/open-sse/executors/opencode.ts @@ -49,11 +49,23 @@ const EFFORT_LEVELS = ["low", "medium", "high", "max"] as const; * low/medium are not supported on the OpenAI transport) * - mimo-v2.5: high/max only (same reasoning; Xiaomi MiMo does not document * low/medium effort tiers) + * - #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 */ const EFFORT_TIERS: Record = { "deepseek-v4-pro": EFFORT_LEVELS, + "deepseek-v4-flash": ["high", "max"], "glm-5.2": ["high", "max"], "mimo-v2.5": ["high", "max"], + "grok-4.5": ["low", "medium", "high"], + hy3: ["none", "low", "high"], + "kimi-k3": ["max"], + "qwen3.6-plus": ["high", "max"], + "qwen3.7-max": ["high", "max"], + "qwen3.7-plus": ["high", "max"], }; /** diff --git a/tests/unit/opencode-go-effort-aliases-8353.test.ts b/tests/unit/opencode-go-effort-aliases-8353.test.ts new file mode 100644 index 0000000000..ee248b504a --- /dev/null +++ b/tests/unit/opencode-go-effort-aliases-8353.test.ts @@ -0,0 +1,190 @@ +/** + * 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) + * 2. parseEffortLevel → base + effort for every listed alias + * 3. transformRequest rewrite + reasoning_effort injection + * 4. MiniMax M3 stays out of the effort-alias path + */ + +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, + stream: boolean, + credentials: unknown + ) => Record; + }; +}; + +const { REGISTRY } = (await import("../../open-sse/config/providerRegistry.ts")) as { + REGISTRY: Record< + string, + { models?: Array<{ id: string; name?: string; targetFormat?: string }> } + >; +}; + +/** Exact alias set from #8353 (MiniMax M3 intentionally excluded). */ +const ISSUE_ALIASES: ReadonlyArray<{ alias: string; base: string; effort: string }> = [ + { 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" }, + { alias: "grok-4.5-medium", base: "grok-4.5", effort: "medium" }, + { alias: "grok-4.5-high", base: "grok-4.5", effort: "high" }, + { alias: "hy3-none", base: "hy3", effort: "none" }, + { alias: "hy3-low", base: "hy3", effort: "low" }, + { alias: "hy3-high", base: "hy3", effort: "high" }, + { alias: "kimi-k3-max", base: "kimi-k3", effort: "max" }, + { alias: "qwen3.6-plus-high", base: "qwen3.6-plus", effort: "high" }, + { alias: "qwen3.6-plus-max", base: "qwen3.6-plus", effort: "max" }, + { alias: "qwen3.7-max-high", base: "qwen3.7-max", effort: "high" }, + { alias: "qwen3.7-max-max", base: "qwen3.7-max", effort: "max" }, + { alias: "qwen3.7-plus-high", base: "qwen3.7-plus", effort: "high" }, + { alias: "qwen3.7-plus-max", base: "qwen3.7-plus", effort: "max" }, +]; + +const NEW_BASES = ["grok-4.5", "hy3", "kimi-k3", "qwen3.7-plus"] as const; + +function goModelIds(): string[] { + const entry = REGISTRY["opencode-go"]; + assert.ok(entry, "opencode-go registry entry must exist"); + return (entry.models ?? []).map((m) => m.id); +} + +function zenModelIds(): string[] { + const entry = REGISTRY["opencode-zen"]; + assert.ok(entry, "opencode-zen registry entry must exist"); + return (entry.models ?? []).map((m) => m.id); +} + +// ─── Catalog exposure ────────────────────────────────────────────────────── + +test("#8353 catalog: every listed alias is registered on opencode-go", () => { + const ids = new Set(goModelIds()); + for (const { alias } of ISSUE_ALIASES) { + assert.ok(ids.has(alias), `opencode-go must expose ${alias}`); + } +}); + +test("#8353 catalog: new base models are registered on opencode-go", () => { + const ids = new Set(goModelIds()); + for (const base of NEW_BASES) { + assert.ok(ids.has(base), `opencode-go must expose base model ${base}`); + } +}); + +test("#8353 catalog: hy3 base is distinct from hy3-preview", () => { + const ids = new Set(goModelIds()); + assert.ok(ids.has("hy3"), "hy3 Go-tier base must exist"); + assert.ok(ids.has("hy3-preview"), "hy3-preview must remain"); + assert.equal( + parseEffortLevel("hy3-preview"), + null, + "hy3-preview must not parse as an effort alias" + ); +}); + +test("#8353 catalog: aliases are NOT synthesized on opencode-zen", () => { + const zenIds = new Set(zenModelIds()); + for (const { alias } of ISSUE_ALIASES) { + assert.equal(zenIds.has(alias), false, `opencode-zen must not expose ${alias}`); + } + for (const base of NEW_BASES) { + assert.equal(zenIds.has(base), false, `opencode-zen must not expose base ${base}`); + } +}); + +test("#8353 catalog: qwen effort aliases keep Claude targetFormat", () => { + const models = REGISTRY["opencode-go"]?.models ?? []; + for (const id of [ + "qwen3.6-plus-high", + "qwen3.6-plus-max", + "qwen3.7-max-high", + "qwen3.7-max-max", + "qwen3.7-plus-high", + "qwen3.7-plus-max", + ]) { + const entry = models.find((m) => m.id === id); + assert.ok(entry, `${id} must exist`); + assert.equal(entry.targetFormat, "claude", `${id} must keep targetFormat: claude`); + } +}); + +// ─── parseEffortLevel ────────────────────────────────────────────────────── + +for (const { alias, base, effort } of ISSUE_ALIASES) { + test(`#8353 parseEffortLevel: ${alias} → ${effort}`, () => { + assert.deepEqual(parseEffortLevel(alias), { baseModel: base, effort }); + }); +} + +test("#8353 parseEffortLevel: unsupported tiers stay null", () => { + assert.equal(parseEffortLevel("deepseek-v4-flash-low"), null); + assert.equal(parseEffortLevel("grok-4.5-max"), null); + assert.equal(parseEffortLevel("hy3-max"), null); + assert.equal(parseEffortLevel("kimi-k3-high"), null); + assert.equal(parseEffortLevel("qwen3.6-plus-low"), null); +}); + +test("#8353 parseEffortLevel: existing DeepSeek V4 Pro / GLM / MiMo aliases still work", () => { + assert.deepEqual(parseEffortLevel("deepseek-v4-pro-max"), { + baseModel: "deepseek-v4-pro", + effort: "max", + }); + assert.deepEqual(parseEffortLevel("glm-5.2-high"), { baseModel: "glm-5.2", effort: "high" }); + assert.deepEqual(parseEffortLevel("mimo-v2.5-max"), { baseModel: "mimo-v2.5", effort: "max" }); +}); + +test("#8353 parseEffortLevel: MiniMax M3 has no effort-tier aliases", () => { + assert.equal(parseEffortLevel("minimax-m3-thinking"), null); + assert.equal(parseEffortLevel("minimax-m3-none"), null); + assert.equal(parseEffortLevel("minimax-m3-high"), null); +}); + +// ─── transformRequest rewrite ────────────────────────────────────────────── + +const CREDENTIALS = { apiKey: "k" } as Record; + +const TRANSFORM_SAMPLES = [ + { alias: "deepseek-v4-flash-high", base: "deepseek-v4-flash", effort: "high" }, + { 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" }, + { alias: "qwen3.7-plus-max", base: "qwen3.7-plus", effort: "max" }, + { alias: "qwen3.7-max-high", base: "qwen3.7-max", effort: "high" }, +] as const; + +for (const { alias, base, effort } of TRANSFORM_SAMPLES) { + test(`#8353 transformRequest: ${alias} → model=${base}, reasoning_effort=${effort}`, () => { + const executor = new OpencodeExecutor("opencode-go"); + const body = { model: alias, messages: [{ role: "user", content: "hi" }] }; + + const out = executor.transformRequest(alias, body, true, CREDENTIALS); + + assert.equal(out.model, base, "model id must be rewritten to the base id"); + assert.equal(out.reasoning_effort, effort, "reasoning_effort must be injected from the alias"); + }); +} + +test("#8353 transformRequest: does not clobber an already-set reasoning_effort", () => { + const executor = new OpencodeExecutor("opencode-go"); + const body = { + model: "deepseek-v4-flash-max", + reasoning_effort: "caller-supplied", + messages: [{ role: "user", content: "hi" }], + }; + + const out = executor.transformRequest("deepseek-v4-flash-max", body, true, CREDENTIALS); + + assert.equal(out.model, "deepseek-v4-flash"); + assert.equal(out.reasoning_effort, "caller-supplied"); +});