opencode-cmd-provider 1.5.0 → 1.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +65 -0
- package/README.md +9 -4
- package/dist/src/catalog/facts.d.ts +4 -4
- package/dist/src/catalog/facts.js +14 -8
- package/dist/src/catalog/snapshot.js +4 -1
- package/dist/src/deals/catalog.d.ts +1 -1
- package/dist/src/deals/catalog.js +6 -3
- package/dist/src/plugin/models.js +8 -2
- package/dist/src/provider/pricing.d.ts +7 -0
- package/dist/src/provider/pricing.js +13 -0
- package/dist/src/provider/reasoning.js +1 -1
- package/dist/src/provider/stream.js +120 -14
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,70 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.5.2 - 2026-08-28
|
|
4
|
+
|
|
5
|
+
Chore: catalog refresh to `command-code@1.36.0`, with a deals-coverage gate
|
|
6
|
+
fix for name-colliding free variants.
|
|
7
|
+
|
|
8
|
+
- Added `z-ai/glm-5.3-flash` (GLM-5.3 Flash) and `Qwen/Qwen3.8-Flash` with
|
|
9
|
+
deals records; removed `stealth/ox-alpha` (dropped from the upstream
|
|
10
|
+
catalog).
|
|
11
|
+
- MiniMax free variants (`minimax/minimax-m3-free`,
|
|
12
|
+
`minimax/minimax-m2.7-free`) now append `(free)` to their picker display
|
|
13
|
+
name — upstream renamed them to share the paid display name — derived
|
|
14
|
+
data-driven from the zero-cost table, with updated deal allowance pricing
|
|
15
|
+
for `deepseek/deepseek-v4-flash-vision-exp`.
|
|
16
|
+
- The deals-coverage gate now iterates every snapshot entry by id, so free
|
|
17
|
+
variants whose display names collide with paid siblings are actually
|
|
18
|
+
coverage-checked (a fixture that silently dropped them previously passed
|
|
19
|
+
with exit 0 and emitted a partial deals catalog); a shared
|
|
20
|
+
`scripts/snapshot-index.mjs` parser replaced the duplicated regex parsing.
|
|
21
|
+
|
|
22
|
+
### Fixes
|
|
23
|
+
|
|
24
|
+
- **Deals-coverage gate**: `check-deals-coverage.mjs` and the
|
|
25
|
+
`missingDealsModels` check in `refresh-deals.mjs` iterated a first-wins
|
|
26
|
+
name→id map, so MiniMax free variants — whose snapshot display names
|
|
27
|
+
collide with their paid siblings — were never actually checked. Both gates
|
|
28
|
+
now iterate by id, with the name fallback applying only to unambiguous
|
|
29
|
+
names; records that resolve to no snapshot id are skipped instead of
|
|
30
|
+
collapsing under `undefined`.
|
|
31
|
+
- Catalog refresh to `command-code@1.33.0` added the MiniMax free variants;
|
|
32
|
+
the `1.36.0` refresh added GLM-5.3 Flash and Qwen 3.8 Flash, dropped Ox
|
|
33
|
+
Alpha, and extended `src/plugin/models.ts` with the zero-cost `(free)`
|
|
34
|
+
suffix. The extended pricing import now fits the print width again
|
|
35
|
+
(`format:check` passes).
|
|
36
|
+
|
|
37
|
+
### Chores
|
|
38
|
+
|
|
39
|
+
- New `tests/deals-coverage.test.ts` regression cases: removed free variants
|
|
40
|
+
now fail the gate; deals free flag ⇔ facts zero-cost table consistency;
|
|
41
|
+
negative suffix test (absent cost entry must not get `(free)`).
|
|
42
|
+
- README documents the `(free)` suffix and its zero-cost derivation.
|
|
43
|
+
|
|
44
|
+
## 1.5.1 - 2026-08-24
|
|
45
|
+
|
|
46
|
+
Fix: provider parsers now synthesize the full reasoning and text lifecycle —
|
|
47
|
+
`reasoning-start`/`reasoning-end` and `text-start`/`text-end` — for both
|
|
48
|
+
OpenAI-style and Anthropic-style streams, so AI SDK consumers see balanced
|
|
49
|
+
section boundaries instead of missing or duplicated end events.
|
|
50
|
+
|
|
51
|
+
### Fixes
|
|
52
|
+
|
|
53
|
+
- **OpenAI-style streams** now emit `reasoning-start` before the first
|
|
54
|
+
reasoning delta and `reasoning-end` before text, tool calls, or finish; the
|
|
55
|
+
same for `text-start`/`text-end`. Reasoning and text sections use stable ids
|
|
56
|
+
from the first chunk (instead of per-chunk ids), and unfinished sections are
|
|
57
|
+
closed when the stream finishes.
|
|
58
|
+
- **Anthropic-style streams** now recognize `thinking` blocks and emit
|
|
59
|
+
`reasoning-start`/`reasoning-delta`/`reasoning-end` for them. `content_block_stop`
|
|
60
|
+
closes each block with the correct end event per its type (`text-end`,
|
|
61
|
+
`reasoning-end`, or `tool-input-end` + a single `tool-call`), replacing the
|
|
62
|
+
previous "emit both text-end and tool-input-end" pair that left consumers to
|
|
63
|
+
ignore the spurious one.
|
|
64
|
+
- New `tests/stream.test.ts` cases cover the OpenAI reasoning→text ordering,
|
|
65
|
+
reasoning-only finishes, and the Anthropic thinking-block lifecycle;
|
|
66
|
+
`tests/provider-parity.test.ts` accepts `text-start` as the first text part.
|
|
67
|
+
|
|
3
68
|
## 1.5.0 - 2026-08-23
|
|
4
69
|
|
|
5
70
|
Feature: the `[CMD] ` display-name prefix for auto-registered models is now
|
package/README.md
CHANGED
|
@@ -128,10 +128,15 @@ bundled. Core (models, auth, streaming) is unaffected.
|
|
|
128
128
|
The plugin ships two bundled catalogs and auto-registers every model into
|
|
129
129
|
OpenCode's config at startup, with the `[CMD]` display-name prefix (e.g.
|
|
130
130
|
`[CMD] Claude Sonnet 5`) so they aren't confused with same-named models from
|
|
131
|
-
other providers.
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
131
|
+
other providers. Free-tier variants that share an upstream display name with a
|
|
132
|
+
paid model (e.g. the MiniMax M3 free tier) get a `(free)` suffix —
|
|
133
|
+
`[CMD] MiniMax M3 (free)` — so the two are distinguishable in the model
|
|
134
|
+
picker. The suffix is derived from the bundled pricing table: a model is
|
|
135
|
+
labeled free only when the catalog carries an explicit zero-cost entry. Model
|
|
136
|
+
availability changes when the package is updated. You can still declare your
|
|
137
|
+
own `provider.commandcode` entry; your declarations always win and the
|
|
138
|
+
snapshot fills in only what's missing (`whitelist`/`blacklist` on a declared
|
|
139
|
+
entry filter the auto-registered models too).
|
|
135
140
|
|
|
136
141
|
The `[CMD] ` display-name prefix is configurable through the declared
|
|
137
142
|
provider entry's options:
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export declare const FACTS_SOURCE_URL = "https://unpkg.com/command-code@1.
|
|
2
|
-
export declare const MODALITIES_SOURCE_URL = "https://unpkg.com/command-code@1.
|
|
3
|
-
export declare const FACTS_PACKAGE_VERSION = "1.
|
|
4
|
-
export declare const FACTS_LAST_REFRESHED = "2026-08-
|
|
1
|
+
export declare const FACTS_SOURCE_URL = "https://unpkg.com/command-code@1.36.0/dist/bundled/command-code-knowledge/reference/models.md";
|
|
2
|
+
export declare const MODALITIES_SOURCE_URL = "https://unpkg.com/command-code@1.36.0/dist/cli.mjs";
|
|
3
|
+
export declare const FACTS_PACKAGE_VERSION = "1.36.0";
|
|
4
|
+
export declare const FACTS_LAST_REFRESHED = "2026-08-27";
|
|
5
5
|
export declare const MODEL_EFFORTS: Readonly<Record<string, readonly string[]>>;
|
|
6
6
|
export declare const MODEL_COSTS: Readonly<Record<string, {
|
|
7
7
|
input: number;
|
|
@@ -4,19 +4,20 @@
|
|
|
4
4
|
// command-code npm package's bundled model catalog (models.md), plus input
|
|
5
5
|
// modalities parsed from its CLI bundle (dist/cli.mjs). Regenerate
|
|
6
6
|
// with `npm run refresh:snapshot`.
|
|
7
|
-
export const FACTS_SOURCE_URL = "https://unpkg.com/command-code@1.
|
|
8
|
-
export const MODALITIES_SOURCE_URL = "https://unpkg.com/command-code@1.
|
|
9
|
-
export const FACTS_PACKAGE_VERSION = "1.
|
|
10
|
-
export const FACTS_LAST_REFRESHED = "2026-08-
|
|
7
|
+
export const FACTS_SOURCE_URL = "https://unpkg.com/command-code@1.36.0/dist/bundled/command-code-knowledge/reference/models.md";
|
|
8
|
+
export const MODALITIES_SOURCE_URL = "https://unpkg.com/command-code@1.36.0/dist/cli.mjs";
|
|
9
|
+
export const FACTS_PACKAGE_VERSION = "1.36.0";
|
|
10
|
+
export const FACTS_LAST_REFRESHED = "2026-08-27";
|
|
11
11
|
export const MODEL_EFFORTS = {
|
|
12
12
|
"deepseek/deepseek-v4-pro": ["high", "max"],
|
|
13
13
|
"deepseek/deepseek-v4-flash": ["high", "max"],
|
|
14
14
|
"deepseek/deepseek-v4-flash-vision-exp": ["high", "max"],
|
|
15
|
+
"z-ai/glm-5.3-flash": ["low", "high", "max"],
|
|
15
16
|
"zai-org/GLM-5.3": ["low", "high", "max"],
|
|
16
17
|
"zai-org/GLM-5.2": ["high", "max"],
|
|
17
18
|
"Qwen/Qwen3.8-Max": ["low", "medium", "xhigh"],
|
|
18
19
|
"Qwen/Qwen3.8-27B": ["low", "medium", "xhigh"],
|
|
19
|
-
"
|
|
20
|
+
"Qwen/Qwen3.8-Flash": ["low", "medium", "xhigh"],
|
|
20
21
|
"claude-sonnet-5": ["low", "medium", "high", "xhigh", "max"],
|
|
21
22
|
"claude-sonnet-4-6": ["low", "medium", "high", "xhigh", "max"],
|
|
22
23
|
"claude-fable-5": ["low", "medium", "high", "xhigh", "max"],
|
|
@@ -42,12 +43,13 @@ export const MODEL_EFFORTS = {
|
|
|
42
43
|
export const MODEL_COSTS = {
|
|
43
44
|
"deepseek/deepseek-v4-pro": { input: 0.66, output: 1.98, cacheRead: 0.022, cacheWrite: 0 },
|
|
44
45
|
"deepseek/deepseek-v4-flash": { input: 0.22, output: 0.66, cacheRead: 0.007, cacheWrite: 0 },
|
|
45
|
-
"deepseek/deepseek-v4-flash-vision-exp": { input: 0.22, output: 0.66, cacheRead: 0.
|
|
46
|
+
"deepseek/deepseek-v4-flash-vision-exp": { input: 0.22, output: 0.66, cacheRead: 0.007, cacheWrite: 0 },
|
|
46
47
|
"moonshotai/Kimi-K3": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 0 },
|
|
47
48
|
"moonshotai/Kimi-K2.7-Code": { input: 0.95, output: 4, cacheRead: 0.19, cacheWrite: 0 },
|
|
48
49
|
"moonshotai/Kimi-K2.7-Code-Highspeed": { input: 1.9, output: 8, cacheRead: 0.38, cacheWrite: 0 },
|
|
49
50
|
"moonshotai/Kimi-K2.6": { input: 0.95, output: 4, cacheRead: 0.16, cacheWrite: 0 },
|
|
50
51
|
"moonshotai/Kimi-K2.5": { input: 0.6, output: 3, cacheRead: 0.1, cacheWrite: 0 },
|
|
52
|
+
"z-ai/glm-5.3-flash": { input: 0.15, output: 0.5, cacheRead: 0.03, cacheWrite: 0 },
|
|
51
53
|
"zai-org/GLM-5.3": { input: 1.4, output: 4.4, cacheRead: 0.26, cacheWrite: 0 },
|
|
52
54
|
"zai-org/GLM-5.2": { input: 1.4, output: 4.4, cacheRead: 0.26, cacheWrite: 0 },
|
|
53
55
|
"zai-org/GLM-5.2-Fast": { input: 3, output: 10.25, cacheRead: 0.5, cacheWrite: 0 },
|
|
@@ -55,11 +57,14 @@ export const MODEL_COSTS = {
|
|
|
55
57
|
"zai-org/GLM-5": { input: 1, output: 3.2, cacheRead: 0.2, cacheWrite: 0 },
|
|
56
58
|
"MiniMaxAI/MiniMax-M3": { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0 },
|
|
57
59
|
"MiniMaxAI/MiniMax-M2.7": { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0 },
|
|
60
|
+
"minimax/minimax-m3-free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
61
|
+
"minimax/minimax-m2.7-free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
58
62
|
"MiniMaxAI/MiniMax-M2.5": { input: 0.3, output: 1.2, cacheRead: 0.03, cacheWrite: 0 },
|
|
59
63
|
"xiaomi/mimo-v2.5-pro": { input: 0.435, output: 0.87, cacheRead: 0.0036, cacheWrite: 0 },
|
|
60
64
|
"xiaomi/mimo-v2.5": { input: 0.14, output: 0.28, cacheRead: 0.0028, cacheWrite: 0 },
|
|
61
65
|
"Qwen/Qwen3.8-Max": { input: 2, output: 6, cacheRead: 0.25, cacheWrite: 2.5 },
|
|
62
66
|
"Qwen/Qwen3.8-27B": { input: 0.4, output: 3, cacheRead: 0.04, cacheWrite: 0 },
|
|
67
|
+
"Qwen/Qwen3.8-Flash": { input: 0.16, output: 0.47, cacheRead: 0.016, cacheWrite: 0 },
|
|
63
68
|
"Qwen/Qwen3.7-Max": { input: 2.5, output: 7.5, cacheRead: 0.5, cacheWrite: 3.13 },
|
|
64
69
|
"Qwen/Qwen3.7-Plus": { input: 0.4, output: 1.6, cacheRead: 0.08, cacheWrite: 0.5 },
|
|
65
70
|
"Qwen/Qwen3.7-Flash": { input: 0.03, output: 0.13, cacheRead: 0.006, cacheWrite: 0.038 },
|
|
@@ -72,7 +77,6 @@ export const MODEL_COSTS = {
|
|
|
72
77
|
"thinkingmachines/inkling": { input: 1, output: 4.05, cacheRead: 0.17, cacheWrite: 0 },
|
|
73
78
|
"thinkingmachines/inkling-small": { input: 0.5, output: 1.2, cacheRead: 0.1, cacheWrite: 0 },
|
|
74
79
|
"poolside/laguna-s-2.1-free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
75
|
-
"stealth/ox-alpha": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
76
80
|
"claude-sonnet-5": { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 },
|
|
77
81
|
"claude-sonnet-4-6": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 },
|
|
78
82
|
"claude-fable-5": { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 },
|
|
@@ -105,6 +109,7 @@ export const MODEL_INPUT_MODALITIES = {
|
|
|
105
109
|
"Qwen/Qwen3.7-Flash": ["text", "image"],
|
|
106
110
|
"Qwen/Qwen3.7-Plus": ["text", "image"],
|
|
107
111
|
"Qwen/Qwen3.8-27B": ["text", "image"],
|
|
112
|
+
"Qwen/Qwen3.8-Flash": ["text", "image"],
|
|
108
113
|
"Qwen/Qwen3.8-Max": ["text", "image"],
|
|
109
114
|
"claude-fable-5": ["text", "image"],
|
|
110
115
|
"claude-haiku-4-5-20251001": ["text", "image"],
|
|
@@ -129,16 +134,17 @@ export const MODEL_INPUT_MODALITIES = {
|
|
|
129
134
|
"meta/muse-spark-1.1": ["text", "image"],
|
|
130
135
|
"meta/muse-spark-1.2": ["text", "image"],
|
|
131
136
|
"meta/muse-spark-1.2-contributor": ["text", "image"],
|
|
137
|
+
"minimax/minimax-m3-free": ["text", "image"],
|
|
132
138
|
"moonshotai/Kimi-K2.5": ["text", "image"],
|
|
133
139
|
"moonshotai/Kimi-K2.6": ["text", "image"],
|
|
134
140
|
"moonshotai/Kimi-K2.7-Code": ["text", "image"],
|
|
135
141
|
"moonshotai/Kimi-K2.7-Code-Highspeed": ["text", "image"],
|
|
136
142
|
"moonshotai/Kimi-K3": ["text", "image"],
|
|
137
143
|
"sakana/fugu-ultra": ["text", "image"],
|
|
138
|
-
"stealth/ox-alpha": ["text", "image"],
|
|
139
144
|
"stepfun/Step-3.7-Flash": ["text", "image"],
|
|
140
145
|
"thinkingmachines/inkling": ["text", "image"],
|
|
141
146
|
"thinkingmachines/inkling-small": ["text", "image"],
|
|
142
147
|
"xai/grok-4.5": ["text", "image"],
|
|
143
148
|
"xiaomi/mimo-v2.5": ["text", "image"],
|
|
149
|
+
"z-ai/glm-5.3-flash": ["text", "image"],
|
|
144
150
|
};
|
|
@@ -26,6 +26,7 @@ export const MODEL_SNAPSHOT = [
|
|
|
26
26
|
{ id: "moonshotai/Kimi-K2.7-Code-Highspeed", name: "Kimi K2.7 Code HighSpeed", contextLength: 262000 },
|
|
27
27
|
{ id: "moonshotai/Kimi-K2.6", name: "Kimi K2.6", contextLength: 256000 },
|
|
28
28
|
{ id: "moonshotai/Kimi-K2.5", name: "Kimi K2.5", contextLength: 256000 },
|
|
29
|
+
{ id: "z-ai/glm-5.3-flash", name: "GLM-5.3 Flash", contextLength: 1048576 },
|
|
29
30
|
{ id: "zai-org/GLM-5.3", name: "GLM-5.3", contextLength: 1000000 },
|
|
30
31
|
{ id: "zai-org/GLM-5.2", name: "GLM-5.2", contextLength: 1000000 },
|
|
31
32
|
{ id: "zai-org/GLM-5.2-Fast", name: "GLM-5.2 Fast", contextLength: 1000000 },
|
|
@@ -33,11 +34,14 @@ export const MODEL_SNAPSHOT = [
|
|
|
33
34
|
{ id: "zai-org/GLM-5", name: "GLM-5", contextLength: 200000 },
|
|
34
35
|
{ id: "MiniMaxAI/MiniMax-M3", name: "MiniMax M3", contextLength: 1000000 },
|
|
35
36
|
{ id: "MiniMaxAI/MiniMax-M2.7", name: "MiniMax M2.7", contextLength: 200000 },
|
|
37
|
+
{ id: "minimax/minimax-m3-free", name: "MiniMax M3", contextLength: 1000000 },
|
|
38
|
+
{ id: "minimax/minimax-m2.7-free", name: "MiniMax M2.7", contextLength: 197000 },
|
|
36
39
|
{ id: "MiniMaxAI/MiniMax-M2.5", name: "MiniMax M2.5", contextLength: 200000 },
|
|
37
40
|
{ id: "xiaomi/mimo-v2.5-pro", name: "MiMo V2.5 Pro", contextLength: 1000000 },
|
|
38
41
|
{ id: "xiaomi/mimo-v2.5", name: "MiMo V2.5", contextLength: 1000000 },
|
|
39
42
|
{ id: "Qwen/Qwen3.8-Max", name: "Qwen 3.8 Max", contextLength: 1000000 },
|
|
40
43
|
{ id: "Qwen/Qwen3.8-27B", name: "Qwen 3.8 27B", contextLength: 262144 },
|
|
44
|
+
{ id: "Qwen/Qwen3.8-Flash", name: "Qwen 3.8 Flash", contextLength: 1000000 },
|
|
41
45
|
{ id: "Qwen/Qwen3.7-Max", name: "Qwen 3.7 Max", contextLength: 1000000 },
|
|
42
46
|
{ id: "Qwen/Qwen3.7-Plus", name: "Qwen 3.7 Plus", contextLength: 1000000 },
|
|
43
47
|
{ id: "Qwen/Qwen3.7-Flash", name: "Qwen 3.7 Flash", contextLength: 1000000 },
|
|
@@ -55,7 +59,6 @@ export const MODEL_SNAPSHOT = [
|
|
|
55
59
|
{ id: "nvidia/nemotron-3-ultra-550b-a55b", name: "Nemotron 3 Ultra", contextLength: 1000000 },
|
|
56
60
|
{ id: "thinkingmachines/inkling", name: "Inkling", contextLength: 256000 },
|
|
57
61
|
{ id: "thinkingmachines/inkling-small", name: "Inkling Small", contextLength: 1000000 },
|
|
58
|
-
{ id: "stealth/ox-alpha", name: "Ox Alpha", contextLength: 1048576 },
|
|
59
62
|
{ id: "poolside/laguna-s-2.1-free", name: "Laguna S 2.1", contextLength: 256000 },
|
|
60
63
|
{ id: "meta/muse-spark-1.1", name: "Muse Spark 1.1", contextLength: 1048576 },
|
|
61
64
|
{ id: "meta/muse-spark-1.2", name: "Muse Spark 1.2", contextLength: 1048576 },
|
|
@@ -51,5 +51,5 @@ export interface ModelDeals {
|
|
|
51
51
|
export declare const MODEL_DEALS: Readonly<Record<string, ModelDeals>>;
|
|
52
52
|
export declare const PLAN_CATALOG: Readonly<Record<PlanId, PlanInfo>>;
|
|
53
53
|
export declare const DEAL_SOURCE_URL = "https://commandcode.ai/docs/resources/pricing-limits";
|
|
54
|
-
export declare const DEAL_LAST_REFRESHED = "2026-08-
|
|
54
|
+
export declare const DEAL_LAST_REFRESHED = "2026-08-27";
|
|
55
55
|
export declare const DEAL_PACKAGE_VERSION = "docs";
|
|
@@ -13,7 +13,7 @@ export const MODEL_DEALS = {
|
|
|
13
13
|
"claude-sonnet-4-6": { tier: "premium", benchmark: { "intelligence": 48.4 }, free: false, allowance: { "pro": 20 } },
|
|
14
14
|
"claude-sonnet-5": { tier: "premium", benchmark: { "intelligence": 55.3, "tokPerSec": 81.9 }, free: false, allowance: { "pro": 20 } },
|
|
15
15
|
"deepseek/deepseek-v4-flash": { tier: "opensource", benchmark: { "intelligence": 51.8, "tokPerSec": 114.6 }, peakOffPeak: { "peak": { "input": 0.44, "output": 1.32, "cacheRead": 0.014, "cacheWrite": 0 }, "offPeak": { "input": 0.22, "output": 0.66, "cacheRead": 0.007, "cacheWrite": 0 }, "windows": "01–04 & 06–10 UTC" }, free: false, allowance: { "goat": 60, "pro": 70 } },
|
|
16
|
-
"deepseek/deepseek-v4-flash-vision-exp": { tier: "opensource", peakOffPeak: { "peak": { "input": 0.44, "output": 1.32, "cacheRead": 0.
|
|
16
|
+
"deepseek/deepseek-v4-flash-vision-exp": { tier: "opensource", peakOffPeak: { "peak": { "input": 0.44, "output": 1.32, "cacheRead": 0.014, "cacheWrite": 0 }, "offPeak": { "input": 0.22, "output": 0.66, "cacheRead": 0.007, "cacheWrite": 0 }, "windows": "01–04 & 06–10 UTC" }, free: false, allowance: { "goat": 20, "pro": 30 } },
|
|
17
17
|
"deepseek/deepseek-v4-pro": { tier: "opensource", benchmark: { "intelligence": 53.2, "tokPerSec": 75.3 }, peakOffPeak: { "peak": { "input": 1.32, "output": 3.96, "cacheRead": 0.044, "cacheWrite": 0 }, "offPeak": { "input": 0.66, "output": 1.98, "cacheRead": 0.022, "cacheWrite": 0 }, "windows": "01–04 & 06–10 UTC" }, free: false, allowance: { "goat": 20, "pro": 30 } },
|
|
18
18
|
"google/gemini-3.1-flash-lite": { tier: "premium", benchmark: { "intelligence": 25.6 }, free: false, allowance: { "pro": 20 } },
|
|
19
19
|
"google/gemini-3.5-flash": { tier: "premium", benchmark: { "intelligence": 52 }, free: false, allowance: { "pro": 20 } },
|
|
@@ -30,6 +30,8 @@ export const MODEL_DEALS = {
|
|
|
30
30
|
"meta/muse-spark-1.1": { tier: "premium", benchmark: { "intelligence": 53.2 }, free: false, allowance: { "pro": 20 } },
|
|
31
31
|
"meta/muse-spark-1.2": { tier: "opensource", benchmark: { "intelligence": 56.8 }, free: false, allowance: { "goat": 20, "pro": 30 } },
|
|
32
32
|
"meta/muse-spark-1.2-contributor": { tier: "opensource", benchmark: { "intelligence": 56.8 }, free: false, allowance: { "goat": 20, "pro": 30 } },
|
|
33
|
+
"minimax/minimax-m2.7-free": { tier: "opensource", free: true },
|
|
34
|
+
"minimax/minimax-m3-free": { tier: "opensource", free: true },
|
|
33
35
|
"MiniMaxAI/MiniMax-M2.5": { tier: "opensource", benchmark: { "intelligence": 34.5 }, free: false },
|
|
34
36
|
"MiniMaxAI/MiniMax-M2.7": { tier: "opensource", benchmark: { "intelligence": 38.9 }, free: false },
|
|
35
37
|
"MiniMaxAI/MiniMax-M3": { tier: "opensource", discount: { "pct": 50 }, was: { "input": 0.6, "output": 2.4, "cacheRead": 0.12 }, now: { "input": 0.3, "output": 1.2, "cacheRead": 0.06 }, benchmark: { "intelligence": 45.4, "tokPerSec": 104.4 }, free: false, allowance: { "goat": 47, "pro": 57 } },
|
|
@@ -46,9 +48,9 @@ export const MODEL_DEALS = {
|
|
|
46
48
|
"Qwen/Qwen3.7-Max": { tier: "opensource", benchmark: { "intelligence": 46.7 }, free: false, allowance: { "goat": 33, "pro": 43 } },
|
|
47
49
|
"Qwen/Qwen3.7-Plus": { tier: "opensource", benchmark: { "intelligence": 39.4, "tokPerSec": 55.6 }, overContext: { "input": 1.2, "output": 4.8, "cacheRead": 0.24, "cacheWrite": 1.5 }, free: false, allowance: { "goat": 33, "pro": 43 } },
|
|
48
50
|
"Qwen/Qwen3.8-27B": { tier: "opensource", benchmark: { "intelligence": 52 }, free: false, allowance: { "goat": 70, "pro": 80 } },
|
|
51
|
+
"Qwen/Qwen3.8-Flash": { tier: "opensource", free: false, allowance: { "goat": 20, "pro": 30 } },
|
|
49
52
|
"Qwen/Qwen3.8-Max": { tier: "opensource", benchmark: { "intelligence": 58.1, "tokPerSec": 46.7 }, free: false, allowance: { "goat": 20, "pro": 30 } },
|
|
50
53
|
"sakana/fugu-ultra": { tier: "premium", free: false },
|
|
51
|
-
"stealth/ox-alpha": { tier: "opensource", free: true },
|
|
52
54
|
"stepfun/Step-3.5-Flash": { tier: "opensource", benchmark: { "intelligence": 26.5 }, free: false, allowance: { "goat": 20, "pro": 30 } },
|
|
53
55
|
"stepfun/Step-3.7-Flash": { tier: "opensource", benchmark: { "intelligence": 30.9, "tokPerSec": 120.1 }, free: false, allowance: { "goat": 20, "pro": 30 } },
|
|
54
56
|
"tencent/hy3-paid": { tier: "opensource", benchmark: { "intelligence": 42.2, "tokPerSec": 74.8 }, free: false, allowance: { "goat": 70, "pro": 80 } },
|
|
@@ -58,6 +60,7 @@ export const MODEL_DEALS = {
|
|
|
58
60
|
"xai/grok-4.6": { tier: "opensource", benchmark: { "intelligence": 60.9, "tokPerSec": 66 }, overContext: { "input": 4, "output": 12, "cacheRead": 1, "cacheWrite": 0 }, free: false, allowance: { "goat": 20, "pro": 30 } },
|
|
59
61
|
"xiaomi/mimo-v2.5": { tier: "opensource", discount: { "pct": 98 }, was: { "input": 0.8, "output": 4, "cacheRead": 0.16 }, now: { "input": 0.14, "output": 0.28, "cacheRead": 0.0028 }, benchmark: { "intelligence": 38, "tokPerSec": 61.8 }, free: false, allowance: { "goat": 30, "pro": 40 } },
|
|
60
62
|
"xiaomi/mimo-v2.5-pro": { tier: "opensource", discount: { "pct": 99 }, was: { "input": 2, "output": 6, "cacheRead": 0.4 }, now: { "input": 0.435, "output": 0.87, "cacheRead": 0.0036 }, benchmark: { "intelligence": 42.9, "tokPerSec": 58.1 }, free: false, allowance: { "goat": 20, "pro": 30 } },
|
|
63
|
+
"z-ai/glm-5.3-flash": { tier: "opensource", free: false, allowance: { "goat": 40, "pro": 50 } },
|
|
61
64
|
"zai-org/GLM-5": { tier: "opensource", benchmark: { "intelligence": 40.6 }, free: false },
|
|
62
65
|
"zai-org/GLM-5.1": { tier: "opensource", benchmark: { "intelligence": 41, "tokPerSec": 28.2 }, free: false },
|
|
63
66
|
"zai-org/GLM-5.2": { tier: "opensource", benchmark: { "intelligence": 52.6, "tokPerSec": 69 }, free: false, allowance: { "goat": 70, "pro": 80 } },
|
|
@@ -74,5 +77,5 @@ export const PLAN_CATALOG = {
|
|
|
74
77
|
provider: { price: 15, credits: 0, window5h: 0, windowWeek: 0, display: "Provider" },
|
|
75
78
|
};
|
|
76
79
|
export const DEAL_SOURCE_URL = "https://commandcode.ai/docs/resources/pricing-limits";
|
|
77
|
-
export const DEAL_LAST_REFRESHED = "2026-08-
|
|
80
|
+
export const DEAL_LAST_REFRESHED = "2026-08-27";
|
|
78
81
|
export const DEAL_PACKAGE_VERSION = "docs";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { MODEL_COSTS, ZERO_MODEL_COST } from "../provider/pricing.js";
|
|
1
|
+
import { MODEL_COSTS, ZERO_MODEL_COST, isFreeModelCost, } from "../provider/pricing.js";
|
|
2
2
|
import { reasoningVariantsForModel, isReasoningModel } from "../provider/reasoning.js";
|
|
3
3
|
import { inputModalitiesForModel } from "../provider/modalities.js";
|
|
4
4
|
const DEFAULT_MAX_OUTPUT_TOKENS = 65_536;
|
|
@@ -95,8 +95,14 @@ export function augmentConfigCommandCodeModels(config) {
|
|
|
95
95
|
function configModelFor(model, prefix = DEFAULT_DISPLAY_PREFIX) {
|
|
96
96
|
const variants = reasoningVariantsForModel(model.id);
|
|
97
97
|
const costs = MODEL_COSTS[model.id] ?? ZERO_MODEL_COST;
|
|
98
|
+
// Upstream names the paid and free MiniMax variants identically
|
|
99
|
+
// (`MiniMax M3` / `MiniMax M2.7`); append `(free)` to the picker entry so
|
|
100
|
+
// users can tell them apart. Data-driven from the zero cost table — a model
|
|
101
|
+
// is only "free" when the catalog has an actual zero-cost entry (an absent
|
|
102
|
+
// entry falls back to ZERO_MODEL_COST and is NOT free).
|
|
103
|
+
const freeSuffix = MODEL_COSTS[model.id] !== undefined && isFreeModelCost(costs) ? " (free)" : "";
|
|
98
104
|
return {
|
|
99
|
-
name: `${prefix}${model.name}`,
|
|
105
|
+
name: `${prefix}${model.name}${freeSuffix}`,
|
|
100
106
|
limit: {
|
|
101
107
|
context: model.contextLength,
|
|
102
108
|
output: Math.min(model.contextLength, DEFAULT_MAX_OUTPUT_TOKENS),
|
|
@@ -9,3 +9,10 @@ export interface CommandCodeModelCostRates {
|
|
|
9
9
|
export interface CommandCodeModelCost extends CommandCodeModelCostRates {
|
|
10
10
|
}
|
|
11
11
|
export declare const ZERO_MODEL_COST: CommandCodeModelCost;
|
|
12
|
+
/**
|
|
13
|
+
* True when every rate is zero — the model is served free (e.g. the MiniMax
|
|
14
|
+
* M3 / M2.7 free variants). Used to disambiguate display names: the upstream
|
|
15
|
+
* catalog names the paid and free variants identically (`MiniMax M3`), so the
|
|
16
|
+
* auto-registered picker entry appends `(free)` when this matches.
|
|
17
|
+
*/
|
|
18
|
+
export declare function isFreeModelCost(cost: CommandCodeModelCost | undefined): boolean;
|
|
@@ -8,3 +8,16 @@ export const ZERO_MODEL_COST = {
|
|
|
8
8
|
cacheRead: 0,
|
|
9
9
|
cacheWrite: 0,
|
|
10
10
|
};
|
|
11
|
+
/**
|
|
12
|
+
* True when every rate is zero — the model is served free (e.g. the MiniMax
|
|
13
|
+
* M3 / M2.7 free variants). Used to disambiguate display names: the upstream
|
|
14
|
+
* catalog names the paid and free variants identically (`MiniMax M3`), so the
|
|
15
|
+
* auto-registered picker entry appends `(free)` when this matches.
|
|
16
|
+
*/
|
|
17
|
+
export function isFreeModelCost(cost) {
|
|
18
|
+
return (cost !== undefined &&
|
|
19
|
+
cost.input === 0 &&
|
|
20
|
+
cost.output === 0 &&
|
|
21
|
+
cost.cacheRead === 0 &&
|
|
22
|
+
cost.cacheWrite === 0);
|
|
23
|
+
}
|
|
@@ -29,12 +29,12 @@ export const REASONING_MODELS = new Set([
|
|
|
29
29
|
"meta/muse-spark-1.1",
|
|
30
30
|
"meta/muse-spark-1.2",
|
|
31
31
|
"meta/muse-spark-1.2-contributor",
|
|
32
|
+
"minimax/minimax-m3-free",
|
|
32
33
|
"moonshotai/Kimi-K2.7-Code",
|
|
33
34
|
"moonshotai/Kimi-K2.7-Code-Highspeed",
|
|
34
35
|
"moonshotai/Kimi-K3",
|
|
35
36
|
"nvidia/nemotron-3-ultra-550b-a55b",
|
|
36
37
|
"poolside/laguna-s-2.1-free",
|
|
37
|
-
"stealth/ox-alpha",
|
|
38
38
|
"stepfun/Step-3.7-Flash",
|
|
39
39
|
"tencent/hy3-paid",
|
|
40
40
|
"thinkingmachines/inkling",
|
|
@@ -338,6 +338,10 @@ export function anthropicEventToStreamPart(event) {
|
|
|
338
338
|
const id = `text-${index}`;
|
|
339
339
|
return [{ type: "text-start", id }];
|
|
340
340
|
}
|
|
341
|
+
if (blockType === "thinking") {
|
|
342
|
+
const id = stringValue(block?.id) ?? `thinking-${index}`;
|
|
343
|
+
return [{ type: "reasoning-start", id }];
|
|
344
|
+
}
|
|
341
345
|
if (blockType === "tool_use") {
|
|
342
346
|
const id = stringValue(block?.id) ?? `tool-${index}`;
|
|
343
347
|
const name = stringValue(block?.name) ?? "";
|
|
@@ -345,16 +349,32 @@ export function anthropicEventToStreamPart(event) {
|
|
|
345
349
|
}
|
|
346
350
|
return [];
|
|
347
351
|
}
|
|
352
|
+
if (type === "content_block_delta") {
|
|
353
|
+
const delta = asRecord(event.delta);
|
|
354
|
+
const index = numberValue(event.index) ?? 0;
|
|
355
|
+
const text = stringValue(delta?.text);
|
|
356
|
+
if (typeof text === "string" && text.length > 0) {
|
|
357
|
+
const id = `text-${index}`;
|
|
358
|
+
return [{ type: "text-delta", id, delta: text }];
|
|
359
|
+
}
|
|
360
|
+
const thinking = stringValue(delta?.thinking);
|
|
361
|
+
if (typeof thinking === "string" && thinking.length > 0) {
|
|
362
|
+
const id = `thinking-${index}`;
|
|
363
|
+
return [{ type: "reasoning-delta", id, delta: thinking }];
|
|
364
|
+
}
|
|
365
|
+
// Tool input delta: { type: "input_json_delta", partial_json: "..." }
|
|
366
|
+
const partial = stringValue(delta?.partial_json);
|
|
367
|
+
if (typeof partial === "string" && partial.length > 0) {
|
|
368
|
+
const id = `tool-${index}`;
|
|
369
|
+
// Emit as tool-input-delta; caller may have started tool
|
|
370
|
+
return [{ type: "tool-input-delta", id, delta: partial }];
|
|
371
|
+
}
|
|
372
|
+
return [];
|
|
373
|
+
}
|
|
348
374
|
if (type === "content_block_stop") {
|
|
349
375
|
// Stateless codec: the STOP event carries only `index`, not the block type.
|
|
350
|
-
// Anthropic streams either `text` or `tool_use` blocks; the AI SDK expects
|
|
351
|
-
// `text-end` for
|
|
352
|
-
// both is noisy (previous emitted two parts) but guarantees the right end
|
|
353
|
-
// is seen regardless of block type, and the consumer ignores the spurious
|
|
354
|
-
// one per AI SDK spec. Emit a single text-end here would break tool_use
|
|
355
|
-
// streams that rely on tool-input-end, so we keep the conservative pair
|
|
356
|
-
// with an explicit note referencing provider doc streaming (message_delta
|
|
357
|
-
// carries the final usage/finish; per-block ends are AI SDK concerns).
|
|
376
|
+
// Anthropic streams either `text`, `thinking` or `tool_use` blocks; the AI SDK expects
|
|
377
|
+
// `text-end` for text, `reasoning-end` for thinking, and `tool-input-end` for tool_use.
|
|
358
378
|
const index = numberValue(event.index) ?? 0;
|
|
359
379
|
const idText = `text-${index}`;
|
|
360
380
|
const idTool = `tool-${index}`;
|
|
@@ -395,6 +415,26 @@ export function createOpenAIStreamParser() {
|
|
|
395
415
|
// finish_reason here so the usage-only chunk's finish keeps the real reason
|
|
396
416
|
// (e.g. "length") instead of defaulting to "stop".
|
|
397
417
|
let lastFinishReason;
|
|
418
|
+
let reasoningStarted = false;
|
|
419
|
+
let reasoningEnded = false;
|
|
420
|
+
let reasoningId;
|
|
421
|
+
let textStarted = false;
|
|
422
|
+
let textEnded = false;
|
|
423
|
+
let textId;
|
|
424
|
+
function closeReasoning() {
|
|
425
|
+
if (reasoningStarted && !reasoningEnded && reasoningId) {
|
|
426
|
+
reasoningEnded = true;
|
|
427
|
+
return [{ type: "reasoning-end", id: reasoningId }];
|
|
428
|
+
}
|
|
429
|
+
return [];
|
|
430
|
+
}
|
|
431
|
+
function closeText() {
|
|
432
|
+
if (textStarted && !textEnded && textId) {
|
|
433
|
+
textEnded = true;
|
|
434
|
+
return [{ type: "text-end", id: textId }];
|
|
435
|
+
}
|
|
436
|
+
return [];
|
|
437
|
+
}
|
|
398
438
|
return (event) => {
|
|
399
439
|
if (!isRecord(event))
|
|
400
440
|
return [];
|
|
@@ -405,17 +445,42 @@ export function createOpenAIStreamParser() {
|
|
|
405
445
|
const parts = [];
|
|
406
446
|
const choice = firstChoice(event);
|
|
407
447
|
const delta = choice ? deltaFromChoice(choice) : undefined;
|
|
448
|
+
const eventId = stringValue(event.id);
|
|
408
449
|
if (delta) {
|
|
409
|
-
const content = stringValue(delta.content);
|
|
410
|
-
if (typeof content === "string" && content.length > 0) {
|
|
411
|
-
parts.push(textDeltaPart(event.id, content));
|
|
412
|
-
}
|
|
413
450
|
const reasoning = stringValue(delta.reasoning) ?? stringValue(delta.reasoning_content);
|
|
414
451
|
if (typeof reasoning === "string" && reasoning.length > 0) {
|
|
415
|
-
|
|
452
|
+
if (!reasoningStarted || reasoningEnded) {
|
|
453
|
+
if (textStarted && !textEnded) {
|
|
454
|
+
parts.push(...closeText());
|
|
455
|
+
}
|
|
456
|
+
reasoningStarted = true;
|
|
457
|
+
reasoningEnded = false;
|
|
458
|
+
reasoningId = eventId || "reasoning-0";
|
|
459
|
+
parts.push({ type: "reasoning-start", id: reasoningId });
|
|
460
|
+
}
|
|
461
|
+
parts.push(reasoningDeltaPart(reasoningId ?? eventId, reasoning));
|
|
462
|
+
}
|
|
463
|
+
const content = stringValue(delta.content);
|
|
464
|
+
if (typeof content === "string" && content.length > 0) {
|
|
465
|
+
if (reasoningStarted && !reasoningEnded) {
|
|
466
|
+
parts.push(...closeReasoning());
|
|
467
|
+
}
|
|
468
|
+
if (!textStarted || textEnded) {
|
|
469
|
+
textStarted = true;
|
|
470
|
+
textEnded = false;
|
|
471
|
+
textId = eventId || "text-0";
|
|
472
|
+
parts.push({ type: "text-start", id: textId });
|
|
473
|
+
}
|
|
474
|
+
parts.push(textDeltaPart(textId ?? eventId, content));
|
|
416
475
|
}
|
|
417
476
|
const toolCalls = delta.tool_calls ?? delta.toolCalls;
|
|
418
477
|
if (Array.isArray(toolCalls)) {
|
|
478
|
+
if (reasoningStarted && !reasoningEnded) {
|
|
479
|
+
parts.push(...closeReasoning());
|
|
480
|
+
}
|
|
481
|
+
if (textStarted && !textEnded) {
|
|
482
|
+
parts.push(...closeText());
|
|
483
|
+
}
|
|
419
484
|
for (const tc of toolCalls) {
|
|
420
485
|
if (!isRecord(tc))
|
|
421
486
|
continue;
|
|
@@ -475,6 +540,12 @@ export function createOpenAIStreamParser() {
|
|
|
475
540
|
if (finishReason)
|
|
476
541
|
lastFinishReason = finishReason;
|
|
477
542
|
if (lastFinishReason || hasUsage) {
|
|
543
|
+
if (reasoningStarted && !reasoningEnded) {
|
|
544
|
+
parts.push(...closeReasoning());
|
|
545
|
+
}
|
|
546
|
+
if (textStarted && !textEnded) {
|
|
547
|
+
parts.push(...closeText());
|
|
548
|
+
}
|
|
478
549
|
// Flush any tool call whose terminal args chunk never arrived.
|
|
479
550
|
for (const [index, buffer] of toolBuffers) {
|
|
480
551
|
if (buffer.started && !buffer.emitted) {
|
|
@@ -498,6 +569,7 @@ export function createOpenAIStreamParser() {
|
|
|
498
569
|
}
|
|
499
570
|
export function createAnthropicStreamParser() {
|
|
500
571
|
const toolBlocks = new Map();
|
|
572
|
+
const blockTypes = new Map();
|
|
501
573
|
return (event) => {
|
|
502
574
|
if (!isRecord(event))
|
|
503
575
|
return [];
|
|
@@ -507,13 +579,21 @@ export function createAnthropicStreamParser() {
|
|
|
507
579
|
const index = numberValue(event.index) ?? 0;
|
|
508
580
|
const blockType = stringValue(block?.type);
|
|
509
581
|
if (blockType === "tool_use") {
|
|
582
|
+
blockTypes.set(index, "tool_use");
|
|
510
583
|
const id = stringValue(block?.id) ?? `tool-${index}`;
|
|
511
584
|
const name = stringValue(block?.name) ?? "";
|
|
512
585
|
toolBlocks.set(index, { id, name, input: "", started: true, emitted: false });
|
|
513
586
|
return [{ type: "tool-input-start", id, toolName: name }];
|
|
514
587
|
}
|
|
515
|
-
if (blockType === "
|
|
588
|
+
if (blockType === "thinking") {
|
|
589
|
+
blockTypes.set(index, "thinking");
|
|
590
|
+
const id = stringValue(block?.id) ?? `thinking-${index}`;
|
|
591
|
+
return [{ type: "reasoning-start", id }];
|
|
592
|
+
}
|
|
593
|
+
if (blockType === "text") {
|
|
594
|
+
blockTypes.set(index, "text");
|
|
516
595
|
return [{ type: "text-start", id: `text-${index}` }];
|
|
596
|
+
}
|
|
517
597
|
return [];
|
|
518
598
|
}
|
|
519
599
|
if (type === "content_block_delta") {
|
|
@@ -523,6 +603,10 @@ export function createAnthropicStreamParser() {
|
|
|
523
603
|
if (typeof text === "string" && text.length > 0) {
|
|
524
604
|
return [{ type: "text-delta", id: `text-${index}`, delta: text }];
|
|
525
605
|
}
|
|
606
|
+
const thinking = stringValue(delta?.thinking);
|
|
607
|
+
if (typeof thinking === "string" && thinking.length > 0) {
|
|
608
|
+
return [{ type: "reasoning-delta", id: `thinking-${index}`, delta: thinking }];
|
|
609
|
+
}
|
|
526
610
|
const partial = stringValue(delta?.partial_json);
|
|
527
611
|
if (typeof partial === "string" && partial.length > 0) {
|
|
528
612
|
const block = toolBlocks.get(index);
|
|
@@ -557,6 +641,28 @@ export function createAnthropicStreamParser() {
|
|
|
557
641
|
}
|
|
558
642
|
if (type === "content_block_stop") {
|
|
559
643
|
const index = numberValue(event.index) ?? 0;
|
|
644
|
+
const bType = blockTypes.get(index);
|
|
645
|
+
blockTypes.delete(index);
|
|
646
|
+
if (bType === "tool_use") {
|
|
647
|
+
const block = toolBlocks.get(index);
|
|
648
|
+
if (block) {
|
|
649
|
+
toolBlocks.delete(index);
|
|
650
|
+
if (block.emitted)
|
|
651
|
+
return [];
|
|
652
|
+
return [
|
|
653
|
+
{ type: "tool-input-end", id: block.id },
|
|
654
|
+
{
|
|
655
|
+
type: "tool-call",
|
|
656
|
+
toolCallId: block.id,
|
|
657
|
+
toolName: block.name,
|
|
658
|
+
input: block.input,
|
|
659
|
+
},
|
|
660
|
+
];
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
else if (bType === "thinking") {
|
|
664
|
+
return [{ type: "reasoning-end", id: `thinking-${index}` }];
|
|
665
|
+
}
|
|
560
666
|
const block = toolBlocks.get(index);
|
|
561
667
|
if (block) {
|
|
562
668
|
toolBlocks.delete(index);
|