codexmeter 1.0.28 → 1.0.29
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/package.json +1 -1
- package/server/cost-catalog.js +39 -10
- package/server/ingest.js +4 -2
- package/server/pricing-fetch.js +2 -2
package/package.json
CHANGED
package/server/cost-catalog.js
CHANGED
|
@@ -3,6 +3,12 @@ import { fetchPricing } from './pricing-fetch.js';
|
|
|
3
3
|
// Pricing map: populated by initPricing() from online lookup with local fallback
|
|
4
4
|
let PRICING = null;
|
|
5
5
|
|
|
6
|
+
const PRICE_CHANGE_DATE = '2026-07-30';
|
|
7
|
+
const PREVIOUS_PRICING = {
|
|
8
|
+
'gpt-5.6-terra': { input: 2.50, output: 15.00, cached_input: 0.25, cache_write: 3.125 },
|
|
9
|
+
'gpt-5.6-luna': { input: 1.00, output: 6.00, cached_input: 0.10, cache_write: 1.25 },
|
|
10
|
+
};
|
|
11
|
+
|
|
6
12
|
/** Initialize pricing from online source; falls back to local catalog on timeout/failure. Call before cost calculations. */
|
|
7
13
|
export async function initPricing() {
|
|
8
14
|
PRICING = await fetchPricing();
|
|
@@ -14,15 +20,22 @@ function getPricing() {
|
|
|
14
20
|
return PRICING;
|
|
15
21
|
}
|
|
16
22
|
|
|
23
|
+
function getPricingEntry(modelName, pricingDate) {
|
|
24
|
+
if (pricingDate && pricingDate < PRICE_CHANGE_DATE && PREVIOUS_PRICING[modelName]) {
|
|
25
|
+
return PREVIOUS_PRICING[modelName];
|
|
26
|
+
}
|
|
27
|
+
return getPricing()[modelName];
|
|
28
|
+
}
|
|
29
|
+
|
|
17
30
|
// Codex sessions: ~75% input (mostly cached), ~25% output
|
|
18
31
|
// With ~95% prompt cache hit rate (from Codex Monitor)
|
|
19
32
|
const INPUT_FRACTION = 0.75;
|
|
20
33
|
const OUTPUT_FRACTION = 0.25;
|
|
21
34
|
const CACHE_HIT_RATE = 0.95;
|
|
22
35
|
|
|
23
|
-
export function getCacheAwareRate(modelName) {
|
|
36
|
+
export function getCacheAwareRate(modelName, pricingDate = null) {
|
|
24
37
|
if (!modelName) return null;
|
|
25
|
-
const entry =
|
|
38
|
+
const entry = getPricingEntry(modelName, pricingDate);
|
|
26
39
|
if (!entry) return null;
|
|
27
40
|
|
|
28
41
|
const effectiveInputRate =
|
|
@@ -32,9 +45,9 @@ export function getCacheAwareRate(modelName) {
|
|
|
32
45
|
return INPUT_FRACTION * effectiveInputRate + OUTPUT_FRACTION * entry.output;
|
|
33
46
|
}
|
|
34
47
|
|
|
35
|
-
export function calculateCostFromUsage(modelName, usage) {
|
|
48
|
+
export function calculateCostFromUsage(modelName, usage, pricingDate = null) {
|
|
36
49
|
if (!modelName || !usage) return null;
|
|
37
|
-
const entry =
|
|
50
|
+
const entry = getPricingEntry(modelName, pricingDate);
|
|
38
51
|
if (!entry) return null;
|
|
39
52
|
|
|
40
53
|
const inputTokens = usage.input_tokens || 0;
|
|
@@ -52,19 +65,35 @@ export function calculateCostFromUsage(modelName, usage) {
|
|
|
52
65
|
) / 1_000_000;
|
|
53
66
|
}
|
|
54
67
|
|
|
55
|
-
function estimateCostFromTotalTokens(modelName, tokensUsed) {
|
|
56
|
-
const rate = getCacheAwareRate(modelName);
|
|
68
|
+
function estimateCostFromTotalTokens(modelName, tokensUsed, pricingDate) {
|
|
69
|
+
const rate = getCacheAwareRate(modelName, pricingDate);
|
|
57
70
|
if (rate === null) return null;
|
|
58
71
|
return (tokensUsed / 1_000_000) * rate;
|
|
59
72
|
}
|
|
60
73
|
|
|
61
|
-
export function priceSession(modelName, {
|
|
62
|
-
|
|
74
|
+
export function priceSession(modelName, {
|
|
75
|
+
totalTokens = 0,
|
|
76
|
+
usageBuckets = null,
|
|
77
|
+
usageByDay = null,
|
|
78
|
+
pricingDate = null,
|
|
79
|
+
} = {}) {
|
|
80
|
+
const dailyUsage = Object.entries(usageByDay || {});
|
|
81
|
+
if (dailyUsage.length) {
|
|
82
|
+
let cost = 0;
|
|
83
|
+
for (const [day, usage] of dailyUsage) {
|
|
84
|
+
const dailyCost = calculateCostFromUsage(modelName, usage, day);
|
|
85
|
+
if (dailyCost === null) return { cost: null, source: 'unpriced' };
|
|
86
|
+
cost += dailyCost;
|
|
87
|
+
}
|
|
88
|
+
return { cost, source: 'exact' };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const exactCost = calculateCostFromUsage(modelName, usageBuckets, pricingDate);
|
|
63
92
|
if (exactCost !== null) {
|
|
64
93
|
return { cost: exactCost, source: 'exact' };
|
|
65
94
|
}
|
|
66
95
|
|
|
67
|
-
const heuristicCost = estimateCostFromTotalTokens(modelName, totalTokens);
|
|
96
|
+
const heuristicCost = estimateCostFromTotalTokens(modelName, totalTokens, pricingDate);
|
|
68
97
|
if (heuristicCost !== null) {
|
|
69
98
|
return { cost: heuristicCost, source: 'heuristic' };
|
|
70
99
|
}
|
|
@@ -80,7 +109,7 @@ export function getModelPricing(modelName) {
|
|
|
80
109
|
return getPricing()[modelName] || null;
|
|
81
110
|
}
|
|
82
111
|
|
|
83
|
-
export const CATALOG_VERSION = '2026-07-
|
|
112
|
+
export const CATALOG_VERSION = '2026-07-30';
|
|
84
113
|
export const CACHE_ASSUMPTIONS = {
|
|
85
114
|
input_fraction: INPUT_FRACTION,
|
|
86
115
|
output_fraction: OUTPUT_FRACTION,
|
package/server/ingest.js
CHANGED
|
@@ -207,10 +207,10 @@ export async function runIngest(codexHome, state, opts = {}) {
|
|
|
207
207
|
s.usage_by_day = buildUsageByDayMetrics(s.model_name, s._usage_by_day_raw);
|
|
208
208
|
s.has_usage_by_day = s.usage_by_day.length > 0;
|
|
209
209
|
}
|
|
210
|
-
delete s._usage_by_day_raw;
|
|
211
210
|
delete s._first_usage_timestamp_ms;
|
|
212
211
|
delete s._usage_reset_detected;
|
|
213
212
|
finalizeSessionMetrics(s, toDayKey);
|
|
213
|
+
delete s._usage_by_day_raw;
|
|
214
214
|
s.live_sort_day = deriveLiveSortDay(s, toDayKey);
|
|
215
215
|
s.materialized = true;
|
|
216
216
|
}
|
|
@@ -529,6 +529,8 @@ function finalizeSessionMetrics(session, toDayKey) {
|
|
|
529
529
|
const priced = priceSession(session.model_name, {
|
|
530
530
|
totalTokens: session.tokens_used,
|
|
531
531
|
usageBuckets: session.usage_total,
|
|
532
|
+
usageByDay: session._usage_by_day_raw,
|
|
533
|
+
pricingDate: session.started_at ? toDayKey(session.started_at * 1000) : null,
|
|
532
534
|
});
|
|
533
535
|
session.cost = priced.cost;
|
|
534
536
|
session.cost_source = priced.source;
|
|
@@ -539,7 +541,7 @@ function buildUsageByDayMetrics(modelName, usageByDay) {
|
|
|
539
541
|
const entries = [];
|
|
540
542
|
for (const [dayKey, usage] of Object.entries(usageByDay || {})) {
|
|
541
543
|
const tokens = (usage?.input_tokens || 0) + (usage?.output_tokens || 0);
|
|
542
|
-
const cost = calculateCostFromUsage(modelName, usage);
|
|
544
|
+
const cost = calculateCostFromUsage(modelName, usage, dayKey);
|
|
543
545
|
entries.push({
|
|
544
546
|
day: dayKey,
|
|
545
547
|
tokens,
|
package/server/pricing-fetch.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// Local pricing catalog for models used in codex-cli/codex app lifetime.
|
|
2
2
|
const FALLBACK = {
|
|
3
3
|
'gpt-5.6-sol': { input: 5.00, output: 30.00, cached_input: 0.50, cache_write: 6.25 },
|
|
4
|
-
'gpt-5.6-terra': { input: 2.
|
|
5
|
-
'gpt-5.6-luna': { input:
|
|
4
|
+
'gpt-5.6-terra': { input: 2.00, output: 12.00, cached_input: 0.20, cache_write: 2.50 },
|
|
5
|
+
'gpt-5.6-luna': { input: 0.20, output: 1.20, cached_input: 0.02, cache_write: 0.25 },
|
|
6
6
|
'gpt-5.5': { input: 5.00, output: 30.00, cached_input: 0.50 },
|
|
7
7
|
'gpt-5.4': { input: 2.50, output: 15.00, cached_input: 0.25 },
|
|
8
8
|
'gpt-5-mini': { input: 0.75, output: 4.50, cached_input: 0.075},
|