Skip to content
Closed
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
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Fix `opencode-go/muse-spark-1.3-contributor` returning 500 by routing it (base + minimal/low/medium/high/xhigh effort aliases) to the Responses API like the 1.2 family. (#12675 — thanks @bacnh85)
72 changes: 72 additions & 0 deletions open-sse/config/providers/registry/opencode/go/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,78 @@ export const opencode_goProvider: RegistryEntry = {
supportsVideo: true,
targetFormat: "openai-responses",
},
// #12674: Muse Spark 1.3 Contributor — base + effort-tier aliases from the
// OpenCode Go registry (`opencode models opencode-go --refresh --verbose`;
// exact suffix set: minimal/low/medium/high/xhigh, no max — same as 1.2).
// Upstream serves Muse Spark only on the Responses API; without
// targetFormat:"openai-responses" these fall through to /chat/completions
// and the upstream returns 500 (same class as #12196).
{
id: "muse-spark-1.3-contributor",
name: "Muse Spark 1.3 Contributor",
contextLength: 1048576,
maxOutputTokens: 131072,
supportsReasoning: true,
supportsVision: true,
supportsAudio: true,
supportsVideo: true,
targetFormat: "openai-responses",
},
{
id: "muse-spark-1.3-contributor-minimal",
name: "Muse Spark 1.3 Contributor (minimal effort)",
contextLength: 1048576,
maxOutputTokens: 131072,
supportsReasoning: true,
supportsVision: true,
supportsAudio: true,
supportsVideo: true,
targetFormat: "openai-responses",
},
{
id: "muse-spark-1.3-contributor-low",
name: "Muse Spark 1.3 Contributor (low effort)",
contextLength: 1048576,
maxOutputTokens: 131072,
supportsReasoning: true,
supportsVision: true,
supportsAudio: true,
supportsVideo: true,
targetFormat: "openai-responses",
},
{
id: "muse-spark-1.3-contributor-medium",
name: "Muse Spark 1.3 Contributor (medium effort)",
contextLength: 1048576,
maxOutputTokens: 131072,
supportsReasoning: true,
supportsVision: true,
supportsAudio: true,
supportsVideo: true,
targetFormat: "openai-responses",
},
{
id: "muse-spark-1.3-contributor-high",
name: "Muse Spark 1.3 Contributor (high effort)",
contextLength: 1048576,
maxOutputTokens: 131072,
supportsReasoning: true,
supportsVision: true,
supportsAudio: true,
supportsVideo: true,
targetFormat: "openai-responses",
},
{
id: "muse-spark-1.3-contributor-xhigh",
name: "Muse Spark 1.3 Contributor (xhigh effort)",
contextLength: 1048576,
maxOutputTokens: 131072,
supportsReasoning: true,
supportsVision: true,
supportsAudio: true,
supportsVideo: true,
targetFormat: "openai-responses",
},
// #8353: Grok 4.5 + effort tiers from the OpenCode Go registry.
{
id: "grok-4.5",
Expand Down
3 changes: 3 additions & 0 deletions open-sse/executors/opencode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ const OPENCODE_FREE_MODELS = new Set([
* grok-4.5 low/medium/high; hy3 none/low/high; kimi-k3 max;
* qwen3.6-plus / qwen3.7-max / qwen3.7-plus high/max;
* muse-spark-1.2-contributor minimal/low/medium/high/xhigh (no max)
* - #12674 Muse Spark 1.3 Contributor: minimal/low/medium/high/xhigh (no max),
* verified via `opencode models opencode-go --refresh --verbose`
*/
const EFFORT_TIERS: Record<string, readonly string[]> = {
"deepseek-v4-pro": EFFORT_LEVELS,
Expand All @@ -98,6 +100,7 @@ const EFFORT_TIERS: Record<string, readonly string[]> = {
"qwen3.7-max": ["high", "max"],
"qwen3.7-plus": ["high", "max"],
"muse-spark-1.2-contributor": ["minimal", "low", "medium", "high", "xhigh"],
"muse-spark-1.3-contributor": ["minimal", "low", "medium", "high", "xhigh"],
};

/**
Expand Down
75 changes: 75 additions & 0 deletions tests/unit/opencode-go-muse-spark-1-3-12674.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import assert from "node:assert/strict";
import test from "node:test";

import {
parseEffortLevel,
resolveOpencodeTargetFormat,
} from "../../open-sse/executors/opencode.ts";

const { REGISTRY } = (await import("../../open-sse/config/providerRegistry.ts")) as {
REGISTRY: Record<
string,
{
models?: Array<{
id: string;
targetFormat?: string;
supportsReasoning?: boolean;
contextLength?: number;
maxOutputTokens?: number;
}>;
}
>;
};

// #12674: opencode-go/muse-spark-1.3-contributor (upstream release 2026-09-02)
// 500s via /v1/chat/completions because the upstream serves Muse Spark only on
// the Responses API and the model had no registry targetFormat entry, so the
// executor fell back to "openai". Base + effort-tier alias set verified via
// `opencode models opencode-go --refresh --verbose` (minimal/low/medium/high/
// xhigh, no max — same as 1.2).
const BASE = "muse-spark-1.3-contributor";
const ALIASES = ["minimal", "low", "medium", "high", "xhigh"].map((effort) => ({
alias: `${BASE}-${effort}`,
effort,
}));

function goModels() {
const entry = REGISTRY["opencode-go"];
assert.ok(entry, "opencode-go registry entry must exist");
return entry.models ?? [];
}

test("#12674 registry: 1.3 base + effort aliases target the Responses API", () => {
const models = goModels();
for (const id of [BASE, ...ALIASES.map((a) => a.alias)]) {
const model = models.find((m) => m.id === id);
assert.ok(model, `${id} must be registered on opencode-go`);
assert.equal(model?.targetFormat, "openai-responses", `${id} must target Responses`);
assert.equal(model?.supportsReasoning, true, `${id} must support reasoning`);
assert.equal(model?.contextLength, 1048576, `${id} context must be 1M`);
assert.equal(model?.maxOutputTokens, 131072, `${id} max output must be 128K`);
}
});

test("#12674 executor: 1.3 resolves to openai-responses (URL selection)", () => {
assert.equal(resolveOpencodeTargetFormat("opencode-go", BASE), "openai-responses");
assert.equal(resolveOpencodeTargetFormat("opencode-go", `${BASE}-high`), "openai-responses");
});

for (const { alias, effort } of ALIASES) {
test(`#12674 parseEffortLevel: ${alias} → ${effort}`, () => {
assert.deepEqual(parseEffortLevel(alias), { baseModel: BASE, effort });
});
}

test("#12674 parseEffortLevel: 1.3 has no max tier", () => {
assert.equal(parseEffortLevel(`${BASE}-max`), null);
});

test("#12674 catalog: 1.3 aliases stay Go-only (not on opencode-zen)", () => {
const zenIds = new Set((REGISTRY["opencode-zen"]?.models ?? []).map((m) => m.id));
assert.equal(zenIds.has(BASE), false, "opencode-zen must not expose 1.3 base");
for (const { alias } of ALIASES) {
assert.equal(zenIds.has(alias), false, `opencode-zen must not expose ${alias}`);
}
});