@chenlongapps/opencode-token-usage 0.4.1 → 0.4.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/dist/pricing.js CHANGED
@@ -1,591 +1,97 @@
1
+ import { MODEL_ALIASES, PROVIDER_ALIASES } from "./aliases.js";
2
+ import { ORIGINAL_PROVIDERS, PRICE_OVERRIDES } from "./overrides.js";
3
+ import { GENERATED_PRICE_SNAPSHOT } from "./prices.generated.js";
4
+ const index = new Map();
5
+ for (const entry of GENERATED_PRICE_SNAPSHOT.entries) {
6
+ const key = `${entry.providerID}/${entry.id}`.toLowerCase();
7
+ if (index.has(key))
8
+ throw new Error(`Duplicate manufacturer price: ${key}`);
9
+ index.set(key, { ...entry, source: GENERATED_PRICE_SNAPSHOT.source });
10
+ }
11
+ for (const entry of PRICE_OVERRIDES) {
12
+ // Reviewed exceptions replace a source row as a whole; never mix rate fields.
13
+ index.set(`${entry.providerID}/${entry.id}`.toLowerCase(), entry);
14
+ }
15
+ for (const [alias, target] of Object.entries(MODEL_ALIASES)) {
16
+ if (!index.has(target))
17
+ throw new Error(`Unknown manufacturer price alias: ${alias} -> ${target}`);
18
+ }
19
+ /** Checked-in data: updating prices is explicit, not a network request at
20
+ * startup, during a refresh, or during an npm build. */
1
21
  export const OFFICIAL_PRICE_SNAPSHOT = {
2
- verified: "2026-09-23",
3
- newModelCutoff: "2026-03-22",
4
- entries: [
5
- // OpenAI API rates. Tier sizes are exclusive thresholds, so
6
- // 272,000 implements the official ">272K input tokens" boundary.
7
- {
8
- id: "gpt-5.5", released: "2026-04-23", source: "https://developers.openai.com/api/docs/pricing",
9
- prices: [
10
- { input: 5, output: 30, cache: { read: 0.5 } },
11
- { tier: { type: "context", size: 272_000 }, input: 10, output: 45, cache: { read: 1 } },
12
- ],
13
- },
14
- {
15
- id: "gpt-5.5-fast", providers: ["openai"], released: "2026-04-23", source: "https://developers.openai.com/api/docs/pricing",
16
- prices: [
17
- { input: 12.5, output: 75, cache: { read: 1.25 } },
18
- // OpenAI publishes no Fast rate for GPT-5.5 above 272K input tokens.
19
- { tier: { type: "context", size: 272_000 } },
20
- ],
21
- },
22
- {
23
- id: "gpt-5.5-pro", released: "2026-04-23", source: "https://developers.openai.com/api/docs/pricing",
24
- prices: [
25
- { input: 30, output: 180 },
26
- { tier: { type: "context", size: 272_000 }, input: 60, output: 270 },
27
- ],
28
- },
29
- {
30
- id: "gpt-5.6-sol", released: "2026-07-09", source: "https://developers.openai.com/api/docs/pricing",
31
- prices: [
32
- { input: 4, output: 20, cache: { read: 0.4, write: 5 } },
33
- { tier: { type: "context", size: 272_000 }, input: 8, output: 30, cache: { read: 0.8, write: 10 } },
34
- ],
35
- },
36
- {
37
- id: "gpt-5.6-terra", released: "2026-07-09", source: "https://developers.openai.com/api/docs/pricing",
38
- prices: [
39
- { input: 2, output: 12, cache: { read: 0.2, write: 2.5 } },
40
- { tier: { type: "context", size: 272_000 }, input: 4, output: 18, cache: { read: 0.4, write: 5 } },
41
- ],
42
- },
43
- {
44
- id: "gpt-5.6-luna", released: "2026-07-09", source: "https://developers.openai.com/api/docs/pricing",
45
- prices: [
46
- { input: 0.2, output: 1.2, cache: { read: 0.02, write: 0.25 } },
47
- { tier: { type: "context", size: 272_000 }, input: 0.4, output: 1.8, cache: { read: 0.04, write: 0.5 } },
48
- ],
49
- },
50
- {
51
- id: "gpt-6-astra", released: "2026-09-04", source: "https://developers.openai.com/api/docs/pricing",
52
- prices: [
53
- { input: 10, output: 50, cache: { read: 1, write: 12.5 } },
54
- { tier: { type: "context", size: 272_000 }, input: 20, output: 75, cache: { read: 2, write: 25 } },
55
- ],
56
- },
57
- {
58
- id: "gpt-6-sol", released: "2026-09-22", source: "https://developers.openai.com/api/docs/pricing",
59
- prices: [
60
- { input: 2, output: 10, cache: { read: 0.2, write: 2.5 } },
61
- { tier: { type: "context", size: 272_000 }, input: 4, output: 15, cache: { read: 0.4, write: 5 } },
62
- ],
63
- },
64
- {
65
- id: "gpt-6-luna", released: "2026-09-22", source: "https://developers.openai.com/api/docs/pricing",
66
- prices: [
67
- { input: 0.1, output: 0.5, cache: { read: 0.01, write: 0.125 } },
68
- { tier: { type: "context", size: 272_000 }, input: 0.2, output: 0.75, cache: { read: 0.02, write: 0.25 } },
69
- ],
70
- },
71
- {
72
- // OpenAI Fast processing is a separate exact ID and restricted to the
73
- // first-party provider so ordinary or gateway model IDs keep standard rates.
74
- id: "gpt-6-luna-fast", providers: ["openai"], released: "2026-09-22", source: "https://developers.openai.com/api/docs/pricing",
75
- prices: [
76
- { input: 0.2, output: 1, cache: { read: 0.02, write: 0.25 } },
77
- { tier: { type: "context", size: 272_000 }, input: 0.4, output: 1.5, cache: { read: 0.04, write: 0.5 } },
78
- ],
79
- },
80
- {
81
- id: "gpt-5.6-sol-fast", providers: ["openai"], released: "2026-07-09", source: "https://developers.openai.com/api/docs/pricing",
82
- prices: [
83
- { input: 8, output: 40, cache: { read: 0.8, write: 10 } },
84
- { tier: { type: "context", size: 272_000 }, input: 16, output: 60, cache: { read: 1.6, write: 20 } },
85
- ],
86
- },
87
- {
88
- id: "gpt-5.6-terra-fast", providers: ["openai"], released: "2026-07-09", source: "https://developers.openai.com/api/docs/pricing",
89
- prices: [
90
- { input: 4, output: 24, cache: { read: 0.4, write: 5 } },
91
- { tier: { type: "context", size: 272_000 }, input: 8, output: 36, cache: { read: 0.8, write: 10 } },
92
- ],
93
- },
94
- {
95
- id: "gpt-5.6-luna-fast", providers: ["openai"], released: "2026-07-09", source: "https://developers.openai.com/api/docs/pricing",
96
- prices: [
97
- { input: 0.4, output: 2.4, cache: { read: 0.04, write: 0.5 } },
98
- { tier: { type: "context", size: 272_000 }, input: 0.8, output: 3.6, cache: { read: 0.08, write: 1 } },
99
- ],
100
- },
101
- {
102
- id: "gpt-6-astra-fast", providers: ["openai"], released: "2026-09-04", source: "https://developers.openai.com/api/docs/pricing",
103
- prices: [
104
- { input: 20, output: 100, cache: { read: 2, write: 25 } },
105
- { tier: { type: "context", size: 272_000 }, input: 40, output: 150, cache: { read: 4, write: 50 } },
106
- ],
107
- },
108
- {
109
- id: "gpt-6-sol-fast", providers: ["openai"], released: "2026-09-22", source: "https://developers.openai.com/api/docs/pricing",
110
- prices: [
111
- { input: 4, output: 20, cache: { read: 0.4, write: 5 } },
112
- { tier: { type: "context", size: 272_000 }, input: 8, output: 30, cache: { read: 0.8, write: 10 } },
113
- ],
114
- },
115
- // The official ChatGPT SKU `chat-latest`. OpenRouter serves it under the
116
- // slug `openai/gpt-chat-latest`, which is registered as an exact alias.
117
- {
118
- id: "chat-latest", aliases: ["gpt-chat-latest"], released: "2026-05-05",
119
- source: "https://developers.openai.com/api/docs/pricing",
120
- prices: [{ input: 5, output: 30, cache: { read: 0.5 } }],
121
- },
122
- // Anthropic standard processing and 5-minute cache writes. OpenCode's
123
- // aggregate cache-write counter cannot distinguish 5-minute from 1-hour TTL.
124
- {
125
- id: "claude-opus-4-7", aliases: ["claude-opus-4.7"], released: "2026-04-14", source: "https://platform.claude.com/docs/en/about-claude/pricing",
126
- prices: [{ input: 5, output: 25, cache: { read: 0.5, write: 6.25 } }],
127
- },
128
- {
129
- id: "claude-opus-4-8", aliases: ["claude-opus-4.8"], released: "2026-05-28", source: "https://platform.claude.com/docs/en/about-claude/pricing",
130
- prices: [{ input: 5, output: 25, cache: { read: 0.5, write: 6.25 } }],
131
- },
132
- {
133
- id: "claude-fable-5", released: "2026-06-07", source: "https://platform.claude.com/docs/en/about-claude/pricing",
134
- prices: [{ input: 10, output: 50, cache: { read: 1, write: 12.5 } }],
135
- },
136
- {
137
- id: "claude-sonnet-5", released: "2026-06-29", source: "https://platform.claude.com/docs/en/about-claude/pricing",
138
- prices: [{ input: 2, output: 10, cache: { read: 0.2, write: 2.5 } }],
139
- },
140
- {
141
- id: "claude-opus-5", released: "2026-07-24", source: "https://platform.claude.com/docs/en/about-claude/pricing",
142
- prices: [{ input: 5, output: 25, cache: { read: 0.5, write: 6.25 } }],
143
- },
144
- {
145
- // Fast mode is first-party Claude API only. Cache multipliers apply to
146
- // the Fast input price; aggregate cache writes use the 5-minute rate.
147
- id: "claude-opus-5-fast", providers: ["anthropic"], released: "2026-07-24", source: "https://platform.claude.com/docs/en/about-claude/pricing",
148
- prices: [{ input: 10, output: 50, cache: { read: 1, write: 12.5 } }],
149
- },
150
- {
151
- id: "claude-opus-4-8-fast", providers: ["anthropic"], released: "2026-05-28", source: "https://platform.claude.com/docs/en/about-claude/pricing",
152
- prices: [{ input: 10, output: 50, cache: { read: 1, write: 12.5 } }],
153
- },
154
- {
155
- id: "claude-opus-5-5-fast", providers: ["anthropic"], released: "2026-09-22", source: "https://platform.claude.com/docs/en/about-claude/pricing",
156
- prices: [{ input: 8, output: 40, cache: { read: 0.4, write: 10 } }],
157
- },
158
- {
159
- id: "claude-fable-5-1", aliases: ["claude-fable-5.1"], released: "2026-09-01",
160
- source: "https://platform.claude.com/docs/en/about-claude/pricing",
161
- prices: [{ input: 10, output: 50, cache: { read: 0.25, write: 12.5 } }],
162
- },
163
- {
164
- id: "claude-opus-5-5", aliases: ["claude-opus-5.5"], released: "2026-09-22", source: "https://platform.claude.com/docs/en/about-claude/pricing",
165
- prices: [{ input: 4, output: 20, cache: { read: 0.2, write: 5 } }],
166
- },
167
- // Google paid Standard API rates. Cache storage is billed separately by
168
- // time and is intentionally not represented as a cache-write token rate.
169
- {
170
- id: "gemini-3.1-flash-lite", released: "2026-05-07", source: "https://ai.google.dev/gemini-api/docs/pricing",
171
- prices: [{ input: 0.25, output: 1.5, cache: { read: 0.025 } }],
172
- },
173
- {
174
- id: "gemini-3.5-flash", released: "2026-05-19", source: "https://ai.google.dev/gemini-api/docs/pricing",
175
- prices: [{ input: 1.5, output: 9, cache: { read: 0.15 } }],
176
- },
177
- {
178
- id: "gemini-3.5-flash-lite", released: "2026-07-21", source: "https://ai.google.dev/gemini-api/docs/pricing",
179
- prices: [{ input: 0.3, output: 2.5, cache: { read: 0.03 } }],
180
- },
181
- {
182
- id: "gemini-3.6-flash", released: "2026-07-21", source: "https://ai.google.dev/gemini-api/docs/pricing",
183
- prices: [{ input: 0.75, output: 3.75, cache: { read: 0.075 } }],
184
- },
185
- {
186
- id: "gemini-3.7-flash", released: "2026-08-13", source: "https://ai.google.dev/gemini-api/docs/pricing",
187
- prices: [{ input: 0.75, output: 3.75, cache: { read: 0.075 } }],
188
- },
189
- {
190
- id: "gemini-3.8-flash", released: "2026-09-02", source: "https://ai.google.dev/gemini-api/docs/pricing",
191
- prices: [{ input: 0.75, output: 3.75, cache: { read: 0.075 } }],
192
- },
193
- // xAI standard text API rates. 199,999 implements the official higher
194
- // price at 200K prompt tokens with OpenCode's exclusive-tier formula.
195
- {
196
- id: "grok-build-0.1", released: "2026-04-16", source: "https://docs.x.ai/developers/models",
197
- prices: [
198
- { input: 1, output: 2, cache: { read: 0.2 } },
199
- { tier: { type: "context", size: 199_999 }, input: 2, output: 4, cache: { read: 0.4 } },
200
- ],
201
- },
202
- {
203
- id: "grok-4.3", released: "2026-04-17", source: "https://docs.x.ai/developers/models",
204
- prices: [
205
- { input: 1.25, output: 2.5, cache: { read: 0.2 } },
206
- { tier: { type: "context", size: 199_999 }, input: 2.5, output: 5, cache: { read: 0.4 } },
207
- ],
208
- },
209
- {
210
- id: "grok-4.5", released: "2026-07-08", source: "https://docs.x.ai/developers/models",
211
- prices: [
212
- { input: 2, output: 6, cache: { read: 0.3 } },
213
- { tier: { type: "context", size: 199_999 }, input: 4, output: 12, cache: { read: 0.6 } },
214
- ],
215
- },
216
- {
217
- id: "grok-4.6", released: "2026-08-12", source: "https://docs.x.ai/developers/models",
218
- prices: [
219
- { input: 2, output: 6, cache: { read: 0.5 } },
220
- { tier: { type: "context", size: 199_999 }, input: 4, output: 12, cache: { read: 1 } },
221
- ],
222
- },
223
- {
224
- id: "grok-4.7", released: "2026-09-21",
225
- source: "https://docs.x.ai/developers/models",
226
- prices: [
227
- { input: 2, output: 6, cache: { read: 0.5 } },
228
- { tier: { type: "context", size: 199_999 }, input: 4, output: 12, cache: { read: 1 } },
229
- ],
230
- },
231
- {
232
- id: "mistral-medium-3-5-26-04",
233
- aliases: ["mistral-medium-2604", "mistral-medium-3-5"],
234
- released: "2026-04-29",
235
- source: "https://docs.mistral.ai/inference/pricing",
236
- prices: [{ input: 1.5, output: 7.5, cache: { read: 0.15 } }],
237
- },
238
- {
239
- id: "command-a-plus-05-2026",
240
- released: "2026-05-20",
241
- source: "https://cohere.com/pricing",
242
- prices: [{ input: 2.5, output: 10 }],
243
- },
244
- // Meta Model API standard-tier rates.
245
- {
246
- id: "muse-spark-1.1", released: "2026-07-09", source: "https://ai.developer.meta.com/docs/pricing-rate-limits",
247
- prices: [{ input: 1.25, output: 4.25, cache: { read: 0.15 } }],
248
- },
249
- {
250
- id: "muse-spark-1.2", released: "2026-08-05", source: "https://ai.developer.meta.com/docs/pricing-rate-limits",
251
- prices: [{ input: 1.25, output: 4.25, cache: { read: 0.15 } }],
252
- },
253
- {
254
- id: "muse-spark-1.3", released: "2026-09-02", source: "https://ai.developer.meta.com/docs/pricing-rate-limits",
255
- prices: [{ input: 1.25, output: 4.25, cache: { read: 0.15 } }],
256
- },
257
- // Meta Contributor rates are conditional on allowing Meta to use prompts
258
- // and completions for training. OpenCode's contributor-free model IDs
259
- // resolve here after removing their terminal -free suffix.
260
- {
261
- id: "muse-spark-1.2-contributor", released: "2026-08-05", source: "https://ai.developer.meta.com/docs/pricing-rate-limits",
262
- prices: [{ input: 0.1, output: 0.2, cache: { read: 0.002 } }],
263
- },
264
- {
265
- id: "muse-spark-1.3-contributor", released: "2026-09-02", source: "https://ai.developer.meta.com/docs/pricing-rate-limits",
266
- prices: [{ input: 0.1, output: 0.2, cache: { read: 0.002 } }],
267
- },
268
- // Inception's current Mercury 2.5 API page shows an 80% launch discount;
269
- // the snapshot records the billed standard-platform rates on verification
270
- // day rather than the crossed-out list prices. No cache-write token rate is
271
- // published.
272
- {
273
- id: "mercury-2.5", aliases: ["mercury-2.5-preview"], released: "2026-09-08",
274
- source: "https://www.inceptionlabs.ai/models",
275
- prices: [{ input: 0.04, output: 0.15, cache: { read: 0.004 } }],
276
- },
277
- // Upstage Solar Pro 4 standard Console API rates. The dated version ID is
278
- // an exact manufacturer alias; no cache-write token rate is published.
279
- {
280
- id: "solar-pro4", aliases: ["solar-pro4-260806"], released: "2026-08-06",
281
- source: "https://console.upstage.ai/docs/models/solar-pro-4",
282
- prices: [{ input: 0.3, output: 1.2, cache: { read: 0.06 } }],
283
- },
284
- // Arcee AI's hosted API rates for the official Trinity reasoning release.
285
- // The model is also available as open weights, but only the hosted API
286
- // price is relevant to this token-cost snapshot.
287
- {
288
- id: "trinity-large-thinking", released: "2026-04-01", source: "https://docs.arcee.ai/get-started/pricing",
289
- prices: [{ input: 0.25, output: 0.8, cache: { read: 0.06 } }],
290
- },
291
- // Aion Labs' own model catalog publishes these per-token API rates. The
292
- // OpenRouter slugs retain the manufacturer's `aion-labs/` prefix, so it is
293
- // registered as an exact alias rather than inferred from the name.
294
- {
295
- id: "aion-3.0", aliases: ["aion-labs/aion-3.0"], released: "2026-05-05",
296
- source: "https://www.aionlabs.ai/docs/models",
297
- prices: [{ input: 3, output: 6, cache: { read: 0.75 } }],
298
- },
299
- {
300
- id: "aion-3.0-mini", aliases: ["aion-labs/aion-3.0-mini"], released: "2026-05-14",
301
- source: "https://www.aionlabs.ai/docs/models",
302
- prices: [{ input: 0.7, output: 1.4, cache: { read: 0.18 } }],
303
- },
304
- // Z.ai (Zhipu GLM) standard API rates. The page publishes a cache-hit input
305
- // rate and prices cache storage by time instead of a cache-write token rate,
306
- // so no cache-write rate is stored for these models.
307
- {
308
- id: "glm-5.1", released: "2026-04-06", source: "https://docs.z.ai/guides/overview/pricing",
309
- prices: [{ input: 1.4, output: 4.4, cache: { read: 0.26 } }],
310
- },
311
- {
312
- id: "glm-5.2", released: "2026-06-16", source: "https://docs.z.ai/guides/overview/pricing",
313
- prices: [{ input: 1.4, output: 4.4, cache: { read: 0.26 } }],
314
- },
315
- {
316
- id: "glm-5.3", released: "2026-08-16", source: "https://docs.z.ai/guides/overview/pricing",
317
- prices: [{ input: 1.4, output: 4.4, cache: { read: 0.26 } }],
318
- },
319
- {
320
- id: "glm-5.3-flash", released: "2026-08-26", source: "https://docs.z.ai/guides/overview/pricing",
321
- prices: [{ input: 0.15, output: 0.5, cache: { read: 0.03 } }],
322
- },
323
- {
324
- id: "glm-5.3-flashx", released: "2026-09-18", source: "https://docs.z.ai/guides/overview/pricing",
325
- prices: [{ input: 0.37, output: 1.25, cache: { read: 0.075 } }],
326
- },
327
- // DeepSeek standard API peak rates. The vendor charges half these rates
328
- // off-peak; using the peak tier provides a conservative upper-bound
329
- // estimate because historical messages do not retain the billing hour.
330
- // Retired V4 Flash and Vision Exp names currently route to V4.1 Flash at
331
- // the Flash price. The dated 0731 and 0813 IDs are exact gateway aliases.
332
- {
333
- id: "deepseek-v4.1-flash",
334
- aliases: ["deepseek-flash", "deepseek-v4-flash", "deepseek-v4-flash-0731", "deepseek-v4-flash-vision-exp"],
335
- released: "2026-09-10",
336
- source: "https://api-docs.deepseek.com/quick_start/pricing",
337
- prices: [{ input: 0.3, output: 1.2, cache: { read: 0.006 } }],
338
- },
339
- {
340
- id: "deepseek-v4-pro-0813", aliases: ["deepseek-v4-pro"], released: "2026-08-13",
341
- source: "https://api-docs.deepseek.com/quick_start/pricing",
342
- prices: [{ input: 1.32, output: 3.96, cache: { read: 0.044 } }],
343
- },
344
- // Moonshot Kimi standard API rates. K3 publishes 5-minute and 1-hour cache
345
- // writes; following the Anthropic convention, the aggregate counter cannot
346
- // tell them apart, so the snapshot stores the 5-minute write. The K2 table
347
- // publishes only a cache-hit input rate and no cache-write price.
348
- {
349
- id: "kimi-k3", released: "2026-07-15", source: "https://platform.moonshot.ai/docs/pricing",
350
- prices: [{ input: 3, output: 15, cache: { read: 0.3, write: 3 } }],
351
- },
352
- {
353
- id: "kimi-k2.7-code", released: "2026-06-12", source: "https://platform.moonshot.ai/docs/pricing",
354
- prices: [{ input: 0.95, output: 4, cache: { read: 0.19 } }],
355
- },
356
- {
357
- id: "kimi-k2.6", released: "2026-04-20", source: "https://platform.moonshot.ai/docs/pricing",
358
- prices: [{ input: 0.95, output: 4, cache: { read: 0.16 } }],
359
- },
360
- // Alibaba Cloud Model Studio standard (Singapore "International") list
361
- // prices. Tier sizes implement the official inclusive boundaries
362
- // ("0<Token≤256K" then "256K<Token≤1M") with the exclusive-threshold formula.
363
- // Cache Read stores the official implicit-cache hit rate, 20% of the tier
364
- // input, where the page publishes it. The qwen3.8 max/flash family reports
365
- // cache rates only in the console, so no cache rate is stored for them, and
366
- // no cache-write rate is stored anywhere because implicit cache writes bill
367
- // at 100% of the input price while explicit cache writes bill at 125% and
368
- // the aggregate counter cannot distinguish the two.
369
- {
370
- id: "qwen3.8-max", aliases: ["qwen3.8-max-0902"], released: "2026-08-03",
371
- source: "https://www.alibabacloud.com/help/en/model-studio/model-pricing",
372
- prices: [{ input: 2, output: 6 }],
373
- },
374
- {
375
- id: "qwen3.8-2.4t-a95b", released: "2026-08-12",
376
- source: "https://www.alibabacloud.com/help/en/model-studio/model-pricing",
377
- prices: [{ input: 2, output: 6 }],
378
- },
379
- {
380
- id: "qwen3.8-27b", released: "2026-08-14",
381
- source: "https://www.alibabacloud.com/help/en/model-studio/model-pricing",
382
- prices: [{ input: 0.5, output: 3, cache: { read: 0.1 } }],
383
- },
384
- {
385
- id: "qwen3.8-flash", released: "2026-08-26",
386
- source: "https://www.alibabacloud.com/help/en/model-studio/model-pricing",
387
- prices: [{ input: 0.15, output: 0.47 }],
388
- },
389
- {
390
- id: "qwen3.7-max", released: "2026-05-20",
391
- source: "https://www.alibabacloud.com/help/en/model-studio/model-pricing",
392
- prices: [{ input: 2.5, output: 7.5, cache: { read: 0.5 } }],
393
- },
394
- {
395
- id: "qwen3.7-plus", released: "2026-05-26",
396
- source: "https://www.alibabacloud.com/help/en/model-studio/model-pricing",
397
- prices: [
398
- { input: 0.4, output: 1.6, cache: { read: 0.08 } },
399
- { tier: { type: "context", size: 256_000 }, input: 1.2, output: 4.8, cache: { read: 0.24 } },
400
- ],
401
- },
402
- {
403
- id: "qwen3.7-flash", released: "2026-07-15",
404
- source: "https://www.alibabacloud.com/help/en/model-studio/model-pricing",
405
- prices: [
406
- { input: 0.03, output: 0.13, cache: { read: 0.006 } },
407
- { tier: { type: "context", size: 32_000 }, input: 0.1, output: 0.4, cache: { read: 0.02 } },
408
- { tier: { type: "context", size: 256_000 }, input: 0.2, output: 0.8, cache: { read: 0.04 } },
409
- ],
410
- },
411
- {
412
- id: "qwen3.6-max-preview", released: "2026-04-20",
413
- source: "https://www.alibabacloud.com/help/en/model-studio/model-pricing",
414
- prices: [
415
- { input: 1.3, output: 7.8 },
416
- { tier: { type: "context", size: 128_000 }, input: 2, output: 12 },
417
- ],
418
- },
419
- {
420
- id: "qwen3.6-plus", released: "2026-04-02",
421
- source: "https://www.alibabacloud.com/help/en/model-studio/model-pricing",
422
- prices: [
423
- { input: 0.5, output: 3 },
424
- { tier: { type: "context", size: 256_000 }, input: 2, output: 6 },
425
- ],
426
- },
427
- {
428
- id: "qwen3.6-flash", released: "2026-04-16",
429
- source: "https://www.alibabacloud.com/help/en/model-studio/model-pricing",
430
- prices: [
431
- { input: 0.25, output: 1.5 },
432
- { tier: { type: "context", size: 256_000 }, input: 1, output: 4 },
433
- ],
434
- },
435
- {
436
- id: "qwen3.6-27b", released: "2026-04-22",
437
- source: "https://www.alibabacloud.com/help/en/model-studio/model-pricing",
438
- prices: [{ input: 0.6, output: 3.6 }],
439
- },
440
- {
441
- id: "qwen3.6-35b-a3b", released: "2026-04-15",
442
- source: "https://www.alibabacloud.com/help/en/model-studio/model-pricing",
443
- prices: [{ input: 0.375, output: 2.25 }],
444
- },
445
- {
446
- id: "qwen3.5-plus-2026-04-20", aliases: ["qwen3.5-plus-20260420"], released: "2026-04-20",
447
- source: "https://www.alibabacloud.com/help/en/model-studio/model-pricing",
448
- prices: [
449
- { input: 0.4, output: 2.4 },
450
- { tier: { type: "context", size: 256_000 }, input: 0.5, output: 3 },
451
- ],
452
- },
453
- // Xiaomi MiMo overseas USD rates. The MiMo-V2.6 series keeps the V2.5 API
454
- // pricing. Cache writes are free for a limited time, so no cache-write rate
455
- // is stored.
456
- {
457
- id: "mimo-v2.5", released: "2026-04-22", source: "https://mimo.mi.com/docs/price/pay-as-you-go",
458
- prices: [{ input: 0.14, output: 0.28, cache: { read: 0.0028 } }],
459
- },
460
- {
461
- id: "mimo-v2.5-pro", released: "2026-04-22", source: "https://mimo.mi.com/docs/price/pay-as-you-go",
462
- prices: [{ input: 0.435, output: 0.87, cache: { read: 0.0036 } }],
463
- },
464
- {
465
- id: "mimo-v2.6-flash", released: "2026-09-21", source: "https://mimo.mi.com/docs/price/pay-as-you-go",
466
- prices: [{ input: 0.14, output: 0.28, cache: { read: 0.0028 } }],
467
- },
468
- {
469
- id: "mimo-v2.6-pro", released: "2026-09-21", source: "https://mimo.mi.com/docs/price/pay-as-you-go",
470
- prices: [{ input: 0.435, output: 0.87, cache: { read: 0.0036 } }],
471
- },
472
- {
473
- id: "mimo-v2.6-pro-ultraspeed", released: "2026-09-21", source: "https://mimo.mi.com/docs/price/pay-as-you-go",
474
- prices: [{ input: 4.35, output: 8.7, cache: { read: 0.036 } }],
475
- },
476
- // MiniMax pay-as-you-go billed rates. The page labels the M3 rates as a
477
- // permanent 50% off and shows the struck-through list price beside them;
478
- // like the GPT-5.6 Sol promotion, the snapshot stores the billed rates shown
479
- // on the verification date. Only a prompt-caching read rate is published.
480
- {
481
- id: "minimax-m3", released: "2026-05-31", source: "https://platform.minimax.io/docs/guides/pricing-paygo",
482
- prices: [
483
- { input: 0.3, output: 1.2, cache: { read: 0.06 } },
484
- { tier: { type: "context", size: 512_000 }, input: 0.6, output: 2.4, cache: { read: 0.12 } },
485
- ],
486
- },
487
- // Tencent Cloud TokenHub international (Singapore) USD list prices for the
488
- // vendor's own Hunyuan models. Cache is the published cache-hit rate; the
489
- // page publishes no cache-write rate.
490
- {
491
- id: "hy3", released: "2026-07-06", source: "https://intl.cloud.tencent.com/document/product/1300/78937",
492
- prices: [{ input: 0.132, output: 0.528, cache: { read: 0.033 } }],
493
- },
494
- {
495
- id: "hy4-preview", released: "2026-08-27", source: "https://intl.cloud.tencent.com/document/product/1300/78937",
496
- prices: [{ input: 0.834, output: 2.501, cache: { read: 0.042 } }],
497
- },
498
- // StepFun overseas platform rates. The page publishes a cache-hit input
499
- // rate. For Step 5 Preview it explicitly states that cache-miss input
500
- // includes writing new content to the cache, so split cache-write tokens
501
- // retain the same rate as ordinary cache-miss input.
502
- {
503
- id: "step-5-preview", released: "2026-09-21", source: "https://platform.stepfun.ai/docs/en/guides/pricing/details",
504
- prices: [{ input: 1, output: 2.7, cache: { read: 0.05, write: 1 } }],
505
- },
506
- {
507
- id: "step-3.7-flash", released: "2026-05-28", source: "https://platform.stepfun.ai/docs/en/guides/pricing/details",
508
- prices: [{ input: 0.2, output: 1.15, cache: { read: 0.04 } }],
509
- },
510
- // ByteDance Seed 2.1 Turbo standard online inference rates on BytePlus
511
- // ModelArk. The cache-storage fee is time-based rather than a token write
512
- // rate, so only the published cache-hit input price is represented.
513
- {
514
- id: "dola-seed-2-1-turbo",
515
- aliases: ["seed-2-1-turbo", "dola-seed-2-1-turbo-260628"],
516
- released: "2026-06-23",
517
- source: "https://docs.byteplus.com/en/docs/ModelArk/1099320",
518
- prices: [{ input: 0.5, output: 2.5, cache: { read: 0.1 } }],
519
- },
520
- // Sakana Fugu's fixed standard API rates. Fugu Ultra's orchestration
521
- // tokens are included in the API's input/output usage fields and therefore
522
- // use the same token rates. Web search/fetch tool fees are not token fees
523
- // and cannot be represented by the plugin's five usage counters.
524
- {
525
- id: "fugu-ultra-v2.0", aliases: ["fugu-ultra-v2"], released: "2026-09-11",
526
- source: "https://console.sakana.ai/pricing",
527
- prices: [
528
- { input: 5, output: 30, cache: { read: 0.5 } },
529
- { tier: { type: "context", size: 271_999 }, input: 10, output: 45, cache: { read: 1 } },
530
- ],
531
- },
532
- {
533
- id: "fugu-max-v1.0", aliases: ["fugu-max"], released: "2026-09-11",
534
- source: "https://console.sakana.ai/pricing",
535
- prices: [{ input: 2, output: 6, cache: { read: 0.25 } }],
536
- },
537
- // LongCat's official API page shows both list and limited-time discounted
538
- // rates. As with the other documented promotions in this snapshot, record
539
- // the billed discounted rate visible on verification day. Cache storage or
540
- // cache writes have no separate token rate on the page.
541
- {
542
- id: "longcat-2.0", released: "2026-06-30",
543
- source: "https://longcat.chat/platform/docs/Pricing/LongCat-2.0.html",
544
- prices: [{ input: 0.3, output: 1.2, cache: { read: 0.006 } }],
545
- },
546
- ],
22
+ verified: GENERATED_PRICE_SNAPSHOT.verified,
23
+ source: GENERATED_PRICE_SNAPSHOT.source,
24
+ entries: [...index.values()].sort((a, b) => a.providerID.localeCompare(b.providerID) || a.id.localeCompare(b.id)),
547
25
  };
548
- const index = new Map();
549
- for (const entry of OFFICIAL_PRICE_SNAPSHOT.entries) {
550
- for (const id of [entry.id, ...(entry.aliases ?? [])]) {
551
- const key = id.toLowerCase();
552
- if (index.has(key))
553
- throw new Error(`Duplicate official price ID: ${id}`);
554
- index.set(key, entry);
555
- }
26
+ const byBareID = new Map();
27
+ for (const entry of index.values()) {
28
+ const id = entry.id.toLowerCase();
29
+ const matches = byBareID.get(id) ?? [];
30
+ matches.push(entry);
31
+ byBareID.set(id, matches);
32
+ }
33
+ const vendor = (id) => {
34
+ const value = PROVIDER_ALIASES[id] ?? id;
35
+ return value in ORIGINAL_PROVIDERS || PRICE_OVERRIDES.some(entry => entry.providerID === value) ? value : undefined;
36
+ };
37
+ const alternateSpelling = (id) => id.replace(/^claude-opus-(\d+)\.(\d+)(?=$|-)/, "claude-opus-$1-$2");
38
+ function available(entry, model) {
39
+ return entry && (!entry.providers || entry.providers.some(provider => provider === model.providerID.toLowerCase()))
40
+ ? entry : undefined;
41
+ }
42
+ function lookup(manufacturer, id, model) {
43
+ const original = `${manufacturer}/${alternateSpelling(id)}`;
44
+ const key = MODEL_ALIASES[original] ?? original;
45
+ return available(index.get(key), model);
556
46
  }
557
- /**
558
- * Resolves exact manufacturer IDs through common gateway wrappers. It never
559
- * performs substring or model-name matching, so similarly named variants do
560
- * not silently inherit a different model's price.
561
- */
47
+ /** Exact first-party model IDs and known gateway wrappers only. A bare ID may
48
+ * resolve at a gateway only when it is unique across manufacturer catalogs. */
562
49
  export function officialPrice(model) {
563
- const id = model.id.toLowerCase().replace(/@default$/, "");
50
+ const providerID = model.providerID.toLowerCase();
51
+ const raw = model.id.toLowerCase();
52
+ const id = providerID === "google-vertex" ? raw.replace(/@default$/, "") : raw;
564
53
  const candidates = [id];
565
- const slash = id.lastIndexOf("/");
566
- if (slash >= 0)
567
- candidates.push(id.slice(slash + 1));
568
- const dot = id.lastIndexOf(".");
569
- if (dot >= 0)
570
- candidates.push(id.slice(dot + 1));
571
- const available = (candidate) => {
572
- const entry = index.get(candidate);
573
- return entry && (!entry.providers || entry.providers.some(provider => provider.toLowerCase() === model.providerID.toLowerCase()))
574
- ? entry
575
- : undefined;
576
- };
577
- for (const candidate of candidates) {
578
- const entry = available(candidate);
579
- if (entry)
580
- return entry;
54
+ if (id.endsWith("-free"))
55
+ candidates.push(id.slice(0, -5));
56
+ if (id.endsWith(":free"))
57
+ candidates.push(id.slice(0, -5));
58
+ const direct = vendor(providerID);
59
+ if (direct) {
60
+ for (const candidate of candidates) {
61
+ const match = lookup(direct, candidate, model);
62
+ if (match)
63
+ return match;
64
+ }
65
+ return undefined;
581
66
  }
582
67
  for (const candidate of candidates) {
583
- for (const suffix of ["-free", ":free"]) {
584
- if (!candidate.endsWith(suffix))
68
+ const slash = candidate.indexOf("/");
69
+ if (slash >= 0) {
70
+ const slug = candidate.slice(0, slash);
71
+ const manufacturer = vendor(slug);
72
+ if (!manufacturer)
585
73
  continue;
586
- const entry = available(candidate.slice(0, -suffix.length));
587
- if (entry)
588
- return entry;
74
+ const match = lookup(manufacturer, candidate.slice(slash + 1), model)
75
+ ?? lookup(manufacturer, candidate, model);
76
+ if (match)
77
+ return match;
78
+ continue;
79
+ }
80
+ if (providerID === "amazon-bedrock") {
81
+ const bedrock = /^(?:(?:us|eu|apac|global)\.)?([a-z0-9-]+)\.(.+)$/.exec(candidate);
82
+ const manufacturer = bedrock && vendor(bedrock[1]);
83
+ if (manufacturer) {
84
+ const match = lookup(manufacturer, bedrock[2], model);
85
+ if (match)
86
+ return match;
87
+ continue;
88
+ }
89
+ }
90
+ const matches = byBareID.get(alternateSpelling(candidate));
91
+ if (matches?.length === 1) {
92
+ const match = available(matches[0], model);
93
+ if (match)
94
+ return match;
589
95
  }
590
96
  }
591
97
  return undefined;