@juspay/neurolink 12.40.3 → 12.41.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.
Files changed (36) hide show
  1. package/CHANGELOG.md +3 -3
  2. package/dist/browser/neurolink.min.js +447 -443
  3. package/dist/cli/commands/proxy.js +5 -1
  4. package/dist/proxy/accountLedger.js +3 -0
  5. package/dist/proxy/codexOutboundCache.d.ts +52 -0
  6. package/dist/proxy/codexOutboundCache.js +147 -0
  7. package/dist/proxy/codexOutboundFallback.d.ts +27 -2
  8. package/dist/proxy/codexOutboundFallback.js +147 -11
  9. package/dist/proxy/codexResponsesFormat.js +7 -1
  10. package/dist/proxy/codexToAnthropicFallback.js +6 -0
  11. package/dist/proxy/proxyAnalysis.js +4 -0
  12. package/dist/proxy/proxyConfig.js +120 -0
  13. package/dist/proxy/proxyTokenUsage.d.ts +15 -0
  14. package/dist/proxy/proxyTokenUsage.js +33 -0
  15. package/dist/proxy/proxyTracer.d.ts +16 -1
  16. package/dist/proxy/proxyTracer.js +26 -5
  17. package/dist/proxy/requestLogger.js +9 -0
  18. package/dist/proxy/runtimeConfig.js +20 -0
  19. package/dist/proxy/sseInterceptor.js +9 -0
  20. package/dist/proxy/vertexAnthropicFallback.js +9 -0
  21. package/dist/server/routes/claudeProxyRoutes.js +65 -1
  22. package/dist/server/routes/codexProxyRoutes.d.ts +39 -3
  23. package/dist/server/routes/codexProxyRoutes.js +792 -8
  24. package/dist/server/routes/index.d.ts +8 -0
  25. package/dist/server/routes/index.js +9 -1
  26. package/dist/types/analytics.d.ts +25 -0
  27. package/dist/types/codex.d.ts +45 -1
  28. package/dist/types/proxy.d.ts +40 -2
  29. package/dist/types/proxyClient.d.ts +2 -0
  30. package/dist/types/server.d.ts +15 -0
  31. package/dist/types/subscription.d.ts +22 -0
  32. package/dist/utils/anthropicCacheBreakpoints.d.ts +2 -2
  33. package/dist/utils/anthropicCacheBreakpoints.js +14 -3
  34. package/dist/utils/pricing.js +101 -24
  35. package/docs-site/static/search-index.json +17 -6
  36. package/package.json +1 -1
@@ -78,7 +78,8 @@ const PRICING = {
78
78
  // Anthropic (direct API) — updated March 2026
79
79
  anthropic: {
80
80
  // Claude 5 family. Rates from platform.claude.com/docs/en/about-claude/pricing
81
- // (checked 2026-09-23). A 5-minute cache write is 1.25x base input. The cache
81
+ // (checked 2026-09-23). A 5-minute cache write is 1.25x base input and a
82
+ // 1-hour one 2x, on every Claude model below. The cache
82
83
  // hit multiplier is 0.1x for most models but 0.05x on Opus 5.5 and 0.025x on
83
84
  // Fable/Mythos 5.1, so those three are listed in full rather than left to the
84
85
  // longest-prefix fallback — which would silently quote the 5.0 family's rates.
@@ -87,18 +88,22 @@ const PRICING = {
87
88
  output: 50.0 / 1_000_000,
88
89
  cacheRead: 0.25 / 1_000_000,
89
90
  cacheCreation: 12.5 / 1_000_000,
91
+ cacheCreation1h: 20.0 / 1_000_000,
90
92
  },
91
93
  "claude-mythos-5-1": {
92
94
  input: 10.0 / 1_000_000,
93
95
  output: 50.0 / 1_000_000,
94
96
  cacheRead: 0.25 / 1_000_000,
95
97
  cacheCreation: 12.5 / 1_000_000,
98
+ cacheCreation1h: 20.0 / 1_000_000,
96
99
  },
97
100
  "claude-opus-5-5": {
98
101
  input: 4.0 / 1_000_000,
99
102
  output: 20.0 / 1_000_000,
100
103
  cacheRead: 0.2 / 1_000_000,
101
104
  cacheCreation: 5.0 / 1_000_000,
105
+ // 1h TTL = 2x base input (platform.claude.com/docs/en/about-claude/pricing, read 2026-09-29).
106
+ cacheCreation1h: 8.0 / 1_000_000,
102
107
  },
103
108
  // Sonnet 5.5 bills exactly as Sonnet 5 does, cache rates included.
104
109
  "claude-sonnet-5-5": {
@@ -106,36 +111,43 @@ const PRICING = {
106
111
  output: 10.0 / 1_000_000,
107
112
  cacheRead: 0.2 / 1_000_000,
108
113
  cacheCreation: 2.5 / 1_000_000,
114
+ // 1h TTL = 2x base input (platform.claude.com/docs/en/about-claude/pricing, read 2026-09-29).
115
+ cacheCreation1h: 4.0 / 1_000_000,
109
116
  },
110
117
  "claude-fable-5": {
111
118
  input: 10.0 / 1_000_000,
112
119
  output: 50.0 / 1_000_000,
113
120
  cacheRead: 1.0 / 1_000_000,
114
121
  cacheCreation: 12.5 / 1_000_000,
122
+ cacheCreation1h: 20.0 / 1_000_000,
115
123
  },
116
124
  "claude-mythos-5": {
117
125
  input: 10.0 / 1_000_000,
118
126
  output: 50.0 / 1_000_000,
119
127
  cacheRead: 1.0 / 1_000_000,
120
128
  cacheCreation: 12.5 / 1_000_000,
129
+ cacheCreation1h: 20.0 / 1_000_000,
121
130
  },
122
131
  "claude-opus-5": {
123
132
  input: 5.0 / 1_000_000,
124
133
  output: 25.0 / 1_000_000,
125
134
  cacheRead: 0.5 / 1_000_000,
126
135
  cacheCreation: 6.25 / 1_000_000,
136
+ cacheCreation1h: 10.0 / 1_000_000,
127
137
  },
128
138
  "claude-opus-4-8": {
129
139
  input: 5.0 / 1_000_000,
130
140
  output: 25.0 / 1_000_000,
131
141
  cacheRead: 0.5 / 1_000_000,
132
142
  cacheCreation: 6.25 / 1_000_000,
143
+ cacheCreation1h: 10.0 / 1_000_000,
133
144
  },
134
145
  "claude-opus-4-7": {
135
146
  input: 5.0 / 1_000_000,
136
147
  output: 25.0 / 1_000_000,
137
148
  cacheRead: 0.5 / 1_000_000,
138
149
  cacheCreation: 6.25 / 1_000_000,
150
+ cacheCreation1h: 10.0 / 1_000_000,
139
151
  },
140
152
  // Sonnet 5's $2/$10 launch pricing became the standard price; the
141
153
  // previously scheduled 2026-09-01 rise to $3/$15 was cancelled.
@@ -144,6 +156,8 @@ const PRICING = {
144
156
  output: 10.0 / 1_000_000,
145
157
  cacheRead: 0.2 / 1_000_000,
146
158
  cacheCreation: 2.5 / 1_000_000,
159
+ // 1h TTL = 2x base input (platform.claude.com/docs/en/about-claude/pricing).
160
+ cacheCreation1h: 4.0 / 1_000_000,
147
161
  },
148
162
  // Claude 4.6 family
149
163
  "claude-opus-4-6": {
@@ -151,12 +165,14 @@ const PRICING = {
151
165
  output: 25.0 / 1_000_000,
152
166
  cacheRead: 0.5 / 1_000_000,
153
167
  cacheCreation: 6.25 / 1_000_000,
168
+ cacheCreation1h: 10.0 / 1_000_000,
154
169
  },
155
170
  "claude-sonnet-4-6": {
156
171
  input: 3.0 / 1_000_000,
157
172
  output: 15.0 / 1_000_000,
158
173
  cacheRead: 0.3 / 1_000_000,
159
174
  cacheCreation: 3.75 / 1_000_000,
175
+ cacheCreation1h: 6.0 / 1_000_000,
160
176
  },
161
177
  // Claude 4.5 family
162
178
  "claude-sonnet-4-5-20250929": {
@@ -164,6 +180,7 @@ const PRICING = {
164
180
  output: 15.0 / 1_000_000,
165
181
  cacheRead: 0.3 / 1_000_000,
166
182
  cacheCreation: 3.75 / 1_000_000,
183
+ cacheCreation1h: 6.0 / 1_000_000,
167
184
  },
168
185
  // Undated aliases for the same models. Clients report the bare name far
169
186
  // more often than the dated one, and without these the longest-prefix
@@ -175,24 +192,28 @@ const PRICING = {
175
192
  output: 15.0 / 1_000_000,
176
193
  cacheRead: 0.3 / 1_000_000,
177
194
  cacheCreation: 3.75 / 1_000_000,
195
+ cacheCreation1h: 6.0 / 1_000_000,
178
196
  },
179
197
  "claude-opus-4-5": {
180
198
  input: 5.0 / 1_000_000,
181
199
  output: 25.0 / 1_000_000,
182
200
  cacheRead: 0.5 / 1_000_000,
183
201
  cacheCreation: 6.25 / 1_000_000,
202
+ cacheCreation1h: 10.0 / 1_000_000,
184
203
  },
185
204
  "claude-haiku-4-5-20251001": {
186
205
  input: 1.0 / 1_000_000,
187
206
  output: 5.0 / 1_000_000,
188
207
  cacheRead: 0.1 / 1_000_000,
189
208
  cacheCreation: 1.25 / 1_000_000,
209
+ cacheCreation1h: 2.0 / 1_000_000,
190
210
  },
191
211
  "claude-haiku-4-5": {
192
212
  input: 1.0 / 1_000_000,
193
213
  output: 5.0 / 1_000_000,
194
214
  cacheRead: 0.1 / 1_000_000,
195
215
  cacheCreation: 1.25 / 1_000_000,
216
+ cacheCreation1h: 2.0 / 1_000_000,
196
217
  },
197
218
  // Claude 4.0/4.1 family
198
219
  "claude-opus-4-1": {
@@ -200,18 +221,21 @@ const PRICING = {
200
221
  output: 75.0 / 1_000_000,
201
222
  cacheRead: 1.5 / 1_000_000,
202
223
  cacheCreation: 18.75 / 1_000_000,
224
+ cacheCreation1h: 30.0 / 1_000_000,
203
225
  },
204
226
  "claude-opus-4": {
205
227
  input: 15.0 / 1_000_000,
206
228
  output: 75.0 / 1_000_000,
207
229
  cacheRead: 1.5 / 1_000_000,
208
230
  cacheCreation: 18.75 / 1_000_000,
231
+ cacheCreation1h: 30.0 / 1_000_000,
209
232
  },
210
233
  "claude-sonnet-4": {
211
234
  input: 3.0 / 1_000_000,
212
235
  output: 15.0 / 1_000_000,
213
236
  cacheRead: 0.3 / 1_000_000,
214
237
  cacheCreation: 3.75 / 1_000_000,
238
+ cacheCreation1h: 6.0 / 1_000_000,
215
239
  },
216
240
  // Claude 3.x family
217
241
  "claude-3-7-sonnet": {
@@ -219,40 +243,47 @@ const PRICING = {
219
243
  output: 15.0 / 1_000_000,
220
244
  cacheRead: 0.3 / 1_000_000,
221
245
  cacheCreation: 3.75 / 1_000_000,
246
+ cacheCreation1h: 6.0 / 1_000_000,
222
247
  },
223
248
  "claude-3-5-sonnet": {
224
249
  input: 3.0 / 1_000_000,
225
250
  output: 15.0 / 1_000_000,
226
251
  cacheRead: 0.3 / 1_000_000,
227
252
  cacheCreation: 3.75 / 1_000_000,
253
+ cacheCreation1h: 6.0 / 1_000_000,
228
254
  },
229
255
  "claude-3-5-haiku": {
230
256
  input: 0.8 / 1_000_000,
231
257
  output: 4.0 / 1_000_000,
232
258
  cacheRead: 0.08 / 1_000_000,
233
259
  cacheCreation: 1.0 / 1_000_000,
260
+ cacheCreation1h: 1.6 / 1_000_000,
234
261
  },
235
262
  "claude-3-opus": {
236
263
  input: 15.0 / 1_000_000,
237
264
  output: 75.0 / 1_000_000,
238
265
  cacheRead: 1.5 / 1_000_000,
239
266
  cacheCreation: 18.75 / 1_000_000,
267
+ cacheCreation1h: 30.0 / 1_000_000,
240
268
  },
241
269
  "claude-3-sonnet": {
242
270
  input: 3.0 / 1_000_000,
243
271
  output: 15.0 / 1_000_000,
244
272
  cacheRead: 0.3 / 1_000_000,
245
273
  cacheCreation: 3.75 / 1_000_000,
274
+ cacheCreation1h: 6.0 / 1_000_000,
246
275
  },
247
276
  "claude-3-haiku": {
248
277
  input: 0.25 / 1_000_000,
249
278
  output: 1.25 / 1_000_000,
250
279
  cacheRead: 0.025 / 1_000_000,
251
280
  cacheCreation: 0.3125 / 1_000_000,
281
+ cacheCreation1h: 0.5 / 1_000_000,
252
282
  },
253
283
  },
254
284
  // Google Vertex AI — Claude models on Vertex (same pricing, @ date suffix)
255
285
  vertex: {
286
+ // A 1-hour cache write is 2x base input, as on the direct API.
256
287
  // Claude 5 family. Absent here until now, so a Vertex leg serving any of
257
288
  // them resolved to no rate at all and booked the turn at $0 — on the one
258
289
  // provider in the chain that bills in real currency.
@@ -263,30 +294,36 @@ const PRICING = {
263
294
  output: 50.0 / 1_000_000,
264
295
  cacheRead: 0.25 / 1_000_000,
265
296
  cacheCreation: 12.5 / 1_000_000,
297
+ cacheCreation1h: 20.0 / 1_000_000,
266
298
  },
267
299
  "claude-mythos-5-1": {
268
300
  input: 10.0 / 1_000_000,
269
301
  output: 50.0 / 1_000_000,
270
302
  cacheRead: 0.25 / 1_000_000,
271
303
  cacheCreation: 12.5 / 1_000_000,
304
+ cacheCreation1h: 20.0 / 1_000_000,
272
305
  },
273
306
  "claude-fable-5": {
274
307
  input: 10.0 / 1_000_000,
275
308
  output: 50.0 / 1_000_000,
276
309
  cacheRead: 1.0 / 1_000_000,
277
310
  cacheCreation: 12.5 / 1_000_000,
311
+ cacheCreation1h: 20.0 / 1_000_000,
278
312
  },
279
313
  "claude-mythos-5": {
280
314
  input: 10.0 / 1_000_000,
281
315
  output: 50.0 / 1_000_000,
282
316
  cacheRead: 1.0 / 1_000_000,
283
317
  cacheCreation: 12.5 / 1_000_000,
318
+ cacheCreation1h: 20.0 / 1_000_000,
284
319
  },
285
320
  "claude-opus-5-5": {
286
321
  input: 4.0 / 1_000_000,
287
322
  output: 20.0 / 1_000_000,
288
323
  cacheRead: 0.2 / 1_000_000,
289
324
  cacheCreation: 5.0 / 1_000_000,
325
+ // 1h TTL = 2x base input (platform.claude.com/docs/en/about-claude/pricing, read 2026-09-29).
326
+ cacheCreation1h: 8.0 / 1_000_000,
290
327
  },
291
328
  // Sonnet 5.5 bills exactly as Sonnet 5 does, cache rates included.
292
329
  "claude-sonnet-5-5": {
@@ -294,60 +331,72 @@ const PRICING = {
294
331
  output: 10.0 / 1_000_000,
295
332
  cacheRead: 0.2 / 1_000_000,
296
333
  cacheCreation: 2.5 / 1_000_000,
334
+ // 1h TTL = 2x base input (platform.claude.com/docs/en/about-claude/pricing, read 2026-09-29).
335
+ cacheCreation1h: 4.0 / 1_000_000,
297
336
  },
298
337
  "claude-opus-5": {
299
338
  input: 5.0 / 1_000_000,
300
339
  output: 25.0 / 1_000_000,
301
340
  cacheRead: 0.5 / 1_000_000,
302
341
  cacheCreation: 6.25 / 1_000_000,
342
+ cacheCreation1h: 10.0 / 1_000_000,
303
343
  },
304
344
  "claude-sonnet-5": {
305
345
  input: 2.0 / 1_000_000,
306
346
  output: 10.0 / 1_000_000,
307
347
  cacheRead: 0.2 / 1_000_000,
308
348
  cacheCreation: 2.5 / 1_000_000,
349
+ // 1h TTL = 2x base input (platform.claude.com/docs/en/about-claude/pricing).
350
+ cacheCreation1h: 4.0 / 1_000_000,
309
351
  },
310
352
  "claude-sonnet-4-6": {
311
353
  input: 3.0 / 1_000_000,
312
354
  output: 15.0 / 1_000_000,
313
355
  cacheRead: 0.3 / 1_000_000,
314
356
  cacheCreation: 3.75 / 1_000_000,
357
+ cacheCreation1h: 6.0 / 1_000_000,
315
358
  },
316
359
  "claude-opus-4-6": {
317
360
  input: 5.0 / 1_000_000,
318
361
  output: 25.0 / 1_000_000,
319
362
  cacheRead: 0.5 / 1_000_000,
320
363
  cacheCreation: 6.25 / 1_000_000,
364
+ cacheCreation1h: 10.0 / 1_000_000,
321
365
  },
322
366
  "claude-sonnet-4-5": {
323
367
  input: 3.0 / 1_000_000,
324
368
  output: 15.0 / 1_000_000,
325
369
  cacheRead: 0.3 / 1_000_000,
326
370
  cacheCreation: 3.75 / 1_000_000,
371
+ cacheCreation1h: 6.0 / 1_000_000,
327
372
  },
328
373
  "claude-opus-4-5": {
329
374
  input: 5.0 / 1_000_000,
330
375
  output: 25.0 / 1_000_000,
331
376
  cacheRead: 0.5 / 1_000_000,
332
377
  cacheCreation: 6.25 / 1_000_000,
378
+ cacheCreation1h: 10.0 / 1_000_000,
333
379
  },
334
380
  "claude-haiku-4-5": {
335
381
  input: 1.0 / 1_000_000,
336
382
  output: 5.0 / 1_000_000,
337
383
  cacheRead: 0.1 / 1_000_000,
338
384
  cacheCreation: 1.25 / 1_000_000,
385
+ cacheCreation1h: 2.0 / 1_000_000,
339
386
  },
340
387
  "claude-3-5-haiku": {
341
388
  input: 0.8 / 1_000_000,
342
389
  output: 4.0 / 1_000_000,
343
390
  cacheRead: 0.08 / 1_000_000,
344
391
  cacheCreation: 1.0 / 1_000_000,
392
+ cacheCreation1h: 1.6 / 1_000_000,
345
393
  },
346
394
  "claude-3-5-sonnet": {
347
395
  input: 3.0 / 1_000_000,
348
396
  output: 15.0 / 1_000_000,
349
397
  cacheRead: 0.3 / 1_000_000,
350
398
  cacheCreation: 3.75 / 1_000_000,
399
+ cacheCreation1h: 6.0 / 1_000_000,
351
400
  },
352
401
  },
353
402
  // OpenAI — updated March 2026
@@ -826,20 +875,37 @@ function isVersionOnlySuffix(model, key) {
826
875
  return VERSION_SUFFIX_RE.test(model.slice(key.length));
827
876
  }
828
877
  /**
829
- * Whether `model` matches a provider manifest by the manifest's own
830
- * canonical id or by one of its declared aliases — deliberately excludes
878
+ * The manifest's canonical id for `model` when the manifest names it by that
879
+ * id or by one of its declared aliases — deliberately excludes
831
880
  * resolveManifestEntryExact's longest-prefix fallback. See the call site in
832
881
  * findRates for why the prefix path is unsafe to use for pricing precedence.
833
882
  */
834
- function isManifestNamedMatch(provider, model) {
883
+ function manifestCanonicalId(provider, model) {
835
884
  const manifest = getManifestForProvider(provider);
836
885
  if (!manifest) {
837
- return false;
886
+ return undefined;
838
887
  }
839
888
  if (Object.prototype.hasOwnProperty.call(manifest.models, model)) {
840
- return true;
889
+ return model;
841
890
  }
842
- return Object.values(manifest.models).some((entry) => entry.aliases.includes(model));
891
+ return Object.entries(manifest.models).find(([, entry]) => entry.aliases.includes(model))?.[0];
892
+ }
893
+ /**
894
+ * A provider table's entry for `modelKey`: the exact key, else the longest
895
+ * key `modelKey` starts with (never the synthetic "_default"). `exact` is
896
+ * true for a literal key or a version-only suffix of one.
897
+ */
898
+ function findTableEntry(providerPricing, modelKey) {
899
+ if (providerPricing[modelKey]) {
900
+ return { rates: providerPricing[modelKey], exact: true };
901
+ }
902
+ const sortedKeys = Object.keys(providerPricing)
903
+ .filter((k) => k !== "_default")
904
+ .sort((a, b) => b.length - a.length);
905
+ const key = sortedKeys.find((k) => modelKey.startsWith(k));
906
+ return key
907
+ ? { rates: providerPricing[key], exact: isVersionOnlySuffix(modelKey, key) }
908
+ : undefined;
843
909
  }
844
910
  function findRates(provider, model,
845
911
  /**
@@ -907,12 +973,17 @@ matchKind) {
907
973
  // claude-sonnet-5 — falls straight through to PRICING's unchanged
908
974
  // exact+prefix match below, which is exactly "legacy PRICING as the
909
975
  // fallback for entries the manifest lacks."
910
- if (isManifestNamedMatch(normalizedProvider, modelKey)) {
976
+ const canonicalId = manifestCanonicalId(normalizedProvider, modelKey);
977
+ if (canonicalId !== undefined) {
911
978
  const manifestEntry = resolveManifestEntryExact(normalizedProvider, modelKey);
912
979
  if (manifestEntry?.pricingPerMTok) {
913
980
  if (matchKind) {
914
981
  matchKind.exact = true;
915
982
  }
983
+ // The manifest carries no 1-hour cache-write rate; the table entry for
984
+ // the same model does. Without it a 1h write bills at the 5m rate.
985
+ const cacheCreation1h = (findTableEntry(providerPricing, modelKey) ??
986
+ findTableEntry(providerPricing, canonicalId))?.rates.cacheCreation1h;
916
987
  return {
917
988
  input: manifestEntry.pricingPerMTok.input / 1_000_000,
918
989
  output: manifestEntry.pricingPerMTok.output / 1_000_000,
@@ -922,26 +993,17 @@ matchKind) {
922
993
  cacheCreation: manifestEntry.pricingPerMTok.cacheWrite !== undefined
923
994
  ? manifestEntry.pricingPerMTok.cacheWrite / 1_000_000
924
995
  : undefined,
996
+ ...(cacheCreation1h !== undefined ? { cacheCreation1h } : {}),
925
997
  };
926
998
  }
927
999
  }
928
- // Exact match
929
- if (providerPricing[modelKey]) {
930
- if (matchKind) {
931
- matchKind.exact = true;
932
- }
933
- return providerPricing[modelKey];
934
- }
935
- // Longest-prefix match (skip the synthetic "_default" sentinel below)
936
- const sortedKeys = Object.keys(providerPricing)
937
- .filter((k) => k !== "_default")
938
- .sort((a, b) => b.length - a.length);
939
- const key = sortedKeys.find((k) => modelKey.startsWith(k));
940
- if (key) {
941
- if (matchKind && isVersionOnlySuffix(modelKey, key)) {
1000
+ // Exact match, else longest-prefix match
1001
+ const tableEntry = findTableEntry(providerPricing, modelKey);
1002
+ if (tableEntry) {
1003
+ if (matchKind && tableEntry.exact) {
942
1004
  matchKind.exact = true;
943
1005
  }
944
- return providerPricing[key];
1006
+ return tableEntry.rates;
945
1007
  }
946
1008
  // Fallback: Vertex hosts both Claude and Gemini models.
947
1009
  // If no match found under "vertex", try "google" pricing for Gemini models.
@@ -997,9 +1059,24 @@ export function calculateCost(provider, model, usage) {
997
1059
  cost += usage.cacheReadTokens * (rates.cacheRead ?? rates.input);
998
1060
  }
999
1061
  if (usage.cacheCreationTokens) {
1062
+ // `cacheCreation1hTokens` is a subset of `cacheCreationTokens` (the 1h-TTL
1063
+ // share of the total cache-write count), not additive with it — Anthropic
1064
+ // reports the 1h breakdown inside the same total
1065
+ // (`cache_creation.ephemeral_1h_input_tokens` within
1066
+ // `cache_creation_input_tokens`). Clamp to [0, total] so an inconsistent
1067
+ // or negative count can never bill more tokens than were written, or
1068
+ // subtract cost.
1069
+ const oneHourTokens = Math.max(0, Math.min(usage.cacheCreation1hTokens ?? 0, usage.cacheCreationTokens));
1070
+ const fiveMinTokens = usage.cacheCreationTokens - oneHourTokens;
1000
1071
  // Like cache reads, disjoint cache writes must not silently become free
1001
1072
  // when a model has no separate creation rate. Preserve explicit zero rates.
1002
- cost += usage.cacheCreationTokens * (rates.cacheCreation ?? rates.input);
1073
+ cost += fiveMinTokens * (rates.cacheCreation ?? rates.input);
1074
+ // A model without a `cacheCreation1h` rate keeps today's pricing exactly:
1075
+ // it falls back through the 5-minute rate to the input rate, the same
1076
+ // chain the 5-minute share already uses, rather than going unpriced.
1077
+ cost +=
1078
+ oneHourTokens *
1079
+ (rates.cacheCreation1h ?? rates.cacheCreation ?? rates.input);
1003
1080
  }
1004
1081
  return Math.round(cost * 1_000_000) / 1_000_000; // Round to 6 decimal places
1005
1082
  }