Skip to content

Commit 5ff7f61

Browse files
committed
Match Muse Spark models by prefix, not an exact id list
The id list covered the two ids in packages/opencode-go and missed the three in packages/zen: muse-spark-1.3, muse-spark-1.2, and muse-spark-1.3-contributor-free. Nothing normalizes the model string on the way to supportedEfforts, so those three still fell through to the unknown-model ladder and still could not select minimal — the exact symptom this change exists to fix, surviving on the ids nobody tested. Confirmed against the live endpoints that minimal returns 200 and none returns 400 for the two contributor ids and for contributor-free. muse-spark-1.3 and -1.2 answered with a billing gate rather than a model rejection, so their ladder is inferred from the family, not measured. A prefix also matches isMuseSparkLeafProvider in provider-family.ts, which already keyed off /^muse-spark/i — the two would otherwise have disagreed about which models are Muse Spark. CL-7867
1 parent 6a23625 commit 5ff7f61

2 files changed

Lines changed: 35 additions & 18 deletions

File tree

‎src/provider/reasoning-effort.test.ts‎

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -164,15 +164,27 @@ describe("supportedEfforts", () => {
164164
expect(supportedEfforts("glm-5.3-flash")).toEqual(["low", "high", "max"]);
165165
});
166166

167-
test("Muse Spark supports minimal through high", () => {
168-
expect(supportedEfforts("muse-spark-1.3-contributor")).toEqual([
167+
// Five ids ship across two catalogs (packages/opencode-go and packages/zen)
168+
// and nothing normalizes the model string before it reaches supportedEfforts,
169+
// so every one of them has to land on the same ladder.
170+
test.each([
171+
"muse-spark-1.3-contributor",
172+
"muse-spark-1.2-contributor",
173+
"muse-spark-1.3",
174+
"muse-spark-1.2",
175+
"muse-spark-1.3-contributor-free",
176+
])("Muse Spark id %s supports minimal through high", (model) => {
177+
expect(supportedEfforts(model)).toEqual([
169178
"minimal",
170179
"low",
171180
"medium",
172181
"high",
173182
]);
174-
expect(supportedEfforts("muse-spark-1.2-contributor")).toEqual([
175-
"minimal",
183+
expect(defaultEffortForModel(model)).toBe("low");
184+
});
185+
186+
test("a model merely containing muse-spark is not matched", () => {
187+
expect(supportedEfforts("not-muse-spark-1.3")).toEqual([
176188
"low",
177189
"medium",
178190
"high",
@@ -501,11 +513,6 @@ describe("defaultEffortForModel", () => {
501513
expect(defaultEffortForModel("glm-5.3-flash")).toBe("max");
502514
});
503515

504-
test("Muse Spark defaults to low", () => {
505-
expect(defaultEffortForModel("muse-spark-1.3-contributor")).toBe("low");
506-
expect(defaultEffortForModel("muse-spark-1.2-contributor")).toBe("low");
507-
});
508-
509516
test("gpt-5 and o-series default to medium", () => {
510517
expect(defaultEffortForModel("gpt-5")).toBe("medium");
511518
expect(defaultEffortForModel("o1")).toBe("medium");

‎src/provider/reasoning-effort.ts‎

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,19 +61,29 @@ const UNKNOWN_MODEL_EFFORTS: readonly ReasoningEffort[] = [
6161
"high",
6262
];
6363

64-
// Muse Spark (OpenCode Go, Responses protocol) accepts minimal through high.
65-
// Not `none` — the Go gateway rejects it with HTTP 400 on `reasoning.effort`.
66-
// Measured against https://opencode.ai/zen/go/v1/responses; see CL-7867.
64+
// Muse Spark (Responses protocol) accepts minimal through high. Not `none` —
65+
// the gateway rejects it with HTTP 400 on `reasoning.effort`. Measured on
66+
// muse-spark-1.3-contributor and muse-spark-1.2-contributor via the Go
67+
// endpoint and muse-spark-1.3-contributor-free via Zen: `minimal` returns 200
68+
// and `none` returns 400 on all three. See CL-7867.
6769
const MUSE_SPARK_EFFORTS: readonly ReasoningEffort[] = [
6870
"minimal",
6971
"low",
7072
"medium",
7173
"high",
7274
];
73-
const MUSE_SPARK_MODELS: readonly string[] = [
74-
"muse-spark-1.3-contributor",
75-
"muse-spark-1.2-contributor",
76-
];
75+
76+
// Matched by prefix, not by an id list. The family ships under five ids across
77+
// two catalogs — `muse-spark-1.3-contributor` / `-1.2-contributor` in
78+
// packages/opencode-go, and `muse-spark-1.3` / `-1.2` /
79+
// `-1.3-contributor-free` in packages/zen — and nothing normalizes the model
80+
// string before it reaches here. An exact list silently missed three of them
81+
// and left the ladder at the unknown-model default. This also matches
82+
// isMuseSparkLeafProvider in src/subagent/provider-family.ts, which already
83+
// keyed off the same prefix.
84+
function isMuseSparkModel(model: string): boolean {
85+
return /^muse-spark/i.test(model.trim());
86+
}
7787

7888
// grok-4.6 accepts xhigh; grok-4.5 and composer stay on the unknown-model subset.
7989
const GROK_46_EFFORTS: readonly ReasoningEffort[] = [
@@ -157,7 +167,7 @@ export function supportedEfforts(
157167
if (GLM_53_MODELS.includes(model)) {
158168
return [...GLM_53_EFFORTS];
159169
}
160-
if (MUSE_SPARK_MODELS.includes(model)) {
170+
if (isMuseSparkModel(model)) {
161171
return [...MUSE_SPARK_EFFORTS];
162172
}
163173
return [...UNKNOWN_MODEL_EFFORTS];
@@ -227,7 +237,7 @@ export function defaultEffortForModel(
227237
supported.includes(desired) ? desired : undefined;
228238
if (model.startsWith("grok")) return pick("high");
229239
if (GLM_53_MODELS.includes(model)) return pick("max");
230-
if (MUSE_SPARK_MODELS.includes(model)) return pick("low");
240+
if (isMuseSparkModel(model)) return pick("low");
231241
if (!isCodex && supported.includes("none")) return "none";
232242
if (isCodex || isKnownOpenAIReasoningModel(model)) return pick("medium");
233243
return undefined;

0 commit comments

Comments
 (0)