diff --git a/src/adapters/command-code.ts b/src/adapters/command-code.ts index 3744c6fa1b..68ba01882c 100644 --- a/src/adapters/command-code.ts +++ b/src/adapters/command-code.ts @@ -428,10 +428,21 @@ function supportedCommandCodeEffort(provider: OcxProviderConfig, modelId: string const canonicalId = canonicalCommandCodeModelId(modelId); const supported = commandCodeReasoningEfforts(canonicalId) ?? configuredReasoningEfforts(provider, canonicalId); if (!supported) return undefined; - // Command Code's official profiles describe xhigh and ultra as the CLI labels that map to - // the wire value `max`; preserve that mapping without advertising a synthetic tier. - const wire = (requested === "xhigh" || requested === "ultra") && supported.includes("max") ? "max" : requested; - return supported.includes(wire) ? wire : undefined; + // Only remap xhigh/ultra→max for models whose official profile documents that + // aliasing (deepseek v4, glm-5.2). Muse Spark's upstream accepts xhigh as a + // distinct wire value and rejects ultra, so it must not be collapsed. + let wire = requested; + const lower = canonicalId.toLowerCase(); + const needsAlias = + lower === "deepseek/deepseek-v4-pro" || + lower === "deepseek/deepseek-v4-flash" || + lower === "zai-org/glm-5.2"; + if (requested === "xhigh" && !supported.includes("xhigh") && supported.includes("max")) { + wire = "max"; + } else if (requested === "ultra" && needsAlias && supported.includes("max")) { + wire = "max"; + } + return (supported as readonly string[]).includes(wire) ? wire : undefined; } export function createCommandCodeAdapter(provider: OcxProviderConfig): ProviderAdapter { diff --git a/src/providers/command-code-efforts.ts b/src/providers/command-code-efforts.ts index e6e808e8b4..0e3c3f2ac1 100644 --- a/src/providers/command-code-efforts.ts +++ b/src/providers/command-code-efforts.ts @@ -13,6 +13,24 @@ const COMMAND_CODE_MODEL_EFFORTS = { efforts: ["high", "max"], profileUrl: "https://commandcode.ai/models/glm-5-2", }, + // Muse Spark: CLI currently prints "has no adjustable reasoning effort" and + // blocks --effort locally, but the upstream /alpha/generate endpoint accepts + // reasoning_effort low..max for meta/muse-spark-1.2-contributor (verified + // 2026-08-13: direct upstream POST with low/medium/high/xhigh/max all 200, + // ultra 400; reasoningTokens differentiated 114..253; proxy previously stripped + // the field so effort changes had no effect). + "meta/muse-spark-1.2": { + efforts: ["low", "medium", "high", "xhigh", "max"], + profileUrl: "https://commandcode.ai/models/meta-muse-spark-1.2", + }, + "meta/muse-spark-1.2-contributor": { + efforts: ["low", "medium", "high", "xhigh", "max"], + profileUrl: "https://commandcode.ai/models/meta-muse-spark-1.2-contributor", + }, + "meta/muse-spark-1.1": { + efforts: ["low", "medium", "high", "xhigh", "max"], + profileUrl: "https://commandcode.ai/models/meta-muse-spark-1.1", + }, } as const; /** diff --git a/tests/command-code-provider.test.ts b/tests/command-code-provider.test.ts index a2cf33abd5..ce50b8972d 100644 --- a/tests/command-code-provider.test.ts +++ b/tests/command-code-provider.test.ts @@ -293,6 +293,58 @@ describe("Command Code provider", () => { expect(JSON.parse(built.body).params).not.toHaveProperty("reasoning_effort"); }); + test("advertises reasoning efforts for muse spark and rejects ultra at the wire", async () => { + // Muse Spark: CLI prints "has no adjustable reasoning effort", but upstream + // /alpha/generate accepts low..max (verified 2026-08-13: contributor + // variant all 200, ultra 400). The proxy previously stripped the field; + // this covers the actual forwarding behavior. + expect(commandCodeReasoningEfforts("meta/muse-spark-1.2-contributor")).toEqual( + ["low", "medium", "high", "xhigh", "max"], + ); + expect(commandCodeReasoningEfforts("meta/muse-spark-1.2")).toEqual( + ["low", "medium", "high", "xhigh", "max"], + ); + expect(commandCodeReasoningEfforts("meta/muse-spark-1.1")).toEqual( + ["low", "medium", "high", "xhigh", "max"], + ); + // Case-insensitive lookup (keyFor lowercases). + expect(commandCodeReasoningEfforts("Meta/Muse-Spark-1.2-Contributor")).toEqual( + ["low", "medium", "high", "xhigh", "max"], + ); + for (const effort of ["low", "medium", "high", "max"] as const) { + const withEffort = await builtRequest({ + ...parsed("meta/muse-spark-1.2-contributor"), + options: { reasoning: effort, maxOutputTokens: 100 }, + }); + expect(JSON.parse(withEffort.body).params.reasoning_effort).toBe(effort); + } + // xhigh is a distinct wire value for muse spark (upstream accepts it) and + // must not be collapsed to max — only deepseek/glm need that aliasing. + const xhigh = await builtRequest({ + ...parsed("meta/muse-spark-1.2-contributor"), + options: { reasoning: "xhigh", maxOutputTokens: 100 }, + }); + expect(JSON.parse(xhigh.body).params.reasoning_effort).toBe("xhigh"); + // ultra is not advertised for muse spark and upstream rejects it (400). + // The adapter must strip it before request construction. + const ultra = await builtRequest({ + ...parsed("meta/muse-spark-1.2-contributor"), + options: { reasoning: "ultra", maxOutputTokens: 100 }, + }); + expect(JSON.parse(ultra.body).params).not.toHaveProperty("reasoning_effort"); + // Deepseek/glm still alias xhigh/ultra→max per their official profiles. + const deepseekUltra = await builtRequest({ + ...parsed("deepseek/deepseek-v4-flash"), + options: { reasoning: "ultra", maxOutputTokens: 100 }, + }); + expect(JSON.parse(deepseekUltra.body).params.reasoning_effort).toBe("max"); + const deepseekXhigh = await builtRequest({ + ...parsed("deepseek/deepseek-v4-flash"), + options: { reasoning: "xhigh", maxOutputTokens: 100 }, + }); + expect(JSON.parse(deepseekXhigh.body).params.reasoning_effort).toBe("max"); + }); + test("maps ultra and xhigh to the max wire effort and honors legacy alias ids", async () => { const ultra = await builtRequest({ ...parsed(), options: { reasoning: "ultra", maxOutputTokens: 100 } }); expect(JSON.parse(ultra.body).params.reasoning_effort).toBe("max");