prompt-price 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/README.md +234 -0
  2. package/dist/__tests__/count-tokens.test.d.ts +2 -0
  3. package/dist/__tests__/count-tokens.test.d.ts.map +1 -0
  4. package/dist/__tests__/count-tokens.test.js +67 -0
  5. package/dist/__tests__/count-tokens.test.js.map +1 -0
  6. package/dist/__tests__/errors.test.d.ts +2 -0
  7. package/dist/__tests__/errors.test.d.ts.map +1 -0
  8. package/dist/__tests__/errors.test.js +101 -0
  9. package/dist/__tests__/errors.test.js.map +1 -0
  10. package/dist/__tests__/estimate.test.d.ts +2 -0
  11. package/dist/__tests__/estimate.test.d.ts.map +1 -0
  12. package/dist/__tests__/estimate.test.js +187 -0
  13. package/dist/__tests__/estimate.test.js.map +1 -0
  14. package/dist/__tests__/heuristic-counter.test.d.ts +2 -0
  15. package/dist/__tests__/heuristic-counter.test.d.ts.map +1 -0
  16. package/dist/__tests__/heuristic-counter.test.js +99 -0
  17. package/dist/__tests__/heuristic-counter.test.js.map +1 -0
  18. package/dist/__tests__/model-resolver.test.d.ts +2 -0
  19. package/dist/__tests__/model-resolver.test.d.ts.map +1 -0
  20. package/dist/__tests__/model-resolver.test.js +152 -0
  21. package/dist/__tests__/model-resolver.test.js.map +1 -0
  22. package/dist/__tests__/types.test.d.ts +2 -0
  23. package/dist/__tests__/types.test.d.ts.map +1 -0
  24. package/dist/__tests__/types.test.js +109 -0
  25. package/dist/__tests__/types.test.js.map +1 -0
  26. package/dist/cost-calculator.d.ts +9 -0
  27. package/dist/cost-calculator.d.ts.map +1 -0
  28. package/dist/cost-calculator.js +19 -0
  29. package/dist/cost-calculator.js.map +1 -0
  30. package/dist/count-tokens.d.ts +4 -0
  31. package/dist/count-tokens.d.ts.map +1 -0
  32. package/dist/count-tokens.js +38 -0
  33. package/dist/count-tokens.js.map +1 -0
  34. package/dist/errors.d.ts +13 -0
  35. package/dist/errors.d.ts.map +1 -0
  36. package/dist/errors.js +28 -0
  37. package/dist/errors.js.map +1 -0
  38. package/dist/estimate.d.ts +6 -0
  39. package/dist/estimate.d.ts.map +1 -0
  40. package/dist/estimate.js +82 -0
  41. package/dist/estimate.js.map +1 -0
  42. package/dist/guard.d.ts +4 -0
  43. package/dist/guard.d.ts.map +1 -0
  44. package/dist/guard.js +84 -0
  45. package/dist/guard.js.map +1 -0
  46. package/dist/heuristic-counter.d.ts +5 -0
  47. package/dist/heuristic-counter.d.ts.map +1 -0
  48. package/dist/heuristic-counter.js +51 -0
  49. package/dist/heuristic-counter.js.map +1 -0
  50. package/dist/index.d.ts +9 -0
  51. package/dist/index.d.ts.map +1 -0
  52. package/dist/index.js +27 -0
  53. package/dist/index.js.map +1 -0
  54. package/dist/message-overhead.d.ts +9 -0
  55. package/dist/message-overhead.d.ts.map +1 -0
  56. package/dist/message-overhead.js +28 -0
  57. package/dist/message-overhead.js.map +1 -0
  58. package/dist/model-resolver.d.ts +8 -0
  59. package/dist/model-resolver.d.ts.map +1 -0
  60. package/dist/model-resolver.js +132 -0
  61. package/dist/model-resolver.js.map +1 -0
  62. package/dist/tool-tokenizer.d.ts +6 -0
  63. package/dist/tool-tokenizer.d.ts.map +1 -0
  64. package/dist/tool-tokenizer.js +27 -0
  65. package/dist/tool-tokenizer.js.map +1 -0
  66. package/dist/types.d.ts +115 -0
  67. package/dist/types.d.ts.map +1 -0
  68. package/dist/types.js +3 -0
  69. package/dist/types.js.map +1 -0
  70. package/package.json +48 -0
package/README.md ADDED
@@ -0,0 +1,234 @@
1
+ # prompt-price
2
+
3
+ Pre-flight cost estimation for any prompt and model combination. Know what an LLM call will cost before you send it.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install prompt-price
9
+ ```
10
+
11
+ ### Optional: exact token counting
12
+
13
+ ```bash
14
+ npm install js-tiktoken
15
+ ```
16
+
17
+ When `js-tiktoken` is installed, `prompt-price` can use native tiktoken encodings for exact OpenAI token counts. Without it, a calibrated heuristic is used (fast, no WASM overhead, typically within 5% of exact counts).
18
+
19
+ ## Quick Start
20
+
21
+ ```ts
22
+ import { estimate, countTokens, compareModels, guard } from 'prompt-price';
23
+
24
+ // Estimate cost for a prompt
25
+ const est = await estimate({
26
+ model: 'gpt-4o',
27
+ messages: [{ role: 'user', content: 'Explain quantum computing' }],
28
+ });
29
+ console.log(`Estimated cost: $${est.totalCost.toFixed(6)}`);
30
+ // -> Estimated cost: $0.000053
31
+
32
+ // Count tokens without cost calculation
33
+ const tokens = await countTokens('Hello, world!', { model: 'gpt-4o' });
34
+ console.log(`Tokens: ${tokens.tokens} (${tokens.method})`);
35
+ // -> Tokens: 4 (approximate)
36
+
37
+ // Compare costs across models
38
+ const comparison = await compareModels(
39
+ [{ role: 'user', content: 'Write a haiku' }],
40
+ ['gpt-4o', 'gpt-4o-mini', 'claude-3-5-sonnet', 'gemini-2.0-flash'],
41
+ );
42
+ comparison.forEach((e) =>
43
+ console.log(`${e.model}: $${e.totalCost.toFixed(6)}`),
44
+ );
45
+ // Results are sorted cheapest-first
46
+
47
+ // Budget guard -- wraps an OpenAI or Anthropic client
48
+ import OpenAI from 'openai';
49
+ const openai = guard(new OpenAI(), { model: 'gpt-4o', maxCost: 0.05 });
50
+ // Throws BudgetExceededError if a request would exceed $0.05
51
+ ```
52
+
53
+ ## API Reference
54
+
55
+ ### `estimate(options): Promise<Estimate>`
56
+
57
+ Estimate the cost of an LLM call before sending it.
58
+
59
+ ```ts
60
+ const est = await estimate({
61
+ model: 'gpt-4o', // required — model name or "provider/model"
62
+ provider: 'openai', // optional — explicit provider override
63
+ messages: [ // optional — conversation messages
64
+ { role: 'system', content: 'You are a helpful assistant.' },
65
+ { role: 'user', content: 'What is 2+2?' },
66
+ ],
67
+ systemPrompt: 'Be concise.', // optional — prepended system prompt
68
+ maxOutputTokens: 256, // optional — caps output token estimate
69
+ tools: [...], // optional — tool definitions
70
+ });
71
+
72
+ console.log(est.inputTokens); // e.g. 42
73
+ console.log(est.outputTokens); // e.g. 77
74
+ console.log(est.inputCost); // e.g. 0.000105
75
+ console.log(est.outputCost); // e.g. 0.000770
76
+ console.log(est.totalCost); // e.g. 0.000875
77
+ console.log(est.currency); // 'USD'
78
+ console.log(est.method); // 'approximate'
79
+ console.log(est.provider); // 'openai'
80
+ console.log(est.model); // 'gpt-4o'
81
+ ```
82
+
83
+ ### `estimateSync(options): Estimate`
84
+
85
+ Synchronous version of `estimate()`. Same parameters and return value.
86
+
87
+ ```ts
88
+ const est = estimateSync({ model: 'gpt-4o', messages: [{ role: 'user', content: 'Hi' }] });
89
+ ```
90
+
91
+ ### `estimatePrompt(prompt, options?): Promise<Estimate>`
92
+
93
+ Convenience wrapper that treats a plain string as a single user message.
94
+
95
+ ```ts
96
+ const est = await estimatePrompt('Explain general relativity', { model: 'gpt-4o' });
97
+ ```
98
+
99
+ ### `compareModels(messages, models, options?): Promise<Estimate[]>`
100
+
101
+ Run `estimate()` for multiple models and return results sorted by total cost (ascending).
102
+
103
+ ```ts
104
+ const results = await compareModels(
105
+ [{ role: 'user', content: 'Summarize this article...' }],
106
+ ['gpt-4o', 'gpt-4o-mini', 'claude-3-5-sonnet', 'gemini-1.5-flash'],
107
+ );
108
+ results.forEach((r) => console.log(`${r.model}: $${r.totalCost.toFixed(6)}`));
109
+ ```
110
+
111
+ ### `countTokens(content, options?): Promise<TokenCount>`
112
+
113
+ Estimate the token count of a string.
114
+
115
+ ```ts
116
+ const result = await countTokens('Hello, world!', { model: 'gpt-4o' });
117
+ // { tokens: 4, method: 'approximate' }
118
+ ```
119
+
120
+ ### `countTokensSync(content, options?): TokenCount`
121
+
122
+ Synchronous version of `countTokens()`.
123
+
124
+ ```ts
125
+ const result = countTokensSync('Hello, world!', { model: 'claude-3-5-sonnet' });
126
+ ```
127
+
128
+ ### `checkBudget(options): Promise<BudgetResult>`
129
+
130
+ Check whether an API call would fit within a cost budget.
131
+
132
+ ```ts
133
+ const result = await checkBudget({
134
+ model: 'gpt-4o',
135
+ messages: [{ role: 'user', content: 'Hello' }],
136
+ budget: 0.01,
137
+ });
138
+ console.log(result.withinBudget); // true or false
139
+ console.log(result.utilizationPct); // e.g. 0.53 (0.53%)
140
+ console.log(result.remaining); // e.g. 0.009947
141
+ ```
142
+
143
+ ### `guard(client, options): T`
144
+
145
+ Wrap an OpenAI or Anthropic SDK client to automatically check costs before every request.
146
+
147
+ ```ts
148
+ import OpenAI from 'openai';
149
+ import Anthropic from '@anthropic-ai/sdk';
150
+ import { guard, BudgetExceededError } from 'prompt-price';
151
+
152
+ const openai = guard(new OpenAI(), {
153
+ model: 'gpt-4o',
154
+ maxCost: 0.05,
155
+ onExceed: 'throw', // 'throw' | 'warn' | 'log'
156
+ });
157
+
158
+ try {
159
+ const response = await openai.chat.completions.create({ ... });
160
+ } catch (err) {
161
+ if (err instanceof BudgetExceededError) {
162
+ console.log(`Blocked: $${err.estimate.totalCost} > $${err.maxCost}`);
163
+ }
164
+ }
165
+ ```
166
+
167
+ ## Supported Models
168
+
169
+ | Provider | Models |
170
+ |-----------|--------|
171
+ | OpenAI | gpt-4o, gpt-4o-mini, gpt-4.1, gpt-4.1-mini, gpt-4-turbo, gpt-3.5-turbo, o1, o1-mini, o3-mini |
172
+ | Anthropic | claude-opus-4, claude-sonnet-4-5, claude-haiku-4-5, claude-3-5-sonnet, claude-3-5-haiku, claude-3-opus, claude-3-haiku |
173
+ | Google | gemini-2.0-flash, gemini-1.5-pro, gemini-1.5-flash |
174
+ | Meta | llama-3.1-70b, llama-3.3-70b |
175
+ | Mistral | mistral-large, mistral-small |
176
+ | Cohere | command-r-plus, command-r |
177
+
178
+ Models can be specified as bare names (`gpt-4o`) or with a provider prefix (`openai/gpt-4o`). Partial/versioned names are resolved via prefix matching — e.g. `gpt-4o-2024-08-06` resolves to `gpt-4o`.
179
+
180
+ ## Available Exports
181
+
182
+ ### Types
183
+
184
+ All 13 TypeScript interfaces are exported:
185
+
186
+ - `Message` -- a single conversation message
187
+ - `ContentPart` -- multi-modal content (text, image, audio, file)
188
+ - `ToolCall` -- a tool call made by an assistant
189
+ - `ToolDefinition` -- a tool/function definition
190
+ - `EstimateOptions` -- options for `estimate()`
191
+ - `CountTokensOptions` -- options for `countTokens()`
192
+ - `TokenCount` -- result of a token count operation
193
+ - `Estimate` -- a full cost estimate result
194
+ - `GuardOptions` -- options for the `guard()` middleware
195
+ - `CheckBudgetOptions` -- options for `checkBudget()`
196
+ - `BudgetResult` -- result of `checkBudget()`
197
+ - `OpenAILikeClient` -- type for OpenAI-compatible SDK clients
198
+ - `AnthropicLikeClient` -- type for Anthropic-compatible SDK clients
199
+
200
+ ### Error Classes
201
+
202
+ - `BudgetExceededError` -- thrown when a cost estimate exceeds the configured budget. Contains `estimate` and `maxCost` properties.
203
+ - `ModelNotFoundError` -- thrown when a model is not found in the price catalog. Contains the `model` string.
204
+
205
+ ```ts
206
+ import { BudgetExceededError, ModelNotFoundError } from 'prompt-price';
207
+
208
+ try {
209
+ const est = await estimate({ model: 'unknown-model', messages: [] });
210
+ } catch (err) {
211
+ if (err instanceof ModelNotFoundError) {
212
+ console.log(`Unknown model: ${err.model}`);
213
+ }
214
+ }
215
+ ```
216
+
217
+ ## Token Counting Method
218
+
219
+ All token counts use a calibrated heuristic (chars ÷ provider-specific ratio, rounded up):
220
+
221
+ | Provider | Chars per token |
222
+ |-----------|----------------|
223
+ | OpenAI | 3.9 |
224
+ | Anthropic | 3.5 |
225
+ | Google | 4.0 |
226
+ | Mistral | 3.8 |
227
+ | Meta | 3.7 |
228
+ | Cohere | 4.0 |
229
+
230
+ Output tokens default to `min(ceil(inputTokens * 0.3), 1000)` unless `maxOutputTokens` is provided.
231
+
232
+ ## License
233
+
234
+ MIT
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=count-tokens.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"count-tokens.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/count-tokens.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const count_tokens_1 = require("../count-tokens");
5
+ (0, vitest_1.describe)('countTokensSync()', () => {
6
+ (0, vitest_1.it)('returns a positive integer for non-empty string', () => {
7
+ const result = (0, count_tokens_1.countTokensSync)('Hello, world!');
8
+ (0, vitest_1.expect)(result.tokens).toBeGreaterThan(0);
9
+ (0, vitest_1.expect)(Number.isInteger(result.tokens)).toBe(true);
10
+ });
11
+ (0, vitest_1.it)('method is approximate', () => {
12
+ const result = (0, count_tokens_1.countTokensSync)('Hello, world!');
13
+ (0, vitest_1.expect)(result.method).toBe('approximate');
14
+ });
15
+ (0, vitest_1.it)('returns 0 tokens for empty string', () => {
16
+ const result = (0, count_tokens_1.countTokensSync)('');
17
+ (0, vitest_1.expect)(result.tokens).toBe(0);
18
+ });
19
+ (0, vitest_1.it)('more text yields more tokens', () => {
20
+ const short = (0, count_tokens_1.countTokensSync)('Hi');
21
+ const long = (0, count_tokens_1.countTokensSync)('Hi'.repeat(50));
22
+ (0, vitest_1.expect)(long.tokens).toBeGreaterThan(short.tokens);
23
+ });
24
+ (0, vitest_1.it)('uses model to determine provider ratio', () => {
25
+ const openai = (0, count_tokens_1.countTokensSync)('hello world', { model: 'gpt-4o' });
26
+ const anthropic = (0, count_tokens_1.countTokensSync)('hello world', { model: 'claude-3-5-sonnet' });
27
+ // Different ratios → may differ
28
+ (0, vitest_1.expect)(openai.tokens).toBeGreaterThan(0);
29
+ (0, vitest_1.expect)(anthropic.tokens).toBeGreaterThan(0);
30
+ });
31
+ (0, vitest_1.it)('defaults to openai ratio when no model is specified', () => {
32
+ const result = (0, count_tokens_1.countTokensSync)('hello world');
33
+ (0, vitest_1.expect)(result.tokens).toBe(Math.ceil(11 / 3.9));
34
+ });
35
+ (0, vitest_1.it)('anthropic ratio gives more tokens than openai for same text', () => {
36
+ // anthropic ratio = 3.5, openai = 3.9, so anthropic yields more tokens
37
+ const openai = (0, count_tokens_1.countTokensSync)('The quick brown fox', { model: 'gpt-4o' });
38
+ const anthropic = (0, count_tokens_1.countTokensSync)('The quick brown fox', { model: 'claude-3-5-sonnet' });
39
+ (0, vitest_1.expect)(anthropic.tokens).toBeGreaterThanOrEqual(openai.tokens);
40
+ });
41
+ });
42
+ (0, vitest_1.describe)('countTokens()', () => {
43
+ (0, vitest_1.it)('returns a TokenCount with tokens > 0 for non-empty input', async () => {
44
+ const result = await (0, count_tokens_1.countTokens)('Explain quantum computing in simple terms.');
45
+ (0, vitest_1.expect)(result.tokens).toBeGreaterThan(0);
46
+ });
47
+ (0, vitest_1.it)('method is approximate', async () => {
48
+ const result = await (0, count_tokens_1.countTokens)('test');
49
+ (0, vitest_1.expect)(result.method).toBe('approximate');
50
+ });
51
+ (0, vitest_1.it)('accepts model option', async () => {
52
+ const result = await (0, count_tokens_1.countTokens)('hello', { model: 'gpt-4o' });
53
+ (0, vitest_1.expect)(result.tokens).toBeGreaterThan(0);
54
+ });
55
+ (0, vitest_1.it)('returns 0 for empty string', async () => {
56
+ const result = await (0, count_tokens_1.countTokens)('');
57
+ (0, vitest_1.expect)(result.tokens).toBe(0);
58
+ });
59
+ (0, vitest_1.it)('async result matches sync result for same input', async () => {
60
+ const input = 'The same text input for both sync and async';
61
+ const asyncResult = await (0, count_tokens_1.countTokens)(input, { model: 'gpt-4o' });
62
+ const syncResult = (0, count_tokens_1.countTokensSync)(input, { model: 'gpt-4o' });
63
+ (0, vitest_1.expect)(asyncResult.tokens).toBe(syncResult.tokens);
64
+ (0, vitest_1.expect)(asyncResult.method).toBe(syncResult.method);
65
+ });
66
+ });
67
+ //# sourceMappingURL=count-tokens.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"count-tokens.test.js","sourceRoot":"","sources":["../../src/__tests__/count-tokens.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=errors.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/errors.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const errors_1 = require("../errors");
5
+ function makeEstimate(overrides = {}) {
6
+ return {
7
+ model: 'openai/gpt-4o',
8
+ provider: 'openai',
9
+ inputTokens: 100,
10
+ outputTokens: 50,
11
+ inputCost: 0.000250,
12
+ outputCost: 0.001000,
13
+ totalCost: 0.001250,
14
+ currency: 'USD',
15
+ method: 'approximate',
16
+ ...overrides,
17
+ };
18
+ }
19
+ (0, vitest_1.describe)('BudgetExceededError', () => {
20
+ (0, vitest_1.it)('has name BudgetExceededError', () => {
21
+ const err = new errors_1.BudgetExceededError(makeEstimate(), 0.001000);
22
+ (0, vitest_1.expect)(err.name).toBe('BudgetExceededError');
23
+ });
24
+ (0, vitest_1.it)('instanceof Error', () => {
25
+ const err = new errors_1.BudgetExceededError(makeEstimate(), 0.001000);
26
+ (0, vitest_1.expect)(err).toBeInstanceOf(Error);
27
+ });
28
+ (0, vitest_1.it)('instanceof BudgetExceededError', () => {
29
+ const err = new errors_1.BudgetExceededError(makeEstimate(), 0.001000);
30
+ (0, vitest_1.expect)(err).toBeInstanceOf(errors_1.BudgetExceededError);
31
+ });
32
+ (0, vitest_1.it)('message contains cost with 6 decimal places', () => {
33
+ const est = makeEstimate({ totalCost: 0.001234 });
34
+ const err = new errors_1.BudgetExceededError(est, 0.001000);
35
+ (0, vitest_1.expect)(err.message).toContain('0.001234');
36
+ });
37
+ (0, vitest_1.it)('message contains budget with 6 decimal places', () => {
38
+ const est = makeEstimate({ totalCost: 0.001234 });
39
+ const err = new errors_1.BudgetExceededError(est, 0.001000);
40
+ (0, vitest_1.expect)(err.message).toContain('0.001000');
41
+ });
42
+ (0, vitest_1.it)('message contains model name', () => {
43
+ const est = makeEstimate({ model: 'openai/gpt-4o' });
44
+ const err = new errors_1.BudgetExceededError(est, 0.001000);
45
+ (0, vitest_1.expect)(err.message).toContain('openai/gpt-4o');
46
+ });
47
+ (0, vitest_1.it)('message contains input token count', () => {
48
+ const est = makeEstimate({ inputTokens: 100 });
49
+ const err = new errors_1.BudgetExceededError(est, 0.001000);
50
+ (0, vitest_1.expect)(err.message).toContain('100');
51
+ });
52
+ (0, vitest_1.it)('message contains output token count', () => {
53
+ const est = makeEstimate({ outputTokens: 50 });
54
+ const err = new errors_1.BudgetExceededError(est, 0.001000);
55
+ (0, vitest_1.expect)(err.message).toContain('50');
56
+ });
57
+ (0, vitest_1.it)('estimate property is accessible', () => {
58
+ const est = makeEstimate({ totalCost: 0.001234 });
59
+ const err = new errors_1.BudgetExceededError(est, 0.001000);
60
+ (0, vitest_1.expect)(err.estimate).toBe(est);
61
+ (0, vitest_1.expect)(err.estimate.totalCost).toBe(0.001234);
62
+ });
63
+ (0, vitest_1.it)('maxCost property is accessible', () => {
64
+ const err = new errors_1.BudgetExceededError(makeEstimate(), 0.001000);
65
+ (0, vitest_1.expect)(err.maxCost).toBe(0.001000);
66
+ });
67
+ (0, vitest_1.it)('with cost=0.001234 and budget=0.001000, message has 6 decimal places', () => {
68
+ const est = makeEstimate({ totalCost: 0.001234 });
69
+ const err = new errors_1.BudgetExceededError(est, 0.001000);
70
+ // Both values must appear with 6 decimal places in the message
71
+ (0, vitest_1.expect)(err.message).toMatch(/\$0\.001234/);
72
+ (0, vitest_1.expect)(err.message).toMatch(/\$0\.001000/);
73
+ });
74
+ (0, vitest_1.it)('prototype chain is correct', () => {
75
+ const err = new errors_1.BudgetExceededError(makeEstimate(), 0.001000);
76
+ (0, vitest_1.expect)(Object.getPrototypeOf(err)).toBe(errors_1.BudgetExceededError.prototype);
77
+ });
78
+ });
79
+ (0, vitest_1.describe)('ModelNotFoundError', () => {
80
+ (0, vitest_1.it)('has name ModelNotFoundError', () => {
81
+ const err = new errors_1.ModelNotFoundError('fake-model');
82
+ (0, vitest_1.expect)(err.name).toBe('ModelNotFoundError');
83
+ });
84
+ (0, vitest_1.it)('instanceof Error', () => {
85
+ const err = new errors_1.ModelNotFoundError('fake-model');
86
+ (0, vitest_1.expect)(err).toBeInstanceOf(Error);
87
+ });
88
+ (0, vitest_1.it)('message contains the model string', () => {
89
+ const err = new errors_1.ModelNotFoundError('my-custom-model');
90
+ (0, vitest_1.expect)(err.message).toContain('my-custom-model');
91
+ });
92
+ (0, vitest_1.it)('model property is accessible', () => {
93
+ const err = new errors_1.ModelNotFoundError('openai/unknown-model');
94
+ (0, vitest_1.expect)(err.model).toBe('openai/unknown-model');
95
+ });
96
+ (0, vitest_1.it)('prototype chain is correct', () => {
97
+ const err = new errors_1.ModelNotFoundError('some-model');
98
+ (0, vitest_1.expect)(Object.getPrototypeOf(err)).toBe(errors_1.ModelNotFoundError.prototype);
99
+ });
100
+ });
101
+ //# sourceMappingURL=errors.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.test.js","sourceRoot":"","sources":["../../src/__tests__/errors.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=estimate.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"estimate.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/estimate.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,187 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const estimate_1 = require("../estimate");
5
+ (0, vitest_1.describe)('estimate()', () => {
6
+ (0, vitest_1.it)('returns inputTokens > 0 for a user message', async () => {
7
+ const result = await (0, estimate_1.estimate)({
8
+ model: 'gpt-4o',
9
+ messages: [{ role: 'user', content: 'Explain quantum computing' }],
10
+ });
11
+ (0, vitest_1.expect)(result.inputTokens).toBeGreaterThan(0);
12
+ });
13
+ (0, vitest_1.it)('returns positive costs', async () => {
14
+ const result = await (0, estimate_1.estimate)({
15
+ model: 'gpt-4o',
16
+ messages: [{ role: 'user', content: 'Explain quantum computing' }],
17
+ });
18
+ (0, vitest_1.expect)(result.inputCost).toBeGreaterThan(0);
19
+ (0, vitest_1.expect)(result.outputCost).toBeGreaterThan(0);
20
+ (0, vitest_1.expect)(result.totalCost).toBeGreaterThan(0);
21
+ });
22
+ (0, vitest_1.it)('totalCost equals inputCost + outputCost', async () => {
23
+ const result = await (0, estimate_1.estimate)({
24
+ model: 'gpt-4o',
25
+ messages: [{ role: 'user', content: 'Hello' }],
26
+ });
27
+ (0, vitest_1.expect)(result.totalCost).toBeCloseTo(result.inputCost + result.outputCost, 6);
28
+ });
29
+ (0, vitest_1.it)('currency is USD', async () => {
30
+ const result = await (0, estimate_1.estimate)({ model: 'gpt-4o', messages: [] });
31
+ (0, vitest_1.expect)(result.currency).toBe('USD');
32
+ });
33
+ (0, vitest_1.it)('method is approximate', async () => {
34
+ const result = await (0, estimate_1.estimate)({ model: 'gpt-4o', messages: [] });
35
+ (0, vitest_1.expect)(result.method).toBe('approximate');
36
+ });
37
+ (0, vitest_1.it)('provider is set correctly for openai model', async () => {
38
+ const result = await (0, estimate_1.estimate)({
39
+ model: 'gpt-4o',
40
+ messages: [{ role: 'user', content: 'test' }],
41
+ });
42
+ (0, vitest_1.expect)(result.provider).toBe('openai');
43
+ });
44
+ (0, vitest_1.it)('provider is set correctly for anthropic model', async () => {
45
+ const result = await (0, estimate_1.estimate)({
46
+ model: 'claude-3-5-sonnet',
47
+ messages: [{ role: 'user', content: 'test' }],
48
+ });
49
+ (0, vitest_1.expect)(result.provider).toBe('anthropic');
50
+ });
51
+ (0, vitest_1.it)('respects maxOutputTokens when provided', async () => {
52
+ const result = await (0, estimate_1.estimate)({
53
+ model: 'gpt-4o',
54
+ messages: [{ role: 'user', content: 'test' }],
55
+ maxOutputTokens: 500,
56
+ });
57
+ (0, vitest_1.expect)(result.outputTokens).toBe(500);
58
+ });
59
+ (0, vitest_1.it)('estimates output tokens as 30% of input (capped at 1000) by default', async () => {
60
+ const result = await (0, estimate_1.estimate)({
61
+ model: 'gpt-4o',
62
+ messages: [{ role: 'user', content: 'test' }],
63
+ });
64
+ const expected = Math.min(Math.ceil(result.inputTokens * 0.3), 1000);
65
+ (0, vitest_1.expect)(result.outputTokens).toBe(expected);
66
+ });
67
+ (0, vitest_1.it)('includes systemPrompt tokens in input count', async () => {
68
+ const withSystem = await (0, estimate_1.estimate)({
69
+ model: 'gpt-4o',
70
+ messages: [{ role: 'user', content: 'Hello' }],
71
+ systemPrompt: 'You are a helpful assistant.',
72
+ });
73
+ const withoutSystem = await (0, estimate_1.estimate)({
74
+ model: 'gpt-4o',
75
+ messages: [{ role: 'user', content: 'Hello' }],
76
+ });
77
+ (0, vitest_1.expect)(withSystem.inputTokens).toBeGreaterThan(withoutSystem.inputTokens);
78
+ });
79
+ (0, vitest_1.it)('includes breakdown.systemTokens when systemPrompt is set', async () => {
80
+ const result = await (0, estimate_1.estimate)({
81
+ model: 'gpt-4o',
82
+ messages: [{ role: 'user', content: 'Hello' }],
83
+ systemPrompt: 'You are a helpful assistant.',
84
+ });
85
+ (0, vitest_1.expect)(result.breakdown?.systemTokens).toBeDefined();
86
+ (0, vitest_1.expect)(result.breakdown.systemTokens).toBeGreaterThan(0);
87
+ });
88
+ (0, vitest_1.it)('includes tool tokens when tools are provided', async () => {
89
+ const withTools = await (0, estimate_1.estimate)({
90
+ model: 'gpt-4o',
91
+ messages: [{ role: 'user', content: 'Hello' }],
92
+ tools: [{
93
+ type: 'function',
94
+ function: {
95
+ name: 'get_weather',
96
+ description: 'Get current weather for a location',
97
+ parameters: { type: 'object', properties: { location: { type: 'string' } } },
98
+ },
99
+ }],
100
+ });
101
+ const withoutTools = await (0, estimate_1.estimate)({
102
+ model: 'gpt-4o',
103
+ messages: [{ role: 'user', content: 'Hello' }],
104
+ });
105
+ (0, vitest_1.expect)(withTools.inputTokens).toBeGreaterThan(withoutTools.inputTokens);
106
+ });
107
+ (0, vitest_1.it)('works with provider/model format', async () => {
108
+ const result = await (0, estimate_1.estimate)({
109
+ model: 'openai/gpt-4o',
110
+ messages: [{ role: 'user', content: 'test' }],
111
+ });
112
+ (0, vitest_1.expect)(result.provider).toBe('openai');
113
+ (0, vitest_1.expect)(result.inputTokens).toBeGreaterThan(0);
114
+ });
115
+ (0, vitest_1.it)('more text = higher inputTokens', async () => {
116
+ const short = await (0, estimate_1.estimate)({
117
+ model: 'gpt-4o',
118
+ messages: [{ role: 'user', content: 'Hi' }],
119
+ });
120
+ const long = await (0, estimate_1.estimate)({
121
+ model: 'gpt-4o',
122
+ messages: [{ role: 'user', content: 'Hi'.repeat(100) }],
123
+ });
124
+ (0, vitest_1.expect)(long.inputTokens).toBeGreaterThan(short.inputTokens);
125
+ });
126
+ });
127
+ (0, vitest_1.describe)('estimateSync()', () => {
128
+ (0, vitest_1.it)('returns same result as estimate() for same input', async () => {
129
+ const options = {
130
+ model: 'gpt-4o',
131
+ messages: [{ role: 'user', content: 'Hello, world!' }],
132
+ };
133
+ const async_result = await (0, estimate_1.estimate)(options);
134
+ const sync_result = (0, estimate_1.estimateSync)(options);
135
+ (0, vitest_1.expect)(sync_result.inputTokens).toBe(async_result.inputTokens);
136
+ (0, vitest_1.expect)(sync_result.outputTokens).toBe(async_result.outputTokens);
137
+ (0, vitest_1.expect)(sync_result.totalCost).toBe(async_result.totalCost);
138
+ });
139
+ (0, vitest_1.it)('is synchronous (returns Estimate, not Promise)', () => {
140
+ const result = (0, estimate_1.estimateSync)({
141
+ model: 'gpt-4o',
142
+ messages: [{ role: 'user', content: 'test' }],
143
+ });
144
+ (0, vitest_1.expect)(result).not.toBeInstanceOf(Promise);
145
+ (0, vitest_1.expect)(result.inputTokens).toBeGreaterThan(0);
146
+ });
147
+ });
148
+ (0, vitest_1.describe)('estimatePrompt()', () => {
149
+ (0, vitest_1.it)('treats prompt string as a single user message', async () => {
150
+ const result = await (0, estimate_1.estimatePrompt)('Hello, world!');
151
+ (0, vitest_1.expect)(result.inputTokens).toBeGreaterThan(0);
152
+ (0, vitest_1.expect)(result.provider).toBe('openai');
153
+ });
154
+ (0, vitest_1.it)('uses the provided model option', async () => {
155
+ const result = await (0, estimate_1.estimatePrompt)('Hello', { model: 'claude-3-5-sonnet' });
156
+ (0, vitest_1.expect)(result.provider).toBe('anthropic');
157
+ });
158
+ (0, vitest_1.it)('returns positive costs', async () => {
159
+ const result = await (0, estimate_1.estimatePrompt)('Explain the theory of relativity in detail.');
160
+ (0, vitest_1.expect)(result.totalCost).toBeGreaterThan(0);
161
+ });
162
+ });
163
+ (0, vitest_1.describe)('compareModels()', () => {
164
+ const messages = [{ role: 'user', content: 'Write a haiku about the sea.' }];
165
+ (0, vitest_1.it)('returns one estimate per model', async () => {
166
+ const results = await (0, estimate_1.compareModels)(messages, ['gpt-4o', 'gpt-4o-mini']);
167
+ (0, vitest_1.expect)(results).toHaveLength(2);
168
+ });
169
+ (0, vitest_1.it)('returns results sorted by totalCost ascending', async () => {
170
+ const results = await (0, estimate_1.compareModels)(messages, ['gpt-4o', 'gpt-4o-mini', 'gpt-3.5-turbo']);
171
+ for (let i = 1; i < results.length; i++) {
172
+ (0, vitest_1.expect)(results[i].totalCost).toBeGreaterThanOrEqual(results[i - 1].totalCost);
173
+ }
174
+ });
175
+ (0, vitest_1.it)('cheaper model comes first (gpt-4o-mini cheaper than gpt-4o)', async () => {
176
+ const results = await (0, estimate_1.compareModels)(messages, ['gpt-4o', 'gpt-4o-mini']);
177
+ (0, vitest_1.expect)(results[0].model).toBe('gpt-4o-mini');
178
+ });
179
+ (0, vitest_1.it)('each result has correct provider', async () => {
180
+ const results = await (0, estimate_1.compareModels)(messages, ['gpt-4o', 'claude-3-5-sonnet']);
181
+ const openaiResult = results.find((r) => r.model === 'gpt-4o');
182
+ const anthropicResult = results.find((r) => r.model === 'claude-3-5-sonnet');
183
+ (0, vitest_1.expect)(openaiResult?.provider).toBe('openai');
184
+ (0, vitest_1.expect)(anthropicResult?.provider).toBe('anthropic');
185
+ });
186
+ });
187
+ //# sourceMappingURL=estimate.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"estimate.test.js","sourceRoot":"","sources":["../../src/__tests__/estimate.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=heuristic-counter.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heuristic-counter.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/heuristic-counter.test.ts"],"names":[],"mappings":""}