@trendyvideo/billing 1.2.0 → 1.4.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/__tests__/billing-coverage.test.js +32 -8
- package/dist/__tests__/billing-coverage.test.js.map +1 -1
- package/dist/__tests__/pricing-gemini-billing.test.d.ts +2 -0
- package/dist/__tests__/pricing-gemini-billing.test.d.ts.map +1 -0
- package/dist/__tests__/pricing-gemini-billing.test.js +296 -0
- package/dist/__tests__/pricing-gemini-billing.test.js.map +1 -0
- package/dist/__tests__/pricing-gemini-embedding-2.test.d.ts +2 -0
- package/dist/__tests__/pricing-gemini-embedding-2.test.d.ts.map +1 -0
- package/dist/__tests__/pricing-gemini-embedding-2.test.js +104 -0
- package/dist/__tests__/pricing-gemini-embedding-2.test.js.map +1 -0
- package/dist/__tests__/pricing.test.js +138 -0
- package/dist/__tests__/pricing.test.js.map +1 -1
- package/dist/__tests__/usage-tracker.test.js +201 -3
- package/dist/__tests__/usage-tracker.test.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -1
- package/dist/index.js.map +1 -1
- package/dist/pricing.d.ts +151 -14
- package/dist/pricing.d.ts.map +1 -1
- package/dist/pricing.js +352 -25
- package/dist/pricing.js.map +1 -1
- package/dist/types.d.ts +21 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/usage-tracker.d.ts.map +1 -1
- package/dist/usage-tracker.js +6 -1
- package/dist/usage-tracker.js.map +1 -1
- package/package.json +1 -1
|
@@ -95,7 +95,11 @@ const COST_POINTS = [
|
|
|
95
95
|
},
|
|
96
96
|
{
|
|
97
97
|
file: 'trendy-chunk-analyzer/src/utils/embeddings.ts',
|
|
98
|
-
description: '
|
|
98
|
+
description: 'gemini-embedding-2 usage (text + multimodal call sites)',
|
|
99
|
+
pattern: 'recordUsage(',
|
|
100
|
+
// Two separate POSTs to `gemini-embedding-2:embedContent`; each must bill.
|
|
101
|
+
// Unbilled from the 2026-04-26 switch off text-embedding-005 until 2026-09-05.
|
|
102
|
+
requiredInFunctions: ['generateTextEmbeddingV2', 'generateMultimodalEmbedding'],
|
|
99
103
|
},
|
|
100
104
|
{
|
|
101
105
|
file: 'trendy-story-planner/src/StoryPlannerService.ts',
|
|
@@ -130,18 +134,38 @@ const COST_POINTS = [
|
|
|
130
134
|
description: 'Thumbnail frame analysis (Gemini) usage',
|
|
131
135
|
},
|
|
132
136
|
];
|
|
137
|
+
/**
|
|
138
|
+
* Source of a top-level `function <name>(` up to the next top-level
|
|
139
|
+
* `export`/`function` declaration (or EOF). Good enough for the
|
|
140
|
+
* one-function-per-cost-point files this test guards; not a parser.
|
|
141
|
+
*/
|
|
142
|
+
function extractFunctionBody(source, name) {
|
|
143
|
+
const start = source.search(new RegExp(`^(export\\s+)?(async\\s+)?function\\s+${name}\\s*[(<]`, 'm'));
|
|
144
|
+
if (start === -1)
|
|
145
|
+
return null;
|
|
146
|
+
const rest = source.slice(start + 1);
|
|
147
|
+
const next = rest.search(/^(export\s+)?(async\s+)?function\s|^export\s+(const|let|class|interface|type)\s/m);
|
|
148
|
+
return next === -1 ? source.slice(start) : source.slice(start, start + 1 + next);
|
|
149
|
+
}
|
|
133
150
|
(0, vitest_1.describe)('billing coverage — recordUsage present at all cost points', () => {
|
|
134
151
|
for (const point of COST_POINTS) {
|
|
135
|
-
(0, vitest_1.it)(`${point.file} — ${point.description}`, () => {
|
|
152
|
+
(0, vitest_1.it)(`${point.file} — ${point.description}`, (ctx) => {
|
|
136
153
|
const fullPath = path.join(ROOT, point.file);
|
|
137
|
-
|
|
154
|
+
if (!fs.existsSync(fullPath)) {
|
|
155
|
+
// Submodule not checked out in this environment (e.g. a git worktree).
|
|
156
|
+
// The test is meaningful only when running in the full monorepo with
|
|
157
|
+
// all submodules initialized; skip rather than fail.
|
|
158
|
+
ctx.skip();
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
138
161
|
const content = fs.readFileSync(fullPath, 'utf-8');
|
|
139
162
|
const pattern = point.pattern ?? 'recordUsage';
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
(0, vitest_1.expect)(
|
|
163
|
+
const matches = (source) => typeof pattern === 'string' ? source.includes(pattern) : pattern.test(source);
|
|
164
|
+
(0, vitest_1.expect)(matches(content), `${point.file} must contain ${String(pattern)} for billing tracking (${point.description})`).toBe(true);
|
|
165
|
+
for (const fn of point.requiredInFunctions ?? []) {
|
|
166
|
+
const body = extractFunctionBody(content, fn);
|
|
167
|
+
(0, vitest_1.expect)(body, `${point.file} must define function ${fn}`).not.toBeNull();
|
|
168
|
+
(0, vitest_1.expect)(matches(body), `${point.file}: function ${fn} must call ${String(pattern)} (${point.description})`).toBe(true);
|
|
145
169
|
}
|
|
146
170
|
});
|
|
147
171
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"billing-coverage.test.js","sourceRoot":"","sources":["../../src/__tests__/billing-coverage.test.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,mCAA8C;AAC9C,uCAAyB;AACzB,2CAA6B;AAE7B;;;;;;GAMG;AAEH,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"billing-coverage.test.js","sourceRoot":"","sources":["../../src/__tests__/billing-coverage.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pricing-gemini-billing.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/pricing-gemini-billing.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const vitest_1 = require("vitest");
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const pricing_1 = require("../pricing");
|
|
40
|
+
/**
|
|
41
|
+
* Regression suite for the agent-turn overcharge fixed in
|
|
42
|
+
* docs/architecture/gemini-cache-with-tools.md (§5, §6).
|
|
43
|
+
*
|
|
44
|
+
* Two defects compounded:
|
|
45
|
+
* 1. `gemini-3.7-flash` had no pricing row and fell through to
|
|
46
|
+
* DEFAULT_PRICING (Claude Sonnet $3 / $15).
|
|
47
|
+
* 2. Gemini reports cached tokens inside `promptTokenCount`, so the
|
|
48
|
+
* Anthropic-style formula billed them twice.
|
|
49
|
+
*/
|
|
50
|
+
const ROOT = path.resolve(__dirname, '..', '..', '..', '..');
|
|
51
|
+
const PROMO_END = new Date('2026-12-31T23:59:59Z');
|
|
52
|
+
const STANDARD_START = new Date('2027-01-01T00:00:00Z');
|
|
53
|
+
// ---------------------------------------------------------------------------
|
|
54
|
+
// Pricing rows
|
|
55
|
+
// ---------------------------------------------------------------------------
|
|
56
|
+
(0, vitest_1.describe)('gemini-3.7-flash / gemini-3.8-flash pricing rows', () => {
|
|
57
|
+
for (const model of ['gemini-3.7-flash', 'gemini-3.8-flash']) {
|
|
58
|
+
(0, vitest_1.it)(`${model} has its own row (not DEFAULT_PRICING)`, () => {
|
|
59
|
+
(0, vitest_1.expect)((0, pricing_1.findPricingRow)(model)).toBeDefined();
|
|
60
|
+
(0, vitest_1.expect)((0, pricing_1.getPricing)(model)).not.toBe(pricing_1.DEFAULT_PRICING);
|
|
61
|
+
});
|
|
62
|
+
(0, vitest_1.it)(`${model} promotional rates apply through 2026-12-31`, () => {
|
|
63
|
+
const p = (0, pricing_1.getPricing)(model, PROMO_END);
|
|
64
|
+
(0, vitest_1.expect)(p.input).toBe(0.75);
|
|
65
|
+
(0, vitest_1.expect)(p.output).toBe(3.75);
|
|
66
|
+
(0, vitest_1.expect)(p.cacheRead).toBe(0.075);
|
|
67
|
+
(0, vitest_1.expect)(p.cacheWrite).toBe(0.75);
|
|
68
|
+
(0, vitest_1.expect)(p.cacheStoragePerHour).toBe(0.50);
|
|
69
|
+
});
|
|
70
|
+
(0, vitest_1.it)(`${model} standard rates apply from 2027-01-01 (no silent cliff)`, () => {
|
|
71
|
+
const p = (0, pricing_1.getPricing)(model, STANDARD_START);
|
|
72
|
+
(0, vitest_1.expect)(p.input).toBe(1.50);
|
|
73
|
+
(0, vitest_1.expect)(p.output).toBe(7.50);
|
|
74
|
+
(0, vitest_1.expect)(p.cacheRead).toBe(0.15);
|
|
75
|
+
(0, vitest_1.expect)(p.cacheWrite).toBe(1.50);
|
|
76
|
+
(0, vitest_1.expect)(p.cacheStoragePerHour).toBe(1.00);
|
|
77
|
+
});
|
|
78
|
+
(0, vitest_1.it)(`${model} resolves today to whichever side of the cutover today is on`, () => {
|
|
79
|
+
const now = new Date();
|
|
80
|
+
const p = (0, pricing_1.getPricing)(model);
|
|
81
|
+
const expectedInput = now.getTime() >= STANDARD_START.getTime() ? 1.50 : 0.75;
|
|
82
|
+
(0, vitest_1.expect)(p.input).toBe(expectedInput);
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
(0, vitest_1.it)('cache write is priced off the model row, not DEFAULT_PRICING', () => {
|
|
86
|
+
const p = (0, pricing_1.getPricing)('gemini-3.7-flash', PROMO_END);
|
|
87
|
+
(0, vitest_1.expect)(p.cacheWrite).not.toBe(pricing_1.DEFAULT_PRICING.cacheWrite);
|
|
88
|
+
// 31,943 cache-creation tokens: $0.75/M → 23,957.25 µ$, not 119,786.25 at $3.75/M.
|
|
89
|
+
const cost = (0, pricing_1.calculateCostMicrodollars)('gemini-3.7-flash', 0, 0, 0, 31_943, undefined, PROMO_END);
|
|
90
|
+
(0, vitest_1.expect)(cost).toBe(Math.round(31_943 * 0.75));
|
|
91
|
+
});
|
|
92
|
+
(0, vitest_1.it)('rows without a scheduled change are returned untouched', () => {
|
|
93
|
+
(0, vitest_1.expect)((0, pricing_1.getPricing)('claude-sonnet-4-6')).toBe(pricing_1.MODEL_PRICING['claude-sonnet-4-6']);
|
|
94
|
+
(0, vitest_1.expect)((0, pricing_1.getPricing)('completely-unknown-model')).toBe(pricing_1.DEFAULT_PRICING);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
// ---------------------------------------------------------------------------
|
|
98
|
+
// Formula: cached tokens billed once
|
|
99
|
+
// ---------------------------------------------------------------------------
|
|
100
|
+
(0, vitest_1.describe)('calculateCostMicrodollars — cached tokens billed once', () => {
|
|
101
|
+
(0, vitest_1.it)('flags Gemini as reporting cached tokens inside inputTokens', () => {
|
|
102
|
+
(0, vitest_1.expect)((0, pricing_1.promptTokensIncludeCacheReads)('gemini-3.7-flash')).toBe(true);
|
|
103
|
+
(0, vitest_1.expect)((0, pricing_1.promptTokensIncludeCacheReads)('gemini-2.5-pro')).toBe(true);
|
|
104
|
+
(0, vitest_1.expect)((0, pricing_1.promptTokensIncludeCacheReads)('claude-sonnet-4-6')).toBe(false);
|
|
105
|
+
(0, vitest_1.expect)((0, pricing_1.promptTokensIncludeCacheReads)('claude-opus-5')).toBe(false);
|
|
106
|
+
});
|
|
107
|
+
(0, vitest_1.it)('Gemini: subtracts cached tokens from the input line and bills them at the cache-read rate', () => {
|
|
108
|
+
// 10,000 prompt tokens of which 8,000 cached.
|
|
109
|
+
// uncached 2,000 × 0.75 = 1,500; cached 8,000 × 0.075 = 600; output 100 × 3.75 = 375
|
|
110
|
+
const cost = (0, pricing_1.calculateCostMicrodollars)('gemini-3.7-flash', 10_000, 100, 8_000, 0, undefined, PROMO_END);
|
|
111
|
+
(0, vitest_1.expect)(cost).toBe(1_500 + 600 + 375);
|
|
112
|
+
});
|
|
113
|
+
(0, vitest_1.it)('Gemini: a fully cached prompt is never billed at the input rate', () => {
|
|
114
|
+
// 27,944 prompt / 27,925 cached (live run A, call 1 in the doc)
|
|
115
|
+
const cost = (0, pricing_1.calculateCostMicrodollars)('gemini-3.7-flash', 27_944, 64, 27_925, 0, undefined, PROMO_END);
|
|
116
|
+
(0, vitest_1.expect)(cost).toBe(Math.round(19 * 0.75 + 27_925 * 0.075 + 64 * 3.75));
|
|
117
|
+
});
|
|
118
|
+
(0, vitest_1.it)('Gemini: cacheReadTokens larger than inputTokens clamps the input line to zero', () => {
|
|
119
|
+
const cost = (0, pricing_1.calculateCostMicrodollars)('gemini-3.7-flash', 100, 0, 150, 0, undefined, PROMO_END);
|
|
120
|
+
(0, vitest_1.expect)(cost).toBe(Math.round(150 * 0.075));
|
|
121
|
+
});
|
|
122
|
+
(0, vitest_1.it)('Gemini row with no cache-read rate: cached tokens stay in the input line, still billed once', () => {
|
|
123
|
+
// gemini-2.5-pro has cacheRead: 0 → the 8,000 cached tokens are charged at
|
|
124
|
+
// the input rate as part of the 10,000, and nothing extra.
|
|
125
|
+
const cost = (0, pricing_1.calculateCostMicrodollars)('gemini-2.5-pro', 10_000, 0, 8_000, 0);
|
|
126
|
+
(0, vitest_1.expect)(cost).toBe(10_000 * 1.25);
|
|
127
|
+
});
|
|
128
|
+
(0, vitest_1.it)('Anthropic: disjoint counts are billed line by line (unchanged)', () => {
|
|
129
|
+
// 1000*3 + 500*15 + 200*0.30 + 100*3.75 = 10935
|
|
130
|
+
const cost = (0, pricing_1.calculateCostMicrodollars)('claude-sonnet-4-6', 1_000, 500, 200, 100);
|
|
131
|
+
(0, vitest_1.expect)(cost).toBe(10_935);
|
|
132
|
+
});
|
|
133
|
+
(0, vitest_1.it)('honours `at` for the scheduled rate change', () => {
|
|
134
|
+
const promo = (0, pricing_1.calculateCostMicrodollars)('gemini-3.7-flash', 1_000, 0, 0, 0, undefined, PROMO_END);
|
|
135
|
+
const standard = (0, pricing_1.calculateCostMicrodollars)('gemini-3.7-flash', 1_000, 0, 0, 0, undefined, STANDARD_START);
|
|
136
|
+
(0, vitest_1.expect)(promo).toBe(750);
|
|
137
|
+
(0, vitest_1.expect)(standard).toBe(1_500);
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
const PROD_ROWS = [
|
|
141
|
+
{
|
|
142
|
+
label: '2026-09-03T23:30 (cache write, 2 calls)',
|
|
143
|
+
at: new Date('2026-09-03T23:30:00Z'),
|
|
144
|
+
model: 'gemini-3.7-flash',
|
|
145
|
+
inputTokens: 64_409,
|
|
146
|
+
outputTokens: 105,
|
|
147
|
+
cacheReadTokens: 63_886,
|
|
148
|
+
cacheCreationTokens: 31_943,
|
|
149
|
+
storedCostMicrodollars: 500_631,
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
label: '2026-09-03T15:42 (no cache write)',
|
|
153
|
+
at: new Date('2026-09-03T15:42:00Z'),
|
|
154
|
+
model: 'gemini-3.7-flash',
|
|
155
|
+
inputTokens: 49_602,
|
|
156
|
+
outputTokens: 145,
|
|
157
|
+
cacheReadTokens: 45_948,
|
|
158
|
+
cacheCreationTokens: 0,
|
|
159
|
+
storedCostMicrodollars: 247_148,
|
|
160
|
+
},
|
|
161
|
+
];
|
|
162
|
+
/** The formula prod ran when those rows were written: DEFAULT_PRICING, double count, ×1.5. */
|
|
163
|
+
function legacyBilledMicrodollars(r) {
|
|
164
|
+
const raw = r.inputTokens * pricing_1.DEFAULT_PRICING.input +
|
|
165
|
+
r.outputTokens * pricing_1.DEFAULT_PRICING.output +
|
|
166
|
+
r.cacheReadTokens * pricing_1.DEFAULT_PRICING.cacheRead +
|
|
167
|
+
r.cacheCreationTokens * pricing_1.DEFAULT_PRICING.cacheWrite;
|
|
168
|
+
return Math.round(raw * pricing_1.COST_MARKUP);
|
|
169
|
+
}
|
|
170
|
+
/** Google's bill for the row at the published 3.7-flash promotional rates. */
|
|
171
|
+
function trueProviderMicrodollars(r) {
|
|
172
|
+
const uncached = r.inputTokens - r.cacheReadTokens;
|
|
173
|
+
return Math.round(uncached * 0.75 + r.outputTokens * 3.75 + r.cacheReadTokens * 0.075 + r.cacheCreationTokens * 0.75);
|
|
174
|
+
}
|
|
175
|
+
(0, vitest_1.describe)('reconciliation against prod usage_events rows (#252 §5)', () => {
|
|
176
|
+
for (const row of PROD_ROWS) {
|
|
177
|
+
(0, vitest_1.it)(`${row.label}: the legacy formula reproduces the stored cost exactly`, () => {
|
|
178
|
+
(0, vitest_1.expect)(legacyBilledMicrodollars(row)).toBe(row.storedCostMicrodollars);
|
|
179
|
+
});
|
|
180
|
+
(0, vitest_1.it)(`${row.label}: the corrected formula reproduces the true provider cost to the microdollar`, () => {
|
|
181
|
+
const corrected = (0, pricing_1.calculateCostMicrodollars)(row.model, row.inputTokens, row.outputTokens, row.cacheReadTokens, row.cacheCreationTokens, undefined, row.at);
|
|
182
|
+
(0, vitest_1.expect)(corrected).toBe(trueProviderMicrodollars(row));
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
(0, vitest_1.it)('row 1: 29,535 µ$ true cost (≈2.95 credits raw) versus 500,631 µ$ stored (50.06 credits)', () => {
|
|
186
|
+
const r = PROD_ROWS[0];
|
|
187
|
+
(0, vitest_1.expect)(trueProviderMicrodollars(r)).toBe(29_535);
|
|
188
|
+
(0, vitest_1.expect)(Math.round(trueProviderMicrodollars(r) * pricing_1.COST_MARKUP)).toBe(44_303);
|
|
189
|
+
(0, vitest_1.expect)(r.storedCostMicrodollars / pricing_1.MICRODOLLARS_PER_CREDIT).toBeCloseTo(50.06, 2);
|
|
190
|
+
});
|
|
191
|
+
(0, vitest_1.it)('row 2: 6,730 µ$ true cost (≈0.67 credits raw) versus 247,148 µ$ stored (24.71 credits)', () => {
|
|
192
|
+
const r = PROD_ROWS[1];
|
|
193
|
+
(0, vitest_1.expect)(trueProviderMicrodollars(r)).toBe(6_730);
|
|
194
|
+
(0, vitest_1.expect)(Math.round(trueProviderMicrodollars(r) * pricing_1.COST_MARKUP)).toBe(10_095);
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
// ---------------------------------------------------------------------------
|
|
198
|
+
// Per-call scenarios from #252 §6 (legacy path, 31.9k cached prefix,
|
|
199
|
+
// 500 visible output tokens). Credits include the 1.5× markup prod applies.
|
|
200
|
+
// ---------------------------------------------------------------------------
|
|
201
|
+
(0, vitest_1.describe)('per-call credits, before and after (#252 §6.2 vs §6.3)', () => {
|
|
202
|
+
const PREFIX = 31_900;
|
|
203
|
+
const OUTPUT = 500;
|
|
204
|
+
// `before` / `after` are exact; the doc rounds them to 19.2 / 26 / 44 and 1.2 / 2.9 / 7.4.
|
|
205
|
+
// `charged` is what recordUsage writes to credits_consumed: the true cost
|
|
206
|
+
// rounded to the microdollar, converted, × 1.5, rounded once to 0.01 credit.
|
|
207
|
+
const scenarios = [
|
|
208
|
+
{ name: 'early', uncached: 5_000, before: 19.1655, after: 1.2026, charged: 1.2 },
|
|
209
|
+
{ name: 'typical', uncached: 20_000, before: 25.9155, after: 2.8901, charged: 2.89 },
|
|
210
|
+
{ name: 'late', uncached: 60_000, before: 43.9155, after: 7.3901, charged: 7.39 },
|
|
211
|
+
];
|
|
212
|
+
for (const s of scenarios) {
|
|
213
|
+
(0, vitest_1.it)(`${s.name} (${s.uncached.toLocaleString()} uncached): ${s.before.toFixed(1)} → ${s.after.toFixed(1)} credits`, () => {
|
|
214
|
+
const promptTokens = PREFIX + s.uncached;
|
|
215
|
+
const legacyRaw = promptTokens * pricing_1.DEFAULT_PRICING.input +
|
|
216
|
+
OUTPUT * pricing_1.DEFAULT_PRICING.output +
|
|
217
|
+
PREFIX * pricing_1.DEFAULT_PRICING.cacheRead;
|
|
218
|
+
const before = (legacyRaw * pricing_1.COST_MARKUP) / pricing_1.MICRODOLLARS_PER_CREDIT;
|
|
219
|
+
const after = ((0, pricing_1.calculateCostMicrodollars)('gemini-3.7-flash', promptTokens, OUTPUT, PREFIX, 0, undefined, PROMO_END) *
|
|
220
|
+
pricing_1.COST_MARKUP) /
|
|
221
|
+
pricing_1.MICRODOLLARS_PER_CREDIT;
|
|
222
|
+
(0, vitest_1.expect)(before).toBeCloseTo(s.before, 3);
|
|
223
|
+
(0, vitest_1.expect)(after).toBeCloseTo(s.after, 3);
|
|
224
|
+
const trueCost = (0, pricing_1.calculateCostMicrodollars)('gemini-3.7-flash', promptTokens, OUTPUT, PREFIX, 0, undefined, PROMO_END);
|
|
225
|
+
(0, vitest_1.expect)((0, pricing_1.calculateBilledCredits)(trueCost)).toBe(s.charged);
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
// ---------------------------------------------------------------------------
|
|
230
|
+
// Guard: every LLM default in trendy-video-agent/src/config.ts must resolve
|
|
231
|
+
// to its own pricing row. This is the test that would have caught the
|
|
232
|
+
// 3.7-flash fall-through. Remove a row from MODEL_PRICING and it fails.
|
|
233
|
+
// ---------------------------------------------------------------------------
|
|
234
|
+
/**
|
|
235
|
+
* Snapshot of the `optionalEnv('*_MODEL', ...)` defaults at the submodule
|
|
236
|
+
* commit the umbrella pins (7eae48b), plus the models this PR prices. Always
|
|
237
|
+
* checked, even when the submodule is not checked out (git worktrees).
|
|
238
|
+
*/
|
|
239
|
+
const CONFIG_MODEL_DEFAULTS_SNAPSHOT = [
|
|
240
|
+
'gemini-3.7-flash',
|
|
241
|
+
'gemini-3.8-flash',
|
|
242
|
+
'gemini-3.5-flash',
|
|
243
|
+
'claude-opus-5',
|
|
244
|
+
'gemini-3.1-flash-lite',
|
|
245
|
+
'gemini-2.5-pro',
|
|
246
|
+
'gemini-3.1-pro-preview-customtools',
|
|
247
|
+
];
|
|
248
|
+
/** Config keys whose model is billed flat-rate via costMicrodollarsOverride, not per token. */
|
|
249
|
+
const NON_TOKEN_CONFIG_KEYS = new Set(['GEMINI_FLASH_IMAGE_MODEL', 'VEO_MODEL']);
|
|
250
|
+
function readConfigModelDefaults() {
|
|
251
|
+
const file = path.join(ROOT, 'trendy-video-agent', 'src', 'config.ts');
|
|
252
|
+
if (!fs.existsSync(file))
|
|
253
|
+
return null;
|
|
254
|
+
const src = fs.readFileSync(file, 'utf8');
|
|
255
|
+
const out = [];
|
|
256
|
+
const re = /optionalEnv\(\s*'([A-Z0-9_]*MODEL)'\s*,\s*'([^']+)'\s*\)/g;
|
|
257
|
+
let m;
|
|
258
|
+
while ((m = re.exec(src)) !== null)
|
|
259
|
+
out.push({ key: m[1], model: m[2] });
|
|
260
|
+
return out;
|
|
261
|
+
}
|
|
262
|
+
function expectPricedByOwnRow(model, origin) {
|
|
263
|
+
const row = (0, pricing_1.findPricingRow)(model);
|
|
264
|
+
(0, vitest_1.expect)(row, `${model} (${origin}) has no MODEL_PRICING row and would be billed at DEFAULT_PRICING (Claude Sonnet $3/$15). Add a row.`).toBeDefined();
|
|
265
|
+
(0, vitest_1.expect)((0, pricing_1.getPricing)(model), `${model} (${origin}) resolves to DEFAULT_PRICING`).not.toBe(pricing_1.DEFAULT_PRICING);
|
|
266
|
+
(0, vitest_1.expect)(row.input, `${model} (${origin}) has a zero input rate`).toBeGreaterThan(0);
|
|
267
|
+
}
|
|
268
|
+
(0, vitest_1.describe)('guard: every trendy-video-agent config model default has its own pricing row', () => {
|
|
269
|
+
for (const model of CONFIG_MODEL_DEFAULTS_SNAPSHOT) {
|
|
270
|
+
(0, vitest_1.it)(`snapshot: ${model}`, () => {
|
|
271
|
+
expectPricedByOwnRow(model, 'config snapshot');
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
const live = readConfigModelDefaults();
|
|
275
|
+
if (live === null) {
|
|
276
|
+
vitest_1.it.skip('live: trendy-video-agent/src/config.ts not checked out (git worktree) — snapshot list still enforced', () => { });
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
(0, vitest_1.it)('live: config.ts parsed at least one *_MODEL default', () => {
|
|
280
|
+
(0, vitest_1.expect)(live.length).toBeGreaterThan(0);
|
|
281
|
+
});
|
|
282
|
+
for (const { key, model } of live) {
|
|
283
|
+
if (NON_TOKEN_CONFIG_KEYS.has(key)) {
|
|
284
|
+
// Image / video generation is recorded under its own SKU
|
|
285
|
+
// ('veo-video-gen', image models) with costMicrodollarsOverride, so
|
|
286
|
+
// the config model ID is not the billing model ID.
|
|
287
|
+
vitest_1.it.skip(`live: ${key}=${model} is flat-rate via override, not token-priced`, () => { });
|
|
288
|
+
continue;
|
|
289
|
+
}
|
|
290
|
+
(0, vitest_1.it)(`live: ${key}=${model}`, () => {
|
|
291
|
+
expectPricedByOwnRow(model, key);
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
//# sourceMappingURL=pricing-gemini-billing.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pricing-gemini-billing.test.js","sourceRoot":"","sources":["../../src/__tests__/pricing-gemini-billing.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pricing-gemini-embedding-2.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/pricing-gemini-embedding-2.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const pricing_1 = require("../pricing");
|
|
5
|
+
/**
|
|
6
|
+
* Guard suite for `gemini-embedding-2`.
|
|
7
|
+
*
|
|
8
|
+
* trendy-chunk-analyzer embeds every 30 s chunk (video) and every file
|
|
9
|
+
* (text) with this model and, until 2026-09-05, never recorded the usage.
|
|
10
|
+
* trendy-video-agent recorded it but the model had no pricing row, so it
|
|
11
|
+
* fell through to DEFAULT_PRICING (Claude Sonnet $3/1M — 15x the text rate).
|
|
12
|
+
*
|
|
13
|
+
* Rates: Vertex AI pricing, "Gemini Embedding 2 (Unified Multimodal,
|
|
14
|
+
* Preview)", online requests, USD per 1M input tokens, fetched 2026-09-04.
|
|
15
|
+
*/
|
|
16
|
+
(0, vitest_1.describe)('gemini-embedding-2 pricing row', () => {
|
|
17
|
+
(0, vitest_1.it)('has its own row and does not fall through to DEFAULT_PRICING', () => {
|
|
18
|
+
(0, vitest_1.expect)((0, pricing_1.findPricingRow)('gemini-embedding-2')).toBeDefined();
|
|
19
|
+
(0, vitest_1.expect)((0, pricing_1.getPricing)('gemini-embedding-2')).not.toBe(pricing_1.DEFAULT_PRICING);
|
|
20
|
+
(0, vitest_1.expect)((0, pricing_1.getPricing)('gemini-embedding-2')).not.toEqual(pricing_1.DEFAULT_PRICING);
|
|
21
|
+
});
|
|
22
|
+
(0, vitest_1.it)('bills text input at $0.20 / 1M tokens and output at $0', () => {
|
|
23
|
+
const p = (0, pricing_1.getPricing)('gemini-embedding-2');
|
|
24
|
+
(0, vitest_1.expect)(p.input).toBe(0.20);
|
|
25
|
+
(0, vitest_1.expect)(p.output).toBe(0);
|
|
26
|
+
(0, vitest_1.expect)(p.cacheRead).toBe(0);
|
|
27
|
+
(0, vitest_1.expect)(p.cacheWrite).toBe(0);
|
|
28
|
+
});
|
|
29
|
+
(0, vitest_1.it)('row text rate matches the per-modality table', () => {
|
|
30
|
+
(0, vitest_1.expect)(pricing_1.MODEL_PRICING['gemini-embedding-2'].input).toBe(pricing_1.GEMINI_EMBEDDING_2_INPUT_PRICING.text);
|
|
31
|
+
});
|
|
32
|
+
(0, vitest_1.it)('a 1,000-token text embed costs 200 microdollars via the row (not 3,000 at Sonnet rates)', () => {
|
|
33
|
+
(0, vitest_1.expect)((0, pricing_1.calculateCostMicrodollars)('gemini-embedding-2', 1_000, 0)).toBe(200);
|
|
34
|
+
(0, vitest_1.expect)((0, pricing_1.calculateCostMicrodollars)('gemini-embedding-2', 1_000, 0)).toBeLessThan(1_000 * pricing_1.DEFAULT_PRICING.input);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
(0, vitest_1.describe)('gemini-embedding-2 per-modality rates', () => {
|
|
38
|
+
(0, vitest_1.it)('match the published Vertex AI table (USD / 1M input tokens)', () => {
|
|
39
|
+
(0, vitest_1.expect)(pricing_1.GEMINI_EMBEDDING_2_INPUT_PRICING).toEqual({
|
|
40
|
+
text: 0.20,
|
|
41
|
+
image: 0.45,
|
|
42
|
+
audio: 6.50,
|
|
43
|
+
video: 12.00,
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
(0, vitest_1.it)('per-unit fallbacks match the published per-unit equivalents', () => {
|
|
47
|
+
(0, vitest_1.expect)(pricing_1.GEMINI_EMBEDDING_2_UNIT_RATES.microdollarsPerImage).toBe(120); // $0.00012
|
|
48
|
+
(0, vitest_1.expect)(pricing_1.GEMINI_EMBEDDING_2_UNIT_RATES.microdollarsPerAudioSecond).toBe(160); // $0.00016
|
|
49
|
+
(0, vitest_1.expect)(pricing_1.GEMINI_EMBEDDING_2_UNIT_RATES.microdollarsPerVideoFrame).toBe(790); // $0.00079
|
|
50
|
+
(0, vitest_1.expect)(pricing_1.GEMINI_EMBEDDING_2_UNIT_RATES.videoMaxFrames).toBe(32);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
(0, vitest_1.describe)('geminiEmbedding2VideoFrames', () => {
|
|
54
|
+
(0, vitest_1.it)('samples 1 fps up to 32 s', () => {
|
|
55
|
+
(0, vitest_1.expect)((0, pricing_1.geminiEmbedding2VideoFrames)(30)).toBe(30);
|
|
56
|
+
(0, vitest_1.expect)((0, pricing_1.geminiEmbedding2VideoFrames)(29.2)).toBe(30);
|
|
57
|
+
(0, vitest_1.expect)((0, pricing_1.geminiEmbedding2VideoFrames)(32)).toBe(32);
|
|
58
|
+
});
|
|
59
|
+
(0, vitest_1.it)('caps at 32 frames for longer videos', () => {
|
|
60
|
+
(0, vitest_1.expect)((0, pricing_1.geminiEmbedding2VideoFrames)(120)).toBe(32);
|
|
61
|
+
});
|
|
62
|
+
(0, vitest_1.it)('returns 0 for empty / invalid durations', () => {
|
|
63
|
+
(0, vitest_1.expect)((0, pricing_1.geminiEmbedding2VideoFrames)(0)).toBe(0);
|
|
64
|
+
(0, vitest_1.expect)((0, pricing_1.geminiEmbedding2VideoFrames)(NaN)).toBe(0);
|
|
65
|
+
(0, vitest_1.expect)((0, pricing_1.geminiEmbedding2VideoFrames)(-5)).toBe(0);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
(0, vitest_1.describe)('calculateGeminiEmbedding2CostMicrodollars', () => {
|
|
69
|
+
(0, vitest_1.it)('prefers reported tokens: 2,000 video tokens at $12/1M = 24,000 µ$', () => {
|
|
70
|
+
const c = (0, pricing_1.calculateGeminiEmbedding2CostMicrodollars)({ modality: 'video', promptTokens: 2_000, durationSec: 30 });
|
|
71
|
+
(0, vitest_1.expect)(c).toEqual({ costMicrodollars: 24_000, inputTokens: 2_000, basis: 'reported_tokens' });
|
|
72
|
+
});
|
|
73
|
+
(0, vitest_1.it)('reported text tokens use the text rate', () => {
|
|
74
|
+
const c = (0, pricing_1.calculateGeminiEmbedding2CostMicrodollars)({ modality: 'text', promptTokens: 1_000 });
|
|
75
|
+
(0, vitest_1.expect)(c.costMicrodollars).toBe(200);
|
|
76
|
+
(0, vitest_1.expect)(c.basis).toBe('reported_tokens');
|
|
77
|
+
});
|
|
78
|
+
(0, vitest_1.it)('30 s chunk with no token count falls back to 30 frames × 790 µ$ = 23,700 µ$ (~$0.024)', () => {
|
|
79
|
+
const c = (0, pricing_1.calculateGeminiEmbedding2CostMicrodollars)({ modality: 'video', durationSec: 30 });
|
|
80
|
+
(0, vitest_1.expect)(c).toEqual({ costMicrodollars: 23_700, inputTokens: 0, basis: 'estimated_units' });
|
|
81
|
+
});
|
|
82
|
+
(0, vitest_1.it)('text fallback estimates ~4 chars / token', () => {
|
|
83
|
+
const c = (0, pricing_1.calculateGeminiEmbedding2CostMicrodollars)({ modality: 'text', textChars: 4_000 });
|
|
84
|
+
(0, vitest_1.expect)(c.inputTokens).toBe(1_000);
|
|
85
|
+
(0, vitest_1.expect)(c.costMicrodollars).toBe(200);
|
|
86
|
+
(0, vitest_1.expect)(c.basis).toBe('estimated_units');
|
|
87
|
+
});
|
|
88
|
+
(0, vitest_1.it)('image and audio fallbacks use the per-unit rates', () => {
|
|
89
|
+
(0, vitest_1.expect)((0, pricing_1.calculateGeminiEmbedding2CostMicrodollars)({ modality: 'image', imageCount: 2 }).costMicrodollars).toBe(240);
|
|
90
|
+
(0, vitest_1.expect)((0, pricing_1.calculateGeminiEmbedding2CostMicrodollars)({ modality: 'audio', durationSec: 60 }).costMicrodollars).toBe(9_600);
|
|
91
|
+
});
|
|
92
|
+
(0, vitest_1.it)('video is ~60x the text rate per token — a bare token count against the row would under-bill', () => {
|
|
93
|
+
const tokens = 2_000;
|
|
94
|
+
const viaRow = (0, pricing_1.calculateCostMicrodollars)('gemini-embedding-2', tokens, 0);
|
|
95
|
+
const viaHelper = (0, pricing_1.calculateGeminiEmbedding2CostMicrodollars)({ modality: 'video', promptTokens: tokens }).costMicrodollars;
|
|
96
|
+
(0, vitest_1.expect)(viaHelper / viaRow).toBe(60);
|
|
97
|
+
});
|
|
98
|
+
(0, vitest_1.it)('ignores a zero token count and falls back to units', () => {
|
|
99
|
+
const c = (0, pricing_1.calculateGeminiEmbedding2CostMicrodollars)({ modality: 'video', promptTokens: 0, durationSec: 10 });
|
|
100
|
+
(0, vitest_1.expect)(c.basis).toBe('estimated_units');
|
|
101
|
+
(0, vitest_1.expect)(c.costMicrodollars).toBe(7_900);
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
//# sourceMappingURL=pricing-gemini-embedding-2.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pricing-gemini-embedding-2.test.js","sourceRoot":"","sources":["../../src/__tests__/pricing-gemini-embedding-2.test.ts"],"names":[],"mappings":"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"}
|