@trazum/core 2.4.3 → 2.5.0
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/advisories.d.ts.map +1 -1
- package/dist/advisories.js +17 -10
- package/dist/advisories.js.map +1 -1
- package/dist/answer.d.ts.map +1 -1
- package/dist/answer.js +2 -1
- package/dist/answer.js.map +1 -1
- package/dist/anthropic-usage.d.ts +6 -0
- package/dist/anthropic-usage.d.ts.map +1 -1
- package/dist/anthropic-usage.js +1 -0
- package/dist/anthropic-usage.js.map +1 -1
- package/dist/billing.d.ts +20 -0
- package/dist/billing.d.ts.map +1 -0
- package/dist/billing.js +32 -0
- package/dist/billing.js.map +1 -0
- package/dist/budget.d.ts.map +1 -1
- package/dist/budget.js +18 -8
- package/dist/budget.js.map +1 -1
- package/dist/connector.d.ts +20 -1
- package/dist/connector.d.ts.map +1 -1
- package/dist/connector.js +42 -11
- package/dist/connector.js.map +1 -1
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +4 -2
- package/dist/conversation.js.map +1 -1
- package/dist/gateway.d.ts.map +1 -1
- package/dist/gateway.js +5 -3
- package/dist/gateway.js.map +1 -1
- package/dist/guard.d.ts.map +1 -1
- package/dist/guard.js +7 -5
- package/dist/guard.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/input-shape.d.ts.map +1 -1
- package/dist/input-shape.js +4 -2
- package/dist/input-shape.js.map +1 -1
- package/dist/ladder.d.ts.map +1 -1
- package/dist/ladder.js +2 -1
- package/dist/ladder.js.map +1 -1
- package/dist/levers.d.ts.map +1 -1
- package/dist/levers.js +5 -2
- package/dist/levers.js.map +1 -1
- package/dist/openai-usage.d.ts +18 -0
- package/dist/openai-usage.d.ts.map +1 -1
- package/dist/openai-usage.js +26 -1
- package/dist/openai-usage.js.map +1 -1
- package/dist/openrouter-activity.d.ts +6 -0
- package/dist/openrouter-activity.d.ts.map +1 -1
- package/dist/openrouter-activity.js +7 -0
- package/dist/openrouter-activity.js.map +1 -1
- package/dist/output-shape.d.ts.map +1 -1
- package/dist/output-shape.js +2 -1
- package/dist/output-shape.js.map +1 -1
- package/dist/pricing.d.ts +35 -3
- package/dist/pricing.d.ts.map +1 -1
- package/dist/pricing.js +569 -54
- package/dist/pricing.js.map +1 -1
- package/dist/receipt.d.ts +17 -0
- package/dist/receipt.d.ts.map +1 -1
- package/dist/receipt.js +10 -0
- package/dist/receipt.js.map +1 -1
- package/dist/repeats.d.ts.map +1 -1
- package/dist/repeats.js +4 -2
- package/dist/repeats.js.map +1 -1
- package/dist/reprice.d.ts +18 -2
- package/dist/reprice.d.ts.map +1 -1
- package/dist/reprice.js +34 -12
- package/dist/reprice.js.map +1 -1
- package/dist/rollup.d.ts.map +1 -1
- package/dist/rollup.js +3 -0
- package/dist/rollup.js.map +1 -1
- package/dist/savings.d.ts.map +1 -1
- package/dist/savings.js +10 -3
- package/dist/savings.js.map +1 -1
- package/dist/session-cost.d.ts.map +1 -1
- package/dist/session-cost.js +5 -2
- package/dist/session-cost.js.map +1 -1
- package/dist/session-ledger.d.ts.map +1 -1
- package/dist/session-ledger.js +12 -7
- package/dist/session-ledger.js.map +1 -1
- package/dist/truncation-retry.d.ts.map +1 -1
- package/dist/truncation-retry.js +4 -2
- package/dist/truncation-retry.js.map +1 -1
- package/dist/ttl-fit.d.ts +8 -0
- package/dist/ttl-fit.d.ts.map +1 -1
- package/dist/ttl-fit.js +25 -14
- package/dist/ttl-fit.js.map +1 -1
- package/dist/types.d.ts +24 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/usage.d.ts +31 -0
- package/dist/usage.d.ts.map +1 -1
- package/dist/usage.js +79 -10
- package/dist/usage.js.map +1 -1
- package/package.json +1 -1
- package/src/advisories.ts +18 -10
- package/src/answer.ts +6 -1
- package/src/anthropic-usage.ts +7 -0
- package/src/billing.ts +37 -0
- package/src/budget.ts +18 -8
- package/src/connector.ts +58 -10
- package/src/conversation.ts +4 -2
- package/src/gateway.ts +5 -3
- package/src/guard.ts +7 -5
- package/src/index.ts +1 -1
- package/src/input-shape.ts +4 -2
- package/src/ladder.ts +2 -1
- package/src/levers.ts +5 -2
- package/src/openai-usage.ts +44 -2
- package/src/openrouter-activity.ts +13 -0
- package/src/output-shape.ts +2 -1
- package/src/pricing.ts +614 -59
- package/src/receipt.ts +23 -1
- package/src/repeats.ts +4 -2
- package/src/reprice.ts +57 -16
- package/src/rollup.ts +3 -0
- package/src/savings.ts +12 -5
- package/src/session-cost.ts +5 -2
- package/src/session-ledger.ts +18 -9
- package/src/truncation-retry.ts +4 -2
- package/src/ttl-fit.ts +39 -15
- package/src/types.ts +18 -0
- package/src/usage.ts +112 -10
package/src/pricing.ts
CHANGED
|
@@ -32,9 +32,9 @@ import type { ModelPricing, PricingTier, TierCondition } from './types.js';
|
|
|
32
32
|
export const PROVIDER_REVIEWED: Readonly<Record<string, string>> = Object.freeze({
|
|
33
33
|
/*
|
|
34
34
|
* platform.claude.com/docs/en/about-claude/pricing, the models overview and
|
|
35
|
-
* each model's own page, read 2026-10-10. Every existing row matched
|
|
36
|
-
* models were added
|
|
37
|
-
*
|
|
35
|
+
* each model's own page, read 2026-10-10. Every existing row matched and
|
|
36
|
+
* five models were added. Claude Haiku 5.5 waited for per-request pricing,
|
|
37
|
+
* because it bills by prompt length, and was added with it on 2026-10-11.
|
|
38
38
|
*/
|
|
39
39
|
anthropic: '2026-10-10',
|
|
40
40
|
/*
|
|
@@ -54,9 +54,9 @@ export const PROVIDER_REVIEWED: Readonly<Record<string, string>> = Object.freeze
|
|
|
54
54
|
* dated snapshots (`gpt-5-2025-08-07` and the mini and nano ones), which is
|
|
55
55
|
* the id a usage log usually carries, shut down on 2026-12-11 and are now
|
|
56
56
|
* declared as aliases. The current generation (gpt-6-astra, gpt-6.1-sol,
|
|
57
|
-
* gpt-6-sol, gpt-6-luna and gpt-5.6 sol, terra and luna)
|
|
58
|
-
*
|
|
59
|
-
*
|
|
57
|
+
* gpt-6-sol, gpt-6-luna and gpt-5.6 sol, terra and luna) waited for
|
|
58
|
+
* per-request pricing, since each doubles its rates for prompts over 272K
|
|
59
|
+
* tokens, and was added with it the same day, from each model's own page.
|
|
60
60
|
*/
|
|
61
61
|
openai: '2026-10-11',
|
|
62
62
|
/*
|
|
@@ -66,24 +66,20 @@ export const PROVIDER_REVIEWED: Readonly<Record<string, string>> = Object.freeze
|
|
|
66
66
|
* for every Gemini 2.5 and newer model, so `caching` is 'automatic' across
|
|
67
67
|
* the board; the minimums moved to 4,096 on 3.6 and 3.8 Flash and 2,048 on
|
|
68
68
|
* 2.5 Flash; and the 2.5 models read the cache at 10% of input today, not
|
|
69
|
-
* the 25% this table carried. Gemini 3.8 Flash was added
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
* out and the second's tier is named in its note rather than guessed.
|
|
69
|
+
* the 25% this table carried. Gemini 3.8 Flash was added, and Gemini 3.1
|
|
70
|
+
* Pro Preview on 2026-10-11 with per-request pricing, which its prompts
|
|
71
|
+
* over 200k need. 2.5 Pro's own long-context rate is named in its note.
|
|
73
72
|
*/
|
|
74
73
|
google: '2026-10-10',
|
|
75
74
|
/*
|
|
76
|
-
* platform.kimi.ai/docs/pricing/chat
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
* repository does not hold. The newer models are not added: the page states
|
|
83
|
-
* no context window for any of them, and a context window this table did
|
|
84
|
-
* not read is a number it would be inventing.
|
|
75
|
+
* platform.kimi.ai/docs/pricing/chat, models and pricing/batch, read
|
|
76
|
+
* 2026-10-11 in their Markdown form; the HTML renders its tables in the
|
|
77
|
+
* browser, which is why the review of 2026-09-12 found no context window
|
|
78
|
+
* and added nothing. Kimi K3, K2.7 Code (and its high-speed variant) and
|
|
79
|
+
* K2.6 are priced now. `kimi-k2` was discontinued on 2026-05-25 by the
|
|
80
|
+
* provider's own notice, so it stays priced and is no longer recommended.
|
|
85
81
|
*/
|
|
86
|
-
moonshot: '2026-
|
|
82
|
+
moonshot: '2026-10-11',
|
|
87
83
|
/*
|
|
88
84
|
* api-docs.deepseek.com/quick_start/pricing read 2026-10-10, and the
|
|
89
85
|
* 2026-09-10 announcement (api-docs.deepseek.com/news/news260910) read
|
|
@@ -94,15 +90,14 @@ export const PROVIDER_REVIEWED: Readonly<Record<string, string>> = Object.freeze
|
|
|
94
90
|
*/
|
|
95
91
|
deepseek: '2026-10-10',
|
|
96
92
|
/*
|
|
97
|
-
* docs.x.ai/
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
* would understate it by half while looking exact.
|
|
93
|
+
* docs.x.ai/developers/models, each model's page and the 2026-05-15
|
|
94
|
+
* retirement notice, read 2026-10-11 in their Markdown form. Grok 4.7, 4.6,
|
|
95
|
+
* 4.5, 4.3, the 4.20 family and Build 0.1 are priced, each with the rate a
|
|
96
|
+
* request pays once its prompt reaches 200k tokens, which per-request
|
|
97
|
+
* pricing can now express. `grok-4` was retired on 2026-05-15 and its calls
|
|
98
|
+
* have billed at Grok 4.3's prices since, so it carries both periods.
|
|
104
99
|
*/
|
|
105
|
-
xai: '2026-
|
|
100
|
+
xai: '2026-10-11',
|
|
106
101
|
/*
|
|
107
102
|
* `mistral.ai/pricing`, read 2026-08-28 — by a human, because the page
|
|
108
103
|
* renders its table in the browser and serves a fetch only an FAQ example
|
|
@@ -194,6 +189,14 @@ export function multipliersFor(model: ModelPricing, on?: Date): {
|
|
|
194
189
|
return result;
|
|
195
190
|
}
|
|
196
191
|
|
|
192
|
+
/** Five minutes and an hour: Anthropic's two cache entries, and the default. */
|
|
193
|
+
const ANTHROPIC_TTL = Object.freeze({ writeMs: 5 * 60_000, longerMs: 60 * 60_000 });
|
|
194
|
+
|
|
195
|
+
/** How long a model's cache entries live. See `ModelPricing.cacheTtl`. */
|
|
196
|
+
export function cacheTtlOf(model: ModelPricing): { writeMs: number; longerMs: number | null } {
|
|
197
|
+
return model.cacheTtl ?? ANTHROPIC_TTL;
|
|
198
|
+
}
|
|
199
|
+
|
|
197
200
|
/**
|
|
198
201
|
* Mistral discounts cached input by 90% and publishes nothing else about it
|
|
199
202
|
* that can be read from here: not how caching starts, not a minimum, not a
|
|
@@ -202,6 +205,32 @@ export function multipliersFor(model: ModelPricing, on?: Date): {
|
|
|
202
205
|
* cannot be.
|
|
203
206
|
*/
|
|
204
207
|
/** What the GPT-5 family's three rows share, from OpenAI's guide and deprecations page, read 2026-10-11. */
|
|
208
|
+
/** xAI's long-context band: a request whose prompt reaches 200,000 tokens, at the published higher rates. */
|
|
209
|
+
const GROK_LONG = (inputPerMTok: number, outputPerMTok: number): PricingTier => ({
|
|
210
|
+
id: 'from-200k',
|
|
211
|
+
when: { kind: 'input-tokens-at-least', tokens: 200_000 },
|
|
212
|
+
inputPerMTok,
|
|
213
|
+
outputPerMTok,
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Said on every row that caches but whose provider publishes no minimum
|
|
218
|
+
* prefix. The bill still prices its cache reads and writes, which are
|
|
219
|
+
* published; what goes quiet is the advice that needs the minimum to promise
|
|
220
|
+
* a saving, and the reader is told why rather than handed a number from
|
|
221
|
+
* nowhere. The catalogue tests hold a null minimum on a caching model to
|
|
222
|
+
* carrying this sentence, so a forgotten minimum cannot pass as a deliberate one.
|
|
223
|
+
*/
|
|
224
|
+
const NO_PUBLISHED_CACHE_MINIMUM =
|
|
225
|
+
'Caches automatically, but no minimum prefix length is published, so no caching advice is given for it.';
|
|
226
|
+
|
|
227
|
+
/** OpenAI's GPT-5.6 and later: one cache entry, living at least 30 minutes. */
|
|
228
|
+
const OPENAI_CACHE_TTL = Object.freeze({ writeMs: 30 * 60_000, longerMs: null });
|
|
229
|
+
|
|
230
|
+
const OPENAI_CURRENT_NOTE =
|
|
231
|
+
'Priced per request by prompt length: over 272,000 input tokens, 2x input and cache and 1.5x output for'
|
|
232
|
+
+ ' the whole request. Cache writes cost 1.25x input and an entry lives at least 30 minutes.';
|
|
233
|
+
|
|
205
234
|
const OPENAI_GPT5_NOTE =
|
|
206
235
|
'Caching is automatic, with no cache_control to set. OpenAI says the minimum for models before GPT-5.6 varies by'
|
|
207
236
|
+ ' request settings, so 1,024 here is the nearest published floor. The 2025-08-07 snapshot shuts down on'
|
|
@@ -408,18 +437,45 @@ export const MODELS: ModelPricing[] = [
|
|
|
408
437
|
capability: 'mid',
|
|
409
438
|
tier: 'sonnet',
|
|
410
439
|
},
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
440
|
+
{
|
|
441
|
+
/*
|
|
442
|
+
* The pricing page, the models overview and the prompt-caching page, read
|
|
443
|
+
* 2026-10-10. Priced by prompt length, per request: $0.10/$0.50 for a
|
|
444
|
+
* prompt up to 100,000 tokens and $0.50/$2.50 over it, where the length
|
|
445
|
+
* counts every input token the request carried, cache reads and writes
|
|
446
|
+
* included, and "each request is priced on its own". Caching is the same
|
|
447
|
+
* ratio in both bands (hits $0.01 and $0.05, writes $0.125/$0.20 and
|
|
448
|
+
* $0.625/$1), and so is batch ($0.05/$0.25, $0.25/$1.25). 1M context,
|
|
449
|
+
* 128K output, a 512-token cache minimum.
|
|
450
|
+
*
|
|
451
|
+
* It waited for the change that prices a log per request. A record that
|
|
452
|
+
* is one call carries its own prompt; a row out of a usage report sums
|
|
453
|
+
* requests, and is billed at the over-100,000 rate unless its whole
|
|
454
|
+
* prompt total is under the line, with the cheaper figure printed beside
|
|
455
|
+
* it. See `PromptSize`.
|
|
456
|
+
*/
|
|
457
|
+
id: 'claude-haiku-5-5',
|
|
458
|
+
provider: 'anthropic',
|
|
459
|
+
displayName: 'Claude Haiku 5.5',
|
|
460
|
+
inputPerMTok: 0.1,
|
|
461
|
+
outputPerMTok: 0.5,
|
|
462
|
+
contextWindow: 1_000_000,
|
|
463
|
+
cacheMinTokens: 512,
|
|
464
|
+
multipliers: { cacheRead: 0.1, cacheWrite5m: 1.25, cacheWrite1h: 2, batch: 0.5 },
|
|
465
|
+
tiers: [
|
|
466
|
+
{
|
|
467
|
+
id: 'over-100k',
|
|
468
|
+
when: { kind: 'input-tokens-above', tokens: 100_000 },
|
|
469
|
+
inputPerMTok: 0.5,
|
|
470
|
+
outputPerMTok: 2.5,
|
|
471
|
+
},
|
|
472
|
+
],
|
|
473
|
+
capability: 'small',
|
|
474
|
+
tier: 'haiku',
|
|
475
|
+
notes:
|
|
476
|
+
'Priced per request by prompt length: $0.10/$0.50 up to 100,000 input tokens, cache reads'
|
|
477
|
+
+ ' and writes included, and $0.50/$2.50 over it.',
|
|
478
|
+
},
|
|
423
479
|
{
|
|
424
480
|
id: 'claude-haiku-4-5',
|
|
425
481
|
// The dated form is the canonical API id and is what a real usage log
|
|
@@ -447,6 +503,189 @@ export const MODELS: ModelPricing[] = [
|
|
|
447
503
|
// one OpenAI publishes for GPT-5.6 and later; for these older models its
|
|
448
504
|
// guide says the minimum "varies by request settings", so it is the nearest
|
|
449
505
|
// published floor, not a promise, and each row's note says so.
|
|
506
|
+
// ------------------------------------------------------------------------
|
|
507
|
+
// GPT-5.6 and later: OpenAI's current generation.
|
|
508
|
+
//
|
|
509
|
+
// The pricing page and each model's page, read 2026-10-10 and 2026-10-11,
|
|
510
|
+
// and the prompt-caching guide. Three things set them apart from GPT-5:
|
|
511
|
+
//
|
|
512
|
+
// - **A long-context band, per request.** "Prompts with more than 272K input
|
|
513
|
+
// tokens are priced at 2x input and cache rates and 1.5x output for the
|
|
514
|
+
// full request." 272,000, the GPT-5 era's own input limit; a tier.
|
|
515
|
+
// - **Cache writes are billed**, at 1.25x the uncached input rate, and the
|
|
516
|
+
// usage object reports them (`cache_write_tokens`). Reads are 10% of input,
|
|
517
|
+
// 5% on GPT-6.1 Sol.
|
|
518
|
+
// - **An entry lives at least 30 minutes** after its last write or read, and
|
|
519
|
+
// there is no longer one to buy: `cacheTtl`.
|
|
520
|
+
//
|
|
521
|
+
// Caching is implicit by default (a breakpoint at the end of the latest
|
|
522
|
+
// eligible message) from a 1,024-token minimum. Batch and Flex are half
|
|
523
|
+
// price; Fast, Ultrafast and regional processing are other service tiers
|
|
524
|
+
// and are not priced here. Every model: 1,050,000 context, 922,000 input at
|
|
525
|
+
// most, 128,000 output.
|
|
526
|
+
// ------------------------------------------------------------------------
|
|
527
|
+
{
|
|
528
|
+
id: 'gpt-6-astra',
|
|
529
|
+
provider: 'openai',
|
|
530
|
+
displayName: 'GPT-6 Astra',
|
|
531
|
+
inputPerMTok: 10,
|
|
532
|
+
outputPerMTok: 50,
|
|
533
|
+
contextWindow: 1_050_000,
|
|
534
|
+
cacheMinTokens: 1024,
|
|
535
|
+
caching: 'automatic',
|
|
536
|
+
multipliers: { cacheRead: 0.1, cacheWrite5m: 1.25, cacheWrite1h: 1.25, batch: 0.5 },
|
|
537
|
+
cacheTtl: OPENAI_CACHE_TTL,
|
|
538
|
+
tiers: [
|
|
539
|
+
{
|
|
540
|
+
id: 'over-272k',
|
|
541
|
+
when: { kind: 'input-tokens-above', tokens: 272_000 },
|
|
542
|
+
inputPerMTok: 20,
|
|
543
|
+
outputPerMTok: 75,
|
|
544
|
+
},
|
|
545
|
+
],
|
|
546
|
+
capability: 'frontier',
|
|
547
|
+
tier: 'frontier',
|
|
548
|
+
notes: OPENAI_CURRENT_NOTE,
|
|
549
|
+
},
|
|
550
|
+
{
|
|
551
|
+
id: 'gpt-6.1-sol',
|
|
552
|
+
provider: 'openai',
|
|
553
|
+
displayName: 'GPT-6.1 Sol',
|
|
554
|
+
inputPerMTok: 2,
|
|
555
|
+
outputPerMTok: 10,
|
|
556
|
+
contextWindow: 1_050_000,
|
|
557
|
+
cacheMinTokens: 1024,
|
|
558
|
+
caching: 'automatic',
|
|
559
|
+
multipliers: { cacheRead: 0.05, cacheWrite5m: 1.25, cacheWrite1h: 1.25, batch: 0.5 },
|
|
560
|
+
cacheTtl: OPENAI_CACHE_TTL,
|
|
561
|
+
tiers: [
|
|
562
|
+
{
|
|
563
|
+
id: 'over-272k',
|
|
564
|
+
when: { kind: 'input-tokens-above', tokens: 272_000 },
|
|
565
|
+
inputPerMTok: 4,
|
|
566
|
+
outputPerMTok: 15,
|
|
567
|
+
},
|
|
568
|
+
],
|
|
569
|
+
capability: 'large',
|
|
570
|
+
tier: 'opus',
|
|
571
|
+
notes: OPENAI_CURRENT_NOTE,
|
|
572
|
+
},
|
|
573
|
+
{
|
|
574
|
+
id: 'gpt-6-sol',
|
|
575
|
+
provider: 'openai',
|
|
576
|
+
displayName: 'GPT-6 Sol',
|
|
577
|
+
inputPerMTok: 2,
|
|
578
|
+
outputPerMTok: 10,
|
|
579
|
+
contextWindow: 1_050_000,
|
|
580
|
+
cacheMinTokens: 1024,
|
|
581
|
+
caching: 'automatic',
|
|
582
|
+
multipliers: { cacheRead: 0.1, cacheWrite5m: 1.25, cacheWrite1h: 1.25, batch: 0.5 },
|
|
583
|
+
cacheTtl: OPENAI_CACHE_TTL,
|
|
584
|
+
tiers: [
|
|
585
|
+
{
|
|
586
|
+
id: 'over-272k',
|
|
587
|
+
when: { kind: 'input-tokens-above', tokens: 272_000 },
|
|
588
|
+
inputPerMTok: 4,
|
|
589
|
+
outputPerMTok: 15,
|
|
590
|
+
},
|
|
591
|
+
],
|
|
592
|
+
capability: 'large',
|
|
593
|
+
tier: 'opus',
|
|
594
|
+
notes: OPENAI_CURRENT_NOTE,
|
|
595
|
+
},
|
|
596
|
+
{
|
|
597
|
+
id: 'gpt-6-luna',
|
|
598
|
+
provider: 'openai',
|
|
599
|
+
displayName: 'GPT-6 Luna',
|
|
600
|
+
inputPerMTok: 0.1,
|
|
601
|
+
outputPerMTok: 0.5,
|
|
602
|
+
contextWindow: 1_050_000,
|
|
603
|
+
cacheMinTokens: 1024,
|
|
604
|
+
caching: 'automatic',
|
|
605
|
+
multipliers: { cacheRead: 0.1, cacheWrite5m: 1.25, cacheWrite1h: 1.25, batch: 0.5 },
|
|
606
|
+
cacheTtl: OPENAI_CACHE_TTL,
|
|
607
|
+
tiers: [
|
|
608
|
+
{
|
|
609
|
+
id: 'over-272k',
|
|
610
|
+
when: { kind: 'input-tokens-above', tokens: 272_000 },
|
|
611
|
+
inputPerMTok: 0.2,
|
|
612
|
+
outputPerMTok: 0.75,
|
|
613
|
+
},
|
|
614
|
+
],
|
|
615
|
+
capability: 'small',
|
|
616
|
+
tier: 'haiku',
|
|
617
|
+
notes: OPENAI_CURRENT_NOTE,
|
|
618
|
+
},
|
|
619
|
+
{
|
|
620
|
+
id: 'gpt-5.6-sol',
|
|
621
|
+
provider: 'openai',
|
|
622
|
+
displayName: 'GPT-5.6 Sol',
|
|
623
|
+
inputPerMTok: 4,
|
|
624
|
+
outputPerMTok: 20,
|
|
625
|
+
contextWindow: 1_050_000,
|
|
626
|
+
cacheMinTokens: 1024,
|
|
627
|
+
caching: 'automatic',
|
|
628
|
+
multipliers: { cacheRead: 0.1, cacheWrite5m: 1.25, cacheWrite1h: 1.25, batch: 0.5 },
|
|
629
|
+
cacheTtl: OPENAI_CACHE_TTL,
|
|
630
|
+
tiers: [
|
|
631
|
+
{
|
|
632
|
+
id: 'over-272k',
|
|
633
|
+
when: { kind: 'input-tokens-above', tokens: 272_000 },
|
|
634
|
+
inputPerMTok: 8,
|
|
635
|
+
outputPerMTok: 30,
|
|
636
|
+
},
|
|
637
|
+
],
|
|
638
|
+
capability: 'large',
|
|
639
|
+
tier: 'opus',
|
|
640
|
+
notes: OPENAI_CURRENT_NOTE,
|
|
641
|
+
},
|
|
642
|
+
{
|
|
643
|
+
id: 'gpt-5.6-terra',
|
|
644
|
+
provider: 'openai',
|
|
645
|
+
displayName: 'GPT-5.6 Terra',
|
|
646
|
+
inputPerMTok: 2,
|
|
647
|
+
outputPerMTok: 12,
|
|
648
|
+
contextWindow: 1_050_000,
|
|
649
|
+
cacheMinTokens: 1024,
|
|
650
|
+
caching: 'automatic',
|
|
651
|
+
multipliers: { cacheRead: 0.1, cacheWrite5m: 1.25, cacheWrite1h: 1.25, batch: 0.5 },
|
|
652
|
+
cacheTtl: OPENAI_CACHE_TTL,
|
|
653
|
+
tiers: [
|
|
654
|
+
{
|
|
655
|
+
id: 'over-272k',
|
|
656
|
+
when: { kind: 'input-tokens-above', tokens: 272_000 },
|
|
657
|
+
inputPerMTok: 4,
|
|
658
|
+
outputPerMTok: 18,
|
|
659
|
+
},
|
|
660
|
+
],
|
|
661
|
+
capability: 'mid',
|
|
662
|
+
tier: 'sonnet',
|
|
663
|
+
notes: OPENAI_CURRENT_NOTE,
|
|
664
|
+
},
|
|
665
|
+
{
|
|
666
|
+
id: 'gpt-5.6-luna',
|
|
667
|
+
provider: 'openai',
|
|
668
|
+
displayName: 'GPT-5.6 Luna',
|
|
669
|
+
inputPerMTok: 0.2,
|
|
670
|
+
outputPerMTok: 1.2,
|
|
671
|
+
contextWindow: 1_050_000,
|
|
672
|
+
cacheMinTokens: 1024,
|
|
673
|
+
caching: 'automatic',
|
|
674
|
+
multipliers: { cacheRead: 0.1, cacheWrite5m: 1.25, cacheWrite1h: 1.25, batch: 0.5 },
|
|
675
|
+
cacheTtl: OPENAI_CACHE_TTL,
|
|
676
|
+
tiers: [
|
|
677
|
+
{
|
|
678
|
+
id: 'over-272k',
|
|
679
|
+
when: { kind: 'input-tokens-above', tokens: 272_000 },
|
|
680
|
+
inputPerMTok: 0.4,
|
|
681
|
+
outputPerMTok: 1.8,
|
|
682
|
+
},
|
|
683
|
+
],
|
|
684
|
+
capability: 'small',
|
|
685
|
+
tier: 'haiku',
|
|
686
|
+
notes: OPENAI_CURRENT_NOTE,
|
|
687
|
+
},
|
|
688
|
+
|
|
450
689
|
// ------------------------------------------------------------------------
|
|
451
690
|
{
|
|
452
691
|
id: 'gpt-5',
|
|
@@ -601,10 +840,119 @@ export const MODELS: ModelPricing[] = [
|
|
|
601
840
|
'Implicit caching is automatic above 4,096 tokens. Explicit caching is also billed for storage:'
|
|
602
841
|
+ ' $0.50 per 1M tokens per hour through 2026-12-31, $1.00 after.',
|
|
603
842
|
},
|
|
843
|
+
{
|
|
844
|
+
/*
|
|
845
|
+
* The pricing page, the model page and the caching page, read 2026-10-10
|
|
846
|
+
* and 2026-10-11. The model Google's own refusal of 2.5 Pro names as its
|
|
847
|
+
* replacement, and the second model here priced by prompt length: $2/$12
|
|
848
|
+
* for a prompt up to 200,000 tokens and $4/$18 over it, the cache at
|
|
849
|
+
* $0.20 and $0.40 (10% in both bands), batch $1/$6 and $2/$9 (half in
|
|
850
|
+
* both). 1,048,576 tokens in, 65,536 out, implicit caching from 4,096.
|
|
851
|
+
* The `-customtools` endpoint is "same as Gemini 3.1 Pro Preview pricing".
|
|
852
|
+
*
|
|
853
|
+
* A preview, and priced because a log carries it: Google's 2.5 Pro
|
|
854
|
+
* refusal sends every caller here.
|
|
855
|
+
*/
|
|
856
|
+
id: 'gemini-3.1-pro-preview',
|
|
857
|
+
aliases: ['gemini-3.1-pro-preview-customtools'],
|
|
858
|
+
provider: 'google',
|
|
859
|
+
displayName: 'Gemini 3.1 Pro Preview',
|
|
860
|
+
inputPerMTok: 2,
|
|
861
|
+
outputPerMTok: 12,
|
|
862
|
+
contextWindow: 1_048_576,
|
|
863
|
+
cacheMinTokens: 4096,
|
|
864
|
+
caching: 'automatic',
|
|
865
|
+
multipliers: { cacheRead: 0.1, cacheWrite5m: 1, cacheWrite1h: 1, batch: 0.5 },
|
|
866
|
+
tiers: [
|
|
867
|
+
{
|
|
868
|
+
id: 'over-200k',
|
|
869
|
+
when: { kind: 'input-tokens-above', tokens: 200_000 },
|
|
870
|
+
inputPerMTok: 4,
|
|
871
|
+
outputPerMTok: 18,
|
|
872
|
+
},
|
|
873
|
+
],
|
|
874
|
+
capability: 'large',
|
|
875
|
+
tier: 'opus',
|
|
876
|
+
notes:
|
|
877
|
+
'Priced per request by prompt length: $2/$12 up to 200,000 input tokens and $4/$18 over it.'
|
|
878
|
+
+ ' Implicit caching is automatic above 4,096 tokens; explicit caching is also billed for storage,'
|
|
879
|
+
+ ' $4.50 per 1M tokens per hour.',
|
|
880
|
+
},
|
|
604
881
|
|
|
605
882
|
// ------------------------------------------------------------------------
|
|
606
883
|
// Moonshot
|
|
607
884
|
// ------------------------------------------------------------------------
|
|
885
|
+
/*
|
|
886
|
+
* platform.kimi.ai/docs/pricing/chat, models and pricing/batch, read in
|
|
887
|
+
* their Markdown form on 2026-10-11 (the HTML renders its tables in the
|
|
888
|
+
* browser, which is why the September review saw no context windows). K3
|
|
889
|
+
* bills cache writes as their own line, by TTL, like Anthropic: $3.00 for a
|
|
890
|
+
* 5-minute entry and $6.00 for an hour against a $3.00 input, and reads at
|
|
891
|
+
* $0.30. The K2 series bills no write, and reads at its own hit price. Batch
|
|
892
|
+
* is 60% of standard on K2.7 Code and K2.6 and not offered on K3 or the
|
|
893
|
+
* high-speed K2.7. No cache minimum is published for any of them.
|
|
894
|
+
*/
|
|
895
|
+
{
|
|
896
|
+
id: 'kimi-k3',
|
|
897
|
+
provider: 'moonshot',
|
|
898
|
+
displayName: 'Kimi K3',
|
|
899
|
+
inputPerMTok: 3,
|
|
900
|
+
outputPerMTok: 15,
|
|
901
|
+
contextWindow: 1_048_576,
|
|
902
|
+
cacheMinTokens: null,
|
|
903
|
+
caching: 'automatic',
|
|
904
|
+
multipliers: { cacheRead: 0.1, cacheWrite5m: 1, cacheWrite1h: 2, batch: null },
|
|
905
|
+
capability: 'frontier',
|
|
906
|
+
tier: 'frontier',
|
|
907
|
+
notes:
|
|
908
|
+
'Cache writes are billed as their own line: 1x input for a 5-minute entry, 2x for an hour.'
|
|
909
|
+
+ ` No batch API for this model. ${NO_PUBLISHED_CACHE_MINIMUM}`,
|
|
910
|
+
},
|
|
911
|
+
{
|
|
912
|
+
id: 'kimi-k2.7-code',
|
|
913
|
+
provider: 'moonshot',
|
|
914
|
+
displayName: 'Kimi K2.7 Code',
|
|
915
|
+
inputPerMTok: 0.95,
|
|
916
|
+
outputPerMTok: 4,
|
|
917
|
+
contextWindow: 262_144,
|
|
918
|
+
cacheMinTokens: null,
|
|
919
|
+
caching: 'automatic',
|
|
920
|
+
/* $0.19 on a hit against $0.95; batch $0.57 / $2.40, 60%. */
|
|
921
|
+
multipliers: { cacheRead: 0.2, cacheWrite5m: 1, cacheWrite1h: 1, batch: 0.6 },
|
|
922
|
+
capability: 'mid',
|
|
923
|
+
tier: 'sonnet',
|
|
924
|
+
notes: NO_PUBLISHED_CACHE_MINIMUM,
|
|
925
|
+
},
|
|
926
|
+
{
|
|
927
|
+
id: 'kimi-k2.7-code-highspeed',
|
|
928
|
+
provider: 'moonshot',
|
|
929
|
+
displayName: 'Kimi K2.7 Code (high speed)',
|
|
930
|
+
inputPerMTok: 1.9,
|
|
931
|
+
outputPerMTok: 8,
|
|
932
|
+
contextWindow: 262_144,
|
|
933
|
+
cacheMinTokens: null,
|
|
934
|
+
caching: 'automatic',
|
|
935
|
+
/* $0.38 on a hit against $1.90; no batch API for this variant. */
|
|
936
|
+
multipliers: { cacheRead: 0.2, cacheWrite5m: 1, cacheWrite1h: 1, batch: null },
|
|
937
|
+
capability: 'mid',
|
|
938
|
+
tier: 'sonnet',
|
|
939
|
+
notes: NO_PUBLISHED_CACHE_MINIMUM,
|
|
940
|
+
},
|
|
941
|
+
{
|
|
942
|
+
id: 'kimi-k2.6',
|
|
943
|
+
provider: 'moonshot',
|
|
944
|
+
displayName: 'Kimi K2.6',
|
|
945
|
+
inputPerMTok: 0.95,
|
|
946
|
+
outputPerMTok: 4,
|
|
947
|
+
contextWindow: 262_144,
|
|
948
|
+
cacheMinTokens: null,
|
|
949
|
+
caching: 'automatic',
|
|
950
|
+
/* $0.16 on a hit against $0.95, written as the ratio so the product is the page's figure. */
|
|
951
|
+
multipliers: { cacheRead: 0.16 / 0.95, cacheWrite5m: 1, cacheWrite1h: 1, batch: 0.6 },
|
|
952
|
+
capability: 'mid',
|
|
953
|
+
tier: 'sonnet',
|
|
954
|
+
notes: NO_PUBLISHED_CACHE_MINIMUM,
|
|
955
|
+
},
|
|
608
956
|
{
|
|
609
957
|
id: 'kimi-k2',
|
|
610
958
|
provider: 'moonshot',
|
|
@@ -612,14 +960,23 @@ export const MODELS: ModelPricing[] = [
|
|
|
612
960
|
inputPerMTok: 0.6,
|
|
613
961
|
outputPerMTok: 2.5,
|
|
614
962
|
contextWindow: 256_000,
|
|
615
|
-
cacheMinTokens:
|
|
963
|
+
cacheMinTokens: null,
|
|
616
964
|
caching: 'automatic',
|
|
617
965
|
multipliers: { cacheRead: 0.1, cacheWrite5m: 1, cacheWrite1h: 1, batch: null },
|
|
966
|
+
/*
|
|
967
|
+
* Discontinued: "The kimi-k2 series models were officially discontinued
|
|
968
|
+
* on May 25, 2026" (the provider's model list, read 2026-10-11). Kept at
|
|
969
|
+
* its last published price, because calls in somebody's log really
|
|
970
|
+
* happened at it, and never offered as somewhere to move. Not `retired`,
|
|
971
|
+
* which records the provider refusing a request, and no key was here to
|
|
972
|
+
* send one.
|
|
973
|
+
*/
|
|
974
|
+
recommendable: false,
|
|
618
975
|
capability: 'mid',
|
|
619
976
|
tier: 'sonnet',
|
|
620
977
|
notes:
|
|
621
|
-
'
|
|
622
|
-
+
|
|
978
|
+
'Discontinued by Moonshot on 2026-05-25; priced at the last rate it published. No batch API.'
|
|
979
|
+
+ ` ${NO_PUBLISHED_CACHE_MINIMUM}`,
|
|
623
980
|
},
|
|
624
981
|
|
|
625
982
|
// ------------------------------------------------------------------------
|
|
@@ -766,20 +1123,175 @@ export const MODELS: ModelPricing[] = [
|
|
|
766
1123
|
// ------------------------------------------------------------------------
|
|
767
1124
|
// xAI
|
|
768
1125
|
// ------------------------------------------------------------------------
|
|
1126
|
+
/*
|
|
1127
|
+
* docs.x.ai/developers/models and each model's page, read in their
|
|
1128
|
+
* Markdown form on 2026-10-11. Every text model has two rates: "requests
|
|
1129
|
+
* whose prompt reaches 200k tokens are billed at the higher rate for all
|
|
1130
|
+
* tokens in the request", which is a size tier at 200,000 inclusive and is
|
|
1131
|
+
* priced per request. Cached input scales with the band; writes are not
|
|
1132
|
+
* billed; batch is a 20% discount where the model's page offers it at all.
|
|
1133
|
+
* No cache minimum is published. Aliases are the stable family names the
|
|
1134
|
+
* pages list, never the `-latest` names, which move.
|
|
1135
|
+
*/
|
|
1136
|
+
{
|
|
1137
|
+
id: 'grok-4.7',
|
|
1138
|
+
provider: 'xai',
|
|
1139
|
+
displayName: 'Grok 4.7',
|
|
1140
|
+
inputPerMTok: 2,
|
|
1141
|
+
outputPerMTok: 6,
|
|
1142
|
+
contextWindow: 500_000,
|
|
1143
|
+
cacheMinTokens: null,
|
|
1144
|
+
caching: 'automatic',
|
|
1145
|
+
multipliers: { cacheRead: 0.25, cacheWrite5m: 1, cacheWrite1h: 1, batch: null },
|
|
1146
|
+
tiers: [GROK_LONG(4, 12)],
|
|
1147
|
+
capability: 'frontier',
|
|
1148
|
+
tier: 'frontier',
|
|
1149
|
+
notes: NO_PUBLISHED_CACHE_MINIMUM,
|
|
1150
|
+
},
|
|
1151
|
+
{
|
|
1152
|
+
id: 'grok-4.6',
|
|
1153
|
+
provider: 'xai',
|
|
1154
|
+
displayName: 'Grok 4.6',
|
|
1155
|
+
inputPerMTok: 2,
|
|
1156
|
+
outputPerMTok: 6,
|
|
1157
|
+
contextWindow: 500_000,
|
|
1158
|
+
cacheMinTokens: null,
|
|
1159
|
+
caching: 'automatic',
|
|
1160
|
+
multipliers: { cacheRead: 0.25, cacheWrite5m: 1, cacheWrite1h: 1, batch: null },
|
|
1161
|
+
tiers: [GROK_LONG(4, 12)],
|
|
1162
|
+
capability: 'large',
|
|
1163
|
+
tier: 'opus',
|
|
1164
|
+
notes: NO_PUBLISHED_CACHE_MINIMUM,
|
|
1165
|
+
},
|
|
1166
|
+
{
|
|
1167
|
+
id: 'grok-4.5',
|
|
1168
|
+
provider: 'xai',
|
|
1169
|
+
displayName: 'Grok 4.5',
|
|
1170
|
+
inputPerMTok: 2,
|
|
1171
|
+
outputPerMTok: 6,
|
|
1172
|
+
contextWindow: 500_000,
|
|
1173
|
+
cacheMinTokens: null,
|
|
1174
|
+
caching: 'automatic',
|
|
1175
|
+
/* $0.30 cached against $2.00. */
|
|
1176
|
+
multipliers: { cacheRead: 0.15, cacheWrite5m: 1, cacheWrite1h: 1, batch: null },
|
|
1177
|
+
tiers: [GROK_LONG(4, 12)],
|
|
1178
|
+
capability: 'large',
|
|
1179
|
+
tier: 'opus',
|
|
1180
|
+
notes: NO_PUBLISHED_CACHE_MINIMUM,
|
|
1181
|
+
},
|
|
1182
|
+
{
|
|
1183
|
+
id: 'grok-4.3',
|
|
1184
|
+
provider: 'xai',
|
|
1185
|
+
displayName: 'Grok 4.3',
|
|
1186
|
+
inputPerMTok: 1.25,
|
|
1187
|
+
outputPerMTok: 2.5,
|
|
1188
|
+
contextWindow: 1_000_000,
|
|
1189
|
+
cacheMinTokens: null,
|
|
1190
|
+
caching: 'automatic',
|
|
1191
|
+
/* $0.20 cached against $1.25; batch 20% off. */
|
|
1192
|
+
multipliers: { cacheRead: 0.16, cacheWrite5m: 1, cacheWrite1h: 1, batch: 0.8 },
|
|
1193
|
+
tiers: [GROK_LONG(2.5, 5)],
|
|
1194
|
+
capability: 'mid',
|
|
1195
|
+
tier: 'sonnet',
|
|
1196
|
+
notes: NO_PUBLISHED_CACHE_MINIMUM,
|
|
1197
|
+
},
|
|
1198
|
+
{
|
|
1199
|
+
id: 'grok-4.20-0309-reasoning',
|
|
1200
|
+
aliases: ['grok-4.20', 'grok-4.20-reasoning', 'grok-4.20-0309'],
|
|
1201
|
+
provider: 'xai',
|
|
1202
|
+
displayName: 'Grok 4.20 (reasoning)',
|
|
1203
|
+
inputPerMTok: 1.25,
|
|
1204
|
+
outputPerMTok: 2.5,
|
|
1205
|
+
contextWindow: 1_000_000,
|
|
1206
|
+
cacheMinTokens: null,
|
|
1207
|
+
caching: 'automatic',
|
|
1208
|
+
multipliers: { cacheRead: 0.16, cacheWrite5m: 1, cacheWrite1h: 1, batch: 0.8 },
|
|
1209
|
+
tiers: [GROK_LONG(2.5, 5)],
|
|
1210
|
+
capability: 'mid',
|
|
1211
|
+
tier: 'sonnet',
|
|
1212
|
+
notes: NO_PUBLISHED_CACHE_MINIMUM,
|
|
1213
|
+
},
|
|
1214
|
+
{
|
|
1215
|
+
id: 'grok-4.20-0309-non-reasoning',
|
|
1216
|
+
aliases: ['grok-4.20-non-reasoning'],
|
|
1217
|
+
provider: 'xai',
|
|
1218
|
+
displayName: 'Grok 4.20 (non-reasoning)',
|
|
1219
|
+
inputPerMTok: 1.25,
|
|
1220
|
+
outputPerMTok: 2.5,
|
|
1221
|
+
contextWindow: 1_000_000,
|
|
1222
|
+
cacheMinTokens: null,
|
|
1223
|
+
caching: 'automatic',
|
|
1224
|
+
multipliers: { cacheRead: 0.16, cacheWrite5m: 1, cacheWrite1h: 1, batch: 0.8 },
|
|
1225
|
+
tiers: [GROK_LONG(2.5, 5)],
|
|
1226
|
+
capability: 'mid',
|
|
1227
|
+
tier: 'sonnet',
|
|
1228
|
+
notes: NO_PUBLISHED_CACHE_MINIMUM,
|
|
1229
|
+
},
|
|
769
1230
|
{
|
|
1231
|
+
id: 'grok-4.20-multi-agent-0309',
|
|
1232
|
+
aliases: ['grok-4.20-multi-agent'],
|
|
1233
|
+
provider: 'xai',
|
|
1234
|
+
displayName: 'Grok 4.20 Multi-Agent',
|
|
1235
|
+
inputPerMTok: 1.25,
|
|
1236
|
+
outputPerMTok: 2.5,
|
|
1237
|
+
contextWindow: 1_000_000,
|
|
1238
|
+
cacheMinTokens: null,
|
|
1239
|
+
caching: 'automatic',
|
|
1240
|
+
multipliers: { cacheRead: 0.16, cacheWrite5m: 1, cacheWrite1h: 1, batch: 0.8 },
|
|
1241
|
+
tiers: [GROK_LONG(2.5, 5)],
|
|
1242
|
+
capability: 'mid',
|
|
1243
|
+
tier: 'sonnet',
|
|
1244
|
+
notes: NO_PUBLISHED_CACHE_MINIMUM,
|
|
1245
|
+
},
|
|
1246
|
+
{
|
|
1247
|
+
id: 'grok-build-0.1',
|
|
1248
|
+
provider: 'xai',
|
|
1249
|
+
displayName: 'Grok Build 0.1',
|
|
1250
|
+
inputPerMTok: 1,
|
|
1251
|
+
outputPerMTok: 2,
|
|
1252
|
+
contextWindow: 256_000,
|
|
1253
|
+
cacheMinTokens: null,
|
|
1254
|
+
caching: 'automatic',
|
|
1255
|
+
multipliers: { cacheRead: 0.2, cacheWrite5m: 1, cacheWrite1h: 1, batch: null },
|
|
1256
|
+
tiers: [GROK_LONG(2, 4)],
|
|
1257
|
+
capability: 'mid',
|
|
1258
|
+
tier: 'sonnet',
|
|
1259
|
+
notes: NO_PUBLISHED_CACHE_MINIMUM,
|
|
1260
|
+
},
|
|
1261
|
+
{
|
|
1262
|
+
/*
|
|
1263
|
+
* Retired on 2026-05-15 at 12:00 PT (19:00 UTC), and billed since at
|
|
1264
|
+
* Grok 4.3's prices: "requests to the retired model slugs above will
|
|
1265
|
+
* automatically redirect to grok-4.3 ... you will be billed at grok-4.3
|
|
1266
|
+
* pricing" (xAI's retirement notice, read 2026-10-11). So the id has two
|
|
1267
|
+
* periods, and a log that spans the date is billed both ways, at the
|
|
1268
|
+
* instant xAI gave. `grok-4-0709` is the dated id the notice names.
|
|
1269
|
+
*/
|
|
770
1270
|
id: 'grok-4',
|
|
1271
|
+
aliases: ['grok-4-0709'],
|
|
771
1272
|
provider: 'xai',
|
|
772
1273
|
displayName: 'Grok 4',
|
|
773
|
-
inputPerMTok:
|
|
774
|
-
outputPerMTok:
|
|
1274
|
+
inputPerMTok: 1.25,
|
|
1275
|
+
outputPerMTok: 2.5,
|
|
775
1276
|
contextWindow: 256_000,
|
|
776
|
-
cacheMinTokens:
|
|
1277
|
+
cacheMinTokens: null,
|
|
777
1278
|
caching: 'automatic',
|
|
778
|
-
multipliers: { cacheRead: 0.
|
|
1279
|
+
multipliers: { cacheRead: 0.16, cacheWrite5m: 1, cacheWrite1h: 1, batch: null },
|
|
1280
|
+
tiers: [GROK_LONG(2.5, 5)],
|
|
1281
|
+
history: [
|
|
1282
|
+
{
|
|
1283
|
+
until: '2026-05-15T19:00:00Z',
|
|
1284
|
+
inputPerMTok: 3,
|
|
1285
|
+
outputPerMTok: 15,
|
|
1286
|
+
multipliers: { cacheRead: 0.25, cacheWrite5m: 1, cacheWrite1h: 1, batch: null },
|
|
1287
|
+
},
|
|
1288
|
+
],
|
|
1289
|
+
recommendable: false,
|
|
779
1290
|
capability: 'large',
|
|
780
1291
|
tier: 'opus',
|
|
781
1292
|
notes:
|
|
782
|
-
'
|
|
1293
|
+
'Retired by xAI on 2026-05-15 and redirected to Grok 4.3, whose price it bills at from then;'
|
|
1294
|
+
+ ` $3/$15 before. ${NO_PUBLISHED_CACHE_MINIMUM}`,
|
|
783
1295
|
},
|
|
784
1296
|
|
|
785
1297
|
// ------------------------------------------------------------------------
|
|
@@ -1035,7 +1547,38 @@ interface Rates {
|
|
|
1035
1547
|
inputPerMTok: number;
|
|
1036
1548
|
outputPerMTok: number;
|
|
1037
1549
|
promoApplied: boolean;
|
|
1038
|
-
tier: {
|
|
1550
|
+
tier: {
|
|
1551
|
+
applied: string | null;
|
|
1552
|
+
decided: boolean;
|
|
1553
|
+
because: string;
|
|
1554
|
+
/**
|
|
1555
|
+
* The cheapest rate the undecided condition allows, present only when it
|
|
1556
|
+
* was not decided. The figure above is the ceiling and stays the one
|
|
1557
|
+
* billed; this is the other end, so a report can say how wide the
|
|
1558
|
+
* uncertainty is instead of only that there is some.
|
|
1559
|
+
*/
|
|
1560
|
+
floor?: { inputPerMTok: number; outputPerMTok: number };
|
|
1561
|
+
} | null;
|
|
1562
|
+
}
|
|
1563
|
+
|
|
1564
|
+
/**
|
|
1565
|
+
* What is known about the size of the prompt being priced.
|
|
1566
|
+
*
|
|
1567
|
+
* `inputTokens` is one request's prompt, every input token it carried, cache
|
|
1568
|
+
* reads and writes included, and decides a size tier outright.
|
|
1569
|
+
*
|
|
1570
|
+
* `inputTokensAtMost` is a bound, for a row that sums requests: a usage
|
|
1571
|
+
* report's hourly or daily bucket, an export's per-day line. No single
|
|
1572
|
+
* request in it can be larger than the whole row, so a row whose total is at
|
|
1573
|
+
* or under a threshold proves every request in it was under, and that decides
|
|
1574
|
+
* the tier. A row over the threshold proves nothing about any one request,
|
|
1575
|
+
* and the tier stays undecided. The bound is never treated as a size: a day of
|
|
1576
|
+
* 2,000 short prompts sums past 100,000 tokens without a single request
|
|
1577
|
+
* getting near it.
|
|
1578
|
+
*/
|
|
1579
|
+
export interface PromptSize {
|
|
1580
|
+
inputTokens?: number;
|
|
1581
|
+
inputTokensAtMost?: number;
|
|
1039
1582
|
}
|
|
1040
1583
|
|
|
1041
1584
|
const pricingMemo = new WeakMap<
|
|
@@ -1111,18 +1654,18 @@ function cache(model: ModelPricing): {
|
|
|
1111
1654
|
* because "this does not apply" and "nobody said" lead to different reports and
|
|
1112
1655
|
* collapsing them is the oldest mistake in this repository.
|
|
1113
1656
|
*/
|
|
1114
|
-
function holds(
|
|
1115
|
-
when: TierCondition,
|
|
1116
|
-
on: Date,
|
|
1117
|
-
inputTokens: number | undefined,
|
|
1118
|
-
): boolean | null {
|
|
1657
|
+
function holds(when: TierCondition, on: Date, size: PromptSize): boolean | null {
|
|
1119
1658
|
if (when.kind === 'utc-hours') {
|
|
1120
1659
|
const day = on.getUTCDay();
|
|
1121
1660
|
if (when.weekdaysOnly && (day === 0 || day === 6)) return false;
|
|
1122
1661
|
return when.hours.includes(on.getUTCHours());
|
|
1123
1662
|
}
|
|
1124
|
-
|
|
1125
|
-
|
|
1663
|
+
const over = (tokens: number): boolean =>
|
|
1664
|
+
when.kind === 'input-tokens-at-least' ? tokens >= when.tokens : tokens > when.tokens;
|
|
1665
|
+
if (size.inputTokens !== undefined) return over(size.inputTokens);
|
|
1666
|
+
// A whole row under the line puts every request in it under the line.
|
|
1667
|
+
if (size.inputTokensAtMost !== undefined && !over(size.inputTokensAtMost)) return false;
|
|
1668
|
+
return null;
|
|
1126
1669
|
}
|
|
1127
1670
|
|
|
1128
1671
|
/**
|
|
@@ -1144,7 +1687,7 @@ function holds(
|
|
|
1144
1687
|
export function effectivePricing(
|
|
1145
1688
|
model: ModelPricing,
|
|
1146
1689
|
on: Date = new Date(),
|
|
1147
|
-
context:
|
|
1690
|
+
context: PromptSize = {},
|
|
1148
1691
|
): Rates {
|
|
1149
1692
|
/* A call before a published price change is priced as it was billed then. */
|
|
1150
1693
|
if (model.history !== undefined) {
|
|
@@ -1164,7 +1707,7 @@ export function effectivePricing(
|
|
|
1164
1707
|
if (model.tiers !== undefined && model.tiers.length > 0) {
|
|
1165
1708
|
const undecided: PricingTier[] = [];
|
|
1166
1709
|
for (const tier of model.tiers) {
|
|
1167
|
-
const verdict = holds(tier.when, on, context
|
|
1710
|
+
const verdict = holds(tier.when, on, context);
|
|
1168
1711
|
if (verdict === true) {
|
|
1169
1712
|
return {
|
|
1170
1713
|
inputPerMTok: tier.inputPerMTok,
|
|
@@ -1187,6 +1730,11 @@ export function effectivePricing(
|
|
|
1187
1730
|
const dearest = undecided.reduce((worst, tier) =>
|
|
1188
1731
|
tier.inputPerMTok > worst.inputPerMTok ? tier : worst,
|
|
1189
1732
|
);
|
|
1733
|
+
/*
|
|
1734
|
+
* And the cheapest, which is the base: every undecided condition might not
|
|
1735
|
+
* hold, and a tier is never below the base (`pricing-tiers.test.js`).
|
|
1736
|
+
*/
|
|
1737
|
+
const floor = { inputPerMTok: model.inputPerMTok, outputPerMTok: model.outputPerMTok };
|
|
1190
1738
|
const ceiling =
|
|
1191
1739
|
dearest.inputPerMTok > model.inputPerMTok
|
|
1192
1740
|
? {
|
|
@@ -1206,7 +1754,11 @@ export function effectivePricing(
|
|
|
1206
1754
|
tier: {
|
|
1207
1755
|
applied: ceiling.applied,
|
|
1208
1756
|
decided: false,
|
|
1209
|
-
because:
|
|
1757
|
+
because:
|
|
1758
|
+
context.inputTokensAtMost !== undefined
|
|
1759
|
+
? `${describe(dearest.when)}, and this row sums requests without giving any one prompt's length`
|
|
1760
|
+
: `${describe(dearest.when)}, and the token count was not given`,
|
|
1761
|
+
floor,
|
|
1210
1762
|
},
|
|
1211
1763
|
};
|
|
1212
1764
|
}
|
|
@@ -1220,6 +1772,9 @@ function describe(when: TierCondition): string {
|
|
|
1220
1772
|
if (when.kind === 'input-tokens-above') {
|
|
1221
1773
|
return `prompts over ${when.tokens.toLocaleString('en-US')} input tokens`;
|
|
1222
1774
|
}
|
|
1775
|
+
if (when.kind === 'input-tokens-at-least') {
|
|
1776
|
+
return `prompts of ${when.tokens.toLocaleString('en-US')} input tokens or more`;
|
|
1777
|
+
}
|
|
1223
1778
|
const windows = [];
|
|
1224
1779
|
let start = null;
|
|
1225
1780
|
const sorted = [...when.hours].sort((a, b) => a - b);
|