tokentracker-cli 1.5.2 → 1.5.4
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/dashboard/dist/assets/{AchievementBadge-B5kmt0VD.js → AchievementBadge-CKNb_cwg.js} +1 -1
- package/dashboard/dist/assets/{AchievementsPage-C0FlkOo0.js → AchievementsPage-u9P8DXJI.js} +2 -2
- package/dashboard/dist/assets/{AchievementsSection-CRcp80Pp.js → AchievementsSection-BSCUJ4DR.js} +1 -1
- package/dashboard/dist/assets/{BadgeDetailModal-DAFjGbKW.js → BadgeDetailModal-Bg7cE3Zq.js} +1 -1
- package/dashboard/dist/assets/{BotAnimated-CO0bbimB.js → BotAnimated-C7D2WbQA.js} +1 -1
- package/dashboard/dist/assets/{Card-Xhr5exz8.js → Card-B4IqAhai.js} +1 -1
- package/dashboard/dist/assets/{CloudCheckoutPage-DsQ7FmsI.js → CloudCheckoutPage-P75pH9Ym.js} +1 -1
- package/dashboard/dist/assets/{CloudPage-DkSexu5V.js → CloudPage-DDEZfmZg.js} +2 -2
- package/dashboard/dist/assets/{CommandPalette-Bm0huQdj.js → CommandPalette-CER_AklA.js} +1 -1
- package/dashboard/dist/assets/{CommunityStatsModal-BsL8GN8Q.js → CommunityStatsModal-Cbb74eib.js} +1 -1
- package/dashboard/dist/assets/{ConfirmModal-_WPp292g.js → ConfirmModal-Q1ZQdZHt.js} +1 -1
- package/dashboard/dist/assets/{Controls-ktzn68KM.js → Controls-DaGOfcoz.js} +1 -1
- package/dashboard/dist/assets/DashboardPage-CXI7RmxO.js +1 -0
- package/dashboard/dist/assets/{DateRangePopover-DWr4zIzF.js → DateRangePopover-DSS1Ira_.js} +1 -1
- package/dashboard/dist/assets/{DevicePage-CBa8Mk47.js → DevicePage-6zPLYydh.js} +1 -1
- package/dashboard/dist/assets/{DialogClose-CZ5jzgtb.js → DialogClose-DdCQ36LK.js} +1 -1
- package/dashboard/dist/assets/DialogDescription-DztHQvj-.js +1 -0
- package/dashboard/dist/assets/{DialogTitle-Dr0N6q15.js → DialogTitle-BjP217Y1.js} +1 -1
- package/dashboard/dist/assets/{ElectricLogo-sYqgrO6-.js → ElectricLogo-Dhq8PM4h.js} +1 -1
- package/dashboard/dist/assets/{FadeIn-Qq-hcrZW.js → FadeIn-CGNbED4E.js} +1 -1
- package/dashboard/dist/assets/{HeaderGithubStar-B77zSv7i.js → HeaderGithubStar-DwqEFzb6.js} +1 -1
- package/dashboard/dist/assets/{HoverTooltip-lRDaUmoW.js → HoverTooltip-CQZTgyQy.js} +1 -1
- package/dashboard/dist/assets/{IpCheckPage-B6AvHZjA.js → IpCheckPage-Bz09HXLn.js} +1 -1
- package/dashboard/dist/assets/{LandingPage-DgzOjf3x.js → LandingPage-DC-lZsYR.js} +2 -2
- package/dashboard/dist/assets/{LeaderboardPage-BtjjtDMC.js → LeaderboardPage-D8MpLM_t.js} +2 -2
- package/dashboard/dist/assets/{LeaderboardProBadge-B2wNTUTU.js → LeaderboardProBadge-pdXgokhE.js} +1 -1
- package/dashboard/dist/assets/{LeaderboardProfileModal-DJJckwHh.js → LeaderboardProfileModal-nHZLiE0m.js} +3 -3
- package/dashboard/dist/assets/{LeaderboardProfilePage-DJdxByl2.js → LeaderboardProfilePage-BKv3oIAW.js} +1 -1
- package/dashboard/dist/assets/LimitsPage-TmRTgSCb.js +6 -0
- package/dashboard/dist/assets/{LocalOnlyNotice-B2lVqf_H.js → LocalOnlyNotice-aF01udyR.js} +1 -1
- package/dashboard/dist/assets/{LoginCard-i0gg1yby.js → LoginCard-BaroD0Ct.js} +1 -1
- package/dashboard/dist/assets/{LoginModal-B-loLNZM.js → LoginModal-0jgyMGVM.js} +1 -1
- package/dashboard/dist/assets/{LoginPage-D_swI75j.js → LoginPage-BUx8U58i.js} +1 -1
- package/dashboard/dist/assets/{PetPage-DDpKvpjG.js → PetPage-CpOjtJqg.js} +2 -2
- package/dashboard/dist/assets/{PopoverPopup-Gja4MyEK.js → PopoverPopup-BYjfer-M.js} +1 -1
- package/dashboard/dist/assets/{ProviderIcon-DOPj7tAZ.js → ProviderIcon-NtYa2h0u.js} +1 -1
- package/dashboard/dist/assets/{ResetPasswordPage-BVADLk89.js → ResetPasswordPage-CYUg7TR1.js} +1 -1
- package/dashboard/dist/assets/{Select-D-38tN-E.js → Select-CYP95o5y.js} +1 -1
- package/dashboard/dist/assets/{SelectItemText-jN61ukxk.js → SelectItemText-BCDfusOM.js} +1 -1
- package/dashboard/dist/assets/{SelfHostPage-k7AkGpl1.js → SelfHostPage-BmVc2rIT.js} +1 -1
- package/dashboard/dist/assets/ServiceStatusPage-Dyp8NwIn.js +1 -0
- package/dashboard/dist/assets/SessionsPage-tGEj6Ztz.js +3 -0
- package/dashboard/dist/assets/{SettingsPage-DfnMCAuA.js → SettingsPage-CCMbq5wc.js} +3 -3
- package/dashboard/dist/assets/{SkillsPage-YyIHIaHN.js → SkillsPage-C4O4fbaQ.js} +1 -1
- package/dashboard/dist/assets/{TokenGalaxy-BLcvZuQ9.js → TokenGalaxy-D2d738xr.js} +1 -1
- package/dashboard/dist/assets/{TooltipPopup-3E8kyVzz.js → TooltipPopup-BJfFYesG.js} +1 -1
- package/dashboard/dist/assets/{TrendMonitor-ByKAdXSF.js → TrendMonitor-CElakFSU.js} +1 -1
- package/dashboard/dist/assets/{WidgetsPage-BgEVIIzL.js → WidgetsPage-Cvd1LbJm.js} +1 -1
- package/dashboard/dist/assets/{WrappedPage-HjbX8QaA.js → WrappedPage-wRC1tE_a.js} +1 -1
- package/dashboard/dist/assets/{__vite-browser-external-Br-KAXh6.css → __vite-browser-external-CMBWGkOq.css} +1 -1
- package/dashboard/dist/assets/__vite-browser-external-V4TPLCJG.js +45 -0
- package/dashboard/dist/assets/{agent-logos-BVF2siPQ.js → agent-logos-Ba57HF3w.js} +1 -1
- package/dashboard/dist/assets/{arrow-left-CYO24PGP.js → arrow-left-B1bKnxXL.js} +1 -1
- package/dashboard/dist/assets/{arrow-right-Xg9PZYhw.js → arrow-right-DrOlKzX5.js} +1 -1
- package/dashboard/dist/assets/{arrow-up-right-B7ah6Qv-.js → arrow-up-right-hlYpo3yw.js} +1 -1
- package/dashboard/dist/assets/{calendar-days-BV_iG938.js → calendar-days-CSY6SEsI.js} +1 -1
- package/dashboard/dist/assets/{check--EZH8RTp.js → check-xrP1gLw5.js} +1 -1
- package/dashboard/dist/assets/{chevron-down-BzGTlk0-.js → chevron-down-6-zT5n9d.js} +1 -1
- package/dashboard/dist/assets/{cloud-checkout-BgyxPHEh.js → cloud-checkout-BZymZD4K.js} +1 -1
- package/dashboard/dist/assets/{composite-C0KrmLEK.js → composite-C9izWafa.js} +1 -1
- package/dashboard/dist/assets/{copy-BtucSK2U.js → copy-Dkas5wZX.js} +1 -1
- package/dashboard/dist/assets/{download-CWHq03Y2.js → download-CagGRs0_.js} +1 -1
- package/dashboard/dist/assets/{external-link-DCTXF5VZ.js → external-link-DRl10hxd.js} +1 -1
- package/dashboard/dist/assets/{flame-BE5TsqVF.js → flame-CkvmsTFB.js} +1 -1
- package/dashboard/dist/assets/{format-tokens-ThNIMWnZ.js → format-tokens-BtwhO3mV.js} +1 -1
- package/dashboard/dist/assets/{gift-DgaN9s4-.js → gift-YzjXkMQx.js} +1 -1
- package/dashboard/dist/assets/{icons-B4r5EiDC.js → icons-CHhKYs0u.js} +1 -1
- package/dashboard/dist/assets/{index-DqCtgU0G.js → index-B0MQZTrM.js} +1 -1
- package/dashboard/dist/assets/{index-fNKH4U7j.js → index-C2DK8av-.js} +1 -1
- package/dashboard/dist/assets/{index-CKhcCLNC.js → index-CJknN9Jd.js} +1 -1
- package/dashboard/dist/assets/{index-DFF9xo6f.js → index-DojzoMqd.js} +1 -1
- package/dashboard/dist/assets/{info-B4YzRR4y.js → info-Torep-Ti.js} +1 -1
- package/dashboard/dist/assets/{link-2-DzbUbaBw.js → link-2-DE5Yu-z6.js} +1 -1
- package/dashboard/dist/assets/{loader-circle-B9c7D-7v.js → loader-circle-BL8LxD9n.js} +1 -1
- package/dashboard/dist/assets/{local-usage-transfer-btuk_b0Y.js → local-usage-transfer-8X1InWix.js} +1 -1
- package/dashboard/dist/assets/{modifiers.esm-BjrU-Xz7.js → modifiers.esm-D60-6UQa.js} +1 -1
- package/dashboard/dist/assets/{monitor-smartphone-Bwn4tb4q.js → monitor-smartphone-C-IFPjqk.js} +1 -1
- package/dashboard/dist/assets/{play-DIFOwGIQ.js → play-n6uWrdH9.js} +1 -1
- package/dashboard/dist/assets/{plus-BpBqnwVg.js → plus-B2f6TaNj.js} +1 -1
- package/dashboard/dist/assets/{provider-display-DSrs4u7T.js → provider-display-DWqCEcsP.js} +1 -1
- package/dashboard/dist/assets/{react-BgG7_MY0.js → react-B-zfi_j6.js} +1 -1
- package/dashboard/dist/assets/{safePolygon-BUGWIDOM.js → safePolygon-C2PsvI-v.js} +1 -1
- package/dashboard/dist/assets/{search-aHrmBmtZ.js → search-DZOaTLF9.js} +1 -1
- package/dashboard/dist/assets/{server-DOEvwlEU.js → server-DIp4Qfsv.js} +1 -1
- package/dashboard/dist/assets/{shield-check-BPTnLhsT.js → shield-check-Cs2M8-iT.js} +1 -1
- package/dashboard/dist/assets/{skills-api-C052Mwez.js → skills-api-CoYy6Tov.js} +1 -1
- package/dashboard/dist/assets/{sortable.esm-DaZKhjhu.js → sortable.esm-B5_hjIfs.js} +1 -1
- package/dashboard/dist/assets/{store-Cq30Pofw.js → store-BLXqtJzb.js} +1 -1
- package/dashboard/dist/assets/{terminal-CoSDSkE7.js → terminal-CEMKX3ba.js} +1 -1
- package/dashboard/dist/assets/{trash-BAmt-kPj.js → trash-DOWYaXjK.js} +1 -1
- package/dashboard/dist/assets/{use-community-stats-Bxq0kBhm.js → use-community-stats-BjRI1Bzz.js} +1 -1
- package/dashboard/dist/assets/{use-latest-request-guard-DmIQDlvk.js → use-latest-request-guard-T7L5qBU6.js} +1 -1
- package/dashboard/dist/assets/use-limits-display-prefs-vNIrCPZA.js +1 -0
- package/dashboard/dist/assets/{use-native-settings-s_CIC8Bb.js → use-native-settings-Cg5Zb4q_.js} +1 -1
- package/dashboard/dist/assets/{use-ordered-list-BHhykAbt.js → use-ordered-list-BF-wIvmG.js} +1 -1
- package/dashboard/dist/assets/use-reduced-motion-B9K5mIx4.js +1 -0
- package/dashboard/dist/assets/{use-transform-CVeMFlS6.js → use-transform-CbJ1IcNc.js} +1 -1
- package/dashboard/dist/assets/use-usage-limits-Dgg3jpC4.js +1 -0
- package/dashboard/dist/assets/{useCurrency-DilqL2Iv.js → useCurrency-3oBHWfSe.js} +1 -1
- package/dashboard/dist/assets/{usePositioner-BcnySw8a.js → usePositioner-D0YrIW0A.js} +1 -1
- package/dashboard/dist/assets/{useTokenFormat-CvKW46WP.js → useTokenFormat-DZAHWE_R.js} +1 -1
- package/dashboard/dist/assets/{zap-D7VRNTwk.js → zap-kLub6Jiv.js} +1 -1
- package/dashboard/dist/index.html +2 -2
- package/dashboard/dist/ip-check.html +2 -2
- package/dashboard/dist/leaderboard.html +2 -2
- package/dashboard/dist/share.html +2 -2
- package/package.json +1 -1
- package/src/commands/serve.js +25 -15
- package/src/lib/accept-encoding.js +59 -0
- package/src/lib/cursor-config.js +3 -1
- package/src/lib/deepseek-limits.js +280 -0
- package/src/lib/deepseek-status.js +157 -0
- package/src/lib/grok-limits.js +40 -1
- package/src/lib/local-api.js +248 -10
- package/src/lib/opencode-status.js +88 -0
- package/src/lib/pricing/index.js +182 -79
- package/src/lib/pricing/seed-snapshot.json +1 -1
- package/src/lib/provider-api-key-store.js +2 -0
- package/src/lib/provider-status.js +27 -2
- package/src/lib/qoder-limits.js +17 -2
- package/src/lib/session-analytics.js +194 -29
- package/src/lib/static-server.js +74 -2
- package/src/lib/usage-limits.js +714 -53
- package/src/lib/workbuddy-limits.js +291 -26
- package/src/lib/zcode-limits.js +143 -35
- package/dashboard/dist/assets/DashboardPage-CdNXi3Im.js +0 -1
- package/dashboard/dist/assets/DialogDescription-kCZ4gN09.js +0 -1
- package/dashboard/dist/assets/LimitsPage-gSBHSBi_.js +0 -6
- package/dashboard/dist/assets/ServiceStatusPage-D_Fa_pYz.js +0 -1
- package/dashboard/dist/assets/SessionsPage-BymccEEz.js +0 -3
- package/dashboard/dist/assets/__vite-browser-external-D_cMeuqI.js +0 -45
- package/dashboard/dist/assets/use-limits-display-prefs-CyAn1fme.js +0 -1
- package/dashboard/dist/assets/use-reduced-motion-BmFyFE3S.js +0 -1
- package/dashboard/dist/assets/use-usage-limits-DRZMI20u.js +0 -1
package/src/lib/pricing/index.js
CHANGED
|
@@ -172,6 +172,17 @@ function computeModelPricingInfo(model, opts, sourceKey) {
|
|
|
172
172
|
output: Number(rates.output) || 0,
|
|
173
173
|
cache_read: Number(rates.cache_read) || 0,
|
|
174
174
|
cache_write: Number(rates.cache_write) || 0,
|
|
175
|
+
// Speed-tier multipliers so the dashboard can label Fast/Ultrafast
|
|
176
|
+
// sub-rows with the actual premium instead of hardcoding 2x/6x (issue 886).
|
|
177
|
+
// Mirrored from the raw entry only when it publishes them — the info
|
|
178
|
+
// object must keep matching getModelPricing key-for-key
|
|
179
|
+
// (session-performance.test.js pins that contract).
|
|
180
|
+
...(Number.isFinite(Number(rates.priority_multiplier))
|
|
181
|
+
? { priority_multiplier: Number(rates.priority_multiplier) }
|
|
182
|
+
: null),
|
|
183
|
+
...(Number.isFinite(Number(rates.ultrafast_multiplier))
|
|
184
|
+
? { ultrafast_multiplier: Number(rates.ultrafast_multiplier) }
|
|
185
|
+
: null),
|
|
175
186
|
};
|
|
176
187
|
}
|
|
177
188
|
|
|
@@ -221,6 +232,110 @@ function getRowPricing(row) {
|
|
|
221
232
|
};
|
|
222
233
|
}
|
|
223
234
|
|
|
235
|
+
// Codex-family reasoning folding, shared by computeRowCost and the speed-tier
|
|
236
|
+
// allocation below. OmO, like Codex, reports reasoning as a subset of `output`
|
|
237
|
+
// (its own usage.cost bills no separate reasoning component), so charging it
|
|
238
|
+
// again here would double-bill every reasoning token. Cline is the same: its
|
|
239
|
+
// `outputTokens` is the AI SDK total (text + reasoning), so
|
|
240
|
+
// reasoning_output_tokens is a subset marker, never a second line item.
|
|
241
|
+
function reasoningFoldsIntoOutput(row) {
|
|
242
|
+
return (
|
|
243
|
+
row.source === "codex" ||
|
|
244
|
+
row.source === "acode" ||
|
|
245
|
+
row.source === "every-code" ||
|
|
246
|
+
row.source === "omo" ||
|
|
247
|
+
row.source === "cline" ||
|
|
248
|
+
row.source === "muse"
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// One row's observed-subset context: the bounded long-context columns that the
|
|
253
|
+
// speed-tier subsets intersect with, plus whether the row's model prices a
|
|
254
|
+
// long-context tier at all. Pure arithmetic on the row; both computeRowCost
|
|
255
|
+
// and computeRowTierCosts build it so their per-tier math cannot drift.
|
|
256
|
+
function rowSubsetContext(row, reasoningIncludedInOutput) {
|
|
257
|
+
const bounded = (value, total) => Math.min(
|
|
258
|
+
Math.max(0, Number(value) || 0),
|
|
259
|
+
Math.max(0, Number(total) || 0),
|
|
260
|
+
);
|
|
261
|
+
const model = String(row?.model || "").toLowerCase();
|
|
262
|
+
const usesOpenAILongContextTier =
|
|
263
|
+
model === "gpt-5.6" || model.includes("gpt-5.6-sol") || model.includes("gpt-6-astra") ||
|
|
264
|
+
model.includes("gpt-6-sol") || model.includes("gpt-6.1-sol") ||
|
|
265
|
+
model.includes("gpt-6.1-terra");
|
|
266
|
+
// Both premium families below read "observed subset" columns: how much of the
|
|
267
|
+
// row's own token columns came from requests with a given property. They are
|
|
268
|
+
// annotations, never addends — total_tokens stays the sum of the base columns
|
|
269
|
+
// whether or not they are present, and a legacy row that omits them prices
|
|
270
|
+
// exactly as it did before.
|
|
271
|
+
//
|
|
272
|
+
// The parser records only usage from requests whose cache-inclusive input
|
|
273
|
+
// exceeded 272K. OpenAI prices the whole such request at 2x input and 1.5x
|
|
274
|
+
// output, so add the premium over the standard-rate base exactly once.
|
|
275
|
+
const longInput = bounded(row.long_context_input_tokens, row.input_tokens);
|
|
276
|
+
const longCached = bounded(row.long_context_cached_input_tokens, row.cached_input_tokens);
|
|
277
|
+
const longCacheWrite = bounded(
|
|
278
|
+
row.long_context_cache_creation_input_tokens,
|
|
279
|
+
row.cache_creation_input_tokens,
|
|
280
|
+
);
|
|
281
|
+
const longOutput = bounded(row.long_context_output_tokens, row.output_tokens);
|
|
282
|
+
const longReasoning = reasoningIncludedInOutput
|
|
283
|
+
? 0
|
|
284
|
+
: bounded(row.long_context_reasoning_output_tokens, row.reasoning_output_tokens);
|
|
285
|
+
return {
|
|
286
|
+
bounded,
|
|
287
|
+
usesOpenAILongContextTier,
|
|
288
|
+
longInput,
|
|
289
|
+
longCached,
|
|
290
|
+
longCacheWrite,
|
|
291
|
+
longOutput,
|
|
292
|
+
longReasoning,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// Standard-rate cost of one observed speed-tier subset (priority_/ultrafast_):
|
|
297
|
+
// the tier's own token columns priced at the row's base rates, plus the same
|
|
298
|
+
// treatment for its long-context intersection. computeRowCost multiplies this
|
|
299
|
+
// by (multiplier - 1) for the premium; computeRowTierCosts books it to the
|
|
300
|
+
// tier itself.
|
|
301
|
+
function speedTierSubsetCost(row, prefix, pricing, ctx) {
|
|
302
|
+
const { bounded, usesOpenAILongContextTier, longInput, longCached, longCacheWrite, longOutput, longReasoning } = ctx;
|
|
303
|
+
const tierInput = bounded(row[`${prefix}input_tokens`], row.input_tokens);
|
|
304
|
+
const tierCached = bounded(row[`${prefix}cached_input_tokens`], row.cached_input_tokens);
|
|
305
|
+
const tierCacheWrite = bounded(
|
|
306
|
+
row[`${prefix}cache_creation_input_tokens`],
|
|
307
|
+
row.cache_creation_input_tokens,
|
|
308
|
+
);
|
|
309
|
+
const tierOutput = bounded(row[`${prefix}output_tokens`], row.output_tokens);
|
|
310
|
+
const tierReasoning = ctx.reasoningIncludedInOutput
|
|
311
|
+
? 0
|
|
312
|
+
: bounded(row[`${prefix}reasoning_output_tokens`], row.reasoning_output_tokens);
|
|
313
|
+
const tierBase = (
|
|
314
|
+
tierInput * (pricing.input || 0) +
|
|
315
|
+
tierCached * (pricing.cache_read || 0) +
|
|
316
|
+
tierCacheWrite * (pricing.cache_write || 0) +
|
|
317
|
+
tierOutput * (pricing.output || 0) +
|
|
318
|
+
tierReasoning * (pricing.output || 0)
|
|
319
|
+
) / 1_000_000;
|
|
320
|
+
const tierLong = usesOpenAILongContextTier ? (
|
|
321
|
+
bounded(row[`${prefix}long_context_input_tokens`], Math.min(tierInput, longInput)) *
|
|
322
|
+
(pricing.input || 0) +
|
|
323
|
+
bounded(row[`${prefix}long_context_cached_input_tokens`], Math.min(tierCached, longCached)) *
|
|
324
|
+
(pricing.cache_read || 0) +
|
|
325
|
+
bounded(
|
|
326
|
+
row[`${prefix}long_context_cache_creation_input_tokens`],
|
|
327
|
+
Math.min(tierCacheWrite, longCacheWrite),
|
|
328
|
+
) * (pricing.cache_write || 0) +
|
|
329
|
+
0.5 * bounded(row[`${prefix}long_context_output_tokens`], Math.min(tierOutput, longOutput)) *
|
|
330
|
+
(pricing.output || 0) +
|
|
331
|
+
0.5 * bounded(
|
|
332
|
+
row[`${prefix}long_context_reasoning_output_tokens`],
|
|
333
|
+
Math.min(tierReasoning, longReasoning),
|
|
334
|
+
) * (pricing.output || 0)
|
|
335
|
+
) / 1_000_000 : 0;
|
|
336
|
+
return tierBase + tierLong;
|
|
337
|
+
}
|
|
338
|
+
|
|
224
339
|
// Same formula and Codex/every-code reasoning-folding rule as the previous
|
|
225
340
|
// computeRowCost in src/lib/local-api.js. Moved here so vite mock + local
|
|
226
341
|
// server share one source of truth.
|
|
@@ -240,18 +355,7 @@ function computeRowCost(row) {
|
|
|
240
355
|
reportedCost > 0
|
|
241
356
|
) return reportedCost;
|
|
242
357
|
const pricing = getRowPricing(row);
|
|
243
|
-
|
|
244
|
-
// usage.cost bills no separate reasoning component), so charging it again
|
|
245
|
-
// here would double-bill every reasoning token. Cline is the same: its
|
|
246
|
-
// `outputTokens` is the AI SDK total (text + reasoning), so
|
|
247
|
-
// reasoning_output_tokens is a subset marker, never a second line item.
|
|
248
|
-
const reasoningIncludedInOutput =
|
|
249
|
-
row.source === "codex" ||
|
|
250
|
-
row.source === "acode" ||
|
|
251
|
-
row.source === "every-code" ||
|
|
252
|
-
row.source === "omo" ||
|
|
253
|
-
row.source === "cline" ||
|
|
254
|
-
row.source === "muse";
|
|
358
|
+
const reasoningIncludedInOutput = reasoningFoldsIntoOutput(row);
|
|
255
359
|
const reasoningCost = reasoningIncludedInOutput
|
|
256
360
|
? 0
|
|
257
361
|
: (row.reasoning_output_tokens || 0) * (pricing.output || 0);
|
|
@@ -264,11 +368,8 @@ function computeRowCost(row) {
|
|
|
264
368
|
1_000_000
|
|
265
369
|
);
|
|
266
370
|
|
|
267
|
-
const
|
|
268
|
-
const usesOpenAILongContextTier =
|
|
269
|
-
model === "gpt-5.6" || model.includes("gpt-5.6-sol") || model.includes("gpt-6-astra") ||
|
|
270
|
-
model.includes("gpt-6-sol") || model.includes("gpt-6.1-sol") ||
|
|
271
|
-
model.includes("gpt-6.1-terra");
|
|
371
|
+
const ctx = rowSubsetContext(row, reasoningIncludedInOutput);
|
|
372
|
+
const { usesOpenAILongContextTier } = ctx;
|
|
272
373
|
// Only models whose curated entry carries an explicit Fast/priority rate get
|
|
273
374
|
// the tier premium. The other OpenAI tiers have no published priority price,
|
|
274
375
|
// and inventing one is worse than reporting Standard.
|
|
@@ -278,35 +379,12 @@ function computeRowCost(row) {
|
|
|
278
379
|
const hasUltrafastRatesEarly = Number.isFinite(ultrafastMultiplierEarly) && ultrafastMultiplierEarly > 1;
|
|
279
380
|
if (!usesOpenAILongContextTier && !hasPriorityRates && !hasUltrafastRatesEarly) return baseCost;
|
|
280
381
|
|
|
281
|
-
const bounded = (value, total) => Math.min(
|
|
282
|
-
Math.max(0, Number(value) || 0),
|
|
283
|
-
Math.max(0, Number(total) || 0),
|
|
284
|
-
);
|
|
285
|
-
// Both premium families below read "observed subset" columns: how much of the
|
|
286
|
-
// row's own token columns came from requests with a given property. They are
|
|
287
|
-
// annotations, never addends — total_tokens stays the sum of the base columns
|
|
288
|
-
// whether or not they are present, and a legacy row that omits them prices
|
|
289
|
-
// exactly as it did before.
|
|
290
|
-
//
|
|
291
|
-
// The parser records only usage from requests whose cache-inclusive input
|
|
292
|
-
// exceeded 272K. OpenAI prices the whole such request at 2x input and 1.5x
|
|
293
|
-
// output, so add the premium over the standard-rate base exactly once.
|
|
294
|
-
const longInput = bounded(row.long_context_input_tokens, row.input_tokens);
|
|
295
|
-
const longCached = bounded(row.long_context_cached_input_tokens, row.cached_input_tokens);
|
|
296
|
-
const longCacheWrite = bounded(
|
|
297
|
-
row.long_context_cache_creation_input_tokens,
|
|
298
|
-
row.cache_creation_input_tokens,
|
|
299
|
-
);
|
|
300
|
-
const longOutput = bounded(row.long_context_output_tokens, row.output_tokens);
|
|
301
|
-
const longReasoning = reasoningIncludedInOutput
|
|
302
|
-
? 0
|
|
303
|
-
: bounded(row.long_context_reasoning_output_tokens, row.reasoning_output_tokens);
|
|
304
382
|
const longContextPremium = usesOpenAILongContextTier ? (
|
|
305
|
-
longInput * (pricing.input || 0) +
|
|
306
|
-
longCached * (pricing.cache_read || 0) +
|
|
307
|
-
longCacheWrite * (pricing.cache_write || 0) +
|
|
308
|
-
0.5 * longOutput * (pricing.output || 0) +
|
|
309
|
-
0.5 * longReasoning * (pricing.output || 0)
|
|
383
|
+
ctx.longInput * (pricing.input || 0) +
|
|
384
|
+
ctx.longCached * (pricing.cache_read || 0) +
|
|
385
|
+
ctx.longCacheWrite * (pricing.cache_write || 0) +
|
|
386
|
+
0.5 * ctx.longOutput * (pricing.output || 0) +
|
|
387
|
+
0.5 * ctx.longReasoning * (pricing.output || 0)
|
|
310
388
|
) / 1_000_000 : 0;
|
|
311
389
|
|
|
312
390
|
const ultrafastMultiplier = ultrafastMultiplierEarly;
|
|
@@ -317,40 +395,7 @@ function computeRowCost(row) {
|
|
|
317
395
|
// are mutually exclusive per request; both can appear in one aggregated row.
|
|
318
396
|
function tierPremium(multiplier, prefix) {
|
|
319
397
|
if (!(Number.isFinite(multiplier) && multiplier > 1)) return 0;
|
|
320
|
-
|
|
321
|
-
const tierCached = bounded(row[`${prefix}cached_input_tokens`], row.cached_input_tokens);
|
|
322
|
-
const tierCacheWrite = bounded(
|
|
323
|
-
row[`${prefix}cache_creation_input_tokens`],
|
|
324
|
-
row.cache_creation_input_tokens,
|
|
325
|
-
);
|
|
326
|
-
const tierOutput = bounded(row[`${prefix}output_tokens`], row.output_tokens);
|
|
327
|
-
const tierReasoning = reasoningIncludedInOutput
|
|
328
|
-
? 0
|
|
329
|
-
: bounded(row[`${prefix}reasoning_output_tokens`], row.reasoning_output_tokens);
|
|
330
|
-
const tierBase = (
|
|
331
|
-
tierInput * (pricing.input || 0) +
|
|
332
|
-
tierCached * (pricing.cache_read || 0) +
|
|
333
|
-
tierCacheWrite * (pricing.cache_write || 0) +
|
|
334
|
-
tierOutput * (pricing.output || 0) +
|
|
335
|
-
tierReasoning * (pricing.output || 0)
|
|
336
|
-
) / 1_000_000;
|
|
337
|
-
const tierLong = usesOpenAILongContextTier ? (
|
|
338
|
-
bounded(row[`${prefix}long_context_input_tokens`], Math.min(tierInput, longInput)) *
|
|
339
|
-
(pricing.input || 0) +
|
|
340
|
-
bounded(row[`${prefix}long_context_cached_input_tokens`], Math.min(tierCached, longCached)) *
|
|
341
|
-
(pricing.cache_read || 0) +
|
|
342
|
-
bounded(
|
|
343
|
-
row[`${prefix}long_context_cache_creation_input_tokens`],
|
|
344
|
-
Math.min(tierCacheWrite, longCacheWrite),
|
|
345
|
-
) * (pricing.cache_write || 0) +
|
|
346
|
-
0.5 * bounded(row[`${prefix}long_context_output_tokens`], Math.min(tierOutput, longOutput)) *
|
|
347
|
-
(pricing.output || 0) +
|
|
348
|
-
0.5 * bounded(
|
|
349
|
-
row[`${prefix}long_context_reasoning_output_tokens`],
|
|
350
|
-
Math.min(tierReasoning, longReasoning),
|
|
351
|
-
) * (pricing.output || 0)
|
|
352
|
-
) / 1_000_000 : 0;
|
|
353
|
-
return (multiplier - 1) * (tierBase + tierLong);
|
|
398
|
+
return (multiplier - 1) * speedTierSubsetCost(row, prefix, pricing, { ...ctx, reasoningIncludedInOutput });
|
|
354
399
|
}
|
|
355
400
|
|
|
356
401
|
// Astra Fast is a flat multiple of whichever context tier the request was on
|
|
@@ -367,6 +412,63 @@ function computeRowCost(row) {
|
|
|
367
412
|
return baseCost + longContextPremium + priorityPremium + ultrafastPremium;
|
|
368
413
|
}
|
|
369
414
|
|
|
415
|
+
// Speed tiers computeRowCost can allocate: prefix of the observed subset
|
|
416
|
+
// columns and the pricing multiplier key that prices them.
|
|
417
|
+
const SPEED_TIERS = [
|
|
418
|
+
{ prefix: "priority_", multiplierKey: "priority_multiplier" },
|
|
419
|
+
{ prefix: "ultrafast_", multiplierKey: "ultrafast_multiplier" },
|
|
420
|
+
];
|
|
421
|
+
|
|
422
|
+
// Cost of one speed-tier subset: its standard-rate portion plus, when the
|
|
423
|
+
// model's pricing carries the tier multiplier, the same (multiplier - 1)
|
|
424
|
+
// premium computeRowCost adds on top. Zero-cost (local inference, Pi
|
|
425
|
+
// subscription) and authoritative-cost (Grok) rows have no tier allocation —
|
|
426
|
+
// everything stays under standard there.
|
|
427
|
+
const SPEED_TIER_COLUMN_SUFFIXES = [
|
|
428
|
+
"input_tokens",
|
|
429
|
+
"cached_input_tokens",
|
|
430
|
+
"cache_creation_input_tokens",
|
|
431
|
+
"output_tokens",
|
|
432
|
+
"reasoning_output_tokens",
|
|
433
|
+
];
|
|
434
|
+
|
|
435
|
+
function speedTierCost(row, prefix, multiplierKey) {
|
|
436
|
+
// Skip the pricing lookup entirely for rows without observed columns of
|
|
437
|
+
// this tier — the allocation below is 0 for them anyway, and the
|
|
438
|
+
// model-breakdown endpoint calls this for every row of every source.
|
|
439
|
+
if (!SPEED_TIER_COLUMN_SUFFIXES.some((suffix) => Number(row?.[`${prefix}${suffix}`]) > 0)) return 0;
|
|
440
|
+
if (LOCAL_INFERENCE_SOURCES.has(String(row?.source || "").toLowerCase())) return 0;
|
|
441
|
+
if (PI_SUBSCRIPTION_SOURCES.has(String(row?.source || "").toLowerCase())) return 0;
|
|
442
|
+
const reportedCost = Number(row?.total_cost_usd);
|
|
443
|
+
if (
|
|
444
|
+
SOURCES_WITH_AUTHORITATIVE_COST.has(row?.source) &&
|
|
445
|
+
Number.isFinite(reportedCost) &&
|
|
446
|
+
reportedCost > 0
|
|
447
|
+
) return 0;
|
|
448
|
+
const pricing = getRowPricing(row);
|
|
449
|
+
const reasoningIncludedInOutput = reasoningFoldsIntoOutput(row);
|
|
450
|
+
const ctx = rowSubsetContext(row, reasoningIncludedInOutput);
|
|
451
|
+
const portion = speedTierSubsetCost(row, prefix, pricing, { ...ctx, reasoningIncludedInOutput });
|
|
452
|
+
const multiplier = Number(pricing[multiplierKey]);
|
|
453
|
+
if (!(Number.isFinite(multiplier) && multiplier > 1)) return portion;
|
|
454
|
+
return portion + (multiplier - 1) * portion;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// Exact per-tier allocation of computeRowCost for one usage row. Fast and
|
|
458
|
+
// Ultrafast book their observed subset tokens at the tier's multiplier;
|
|
459
|
+
// everything else — tokens outside the tier subsets, rows without tier
|
|
460
|
+
// columns, provider-reported costs, zero-cost sources — stays under standard.
|
|
461
|
+
// standard is computed as the residual, so the three values always add up to
|
|
462
|
+
// computeRowCost(row) by construction (issue #886: surface the Fast/Ultrafast
|
|
463
|
+
// split that the parser already records).
|
|
464
|
+
function computeRowTierCosts(row) {
|
|
465
|
+
if (!row || typeof row !== "object") return { standard: 0, priority: 0, ultrafast: 0 };
|
|
466
|
+
const priority = speedTierCost(row, SPEED_TIERS[0].prefix, SPEED_TIERS[0].multiplierKey);
|
|
467
|
+
const ultrafast = speedTierCost(row, SPEED_TIERS[1].prefix, SPEED_TIERS[1].multiplierKey);
|
|
468
|
+
const standard = computeRowCost(row) - priority - ultrafast;
|
|
469
|
+
return { standard, priority, ultrafast };
|
|
470
|
+
}
|
|
471
|
+
|
|
370
472
|
// Backwards-compatible MODEL_PRICING export. Test at
|
|
371
473
|
// test/model-breakdown.test.js:236 reads `localApi.MODEL_PRICING["kiro-agent"]`
|
|
372
474
|
// and expects { input, output, cache_read, cache_write } shape. We expose the
|
|
@@ -382,6 +484,7 @@ module.exports = {
|
|
|
382
484
|
getModelPricingInfo,
|
|
383
485
|
getRowPricing,
|
|
384
486
|
computeRowCost,
|
|
487
|
+
computeRowTierCosts,
|
|
385
488
|
resetPricingForTests,
|
|
386
489
|
MODEL_PRICING,
|
|
387
490
|
ZERO_PRICING,
|