diff --git a/src/models.ts b/src/models.ts index 475b693..9f4c375 100644 --- a/src/models.ts +++ b/src/models.ts @@ -14,13 +14,15 @@ type CommandCodeReasoningEffort = Exclude /** * Per-model reasoning efforts supported by Command Code's generate endpoint. * - * The Provider API does not expose reasoning metadata. These entries are - * maintained from the official Command Code CLI model catalog, so a model is - * marked reasoning-capable only when its upstream effort support is known. + * The Provider API does not expose reasoning metadata. This is an exact + * snapshot of `reasoningEfforts` from the command-code@1.14.1 model catalog + * (`packages/shared/src/model-catalog.ts`, also published in the generated + * `dist/bundled/command-code-knowledge/reference/models.md`). Models omitted + * here let Command Code choose their reasoning depth, matching the CLI. */ export const MODEL_EFFORTS: Readonly> = { + "Qwen/Qwen3.8-Max": ["low", "medium", "xhigh"], "claude-fable-5": ["low", "medium", "high", "xhigh", "max"], - "claude-haiku-4-5-20251001": ["low", "medium", "high", "xhigh", "max"], "claude-opus-4-7": ["low", "medium", "high", "xhigh", "max"], "claude-opus-4-8": ["low", "medium", "high", "xhigh", "max"], "claude-opus-5": ["low", "medium", "high", "xhigh", "max"], @@ -39,11 +41,7 @@ export const MODEL_EFFORTS: Readonly> thinking: { - effortMap: Partial> + mode: "effort" + effortMap: Partial> efforts: readonly CommandCodeReasoningEffort[] - defaultLevel: CommandCodeReasoningEffort } } export function thinkingMetadataForModel(modelId: string): ThinkingMetadata | undefined { const efforts = MODEL_EFFORTS[modelId] if (!efforts) return undefined - const effortMap = thinkingLevelMapForEfforts(efforts) return { - thinkingLevelMap: effortMap, + thinkingLevelMap: thinkingLevelMapForEfforts(efforts), thinking: { - effortMap, + mode: "effort", + effortMap: Object.fromEntries(efforts.map((effort) => [effort, effort])), efforts, - defaultLevel: efforts[efforts.length - 2] ?? efforts[0], }, } } diff --git a/src/types.ts b/src/types.ts index b22cdfb..c520543 100644 --- a/src/types.ts +++ b/src/types.ts @@ -75,9 +75,9 @@ export interface ModelLike { reasoning?: boolean thinkingLevelMap?: Partial> thinking?: { - effortMap?: Partial> + mode?: "effort" + effortMap?: Partial> efforts?: readonly string[] - defaultLevel?: string } } diff --git a/tests/test-models.ts b/tests/test-models.ts index 122e52b..e0a34ad 100644 --- a/tests/test-models.ts +++ b/tests/test-models.ts @@ -94,10 +94,45 @@ describe("commandCodeModelsFromApiResponse()", () => { assert.equal(models[1]?.reasoning, false) }) - it("builds explicit maps for every known effort set", () => { + it("matches the exact command-code@1.14.1 reasoning effort catalog", () => { + assert.deepEqual(MODEL_EFFORTS, { + "Qwen/Qwen3.8-Max": ["low", "medium", "xhigh"], + "claude-fable-5": ["low", "medium", "high", "xhigh", "max"], + "claude-opus-4-7": ["low", "medium", "high", "xhigh", "max"], + "claude-opus-4-8": ["low", "medium", "high", "xhigh", "max"], + "claude-opus-5": ["low", "medium", "high", "xhigh", "max"], + "claude-sonnet-4-6": ["low", "medium", "high", "xhigh", "max"], + "claude-sonnet-5": ["low", "medium", "high", "xhigh", "max"], + "deepseek/deepseek-v4-flash": ["high", "max"], + "deepseek/deepseek-v4-pro": ["high", "max"], + "gpt-5.3-codex": ["low", "medium", "high", "xhigh"], + "gpt-5.4": ["low", "medium", "high", "xhigh"], + "gpt-5.4-mini": ["low", "medium", "high"], + "gpt-5.5": ["low", "medium", "high", "xhigh"], + "gpt-5.6-luna": ["low", "medium", "high", "xhigh", "max"], + "gpt-5.6-sol": ["low", "medium", "high", "xhigh", "max"], + "gpt-5.6-terra": ["low", "medium", "high", "xhigh", "max"], + "google/gemini-3.1-flash-lite": ["low", "medium", "high"], + "google/gemini-3.5-flash": ["low", "medium", "high"], + "google/gemini-3.5-flash-lite": ["low", "medium", "high"], + "google/gemini-3.6-flash": ["low", "medium", "high"], + "sakana/fugu-ultra": ["high", "xhigh"], + "xai/grok-4.5": ["low", "medium", "high"], + "zai-org/GLM-5.2": ["high", "max"], + }) + }) + + it("builds separate canonical pi and OMP metadata", () => { for (const [modelId, efforts] of Object.entries(MODEL_EFFORTS)) { const metadata = thinkingMetadataForModel(modelId) assert.ok(metadata, `${modelId} should have reasoning metadata`) + assert.equal(metadata.thinking.mode, "effort") + assert.deepEqual(metadata.thinking.efforts, efforts) + assert.deepEqual( + metadata.thinking.effortMap, + Object.fromEntries(efforts.map((effort) => [effort, effort])), + ) + assert.equal("defaultLevel" in metadata.thinking, false) for (const level of ["minimal", "low", "medium", "high", "xhigh", "max"] as const) { const expected = efforts.includes(level) assert.equal(