diff --git a/.github/scripts/check-commandcode-model-metadata.ts b/.github/scripts/check-commandcode-model-metadata.ts index 5388cc4..d63fb00 100644 --- a/.github/scripts/check-commandcode-model-metadata.ts +++ b/.github/scripts/check-commandcode-model-metadata.ts @@ -18,7 +18,7 @@ const execFileAsync = promisify(execFile) const MODELS_REFERENCE_PATH = "dist/bundled/command-code-knowledge/reference/models.md" const CLI_BUNDLE_PATH = "dist/cli.mjs" const TEXT_ONLY_MARKER = ',__name(isKnownTextOnlyModel,"isKnownTextOnlyModel")' -const VALID_EFFORTS = new Set(["minimal", "low", "medium", "high", "xhigh", "max"]) +const VALID_EFFORTS = new Set(["off", "minimal", "low", "medium", "high", "xhigh", "max"]) function quoteWindowsArgument(argument: string): string { if (argument.length === 0) return '""' @@ -368,7 +368,7 @@ export function renderCommandCodeCatalog( ) .join("\n") - return `export const COMMAND_CODE_CLI_VERSION = ${quoted(packageVersion)}\n\nexport type CommandCodeInputType = "text" | "image"\nexport type CommandCodeReasoningEffort = "minimal" | "low" | "medium" | "high" | "xhigh" | "max"\n\n/**\n * Generated from command-code@${packageVersion} by \`npm run sync:commandcode-catalog\`.\n * Do not edit manually.\n */\nexport const MODEL_INPUT_MODALITIES: Readonly> = {\n${imageEntries}\n}\n\nexport const MODEL_REASONING: Readonly> = {\n${reasoningEntries}\n}\n\nexport const MODEL_EFFORTS: Readonly> = {\n${effortEntries}\n}\n\nexport const MODEL_MAX_OUTPUT_TOKENS: Readonly> = {\n${maxOutputEntries}\n}\n` + return `export const COMMAND_CODE_CLI_VERSION = ${quoted(packageVersion)}\n\nexport type CommandCodeInputType = "text" | "image"\nexport type CommandCodeReasoningEffort = "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max"\n\n/**\n * Generated from command-code@${packageVersion} by \`npm run sync:commandcode-catalog\`.\n * Do not edit manually.\n */\nexport const MODEL_INPUT_MODALITIES: Readonly> = {\n${imageEntries}\n}\n\nexport const MODEL_REASONING: Readonly> = {\n${reasoningEntries}\n}\n\nexport const MODEL_EFFORTS: Readonly> = {\n${effortEntries}\n}\n\nexport const MODEL_MAX_OUTPUT_TOKENS: Readonly> = {\n${maxOutputEntries}\n}\n` } function updateDocumentedCatalogVersion( diff --git a/.github/workflows/model-metadata.yml b/.github/workflows/model-metadata.yml index 33cccd1..855f5d1 100644 --- a/.github/workflows/model-metadata.yml +++ b/.github/workflows/model-metadata.yml @@ -15,6 +15,7 @@ on: - "src/cost.ts" - "src/models.ts" - "src/pricing.ts" + - "tests/fixtures/commandcode-pricing-page-haiku-5-5.html" - "tests/fixtures/commandcode-pricing-page.html" - "tests/test-model-metadata-check.ts" - "tests/test-models.ts" @@ -43,6 +44,7 @@ jobs: registry-url: https://registry.npmjs.org - run: npm ci - name: Compare with the latest Command Code CLI + shell: bash run: npm run check:commandcode-catalog | tee commandcode-catalog-report.md - name: Publish catalog report if: always() @@ -72,6 +74,7 @@ jobs: registry-url: https://registry.npmjs.org - run: npm ci - name: Synchronize with the latest Command Code CLI + shell: bash run: npm run sync:commandcode-catalog | tee commandcode-catalog-report.md - name: Format and verify synchronized files run: | diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a5e92c..17bb94e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +- Recognize the `off` reasoning effort now published for the DeepSeek V4 and V4.1 models, so the catalog parser no longer rejects it and the generate transport never forwards `off` as `reasoning_effort`. The Provider API and Oh My Pi adapters translate the level from the model's thinking metadata on their own wire. +- Refresh the static capability snapshot to `command-code@1.79.2`: add `claude-haiku-5-5`, `mistral/mistral-large-4` (image input, 262K output limit), and the free `stealth/glyph-cluster:free`; retire `stealth/pixel-canary` and `stealth/space-bunny-alpha`. +- Add reviewed display pricing for the refreshed catalog — `claude-haiku-5-5` with its 100K long-context tier, `mistral/mistral-large-4`, and the free `stealth/glyph-cluster:free` — drop the retired `stealth/space-bunny-alpha`, and correct the `claude-sonnet-5-5` cache-read rate to $0.10 per million tokens, verified against the official pricing page on 2026-10-09. The snapshot now covers all 87 advertised models. + ## 0.7.6 - 2026-10-06 - Correct the display input price for `stepfun/Step-3.5-Flash` to $0.09 per million tokens and add the `Qwen/Qwen3.6-Plus` long-context tier above 256K tokens, verified against the official pricing page on 2026-10-06. Mark the unchanged, expired `qwen-3.7-max-2x-usage` badge as reviewed in the pricing checker while keeping it visible in reports; changed deal terms and price drift still require review. diff --git a/README.md b/README.md index d89c455..3000228 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,7 @@ A model whose catalog entry omits `supported_endpoints` keeps Chat Completions, ### Reasoning support -Reasoning capability and selectable effort levels follow the official CLI catalog independently. Models can therefore be marked as reasoning-capable even when Command Code chooses their depth automatically. Models with explicit effort support register a model-specific `thinkingLevelMap`, so pi and OMP expose only valid levels. For a few reasoning models the CLI catalog ships no effort levels although the endpoint accepts `reasoning_effort`; `src/commandcode-catalog-overrides.ts` adds a manual level set for those (currently `meta/muse-spark-1.1`, `meta/muse-spark-1.2`, and `meta/muse-spark-1.2-contributor`) on top of the generated catalog. The catalog sync removes an override as soon as upstream publishes its own levels. Pi's native OpenAI- and Anthropic-compatible providers translate the selected level for Provider API accounts; the existing Command Code generate transport sends the matching `reasoning_effort` for Go accounts. +Reasoning capability and selectable effort levels follow the official CLI catalog independently. Models can therefore be marked as reasoning-capable even when Command Code chooses their depth automatically. Models with explicit effort support register a model-specific `thinkingLevelMap`, so pi and OMP expose only valid levels. For a few reasoning models the CLI catalog ships no effort levels although the endpoint accepts `reasoning_effort`; `src/commandcode-catalog-overrides.ts` adds a manual level set for those on top of the generated catalog (currently empty because upstream publishes every level). The catalog sync removes an override as soon as upstream publishes its own levels. Pi's native OpenAI- and Anthropic-compatible providers translate the selected level for Provider API accounts; the existing Command Code generate transport sends the matching `reasoning_effort` for Go accounts. List Command Code models from the terminal: @@ -151,7 +151,7 @@ The following environment variables are intended for tests, local mocks, and com ## Image input -The provider advertises image input only for models marked with the `image` input modality in the official Command Code CLI model catalog. The capability snapshot currently follows `command-code@1.72.4`; unknown models default to text-only until their upstream metadata is reviewed. A daily GitHub Actions job synchronizes the CLI version, image capabilities, reasoning flags, reasoning efforts, and model-specific output limits with the latest published CLI package, also dropping manual effort overrides that upstream has published itself, and opens or updates a reviewable pull request when they change. Pricing remains manually reviewed because temporary promotions and long-context tiers require explicit review. +The provider advertises image input only for models marked with the `image` input modality in the official Command Code CLI model catalog. The capability snapshot currently follows `command-code@1.79.2`; unknown models default to text-only until their upstream metadata is reviewed. A daily GitHub Actions job synchronizes the CLI version, image capabilities, reasoning flags, reasoning efforts, and model-specific output limits with the latest published CLI package, also dropping manual effort overrides that upstream has published itself, and opens or updates a reviewable pull request when they change. Pricing remains manually reviewed because temporary promotions and long-context tiers require explicit review. For vision-capable models, Pi's native provider adapters forward image blocks from user messages and tool results using the documented OpenAI or Anthropic message schema. Unknown and text-only models remain marked text-only in Pi. diff --git a/src/commandcode-catalog.ts b/src/commandcode-catalog.ts index 4885785..9f51328 100644 --- a/src/commandcode-catalog.ts +++ b/src/commandcode-catalog.ts @@ -1,16 +1,24 @@ -export const COMMAND_CODE_CLI_VERSION = "1.72.4" +export const COMMAND_CODE_CLI_VERSION = "1.79.2" export type CommandCodeInputType = "text" | "image" -export type CommandCodeReasoningEffort = "minimal" | "low" | "medium" | "high" | "xhigh" | "max" +export type CommandCodeReasoningEffort = + | "off" + | "minimal" + | "low" + | "medium" + | "high" + | "xhigh" + | "max" /** - * Generated from command-code@1.72.4 by `npm run sync:commandcode-catalog`. + * Generated from command-code@1.79.2 by `npm run sync:commandcode-catalog`. * Do not edit manually. */ export const MODEL_INPUT_MODALITIES: Readonly> = { "claude-fable-5": ["text", "image"], "claude-fable-5-1": ["text", "image"], "claude-haiku-4-5-20251001": ["text", "image"], + "claude-haiku-5-5": ["text", "image"], "claude-opus-4-7": ["text", "image"], "claude-opus-4-8": ["text", "image"], "claude-opus-5": ["text", "image"], @@ -44,6 +52,7 @@ export const MODEL_INPUT_MODALITIES: Readonly> = { "claude-fable-5": true, "claude-fable-5-1": true, + "claude-haiku-5-5": true, "claude-opus-4-7": true, "claude-opus-4-8": true, "claude-opus-5": true, @@ -117,6 +125,7 @@ export const MODEL_REASONING: Readonly> = { "meta/muse-spark-1.3": true, "meta/muse-spark-1.3-contributor": true, "MiniMaxAI/MiniMax-M3": true, + "mistral/mistral-large-4": true, "moonshotai/Kimi-K2.7-Code": true, "moonshotai/Kimi-K2.7-Code-Highspeed": true, "moonshotai/Kimi-K3": true, @@ -133,8 +142,7 @@ export const MODEL_REASONING: Readonly> = { "Qwen/Qwen3.8-Max-0902": true, "Qwen/Qwen3.8-Omni-Flash": true, "sakana/fugu-ultra": true, - "stealth/pixel-canary": true, - "stealth/space-bunny-alpha": true, + "stealth/glyph-cluster:free": true, "stepfun/Step-3.5-Flash": true, "stepfun/Step-3.7-Flash": true, "stepfun/Step-5-Preview": true, @@ -154,6 +162,7 @@ export const MODEL_REASONING: Readonly> = { export const MODEL_EFFORTS: Readonly> = { "claude-fable-5": ["low", "medium", "high", "xhigh", "max"], "claude-fable-5-1": ["low", "medium", "high", "xhigh", "max"], + "claude-haiku-5-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"], @@ -161,12 +170,12 @@ export const MODEL_EFFORTS: Readonly> = { "inclusionai/ling-3.0-flash-sante:free": 32_768, "inclusionai/ling-3.1-flash:free": 32_768, + "mistral/mistral-large-4": 262_144, "poolside/laguna-s-2.1-free": 32_768, "Qwen/Qwen3.8-27B": 32_768, "Qwen/Qwen3.8-Omni-Flash": 131_072, - "stealth/pixel-canary": 131_072, - "stealth/space-bunny-alpha": 524_288, + "stealth/glyph-cluster:free": 256_000, "z-ai/glm-5.3-flash": 131_072, "z-ai/glm-5.3-flashx": 131_072, } diff --git a/src/pricing.ts b/src/pricing.ts index 34d9f9e..5d327ff 100644 --- a/src/pricing.ts +++ b/src/pricing.ts @@ -20,7 +20,7 @@ export interface TemporaryPricing { } export const PRICING_SOURCE_URL = "https://commandcode.ai/docs/resources/pricing-limits" -export const PRICING_LAST_VERIFIED = "2026-10-06" +export const PRICING_LAST_VERIFIED = "2026-10-09" export const ZERO_MODEL_COST: CommandCodeModelCost = { input: 0, @@ -42,9 +42,10 @@ export const MODEL_COSTS: Readonly> = { "inclusionai/ling-3.0-flash-sante:free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "inclusionai/ling-3.1-flash:free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "poolside/laguna-s-2.1-free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, - "stealth/space-bunny-alpha": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, + "stealth/glyph-cluster:free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, // Open and open-weight models + "mistral/mistral-large-4": { input: 1.36, output: 4.18, cacheRead: 0.14, cacheWrite: 0 }, "tencent/hy3-paid": { input: 0.14, output: 0.58, cacheRead: 0.035, cacheWrite: 0 }, "tencent/hy4-preview": { input: 0.834, output: 2.501, cacheRead: 0.042, cacheWrite: 0 }, "moonshotai/Kimi-K3": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 0 }, @@ -207,7 +208,7 @@ export const MODEL_COSTS: Readonly> = { }, // Anthropic - "claude-sonnet-5-5": { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, + "claude-sonnet-5-5": { input: 2, output: 10, cacheRead: 0.1, cacheWrite: 2.5 }, "claude-sonnet-5": { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, "claude-sonnet-4-6": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, "claude-fable-5-1": { input: 10, output: 50, cacheRead: 0.25, cacheWrite: 12.5 }, @@ -216,6 +217,21 @@ export const MODEL_COSTS: Readonly> = { "claude-opus-5": { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, "claude-opus-4-8": { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, "claude-opus-4-7": { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, + "claude-haiku-5-5": { + input: 0.1, + output: 0.5, + cacheRead: 0.01, + cacheWrite: 0.125, + tiers: [ + { + inputTokensAbove: 100_000, + input: 0.5, + output: 2.5, + cacheRead: 0.05, + cacheWrite: 0.625, + }, + ], + }, "claude-haiku-4-5-20251001": { input: 1, output: 5, diff --git a/tests/fixtures/commandcode-model-ids.json b/tests/fixtures/commandcode-model-ids.json index 5027738..f48d54a 100644 --- a/tests/fixtures/commandcode-model-ids.json +++ b/tests/fixtures/commandcode-model-ids.json @@ -1,5 +1,5 @@ { - "fetchedAt": "2026-10-05T19:58:38.015Z", + "fetchedAt": "2026-10-09T06:21:21.675Z", "source": "https://api.commandcode.ai/provider/v1/models", "modelIds": [ "claude-sonnet-5-5", @@ -11,6 +11,7 @@ "claude-opus-5", "claude-opus-4-8", "claude-opus-4-7", + "claude-haiku-5-5", "claude-haiku-4-5-20251001", "gpt-6-astra", "gpt-6.1-sol", @@ -75,7 +76,7 @@ "nvidia/nemotron-3-ultra-550b-a55b", "thinkingmachines/inkling", "thinkingmachines/inkling-small", - "stealth/space-bunny-alpha", + "stealth/glyph-cluster:free", "poolside/laguna-s-2.1-free", "inclusionai/ling-3.0-flash-sante:free", "inclusionai/ling-3.1-flash:free", @@ -86,6 +87,7 @@ "meta/muse-spark-1.3-contributor", "xai/grok-4.5", "xai/grok-4.6", - "xai/grok-4.7" + "xai/grok-4.7", + "mistral/mistral-large-4" ] } diff --git a/tests/fixtures/commandcode-pricing-page-haiku-5-5.html b/tests/fixtures/commandcode-pricing-page-haiku-5-5.html new file mode 100644 index 0000000..411629a --- /dev/null +++ b/tests/fixtures/commandcode-pricing-page-haiku-5-5.html @@ -0,0 +1,8 @@ + + diff --git a/tests/fixtures/commandcode-pricing.json b/tests/fixtures/commandcode-pricing.json index 4924630..03b0ef0 100644 --- a/tests/fixtures/commandcode-pricing.json +++ b/tests/fixtures/commandcode-pricing.json @@ -1,5 +1,5 @@ { - "verifiedAt": "2026-10-06", + "verifiedAt": "2026-10-09", "source": "https://commandcode.ai/docs/resources/pricing-limits", "tierPolicy": "Use request-wide input tiers; the highest threshold exceeded by input plus cache tokens applies to the full request.", "tiers": { @@ -9,6 +9,7 @@ [256000, 0.2, 0.8, 0.04, 0.25] ], "Qwen/Qwen3.6-Plus": [[256000, 2, 6, 0.2, 0]], + "claude-haiku-5-5": [[100000, 0.5, 2.5, 0.05, 0.625]], "gpt-6-astra": [[272000, 20, 75, 2, 25]], "gpt-6.1-sol": [[272000, 4, 15, 0.2, 5]], "gpt-6-sol": [[272000, 4, 15, 0.4, 5]], @@ -23,7 +24,8 @@ "inclusionai/ling-3.0-flash-sante:free": [0, 0, 0, 0], "inclusionai/ling-3.1-flash:free": [0, 0, 0, 0], "poolside/laguna-s-2.1-free": [0, 0, 0, 0], - "stealth/space-bunny-alpha": [0, 0, 0, 0], + "stealth/glyph-cluster:free": [0, 0, 0, 0], + "mistral/mistral-large-4": [1.36, 4.18, 0.14, 0], "tencent/hy3-paid": [0.14, 0.58, 0.035, 0], "tencent/hy4-preview": [0.834, 2.501, 0.042, 0], "moonshotai/Kimi-K3": [3, 15, 0.3, 0], @@ -75,7 +77,7 @@ "meta/muse-spark-1.3": [1.25, 4.25, 0.15, 0], "meta/muse-spark-1.2-contributor": [0.1, 0.2, 0.002, 0], "meta/muse-spark-1.3-contributor": [0.1, 0.2, 0.002, 0], - "claude-sonnet-5-5": [2, 10, 0.2, 2.5], + "claude-sonnet-5-5": [2, 10, 0.1, 2.5], "claude-sonnet-5": [2, 10, 0.2, 2.5], "claude-sonnet-4-6": [3, 15, 0.3, 3.75], "claude-fable-5-1": [10, 50, 0.25, 12.5], @@ -84,6 +86,7 @@ "claude-opus-5": [5, 25, 0.5, 6.25], "claude-opus-4-8": [5, 25, 0.5, 6.25], "claude-opus-4-7": [5, 25, 0.5, 6.25], + "claude-haiku-5-5": [0.1, 0.5, 0.01, 0.125], "claude-haiku-4-5-20251001": [1, 5, 0.1, 1.25], "gpt-6-astra": [10, 50, 1, 12.5], "gpt-6.1-sol": [2, 10, 0.1, 2.5], diff --git a/tests/test-model-metadata-check.ts b/tests/test-model-metadata-check.ts index 00e9b47..3c07513 100644 --- a/tests/test-model-metadata-check.ts +++ b/tests/test-model-metadata-check.ts @@ -140,7 +140,7 @@ describe("Command Code model metadata checker", () => { `export const COMMAND_CODE_CLI_VERSION = "1.33.0" export type CommandCodeInputType = "text" | "image" -export type CommandCodeReasoningEffort = "minimal" | "low" | "medium" | "high" | "xhigh" | "max" +export type CommandCodeReasoningEffort = "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max" /** * Generated from command-code@1.33.0 by \`npm run sync:commandcode-catalog\`. diff --git a/tests/test-models.ts b/tests/test-models.ts index 342c733..e66a492 100644 --- a/tests/test-models.ts +++ b/tests/test-models.ts @@ -265,7 +265,7 @@ describe("commandCodeModelsFromApiResponse()", () => { }) it(`uses the command-code@${COMMAND_CODE_CLI_VERSION} reasoning effort catalog`, () => { - const validEfforts = new Set(["minimal", "low", "medium", "high", "xhigh", "max"]) + const validEfforts = new Set(["off", "minimal", "low", "medium", "high", "xhigh", "max"]) assert.ok(Object.keys(MODEL_EFFORTS).length > 0) for (const efforts of Object.values(MODEL_EFFORTS)) { assert.ok(efforts.length > 0) @@ -275,7 +275,7 @@ describe("commandCodeModelsFromApiResponse()", () => { }) it("merges manual effort overrides over the generated catalog", () => { - const validEfforts = new Set(["minimal", "low", "medium", "high", "xhigh", "max"]) + const validEfforts = new Set(["off", "minimal", "low", "medium", "high", "xhigh", "max"]) // An empty override map is the healthy end state once upstream publishes every // level, so asserting it is non-empty made that state unreachable. for (const [modelId, efforts] of Object.entries(MODEL_EFFORT_OVERRIDES)) { diff --git a/tests/test-pricing-check.ts b/tests/test-pricing-check.ts index 2e467d0..b611603 100644 --- a/tests/test-pricing-check.ts +++ b/tests/test-pricing-check.ts @@ -16,6 +16,11 @@ import { MODEL_COSTS, PRICING_SOURCE_URL, type CommandCodeModelCost } from "../s const fixtureUrl = new URL("./fixtures/commandcode-pricing-page.html", import.meta.url) const fixtureHtml = await readFile(fixtureUrl, "utf-8") +const haikuFixtureUrl = new URL( + "./fixtures/commandcode-pricing-page-haiku-5-5.html", + import.meta.url, +) +const haikuFixtureHtml = await readFile(haikuFixtureUrl, "utf-8") const AT_MS = Date.UTC(2026, 9, 5, 12, 0, 0) const SUPPORTED_WINDOWS = "01–04 & 06–10 UTC, Mon–Fri" @@ -169,6 +174,36 @@ describe("parsePricingPage with the live snapshot fixture", () => { }) }) +describe("parsePricingPage with the claude-haiku-5-5 fixture", () => { + const rows = parsePricingPage(haikuFixtureHtml) + + it("extracts the labelled ≤100K / >100K bands", () => { + const row = findRow(rows, "claude-haiku-5-5") + assert.deepEqual(ratesJson(row.cost), { + input: 0.1, + output: 0.5, + cacheRead: 0.01, + cacheWrite: 0.125, + }) + assert.deepEqual(row.cost.tiers, [ + { + inputTokensAbove: 100_000, + input: 0.5, + output: 2.5, + cacheRead: 0.05, + cacheWrite: 0.625, + }, + ]) + }) + + it("agrees with the runtime pricing policy for claude-haiku-5-5", () => { + // Compare the fixture against the real runtime costs (not the fixture's own + // parsed cost) so a drift between the two would actually fail. + const result = checkCommandCodePricing(["claude-haiku-5-5"], rows, MODEL_COSTS, AT_MS) + assert.deepEqual(result.issues, []) + }) +}) + describe("parsePricingPage shape handling", () => { it("accepts script end tags with HTML whitespace", () => { const page = pageWithRows([{ id: "m", tiers: [{ rates: { input: 1, output: 2 } }] }]) diff --git a/tests/test-pricing.ts b/tests/test-pricing.ts index 8fb01c1..8e657d6 100644 --- a/tests/test-pricing.ts +++ b/tests/test-pricing.ts @@ -29,7 +29,7 @@ const pricingFixtureUrl = new URL("./fixtures/commandcode-pricing.json", import. const pricingFixture = JSON.parse(await readFile(pricingFixtureUrl, "utf-8")) as PricingSnapshot const freeModels = new Set([ "poolside/laguna-s-2.1-free", - "stealth/space-bunny-alpha", + "stealth/glyph-cluster:free", "inclusionai/ling-3.0-flash-sante:free", "inclusionai/ling-3.1-flash:free", ]) @@ -55,7 +55,7 @@ function assertCost( describe("MODEL_COSTS pricing overlay", () => { it("covers the current Command Code model catalog snapshot", () => { assert.equal(fixture.source, "https://api.commandcode.ai/provider/v1/models") - assert.match(fixture.fetchedAt, /^2026-10-05T/) + assert.match(fixture.fetchedAt, /^2026-10-09T/) const catalogIds = [...fixture.modelIds].sort() const pricedIds = Object.keys(MODEL_COSTS).sort() @@ -293,9 +293,36 @@ describe("MODEL_COSTS pricing overlay", () => { assertCost("claude-sonnet-5-5", { input: 2, output: 10, - cacheRead: 0.2, + cacheRead: 0.1, cacheWrite: 2.5, }) + assertCost("claude-haiku-5-5", { + input: 0.1, + output: 0.5, + cacheRead: 0.01, + cacheWrite: 0.125, + }) + assert.deepEqual(MODEL_COSTS["claude-haiku-5-5"]?.tiers, [ + { + inputTokensAbove: 100_000, + input: 0.5, + output: 2.5, + cacheRead: 0.05, + cacheWrite: 0.625, + }, + ]) + assertCost("mistral/mistral-large-4", { + input: 1.36, + output: 4.18, + cacheRead: 0.14, + cacheWrite: 0, + }) + assertCost("stealth/glyph-cluster:free", { + input: 0, + output: 0, + cacheRead: 0, + cacheWrite: 0, + }) assertCost("gpt-6.1-sol", { input: 2, output: 10, cacheRead: 0.1, cacheWrite: 2.5 }) assert.deepEqual(MODEL_COSTS["gpt-6.1-sol"]?.tiers, [ { @@ -322,7 +349,7 @@ describe("MODEL_COSTS pricing overlay", () => { it("tracks pricing provenance", () => { assert.equal(PRICING_SOURCE_URL, "https://commandcode.ai/docs/resources/pricing-limits") - assert.equal(PRICING_LAST_VERIFIED, "2026-10-06") + assert.equal(PRICING_LAST_VERIFIED, "2026-10-09") }) it("fails once temporary pricing needs review", () => { diff --git a/tests/test-stream.ts b/tests/test-stream.ts index 9a3486e..b320206 100644 --- a/tests/test-stream.ts +++ b/tests/test-stream.ts @@ -8,7 +8,11 @@ import { after, before, beforeEach, describe, it } from "node:test" import { COMMAND_CODE_CLI_VERSION } from "../src/commandcode-catalog.ts" import type { AssistantMessageEvent } from "../src/core.ts" -import { MODEL_EFFORTS, thinkingLevelMapForEfforts } from "../src/models.ts" +import { + MODEL_EFFORTS, + thinkingLevelMapForEfforts, + thinkingMetadataForModel, +} from "../src/models.ts" import { collectEvents, createTestDeps, @@ -953,10 +957,15 @@ describe("streamCommandCode — request serialization", () => { }) it("omits reasoning_effort for off, unsupported, and unknown reasoning levels", async () => { + // Build from the canonical metadata so this pins the `thinking.effortMap` + // path that `mappedReasoningEffort` prefers, not only the legacy + // `thinkingLevelMap` fallback exercised above. + const metadata = thinkingMetadataForModel("deepseek/deepseek-v4-flash") + assert.ok(metadata, "deepseek-v4-flash should have reasoning metadata") const model = makeModel({ id: "deepseek/deepseek-v4-flash", reasoning: true, - thinkingLevelMap: thinkingLevelMapForEfforts(MODEL_EFFORTS["deepseek/deepseek-v4-flash"]), + ...metadata, }) for (const reasoning of ["off", "low"] as const) {