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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

## Unreleased

- Add DeepSeek V4.1 Flash with image input, reasoning efforts, and display pricing, and InclusionAI Ling 3.0 Flash Sante with reasoning, a 32K output limit, and free pricing; refresh the generated capability catalog to `command-code@1.53.0`.
- Refresh model capabilities to `command-code@1.50.0`, adding GPT-6 Astra reasoning/image support and Grok 4.6 image support; replace Muse Spark manual efforts with published upstream levels.
- Verify pricing coverage for all 68 website-listed models and refresh regression tests, retaining Astra pricing while it is absent from the live Provider API catalog.
- Fixing zero-cost calculation (#83).

## 0.6.4 - 2026-09-03

- Refresh the generated Command Code capability catalog from `command-code@1.40.1` to `command-code@1.44.0`, adding current image-input, reasoning, effort, and output-limit metadata for newly published models.
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,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.44.0`; 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 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.53.0`; 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 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.

Expand Down
10 changes: 1 addition & 9 deletions src/commandcode-catalog-overrides.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,4 @@ import type { CommandCodeReasoningEffort } from "./commandcode-catalog.ts"
*/
export const MODEL_EFFORT_OVERRIDES: Readonly<
Record<string, readonly CommandCodeReasoningEffort[]>
> = {
// Meta Muse Spark: the CLI ships no effort levels, but the endpoint accepts
// `reasoning_effort` for these models and other hosts expose the same set.
"meta/muse-spark-1.1": ["minimal", "low", "medium", "high", "xhigh"],
"meta/muse-spark-1.2": ["minimal", "low", "medium", "high", "xhigh"],
"meta/muse-spark-1.2-contributor": ["minimal", "low", "medium", "high", "xhigh"],
"meta/muse-spark-1.3": ["minimal", "low", "medium", "high", "xhigh"],
"meta/muse-spark-1.3-contributor": ["minimal", "low", "medium", "high", "xhigh"],
}
> = {}
19 changes: 17 additions & 2 deletions src/commandcode-catalog.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
export const COMMAND_CODE_CLI_VERSION = "1.44.0"
export const COMMAND_CODE_CLI_VERSION = "1.53.0"

export type CommandCodeInputType = "text" | "image"
export type CommandCodeReasoningEffort = "minimal" | "low" | "medium" | "high" | "xhigh" | "max"

/**
* Generated from command-code@1.44.0 by `npm run sync:commandcode-catalog`.
* Generated from command-code@1.53.0 by `npm run sync:commandcode-catalog`.
* Do not edit manually.
*/
export const MODEL_INPUT_MODALITIES: Readonly<Record<string, readonly CommandCodeInputType[]>> = {
Expand All @@ -17,6 +17,7 @@ export const MODEL_INPUT_MODALITIES: Readonly<Record<string, readonly CommandCod
"claude-sonnet-4-6": ["text", "image"],
"claude-sonnet-5": ["text", "image"],
"deepseek/deepseek-v4-flash-vision-exp": ["text", "image"],
"deepseek/deepseek-v4.1-flash": ["text", "image"],
"google/gemini-3.1-flash-lite": ["text", "image"],
"google/gemini-3.5-flash": ["text", "image"],
"google/gemini-3.5-flash-lite": ["text", "image"],
Expand All @@ -30,6 +31,7 @@ export const MODEL_INPUT_MODALITIES: Readonly<Record<string, readonly CommandCod
"gpt-5.6-luna": ["text", "image"],
"gpt-5.6-sol": ["text", "image"],
"gpt-5.6-terra": ["text", "image"],
"gpt-6-astra": ["text", "image"],
"meta/muse-spark-1.1": ["text", "image"],
"meta/muse-spark-1.2": ["text", "image"],
"meta/muse-spark-1.2-contributor": ["text", "image"],
Expand All @@ -53,6 +55,7 @@ export const MODEL_INPUT_MODALITIES: Readonly<Record<string, readonly CommandCod
"thinkingmachines/inkling": ["text", "image"],
"thinkingmachines/inkling-small": ["text", "image"],
"xai/grok-4.5": ["text", "image"],
"xai/grok-4.6": ["text", "image"],
"xiaomi/mimo-v2.5": ["text", "image"],
"z-ai/glm-5.3-flash": ["text", "image"],
}
Expand All @@ -69,6 +72,7 @@ export const MODEL_REASONING: Readonly<Record<string, true>> = {
"deepseek/deepseek-v4-flash-fast": true,
"deepseek/deepseek-v4-flash-vision-exp": true,
"deepseek/deepseek-v4-pro": true,
"deepseek/deepseek-v4.1-flash": true,
"google/gemini-3.1-flash-lite": true,
"google/gemini-3.5-flash": true,
"google/gemini-3.5-flash-lite": true,
Expand All @@ -82,6 +86,8 @@ export const MODEL_REASONING: Readonly<Record<string, true>> = {
"gpt-5.6-luna": true,
"gpt-5.6-sol": true,
"gpt-5.6-terra": true,
"gpt-6-astra": true,
"inclusionai/ling-3.0-flash-sante:free": true,
"meituan/LongCat-2.0:free": true,
"meta/muse-spark-1.1": true,
"meta/muse-spark-1.2": true,
Expand Down Expand Up @@ -129,6 +135,7 @@ export const MODEL_EFFORTS: Readonly<Record<string, readonly CommandCodeReasonin
"deepseek/deepseek-v4-flash-fast": ["low", "high", "max"],
"deepseek/deepseek-v4-flash-vision-exp": ["high", "max"],
"deepseek/deepseek-v4-pro": ["high", "max"],
"deepseek/deepseek-v4.1-flash": ["low", "high", "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"],
Expand All @@ -142,6 +149,13 @@ export const MODEL_EFFORTS: Readonly<Record<string, readonly CommandCodeReasonin
"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"],
"gpt-6-astra": ["low", "medium", "high", "xhigh", "max"],
"meta/muse-spark-1.1": ["low", "medium", "high", "xhigh"],
"meta/muse-spark-1.2": ["low", "medium", "high", "xhigh"],
"meta/muse-spark-1.2-contributor": ["low", "medium", "high", "xhigh"],
"meta/muse-spark-1.3": ["low", "medium", "high", "xhigh", "max"],
"meta/muse-spark-1.3-contributor": ["low", "medium", "high", "xhigh"],
"MiniMaxAI/MiniMax-M3": ["low", "medium", "high"],
"moonshotai/Kimi-K3": ["low", "high", "max"],
"Qwen/Qwen3.8-27B": ["low", "medium", "xhigh"],
"Qwen/Qwen3.8-Flash": ["low", "medium", "xhigh"],
Expand All @@ -157,6 +171,7 @@ export const MODEL_EFFORTS: Readonly<Record<string, readonly CommandCodeReasonin
}

export const MODEL_MAX_OUTPUT_TOKENS: Readonly<Record<string, number>> = {
"inclusionai/ling-3.0-flash-sante:free": 32_768,
"poolside/laguna-s-2.1-free": 32_768,
"Qwen/Qwen3.8-27B": 32_768,
"z-ai/glm-5.3-flash": 131_072,
Expand Down
34 changes: 33 additions & 1 deletion src/pricing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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-09-01"
export const PRICING_LAST_VERIFIED = "2026-09-11"

export const ZERO_MODEL_COST: CommandCodeModelCost = {
input: 0,
Expand All @@ -40,6 +40,8 @@ export const ZERO_MODEL_COST: CommandCodeModelCost = {
export const MODEL_COSTS: Readonly<Record<string, CommandCodeModelCost>> = {
// Free models
"poolside/laguna-s-2.1-free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
"meituan/LongCat-2.0:free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
"inclusionai/ling-3.0-flash-sante:free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },

// Open and open-weight models
"tencent/hy3-paid": { input: 0.14, output: 0.58, cacheRead: 0.035, cacheWrite: 0 },
Expand Down Expand Up @@ -89,7 +91,14 @@ export const MODEL_COSTS: Readonly<Record<string, CommandCodeModelCost>> = {
cacheRead: 0.07,
cacheWrite: 0,
},
"deepseek/deepseek-v4.1-flash": {
input: 0.15,
output: 0.6,
cacheRead: 0.003,
cacheWrite: 0,
},
"Qwen/Qwen3.8-Max": { input: 2, output: 6, cacheRead: 0.25, cacheWrite: 2.5 },
"Qwen/Qwen3.8-Max-0902": { input: 2, output: 6, cacheRead: 0.25, cacheWrite: 0 },
"Qwen/Qwen3.8-27B": { input: 0.4, output: 3, cacheRead: 0.04, cacheWrite: 0 },
"Qwen/Qwen3.8-Flash": { input: 0.16, output: 0.47, cacheRead: 0.016, cacheWrite: 0 },
"Qwen/Qwen3.7-Max": { input: 2.5, output: 7.5, cacheRead: 0.5, cacheWrite: 3.13 },
Expand Down Expand Up @@ -164,6 +173,13 @@ export const MODEL_COSTS: Readonly<Record<string, CommandCodeModelCost>> = {
cacheRead: 0.002,
cacheWrite: 0,
},
"meta/muse-spark-1.3": { input: 1.25, output: 4.25, cacheRead: 0.15, cacheWrite: 0 },
"meta/muse-spark-1.3-contributor": {
input: 0.1,
output: 0.2,
cacheRead: 0.002,
cacheWrite: 0,
},

// Anthropic
"claude-sonnet-5": { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 },
Expand All @@ -181,6 +197,21 @@ export const MODEL_COSTS: Readonly<Record<string, CommandCodeModelCost>> = {
},

// OpenAI
"gpt-6-astra": {
input: 10,
output: 50,
cacheRead: 1,
cacheWrite: 12.5,
tiers: [
{
inputTokensAbove: 272_000,
input: 20,
output: 75,
cacheRead: 2,
cacheWrite: 12.5,
},
],
},
"gpt-5.6-sol": { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 6.25 },
"gpt-5.6-terra": { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 2.5 },
"gpt-5.6-luna": { input: 0.2, output: 1.2, cacheRead: 0.02, cacheWrite: 0.25 },
Expand All @@ -190,6 +221,7 @@ export const MODEL_COSTS: Readonly<Record<string, CommandCodeModelCost>> = {
"gpt-5.4-mini": { input: 0.75, output: 4.5, cacheRead: 0.075, cacheWrite: 0 },

// Google and xAI
"google/gemini-3.8-flash": { input: 1.5, output: 7.5, cacheRead: 0.15, cacheWrite: 0 },
"google/gemini-3.7-flash": {
input: 1.5,
output: 7.5,
Expand Down
9 changes: 8 additions & 1 deletion tests/fixtures/commandcode-model-ids.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"fetchedAt": "2026-09-01T21:28:23.974Z",
"fetchedAt": "2026-09-11T14:04:54.920Z",
"source": "https://api.commandcode.ai/provider/v1/models",
"modelIds": [
"claude-sonnet-5",
Expand All @@ -21,6 +21,7 @@
"deepseek/deepseek-v4-flash",
"deepseek/deepseek-v4-flash-vision-exp",
"deepseek/deepseek-v4-flash-fast",
"deepseek/deepseek-v4.1-flash",
"moonshotai/Kimi-K3",
"moonshotai/Kimi-K2.7-Code",
"moonshotai/Kimi-K2.7-Code-Highspeed",
Expand All @@ -37,6 +38,7 @@
"MiniMaxAI/MiniMax-M2.5",
"xiaomi/mimo-v2.5-pro",
"xiaomi/mimo-v2.5",
"Qwen/Qwen3.8-Max-0902",
"Qwen/Qwen3.8-Max",
"Qwen/Qwen3.8-27B",
"Qwen/Qwen3.8-Flash",
Expand All @@ -45,10 +47,12 @@
"Qwen/Qwen3.7-Flash",
"Qwen/Qwen3.6-Max-Preview",
"Qwen/Qwen3.6-Plus",
"meituan/LongCat-2.0:free",
"stepfun/Step-3.7-Flash",
"stepfun/Step-3.5-Flash",
"tencent/hy3-paid",
"tencent/hy4-preview",
"google/gemini-3.8-flash",
"google/gemini-3.7-flash",
"google/gemini-3.6-flash",
"google/gemini-3.5-flash",
Expand All @@ -59,9 +63,12 @@
"thinkingmachines/inkling",
"thinkingmachines/inkling-small",
"poolside/laguna-s-2.1-free",
"inclusionai/ling-3.0-flash-sante:free",
"meta/muse-spark-1.1",
"meta/muse-spark-1.2",
"meta/muse-spark-1.2-contributor",
"meta/muse-spark-1.3",
"meta/muse-spark-1.3-contributor",
"xai/grok-4.5",
"xai/grok-4.6"
]
Expand Down
11 changes: 10 additions & 1 deletion tests/fixtures/commandcode-pricing.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"verifiedAt": "2026-09-01",
"verifiedAt": "2026-09-11",
"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": {
Expand All @@ -8,10 +8,13 @@
[32000, 0.1, 0.4, 0.02, 0.125],
[256000, 0.2, 0.8, 0.04, 0.25]
],
"gpt-6-astra": [[272000, 20, 75, 2, 12.5]],
"xai/grok-4.6": [[200000, 4, 12, 1, 0]]
},
"costs": {
"poolside/laguna-s-2.1-free": [0, 0, 0, 0],
"meituan/LongCat-2.0:free": [0, 0, 0, 0],
"inclusionai/ling-3.0-flash-sante:free": [0, 0, 0, 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],
Expand All @@ -32,7 +35,9 @@
"deepseek/deepseek-v4-flash": [0.22, 0.66, 0.007, 0],
"deepseek/deepseek-v4-flash-vision-exp": [0.22, 0.66, 0.007, 0],
"deepseek/deepseek-v4-flash-fast": [0.28, 0.56, 0.07, 0],
"deepseek/deepseek-v4.1-flash": [0.15, 0.6, 0.003, 0],
"Qwen/Qwen3.8-Max": [2, 6, 0.25, 2.5],
"Qwen/Qwen3.8-Max-0902": [2, 6, 0.25, 0],
"Qwen/Qwen3.8-27B": [0.4, 3, 0.04, 0],
"Qwen/Qwen3.8-Flash": [0.16, 0.47, 0.016, 0],
"Qwen/Qwen3.7-Max": [2.5, 7.5, 0.5, 3.13],
Expand All @@ -51,6 +56,8 @@
"meta/muse-spark-1.1": [1.25, 4.25, 0.15, 0],
"meta/muse-spark-1.2": [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": [1.25, 4.25, 0.15, 0],
"meta/muse-spark-1.3-contributor": [0.1, 0.2, 0.002, 0],
"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],
Expand All @@ -59,13 +66,15 @@
"claude-opus-4-8": [5, 25, 0.5, 6.25],
"claude-opus-4-7": [5, 25, 0.5, 6.25],
"claude-haiku-4-5-20251001": [1, 5, 0.1, 1.25],
"gpt-6-astra": [10, 50, 1, 12.5],
"gpt-5.6-sol": [5, 30, 0.5, 6.25],
"gpt-5.6-terra": [2, 12, 0.2, 2.5],
"gpt-5.6-luna": [0.2, 1.2, 0.02, 0.25],
"gpt-5.5": [5, 30, 0.5, 0],
"gpt-5.4": [2.5, 15, 0.25, 0],
"gpt-5.3-codex": [2, 8, 0.5, 0],
"gpt-5.4-mini": [0.75, 4.5, 0.075, 0],
"google/gemini-3.8-flash": [1.5, 7.5, 0.15, 0],
"google/gemini-3.7-flash": [1.5, 7.5, 0.15, 0.08334],
"google/gemini-3.6-flash": [1.5, 7.5, 0.15, 0],
"google/gemini-3.5-flash": [1.5, 9, 0.15, 0],
Expand Down
24 changes: 23 additions & 1 deletion tests/test-models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,29 @@ describe("commandCodeModelsFromApiResponse()", () => {
assert.equal(modelSupportsImageInput("unknown-new-model"), false)
})

it("includes newly published image and reasoning capabilities", () => {
for (const modelId of ["gpt-6-astra", "xai/grok-4.6"]) {
assert.deepEqual(inputModalitiesForModel(modelId), ["text", "image"])
}
assert.equal(MODEL_REASONING["gpt-6-astra"], true)
assert.deepEqual(MODEL_EFFORTS["gpt-6-astra"], ["low", "medium", "high", "xhigh", "max"])
for (const modelId of [
"meta/muse-spark-1.1",
"meta/muse-spark-1.2",
"meta/muse-spark-1.2-contributor",
"meta/muse-spark-1.3-contributor",
]) {
assert.deepEqual(MODEL_EFFORTS[modelId], ["low", "medium", "high", "xhigh"])
}
assert.deepEqual(MODEL_EFFORTS["meta/muse-spark-1.3"], [
"low",
"medium",
"high",
"xhigh",
"max",
])
})

it("tracks reasoning independently from selectable effort levels", () => {
const reasoningModels = Object.keys(MODEL_REASONING)
const effortModels = Object.keys(MODEL_EFFORTS)
Expand Down Expand Up @@ -198,7 +221,6 @@ describe("commandCodeModelsFromApiResponse()", () => {

it("merges manual effort overrides over the generated catalog", () => {
const validEfforts = new Set(["minimal", "low", "medium", "high", "xhigh", "max"])
assert.ok(Object.keys(MODEL_EFFORT_OVERRIDES).length > 0)
for (const [modelId, efforts] of Object.entries(MODEL_EFFORT_OVERRIDES)) {
assert.equal(MODEL_REASONING[modelId], true, `${modelId} override needs a reasoning flag`)
assert.equal(
Expand Down
Loading