tokentracker-cli 0.96.4 → 0.97.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/README.de.md +3 -3
- package/README.ja.md +3 -3
- package/README.ko.md +3 -3
- package/README.md +7 -5
- package/README.zh-CN.md +3 -3
- package/dashboard/dist/assets/{AchievementBadge-CCcvmz6R.js → AchievementBadge-Bf2T612R.js} +1 -1
- package/dashboard/dist/assets/{AchievementsPage-C5jdktOK.js → AchievementsPage-CnkSNpJx.js} +2 -2
- package/dashboard/dist/assets/{AchievementsSection-BFMtUzn1.js → AchievementsSection-CPwsy04Y.js} +1 -1
- package/dashboard/dist/assets/{BadgeDetailModal-Be8gM7tM.js → BadgeDetailModal-BJBrgn24.js} +1 -1
- package/dashboard/dist/assets/{BotAnimated-CXTGR71z.js → BotAnimated-BJM20N9T.js} +1 -1
- package/dashboard/dist/assets/{Card-CsUsp3CV.js → Card-BRWOMoBk.js} +1 -1
- package/dashboard/dist/assets/{ClawdAnimated-BEjpZjEE.js → ClawdAnimated-CtX8cne4.js} +2 -2
- package/dashboard/dist/assets/{CommandPalette-CHc_Z1r8.js → CommandPalette-C8BwOnSn.js} +1 -1
- package/dashboard/dist/assets/{CommunityStatsModal-Gs6kZ_Mp.js → CommunityStatsModal-BGMbgSjq.js} +1 -1
- package/dashboard/dist/assets/{ConfirmModal-niHkpv2O.js → ConfirmModal-ZZXg_OLV.js} +1 -1
- package/dashboard/dist/assets/{Controls-X2Z1UNUx.js → Controls-VDvgw_ed.js} +1 -1
- package/dashboard/dist/assets/{DashboardPage-B66s3Exi.js → DashboardPage-BcJGzQWK.js} +1 -1
- package/dashboard/dist/assets/{DevicePage-DQdLdEI8.js → DevicePage-CP5m8azV.js} +1 -1
- package/dashboard/dist/assets/{DialogClose-CCUjTxl8.js → DialogClose-8pTCallP.js} +1 -1
- package/dashboard/dist/assets/DialogDescription-DRQEfAWH.js +1 -0
- package/dashboard/dist/assets/{DialogTitle-CgkUGAag.js → DialogTitle-BWYdq4TT.js} +1 -1
- package/dashboard/dist/assets/{FadeIn-D4QD1bPo.js → FadeIn-CEJfaKnL.js} +1 -1
- package/dashboard/dist/assets/{HeaderGithubStar-D0my-Z3a.js → HeaderGithubStar-Bg2vijF8.js} +1 -1
- package/dashboard/dist/assets/{HoverTooltip-nSWgrKlK.js → HoverTooltip-B03JQ3PO.js} +1 -1
- package/dashboard/dist/assets/{IpCheckPage-4hfqHAgi.js → IpCheckPage-DYZucBOf.js} +1 -1
- package/dashboard/dist/assets/{LandingPage-wIc4tVRI.js → LandingPage-m-byhnVx.js} +2 -2
- package/dashboard/dist/assets/{LeaderboardAvatar-DGlN8Vy8.js → LeaderboardAvatar-JtGhJC1s.js} +1 -1
- package/dashboard/dist/assets/{LeaderboardPage-CybuzE87.js → LeaderboardPage-vVDKFLhl.js} +2 -2
- package/dashboard/dist/assets/{LeaderboardProfileModal-D9la3tNd.js → LeaderboardProfileModal-Cm4DDrcY.js} +3 -3
- package/dashboard/dist/assets/{LeaderboardProfilePage-gxXSeJYb.js → LeaderboardProfilePage-bKbMm856.js} +1 -1
- package/dashboard/dist/assets/{LimitsPage-CZH3G54Y.js → LimitsPage-B271tZOj.js} +1 -1
- package/dashboard/dist/assets/{LocalOnlyNotice-Ckc7zohC.js → LocalOnlyNotice-DKIxuBP0.js} +1 -1
- package/dashboard/dist/assets/{LoginCard-BqeRHqWK.js → LoginCard-DA46RXDo.js} +1 -1
- package/dashboard/dist/assets/{LoginModal-BjH6aIBG.js → LoginModal-PxTgIoLk.js} +1 -1
- package/dashboard/dist/assets/{LoginPage-BOyPLNU3.js → LoginPage-uEUnU7NP.js} +1 -1
- package/dashboard/dist/assets/{PetPage-BXRXG40D.js → PetPage-DDPZtxMw.js} +1 -1
- package/dashboard/dist/assets/{PopoverPopup-Dad1ZYVd.js → PopoverPopup-DWIMb8D6.js} +1 -1
- package/dashboard/dist/assets/{ProviderIcon-BDmrNJSl.js → ProviderIcon-DqqwXu3b.js} +1 -1
- package/dashboard/dist/assets/{ResetPasswordPage-CZpE6qfa.js → ResetPasswordPage-BVuJTR9A.js} +1 -1
- package/dashboard/dist/assets/{SegmentedControl-CE1hrQFi.js → SegmentedControl-iHtWKWtc.js} +1 -1
- package/dashboard/dist/assets/{Select-YVj7u6Nv.js → Select-Cr9wq8mD.js} +1 -1
- package/dashboard/dist/assets/{SelectItemText-BMYGgQ3o.js → SelectItemText-BWnP4yuq.js} +1 -1
- package/dashboard/dist/assets/{ServiceStatusPage-HehjDbZg.js → ServiceStatusPage-DLuiUUYV.js} +1 -1
- package/dashboard/dist/assets/{SessionsPage-Chvu4YqZ.js → SessionsPage-CBAH4ieT.js} +1 -1
- package/dashboard/dist/assets/{SettingsPage-BXjS7u9_.js → SettingsPage-Djku-i8K.js} +2 -2
- package/dashboard/dist/assets/{SkillsPage-q3Rjlj9h.js → SkillsPage-DtBRoB8R.js} +1 -1
- package/dashboard/dist/assets/{TokenGalaxy-BqZyj82r.js → TokenGalaxy-nvyPu5eV.js} +1 -1
- package/dashboard/dist/assets/{ToolbarRootContext-Ch8ueI_C.js → ToolbarRootContext-DhpHv55w.js} +1 -1
- package/dashboard/dist/assets/{TrendMonitor-C2aTL9p1.js → TrendMonitor-CCzwGDst.js} +1 -1
- package/dashboard/dist/assets/{WidgetsPage-DYaIai8j.js → WidgetsPage-CcWCidAd.js} +1 -1
- package/dashboard/dist/assets/{WrappedPage-51B0v-Sr.js → WrappedPage-B6dn8eyh.js} +1 -1
- package/dashboard/dist/assets/__vite-browser-external-sJsF0ioo.js +45 -0
- package/dashboard/dist/assets/{agent-logos-DXrPSAdX.js → agent-logos-Dh2k8E_G.js} +1 -1
- package/dashboard/dist/assets/{arrow-up-right-BFkf7l0U.js → arrow-up-right-BLDQog1A.js} +1 -1
- package/dashboard/dist/assets/{check--N8wmgIJ.js → check-DNq_ySSn.js} +1 -1
- package/dashboard/dist/assets/{composite-zF5Pj94e.js → composite-CSBcryzA.js} +1 -1
- package/dashboard/dist/assets/{copy-BG0JMr6A.js → copy-DHRrNtRb.js} +1 -1
- package/dashboard/dist/assets/{download-CPFJf-Sf.js → download-CluyujgG.js} +1 -1
- package/dashboard/dist/assets/{external-link-D2yF0kgP.js → external-link-Cf12tdLf.js} +1 -1
- package/dashboard/dist/assets/{flame-l460AFx9.js → flame-CJEYinxo.js} +1 -1
- package/dashboard/dist/assets/{format-tokens-DKO4ljuH.js → format-tokens-CqiCmYtk.js} +1 -1
- package/dashboard/dist/assets/{icons-RoxRGkz4.js → icons-DD8OvYVG.js} +1 -1
- package/dashboard/dist/assets/{index--ouT5L4N.js → index-21lDN4rA.js} +1 -1
- package/dashboard/dist/assets/{index-PTJ4368-.js → index-Cm8jn8Va.js} +1 -1
- package/dashboard/dist/assets/{index-DhyLCvvv.js → index-DLLivlEh.js} +1 -1
- package/dashboard/dist/assets/{info-DNWMO4Ca.js → info-dv3Y0z8Q.js} +1 -1
- package/dashboard/dist/assets/{link-2-DzWXAz1h.js → link-2-CWHBxVuk.js} +1 -1
- package/dashboard/dist/assets/{loader-circle-BzGMqXNu.js → loader-circle-9l5p9Dwa.js} +1 -1
- package/dashboard/dist/assets/{maximize-2-Dkpyk4x3.js → maximize-2-DQ2t3MJB.js} +1 -1
- package/dashboard/dist/assets/{modifiers.esm-lggHUQpW.js → modifiers.esm-Cwj0l9Zb.js} +1 -1
- package/dashboard/dist/assets/{monitor-smartphone-Ck0-gz9l.js → monitor-smartphone-B-9at3iV.js} +1 -1
- package/dashboard/dist/assets/{plus-qTJpnn43.js → plus-C_CTQjDD.js} +1 -1
- package/dashboard/dist/assets/{provider-display-psY26qmp.js → provider-display-XJQod7k9.js} +2 -2
- package/dashboard/dist/assets/{react-CYS24KmX.js → react-xH4nkyuj.js} +1 -1
- package/dashboard/dist/assets/{search-CUzE6zxr.js → search-Ut41Fw1G.js} +1 -1
- package/dashboard/dist/assets/{skills-api-D9SzxPFG.js → skills-api-B7lb1cjO.js} +1 -1
- package/dashboard/dist/assets/{sortable.esm-Bl2hAUyR.js → sortable.esm-BUPRsWL6.js} +1 -1
- package/dashboard/dist/assets/{store-mHSJAJtE.js → store-DneqOW0h.js} +1 -1
- package/dashboard/dist/assets/{terminal-BlQNEvn1.js → terminal-DPQyZyHR.js} +1 -1
- package/dashboard/dist/assets/{trash-CHdgmOyk.js → trash-CVdV1bBR.js} +1 -1
- package/dashboard/dist/assets/{use-community-stats-DUiCs91N.js → use-community-stats-DB98TGn9.js} +1 -1
- package/dashboard/dist/assets/{use-latest-request-guard-ehXfkvuU.js → use-latest-request-guard-DK3KulKx.js} +1 -1
- package/dashboard/dist/assets/{use-limits-display-prefs-CcwwQ0Fq.js → use-limits-display-prefs-BACCRUMZ.js} +1 -1
- package/dashboard/dist/assets/{use-ordered-list-CCOtI3Wa.js → use-ordered-list-DnKFdI9a.js} +1 -1
- package/dashboard/dist/assets/use-reduced-motion-BfdrKOsS.js +1 -0
- package/dashboard/dist/assets/{use-session-efficiency-pref-CYRDpcc_.js → use-session-efficiency-pref-BTm6RoSm.js} +1 -1
- package/dashboard/dist/assets/{use-transform-btLlTJpj.js → use-transform-DweC2iKa.js} +1 -1
- package/dashboard/dist/assets/{use-usage-limits-BGr5sR-c.js → use-usage-limits-CN5xWIBs.js} +1 -1
- package/dashboard/dist/assets/{useCurrency-CNutuEKd.js → useCurrency-CFjvWawL.js} +1 -1
- package/dashboard/dist/assets/{useTokenFormat-C0bAJFMC.js → useTokenFormat-Cf81HqWi.js} +1 -1
- package/dashboard/dist/assets/{zap-B2fbyjbc.js → zap-Vx_j5oJN.js} +1 -1
- package/dashboard/dist/index.html +13 -11
- package/dashboard/dist/ip-check.html +1 -1
- package/dashboard/dist/leaderboard.html +1 -1
- package/dashboard/dist/llms.txt +3 -2
- package/dashboard/dist/share.html +1 -1
- package/package.json +2 -2
- package/src/commands/init.js +1 -0
- package/src/commands/status.js +13 -0
- package/src/commands/sync.js +46 -0
- package/src/lib/codex-rollout-parser.js +48 -1
- package/src/lib/codex-service-tier.js +49 -0
- package/src/lib/pricing/curated-overrides.json +2 -1
- package/src/lib/pricing/index.js +68 -4
- package/src/lib/pricing/seed-snapshot.json +1 -1
- package/src/lib/rollout.js +283 -34
- package/src/lib/session-analytics.js +11 -0
- package/dashboard/dist/assets/DialogDescription-CjMjYG3N.js +0 -1
- package/dashboard/dist/assets/__vite-browser-external-Cp7dNuCm.js +0 -45
- package/dashboard/dist/assets/use-reduced-motion-CDlahPqe.js +0 -1
|
@@ -30,6 +30,7 @@ const {
|
|
|
30
30
|
currentCodexModel,
|
|
31
31
|
snapshotCodexModelAttributionState,
|
|
32
32
|
} = require("./codex-model-attribution");
|
|
33
|
+
const { readCodexServiceTier, isPriorityServiceTier } = require("./codex-service-tier");
|
|
33
34
|
|
|
34
35
|
const DISCOVERY_FULL_AUDIT_INTERVAL_MS = 60 * 1000;
|
|
35
36
|
const MAX_DISCOVERY_INVENTORIES = 32;
|
|
@@ -592,6 +593,11 @@ async function parseCodexRolloutFile(filePath, {
|
|
|
592
593
|
const modelAttributionState = createCodexModelAttributionState(
|
|
593
594
|
isResuming ? resumeState.modelAttributionState || { model } : {},
|
|
594
595
|
);
|
|
596
|
+
// Codex writes thread_settings_applied immediately before the turn_context of
|
|
597
|
+
// the turn it applies to, and token_count rows carry no turn id, so each one
|
|
598
|
+
// belongs to the most recent preceding tier record. Sessions that never emit
|
|
599
|
+
// the event (most CLI sessions) stay null and are billed at Standard.
|
|
600
|
+
let serviceTier = isResuming ? resumeState.serviceTier || null : null;
|
|
595
601
|
let provider = isResuming ? resumeState.provider || null : null;
|
|
596
602
|
let cliVersion = isResuming ? resumeState.cliVersion || null : null;
|
|
597
603
|
let forkedFromId = isResuming ? resumeState.forkedFromId || null : null;
|
|
@@ -650,9 +656,20 @@ async function parseCodexRolloutFile(filePath, {
|
|
|
650
656
|
long_context_cache_creation_input_tokens: 0,
|
|
651
657
|
long_context_output_tokens: 0,
|
|
652
658
|
long_context_reasoning_output_tokens: 0,
|
|
659
|
+
priority_input_tokens: 0,
|
|
660
|
+
priority_cached_input_tokens: 0,
|
|
661
|
+
priority_cache_creation_input_tokens: 0,
|
|
662
|
+
priority_output_tokens: 0,
|
|
663
|
+
priority_reasoning_output_tokens: 0,
|
|
664
|
+
priority_long_context_input_tokens: 0,
|
|
665
|
+
priority_long_context_cached_input_tokens: 0,
|
|
666
|
+
priority_long_context_cache_creation_input_tokens: 0,
|
|
667
|
+
priority_long_context_output_tokens: 0,
|
|
668
|
+
priority_long_context_reasoning_output_tokens: 0,
|
|
653
669
|
usage_events: 0,
|
|
654
670
|
rerouted_usage_events: 0,
|
|
655
671
|
long_context_usage_events: 0,
|
|
672
|
+
priority_usage_events: 0,
|
|
656
673
|
selected_models: new Set(),
|
|
657
674
|
reroute_reasons: new Set(),
|
|
658
675
|
};
|
|
@@ -672,7 +689,9 @@ async function parseCodexRolloutFile(filePath, {
|
|
|
672
689
|
// OpenAI applies the long-context tier to the whole request when its raw
|
|
673
690
|
// (cache-inclusive) input exceeds 272K tokens. Preserve the exact subset
|
|
674
691
|
// so pricing can be recomputed later without rescanning private logs.
|
|
675
|
-
|
|
692
|
+
const isLongContext =
|
|
693
|
+
Number(rawRequestUsage?.input_tokens || 0) > OPENAI_LONG_CONTEXT_INPUT_THRESHOLD;
|
|
694
|
+
if (isLongContext) {
|
|
676
695
|
row.long_context_usage_events += 1;
|
|
677
696
|
row.long_context_input_tokens += delta.input_tokens;
|
|
678
697
|
row.long_context_cached_input_tokens += delta.cached_input_tokens;
|
|
@@ -680,6 +699,27 @@ async function parseCodexRolloutFile(filePath, {
|
|
|
680
699
|
row.long_context_output_tokens += delta.output_tokens;
|
|
681
700
|
row.long_context_reasoning_output_tokens += delta.reasoning_output_tokens;
|
|
682
701
|
}
|
|
702
|
+
// Astra Fast bills at a flat multiple of whichever context tier the request
|
|
703
|
+
// was on, so the priority premium multiplies the long-context premium
|
|
704
|
+
// instead of replacing it. The two subsets alone cannot say how much usage
|
|
705
|
+
// was on BOTH, so record the intersection explicitly — otherwise a long
|
|
706
|
+
// Fast request prices at 3x Standard input where it should be 4x.
|
|
707
|
+
if (isPriorityServiceTier(serviceTier)) {
|
|
708
|
+
row.priority_usage_events += 1;
|
|
709
|
+
row.priority_input_tokens += delta.input_tokens;
|
|
710
|
+
row.priority_cached_input_tokens += delta.cached_input_tokens;
|
|
711
|
+
row.priority_cache_creation_input_tokens += delta.cache_creation_input_tokens;
|
|
712
|
+
row.priority_output_tokens += delta.output_tokens;
|
|
713
|
+
row.priority_reasoning_output_tokens += delta.reasoning_output_tokens;
|
|
714
|
+
if (isLongContext) {
|
|
715
|
+
row.priority_long_context_input_tokens += delta.input_tokens;
|
|
716
|
+
row.priority_long_context_cached_input_tokens += delta.cached_input_tokens;
|
|
717
|
+
row.priority_long_context_cache_creation_input_tokens +=
|
|
718
|
+
delta.cache_creation_input_tokens;
|
|
719
|
+
row.priority_long_context_output_tokens += delta.output_tokens;
|
|
720
|
+
row.priority_long_context_reasoning_output_tokens += delta.reasoning_output_tokens;
|
|
721
|
+
}
|
|
722
|
+
}
|
|
683
723
|
}
|
|
684
724
|
|
|
685
725
|
function ensureTool(name) {
|
|
@@ -936,6 +976,12 @@ async function parseCodexRolloutFile(filePath, {
|
|
|
936
976
|
}
|
|
937
977
|
}
|
|
938
978
|
|
|
979
|
+
const appliedServiceTier = readCodexServiceTier(obj);
|
|
980
|
+
if (appliedServiceTier) {
|
|
981
|
+
serviceTier = appliedServiceTier;
|
|
982
|
+
continue;
|
|
983
|
+
}
|
|
984
|
+
|
|
939
985
|
if (obj.type === "turn_context") {
|
|
940
986
|
const p = obj.payload || {};
|
|
941
987
|
if (typeof p.cwd === "string") cwd = p.cwd;
|
|
@@ -1020,6 +1066,7 @@ async function parseCodexRolloutFile(filePath, {
|
|
|
1020
1066
|
cwd,
|
|
1021
1067
|
model,
|
|
1022
1068
|
modelAttributionState: snapshotCodexModelAttributionState(modelAttributionState),
|
|
1069
|
+
serviceTier,
|
|
1023
1070
|
provider,
|
|
1024
1071
|
cliVersion,
|
|
1025
1072
|
forkedFromId,
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// Codex service-tier attribution.
|
|
2
|
+
//
|
|
3
|
+
// The request tier is NOT on the token_count rows. Codex emits it as its own
|
|
4
|
+
// rollout record — `type: "event_msg"`, `payload.type:
|
|
5
|
+
// "thread_settings_applied"`, `payload.thread_settings.service_tier` — written
|
|
6
|
+
// immediately before the `turn_context` of the turn it applies to. A session's
|
|
7
|
+
// first turn has no such record, and CLI-originated sessions
|
|
8
|
+
// (originator codex_cli_rs / codex-tui) often have none at all: on a 1213-file
|
|
9
|
+
// local corpus only 167 files carried the event, covering 25% of token_count
|
|
10
|
+
// events.
|
|
11
|
+
//
|
|
12
|
+
// Attribution rule, and the only one the log shape permits: a token_count row
|
|
13
|
+
// belongs to the most recent preceding thread_settings_applied. With no
|
|
14
|
+
// preceding record the tier is unknown, and unknown is never guessed — it is
|
|
15
|
+
// billed at Standard, exactly as before this file existed.
|
|
16
|
+
|
|
17
|
+
"use strict";
|
|
18
|
+
|
|
19
|
+
// Cheap line prefilter for parsers that avoid JSON.parse on most records.
|
|
20
|
+
const CODEX_SERVICE_TIER_MARKER = '"thread_settings_applied"';
|
|
21
|
+
|
|
22
|
+
// Observed values on the local corpus are "default" (814) and "priority" (58).
|
|
23
|
+
// "priority" is what the CLI writes for what OpenAI's price table and the Codex
|
|
24
|
+
// UI both call Fast; accept the product-facing spelling too so a future rename
|
|
25
|
+
// does not silently fall back to Standard.
|
|
26
|
+
const PRIORITY_SERVICE_TIERS = new Set(["priority", "fast"]);
|
|
27
|
+
|
|
28
|
+
function readCodexServiceTier(obj) {
|
|
29
|
+
if (!obj || obj.type !== "event_msg") return null;
|
|
30
|
+
const payload = obj.payload;
|
|
31
|
+
if (!payload || typeof payload !== "object") return null;
|
|
32
|
+
if (payload.type !== "thread_settings_applied") return null;
|
|
33
|
+
const settings = payload.thread_settings;
|
|
34
|
+
if (!settings || typeof settings !== "object") return null;
|
|
35
|
+
const tier = settings.service_tier;
|
|
36
|
+
if (typeof tier !== "string" || !tier.trim()) return null;
|
|
37
|
+
return tier.trim().toLowerCase();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function isPriorityServiceTier(tier) {
|
|
41
|
+
return typeof tier === "string" && PRIORITY_SERVICE_TIERS.has(tier);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
module.exports = {
|
|
45
|
+
CODEX_SERVICE_TIER_MARKER,
|
|
46
|
+
PRIORITY_SERVICE_TIERS,
|
|
47
|
+
readCodexServiceTier,
|
|
48
|
+
isPriorityServiceTier,
|
|
49
|
+
};
|
|
@@ -53,7 +53,8 @@
|
|
|
53
53
|
"output": 50,
|
|
54
54
|
"cache_read": 1,
|
|
55
55
|
"cache_write": 12.5,
|
|
56
|
-
"
|
|
56
|
+
"priority_multiplier": 2,
|
|
57
|
+
"note": "Official Standard USD/MTok rates verified 2026-09-07: https://developers.openai.com/api/docs/models/gpt-6-astra. Requests above 272K input tokens use 2x input/cache and 1.5x output rates; computeRowCost applies this only to observed long-context request subsets. priority_multiplier is the Fast tier, whose published table (20/2/25/100 short, 40/4/50/150 long, verified 2026-09-12) is exactly 2x the Standard rate of the same context tier — it multiplies, it does not replace, the long-context premium. The 2.5x figure in the Codex speed docs is a subscription-credit rate and must not be used here. computeRowCost applies it only to observed priority request subsets; usage whose service tier the logs never recorded stays Standard. Cloud aggregates use Standard short-context estimates because they do not retain per-request context or service tier. Reasoning-effort suffixes use the same base rates."
|
|
57
58
|
},
|
|
58
59
|
"gpt-5.6-sol": {
|
|
59
60
|
"input": 4,
|
package/src/lib/pricing/index.js
CHANGED
|
@@ -194,8 +194,14 @@ function computeRowCost(row) {
|
|
|
194
194
|
reportedCost > 0
|
|
195
195
|
) return reportedCost;
|
|
196
196
|
const pricing = getRowPricing(row);
|
|
197
|
+
// OmO, like Codex, reports reasoning as a subset of `output` (its own
|
|
198
|
+
// usage.cost bills no separate reasoning component), so charging it again
|
|
199
|
+
// here would double-bill every reasoning token.
|
|
197
200
|
const reasoningIncludedInOutput =
|
|
198
|
-
row.source === "codex" ||
|
|
201
|
+
row.source === "codex" ||
|
|
202
|
+
row.source === "acode" ||
|
|
203
|
+
row.source === "every-code" ||
|
|
204
|
+
row.source === "omo";
|
|
199
205
|
const reasoningCost = reasoningIncludedInOutput
|
|
200
206
|
? 0
|
|
201
207
|
: (row.reasoning_output_tokens || 0) * (pricing.output || 0);
|
|
@@ -211,12 +217,23 @@ function computeRowCost(row) {
|
|
|
211
217
|
const model = String(row?.model || "").toLowerCase();
|
|
212
218
|
const usesOpenAILongContextTier =
|
|
213
219
|
model === "gpt-5.6" || model.includes("gpt-5.6-sol") || model.includes("gpt-6-astra");
|
|
214
|
-
|
|
220
|
+
// Only models whose curated entry carries an explicit Fast/priority rate get
|
|
221
|
+
// the tier premium. The other OpenAI tiers have no published priority price,
|
|
222
|
+
// and inventing one is worse than reporting Standard.
|
|
223
|
+
const priorityMultiplier = Number(pricing.priority_multiplier);
|
|
224
|
+
const hasPriorityRates = Number.isFinite(priorityMultiplier) && priorityMultiplier > 1;
|
|
225
|
+
if (!usesOpenAILongContextTier && !hasPriorityRates) return baseCost;
|
|
215
226
|
|
|
216
227
|
const bounded = (value, total) => Math.min(
|
|
217
228
|
Math.max(0, Number(value) || 0),
|
|
218
229
|
Math.max(0, Number(total) || 0),
|
|
219
230
|
);
|
|
231
|
+
// Both premium families below read "observed subset" columns: how much of the
|
|
232
|
+
// row's own token columns came from requests with a given property. They are
|
|
233
|
+
// annotations, never addends — total_tokens stays the sum of the base columns
|
|
234
|
+
// whether or not they are present, and a legacy row that omits them prices
|
|
235
|
+
// exactly as it did before.
|
|
236
|
+
//
|
|
220
237
|
// The parser records only usage from requests whose cache-inclusive input
|
|
221
238
|
// exceeded 272K. OpenAI prices the whole such request at 2x input and 1.5x
|
|
222
239
|
// output, so add the premium over the standard-rate base exactly once.
|
|
@@ -230,14 +247,61 @@ function computeRowCost(row) {
|
|
|
230
247
|
const longReasoning = reasoningIncludedInOutput
|
|
231
248
|
? 0
|
|
232
249
|
: bounded(row.long_context_reasoning_output_tokens, row.reasoning_output_tokens);
|
|
233
|
-
const longContextPremium = (
|
|
250
|
+
const longContextPremium = usesOpenAILongContextTier ? (
|
|
234
251
|
longInput * (pricing.input || 0) +
|
|
235
252
|
longCached * (pricing.cache_read || 0) +
|
|
236
253
|
longCacheWrite * (pricing.cache_write || 0) +
|
|
237
254
|
0.5 * longOutput * (pricing.output || 0) +
|
|
238
255
|
0.5 * longReasoning * (pricing.output || 0)
|
|
256
|
+
) / 1_000_000 : 0;
|
|
257
|
+
|
|
258
|
+
if (!hasPriorityRates) return baseCost + longContextPremium;
|
|
259
|
+
|
|
260
|
+
// Astra Fast is a flat multiple of whichever context tier the request was on
|
|
261
|
+
// (short 10/1/12.5/50 -> 20/2/25/100; long 20/2/25/75 -> 40/4/50/150), so the
|
|
262
|
+
// tier multiplier and the long-context premium are orthogonal: a request that
|
|
263
|
+
// is both bills at the LONG rate times the multiplier, not standard times the
|
|
264
|
+
// multiplier. That needs the intersection, which is why the parser records
|
|
265
|
+
// priority_long_context_* alongside priority_*; without it (queue rows, which
|
|
266
|
+
// carry no context-length subset at all) the overlap is 0 and the premium
|
|
267
|
+
// falls back to the short-context multiple, matching the row's own base.
|
|
268
|
+
const priorityInput = bounded(row.priority_input_tokens, row.input_tokens);
|
|
269
|
+
const priorityCached = bounded(row.priority_cached_input_tokens, row.cached_input_tokens);
|
|
270
|
+
const priorityCacheWrite = bounded(
|
|
271
|
+
row.priority_cache_creation_input_tokens,
|
|
272
|
+
row.cache_creation_input_tokens,
|
|
273
|
+
);
|
|
274
|
+
const priorityOutput = bounded(row.priority_output_tokens, row.output_tokens);
|
|
275
|
+
const priorityReasoning = reasoningIncludedInOutput
|
|
276
|
+
? 0
|
|
277
|
+
: bounded(row.priority_reasoning_output_tokens, row.reasoning_output_tokens);
|
|
278
|
+
const priorityBase = (
|
|
279
|
+
priorityInput * (pricing.input || 0) +
|
|
280
|
+
priorityCached * (pricing.cache_read || 0) +
|
|
281
|
+
priorityCacheWrite * (pricing.cache_write || 0) +
|
|
282
|
+
priorityOutput * (pricing.output || 0) +
|
|
283
|
+
priorityReasoning * (pricing.output || 0)
|
|
239
284
|
) / 1_000_000;
|
|
240
|
-
|
|
285
|
+
|
|
286
|
+
const priorityLong = usesOpenAILongContextTier ? (
|
|
287
|
+
bounded(row.priority_long_context_input_tokens, Math.min(priorityInput, longInput)) *
|
|
288
|
+
(pricing.input || 0) +
|
|
289
|
+
bounded(row.priority_long_context_cached_input_tokens, Math.min(priorityCached, longCached)) *
|
|
290
|
+
(pricing.cache_read || 0) +
|
|
291
|
+
bounded(
|
|
292
|
+
row.priority_long_context_cache_creation_input_tokens,
|
|
293
|
+
Math.min(priorityCacheWrite, longCacheWrite),
|
|
294
|
+
) * (pricing.cache_write || 0) +
|
|
295
|
+
0.5 * bounded(row.priority_long_context_output_tokens, Math.min(priorityOutput, longOutput)) *
|
|
296
|
+
(pricing.output || 0) +
|
|
297
|
+
0.5 * bounded(
|
|
298
|
+
row.priority_long_context_reasoning_output_tokens,
|
|
299
|
+
Math.min(priorityReasoning, longReasoning),
|
|
300
|
+
) * (pricing.output || 0)
|
|
301
|
+
) / 1_000_000 : 0;
|
|
302
|
+
|
|
303
|
+
const priorityPremium = (priorityMultiplier - 1) * (priorityBase + priorityLong);
|
|
304
|
+
return baseCost + longContextPremium + priorityPremium;
|
|
241
305
|
}
|
|
242
306
|
|
|
243
307
|
// Backwards-compatible MODEL_PRICING export. Test at
|