ai-sdk-cost-calculator 0.1.0 → 0.1.1

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.md CHANGED
@@ -37,8 +37,7 @@ const result = await generateText({
37
37
  });
38
38
 
39
39
  const cost = calculateCost({
40
- provider: "openai",
41
- modelId: "gpt-4o",
40
+ model: "gpt-4o",
42
41
  usage: result.usage,
43
42
  });
44
43
 
@@ -56,16 +55,17 @@ Calculate the cost for a single API request.
56
55
  import { calculateCost } from "ai-sdk-cost-calculator";
57
56
 
58
57
  const cost = calculateCost({
59
- provider: "anthropic",
60
- modelId: "claude-sonnet-4-5",
58
+ model: "claude-sonnet-4-5",
61
59
  usage: {
62
60
  inputTokens: 1000,
63
61
  outputTokens: 500,
64
62
  inputTokenDetails: {
63
+ noCacheTokens: 700,
65
64
  cacheReadTokens: 200,
66
65
  cacheWriteTokens: 100,
67
66
  },
68
67
  outputTokenDetails: {
68
+ textTokens: 500,
69
69
  reasoningTokens: 0,
70
70
  },
71
71
  },
@@ -86,25 +86,24 @@ console.log(cost);
86
86
 
87
87
  #### Options
88
88
 
89
- | Property | Type | Required | Description |
90
- |----------|------|----------|-------------|
91
- | `provider` | `string` | Yes | Provider name: `"openai"`, `"anthropic"`, `"google"`, `"xai"`, `"deepseek"` |
92
- | `modelId` | `string` | Yes | Model identifier (e.g., `"gpt-4o"`, `"claude-sonnet-4-5"`) |
93
- | `usage` | `LanguageModelUsage` | Yes | Token usage from AI SDK |
94
- | `customPricing` | `ModelPricing` | No | Override default pricing |
89
+ | Property | Type | Required | Description |
90
+ | --------------- | -------------------- | -------- | ---------------------------------------------------------- |
91
+ | `model` | `string` | Yes | Model identifier (e.g., `"gpt-4o"`, `"claude-sonnet-4-5"`) |
92
+ | `usage` | `LanguageModelUsage` | Yes | Token usage from AI SDK |
93
+ | `customPricing` | `ModelPricing` | No | Override default pricing |
95
94
 
96
95
  #### Return Value: `CostBreakdown`
97
96
 
98
- | Property | Type | Description |
99
- |----------|------|-------------|
100
- | `inputCost` | `number` | Cost for input tokens (excluding cache) |
101
- | `outputCost` | `number` | Cost for output tokens (excluding reasoning) |
102
- | `cacheReadCost` | `number` | Cost for cached input tokens |
103
- | `cacheWriteCost` | `number` | Cost for writing to cache |
104
- | `reasoningCost` | `number` | Cost for reasoning tokens |
105
- | `totalCost` | `number` | Sum of all costs |
106
- | `currency` | `"USD"` | Always USD |
107
- | `isLongContext` | `boolean` | Whether long context pricing was applied |
97
+ | Property | Type | Description |
98
+ | ---------------- | --------- | -------------------------------------------- |
99
+ | `inputCost` | `number` | Cost for input tokens (excluding cache) |
100
+ | `outputCost` | `number` | Cost for output tokens (excluding reasoning) |
101
+ | `cacheReadCost` | `number` | Cost for cached input tokens |
102
+ | `cacheWriteCost` | `number` | Cost for writing to cache |
103
+ | `reasoningCost` | `number` | Cost for reasoning tokens |
104
+ | `totalCost` | `number` | Sum of all costs |
105
+ | `currency` | `"USD"` | Always USD |
106
+ | `isLongContext` | `boolean` | Whether long context pricing was applied |
108
107
 
109
108
  ### `formatCost(cost, decimals?)`
110
109
 
@@ -113,8 +112,8 @@ Format a cost value as a currency string.
113
112
  ```typescript
114
113
  import { formatCost } from "ai-sdk-cost-calculator";
115
114
 
116
- formatCost(0.0015); // "$0.001500"
117
- formatCost(0.0015, 4); // "$0.0015"
115
+ formatCost(0.0015); // "$0.001500"
116
+ formatCost(0.0015, 4); // "$0.0015"
118
117
  ```
119
118
 
120
119
  ### `formatCostBreakdown(breakdown, decimals?)`
@@ -140,8 +139,7 @@ Track cumulative costs across multiple requests.
140
139
  import { createCostTracker } from "ai-sdk-cost-calculator";
141
140
 
142
141
  const tracker = createCostTracker({
143
- provider: "openai",
144
- modelId: "gpt-4o",
142
+ model: "gpt-4o",
145
143
  });
146
144
 
147
145
  // Add usage from multiple requests
@@ -171,8 +169,7 @@ const stream = await streamText({
171
169
  });
172
170
 
173
171
  const cost = await calculateStreamCost(stream, {
174
- provider: "openai",
175
- modelId: "gpt-4o",
172
+ model: "gpt-4o",
176
173
  onCost: (cost, usage) => {
177
174
  console.log(`Stream completed: ${formatCost(cost.totalCost)}`);
178
175
  },
@@ -220,6 +217,7 @@ const models = getAllSupportedModels();
220
217
  ## Supported Models
221
218
 
222
219
  ### OpenAI (23 models)
220
+
223
221
  - GPT-4o, GPT-4o-mini
224
222
  - GPT-4.1, GPT-4.1-mini, GPT-4.1-nano
225
223
  - GPT-4 Turbo, GPT-4, GPT-4-32k
@@ -229,6 +227,7 @@ const models = getAllSupportedModels();
229
227
  - o4-mini
230
228
 
231
229
  ### Anthropic (23 models)
230
+
232
231
  - Claude Opus 4.5, Sonnet 4.5, Haiku 4.5
233
232
  - Claude Opus 4.1, Sonnet 4, Opus 4
234
233
  - Claude 3.5 Sonnet, 3.5 Haiku
@@ -236,12 +235,14 @@ const models = getAllSupportedModels();
236
235
  - All dated variants (e.g., `claude-3-5-sonnet-20241022`)
237
236
 
238
237
  ### Google Gemini (17 models)
238
+
239
239
  - Gemini 3 Pro, 3 Flash
240
240
  - Gemini 2.5 Pro, 2.5 Flash, 2.5 Flash-Lite
241
241
  - Gemini 2.0 Flash, 2.0 Flash-Lite
242
242
  - Gemini 1.5 Pro, 1.5 Flash, 1.5 Flash-8B
243
243
 
244
244
  ### xAI Grok (12 models)
245
+
245
246
  - Grok 4, Grok 4-0709
246
247
  - Grok 4 Fast (reasoning/non-reasoning)
247
248
  - Grok 4.1 Fast (reasoning/non-reasoning)
@@ -250,6 +251,7 @@ const models = getAllSupportedModels();
250
251
  - Grok 2, Grok 2 Vision
251
252
 
252
253
  ### DeepSeek (10 models)
254
+
253
255
  - DeepSeek Chat (V3, V3.2)
254
256
  - DeepSeek Reasoner (R1)
255
257
  - DeepSeek R1 Distill variants
@@ -259,12 +261,12 @@ const models = getAllSupportedModels();
259
261
 
260
262
  Some models have tiered pricing based on input token count:
261
263
 
262
- | Model | Threshold | Standard | Long Context |
263
- |-------|-----------|----------|--------------|
264
- | Claude Sonnet 4.5 | 200K | $3/$15 | $6/$22.50 |
265
- | Gemini 2.5 Pro | 200K | $1.25/$10 | $2.50/$15 |
266
- | Gemini 1.5 Pro | 128K | $1.25/$5 | $2.50/$10 |
267
- | Grok 4 Fast | 128K | $0.20/$0.50 | $0.40/$1.00 |
264
+ | Model | Threshold | Standard | Long Context |
265
+ | ----------------- | --------- | ----------- | ------------ |
266
+ | Claude Sonnet 4.5 | 200K | $3/$15 | $6/$22.50 |
267
+ | Gemini 2.5 Pro | 200K | $1.25/$10 | $2.50/$15 |
268
+ | Gemini 1.5 Pro | 128K | $1.25/$5 | $2.50/$10 |
269
+ | Grok 4 Fast | 128K | $0.20/$0.50 | $0.40/$1.00 |
268
270
 
269
271
  The calculator automatically applies the correct pricing tier based on input token count.
270
272
 
@@ -274,11 +276,10 @@ Override default pricing for any model:
274
276
 
275
277
  ```typescript
276
278
  const cost = calculateCost({
277
- provider: "openai",
278
- modelId: "gpt-4o",
279
+ model: "gpt-4o",
279
280
  usage: result.usage,
280
281
  customPricing: {
281
- inputPer1MTokens: 2.0, // Custom rate
282
+ inputPer1MTokens: 2.0, // Custom rate
282
283
  outputPer1MTokens: 8.0,
283
284
  cacheReadPer1MTokens: 1.0,
284
285
  },
@@ -11,8 +11,7 @@ export interface CostBreakdown {
11
11
  isLongContext: boolean;
12
12
  }
13
13
  export interface CalculateCostOptions {
14
- provider: string;
15
- modelId: string;
14
+ model: string;
16
15
  usage: LanguageModelUsage;
17
16
  customPricing?: ModelPricing;
18
17
  }
@@ -1 +1 @@
1
- {"version":3,"file":"calculator.d.ts","sourceRoot":"","sources":["../src/calculator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,IAAI,CAAC;AACxC,OAAO,EAAmB,KAAK,YAAY,EAAE,MAAM,UAAU,CAAC;AAE9D,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,KAAK,CAAC;IAChB,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,kBAAkB,CAAC;IAC1B,aAAa,CAAC,EAAE,YAAY,CAAC;CAC9B;AAqDD,wBAAgB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,aAAa,CAwD1E;AAMD,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAU,GAAG,MAAM,CAErE;AAED,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,aAAa,EACrB,QAAQ,GAAE,MAAU,GACnB,MAAM,CAwBR"}
1
+ {"version":3,"file":"calculator.d.ts","sourceRoot":"","sources":["../src/calculator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,IAAI,CAAC;AACxC,OAAO,EAA4B,KAAK,YAAY,EAAE,MAAM,UAAU,CAAC;AAIvE,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,KAAK,CAAC;IAChB,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,kBAAkB,CAAC;IAC1B,aAAa,CAAC,EAAE,YAAY,CAAC;CAC9B;AAkGD,wBAAgB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,aAAa,CAyD1E;AAMD,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAU,GAAG,MAAM,CAErE;AAED,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,aAAa,EACrB,QAAQ,GAAE,MAAU,GACnB,MAAM,CAwBR"}
@@ -1,4 +1,5 @@
1
- import { getModelPricing } from "./prices";
1
+ import { getModelPricingByModelId } from "./prices";
2
+ const TOKENS_PER_MILLION = 1_000_000;
2
3
  function getEffectivePricing(pricing, inputTokens) {
3
4
  const threshold = pricing.longContextThreshold ?? 200000;
4
5
  const isLongContext = inputTokens > threshold &&
@@ -28,32 +29,48 @@ function getEffectivePricing(pricing, inputTokens) {
28
29
  isLongContext: false,
29
30
  };
30
31
  }
32
+ function getUsageTokenDetails(usage) {
33
+ const inputDetails = usage.inputTokenDetails;
34
+ const outputDetails = usage.outputTokenDetails;
35
+ let noCacheTokens = inputDetails?.noCacheTokens ?? 0;
36
+ let cacheReadTokens = inputDetails?.cacheReadTokens ?? 0;
37
+ let cacheWriteTokens = inputDetails?.cacheWriteTokens ?? 0;
38
+ let textTokens = outputDetails?.textTokens ?? 0;
39
+ let reasoningTokens = outputDetails?.reasoningTokens ?? 0;
40
+ if (!inputDetails && usage.inputTokens !== undefined) {
41
+ noCacheTokens = usage.inputTokens;
42
+ }
43
+ if (!outputDetails && usage.outputTokens !== undefined) {
44
+ textTokens = usage.outputTokens;
45
+ }
46
+ const totalInputTokens = usage.inputTokens ?? noCacheTokens + cacheReadTokens + cacheWriteTokens;
47
+ return {
48
+ noCacheTokens,
49
+ cacheReadTokens,
50
+ cacheWriteTokens,
51
+ textTokens,
52
+ reasoningTokens,
53
+ totalInputTokens,
54
+ };
55
+ }
56
+ function costFromTokens(tokens, per1MTokens) {
57
+ return (tokens / TOKENS_PER_MILLION) * per1MTokens;
58
+ }
31
59
  export function calculateCost(options) {
32
- const { provider, modelId, usage, customPricing } = options;
33
- const pricing = customPricing ?? getModelPricing(provider, modelId);
60
+ const { model, usage, customPricing } = options;
61
+ const pricing = customPricing ?? getModelPricingByModelId(model);
34
62
  if (!pricing) {
35
- throw new Error(`Unknown model: ${provider}/${modelId}. Use customPricing option or add the model to prices.ts`);
63
+ throw new Error(`Unknown model: ${model}. Use customPricing option or add the model to prices.ts`);
36
64
  }
37
- // Extract token counts from details
38
- const noCacheTokens = usage.inputTokenDetails?.noCacheTokens ?? 0;
39
- const cacheReadTokens = usage.inputTokenDetails?.cacheReadTokens ?? 0;
40
- const cacheWriteTokens = usage.inputTokenDetails?.cacheWriteTokens ?? 0;
41
- const textTokens = usage.outputTokenDetails?.textTokens ?? 0;
42
- const reasoningTokens = usage.outputTokenDetails?.reasoningTokens ?? 0;
43
- // Total input tokens for long context threshold check
44
- const totalInputTokens = usage.inputTokens ?? (noCacheTokens + cacheReadTokens);
65
+ const usageDetails = getUsageTokenDetails(usage);
45
66
  // Get effective pricing based on input token count
46
- const effectivePricing = getEffectivePricing(pricing, totalInputTokens);
47
- const inputCost = (noCacheTokens / 1_000_000) * effectivePricing.inputPer1MTokens;
48
- const outputCost = (textTokens / 1_000_000) * effectivePricing.outputPer1MTokens;
49
- const cacheReadCost = (cacheReadTokens / 1_000_000) * effectivePricing.cacheReadPer1MTokens;
50
- const cacheWriteCost = (cacheWriteTokens / 1_000_000) * effectivePricing.cacheWritePer1MTokens;
51
- const reasoningCost = (reasoningTokens / 1_000_000) * effectivePricing.reasoningPer1MTokens;
52
- const totalCost = inputCost +
53
- outputCost +
54
- cacheReadCost +
55
- cacheWriteCost +
56
- reasoningCost;
67
+ const effectivePricing = getEffectivePricing(pricing, usageDetails.totalInputTokens);
68
+ const inputCost = costFromTokens(usageDetails.noCacheTokens, effectivePricing.inputPer1MTokens);
69
+ const outputCost = costFromTokens(usageDetails.textTokens, effectivePricing.outputPer1MTokens);
70
+ const cacheReadCost = costFromTokens(usageDetails.cacheReadTokens, effectivePricing.cacheReadPer1MTokens);
71
+ const cacheWriteCost = costFromTokens(usageDetails.cacheWriteTokens, effectivePricing.cacheWritePer1MTokens);
72
+ const reasoningCost = costFromTokens(usageDetails.reasoningTokens, effectivePricing.reasoningPer1MTokens);
73
+ const totalCost = inputCost + outputCost + cacheReadCost + cacheWriteCost + reasoningCost;
57
74
  return {
58
75
  inputCost: roundToMicroDollars(inputCost),
59
76
  outputCost: roundToMicroDollars(outputCost),
package/dist/index.d.mts CHANGED
@@ -47,8 +47,7 @@ interface CostBreakdown {
47
47
  isLongContext: boolean;
48
48
  }
49
49
  interface CalculateCostOptions {
50
- provider: string;
51
- modelId: string;
50
+ model: string;
52
51
  usage: LanguageModelUsage;
53
52
  customPricing?: ModelPricing;
54
53
  }
@@ -64,14 +63,12 @@ interface CostTracker {
64
63
  reset(): void;
65
64
  }
66
65
  interface CreateCostTrackerOptions {
67
- provider: string;
68
- modelId: string;
66
+ model: string;
69
67
  customPricing?: ModelPricing;
70
68
  }
71
69
  declare function createCostTracker(options: CreateCostTrackerOptions): CostTracker;
72
70
  interface StreamCostOptions {
73
- provider: string;
74
- modelId: string;
71
+ model: string;
75
72
  customPricing?: ModelPricing;
76
73
  onCost?: (cost: CostBreakdown, usage: LanguageModelUsage) => void;
77
74
  }
package/dist/index.d.ts CHANGED
@@ -47,8 +47,7 @@ interface CostBreakdown {
47
47
  isLongContext: boolean;
48
48
  }
49
49
  interface CalculateCostOptions {
50
- provider: string;
51
- modelId: string;
50
+ model: string;
52
51
  usage: LanguageModelUsage;
53
52
  customPricing?: ModelPricing;
54
53
  }
@@ -64,14 +63,12 @@ interface CostTracker {
64
63
  reset(): void;
65
64
  }
66
65
  interface CreateCostTrackerOptions {
67
- provider: string;
68
- modelId: string;
66
+ model: string;
69
67
  customPricing?: ModelPricing;
70
68
  }
71
69
  declare function createCostTracker(options: CreateCostTrackerOptions): CostTracker;
72
70
  interface StreamCostOptions {
73
- provider: string;
74
- modelId: string;
71
+ model: string;
75
72
  customPricing?: ModelPricing;
76
73
  onCost?: (cost: CostBreakdown, usage: LanguageModelUsage) => void;
77
74
  }
package/dist/index.js CHANGED
@@ -629,6 +629,7 @@ function getAllSupportedModels() {
629
629
  }
630
630
 
631
631
  // src/calculator.ts
632
+ var TOKENS_PER_MILLION = 1e6;
632
633
  function getEffectivePricing(pricing, inputTokens) {
633
634
  const threshold = pricing.longContextThreshold ?? 2e5;
634
635
  const isLongContext = inputTokens > threshold && pricing.longContextInputPer1MTokens !== void 0;
@@ -651,26 +652,66 @@ function getEffectivePricing(pricing, inputTokens) {
651
652
  isLongContext: false
652
653
  };
653
654
  }
655
+ function getUsageTokenDetails(usage) {
656
+ const inputDetails = usage.inputTokenDetails;
657
+ const outputDetails = usage.outputTokenDetails;
658
+ let noCacheTokens = inputDetails?.noCacheTokens ?? 0;
659
+ let cacheReadTokens = inputDetails?.cacheReadTokens ?? 0;
660
+ let cacheWriteTokens = inputDetails?.cacheWriteTokens ?? 0;
661
+ let textTokens = outputDetails?.textTokens ?? 0;
662
+ let reasoningTokens = outputDetails?.reasoningTokens ?? 0;
663
+ if (!inputDetails && usage.inputTokens !== void 0) {
664
+ noCacheTokens = usage.inputTokens;
665
+ }
666
+ if (!outputDetails && usage.outputTokens !== void 0) {
667
+ textTokens = usage.outputTokens;
668
+ }
669
+ const totalInputTokens = usage.inputTokens ?? noCacheTokens + cacheReadTokens + cacheWriteTokens;
670
+ return {
671
+ noCacheTokens,
672
+ cacheReadTokens,
673
+ cacheWriteTokens,
674
+ textTokens,
675
+ reasoningTokens,
676
+ totalInputTokens
677
+ };
678
+ }
679
+ function costFromTokens(tokens, per1MTokens) {
680
+ return tokens / TOKENS_PER_MILLION * per1MTokens;
681
+ }
654
682
  function calculateCost(options) {
655
- const { provider, modelId, usage, customPricing } = options;
656
- const pricing = customPricing ?? getModelPricing(provider, modelId);
683
+ const { model, usage, customPricing } = options;
684
+ const pricing = customPricing ?? getModelPricingByModelId(model);
657
685
  if (!pricing) {
658
686
  throw new Error(
659
- `Unknown model: ${provider}/${modelId}. Use customPricing option or add the model to prices.ts`
687
+ `Unknown model: ${model}. Use customPricing option or add the model to prices.ts`
660
688
  );
661
689
  }
662
- const noCacheTokens = usage.inputTokenDetails?.noCacheTokens ?? 0;
663
- const cacheReadTokens = usage.inputTokenDetails?.cacheReadTokens ?? 0;
664
- const cacheWriteTokens = usage.inputTokenDetails?.cacheWriteTokens ?? 0;
665
- const textTokens = usage.outputTokenDetails?.textTokens ?? 0;
666
- const reasoningTokens = usage.outputTokenDetails?.reasoningTokens ?? 0;
667
- const totalInputTokens = usage.inputTokens ?? noCacheTokens + cacheReadTokens;
668
- const effectivePricing = getEffectivePricing(pricing, totalInputTokens);
669
- const inputCost = noCacheTokens / 1e6 * effectivePricing.inputPer1MTokens;
670
- const outputCost = textTokens / 1e6 * effectivePricing.outputPer1MTokens;
671
- const cacheReadCost = cacheReadTokens / 1e6 * effectivePricing.cacheReadPer1MTokens;
672
- const cacheWriteCost = cacheWriteTokens / 1e6 * effectivePricing.cacheWritePer1MTokens;
673
- const reasoningCost = reasoningTokens / 1e6 * effectivePricing.reasoningPer1MTokens;
690
+ const usageDetails = getUsageTokenDetails(usage);
691
+ const effectivePricing = getEffectivePricing(
692
+ pricing,
693
+ usageDetails.totalInputTokens
694
+ );
695
+ const inputCost = costFromTokens(
696
+ usageDetails.noCacheTokens,
697
+ effectivePricing.inputPer1MTokens
698
+ );
699
+ const outputCost = costFromTokens(
700
+ usageDetails.textTokens,
701
+ effectivePricing.outputPer1MTokens
702
+ );
703
+ const cacheReadCost = costFromTokens(
704
+ usageDetails.cacheReadTokens,
705
+ effectivePricing.cacheReadPer1MTokens
706
+ );
707
+ const cacheWriteCost = costFromTokens(
708
+ usageDetails.cacheWriteTokens,
709
+ effectivePricing.cacheWritePer1MTokens
710
+ );
711
+ const reasoningCost = costFromTokens(
712
+ usageDetails.reasoningTokens,
713
+ effectivePricing.reasoningPer1MTokens
714
+ );
674
715
  const totalCost = inputCost + outputCost + cacheReadCost + cacheWriteCost + reasoningCost;
675
716
  return {
676
717
  inputCost: roundToMicroDollars(inputCost),
@@ -715,7 +756,7 @@ function formatCostBreakdown(result, decimals = 6) {
715
756
 
716
757
  // src/streaming.ts
717
758
  function createCostTracker(options) {
718
- const { provider, modelId, customPricing } = options;
759
+ const { model, customPricing } = options;
719
760
  let totalNoCacheTokens = 0;
720
761
  let totalCacheReadTokens = 0;
721
762
  let totalCacheWriteTokens = 0;
@@ -724,15 +765,25 @@ function createCostTracker(options) {
724
765
  let requestCount = 0;
725
766
  return {
726
767
  addUsage(usage) {
727
- totalNoCacheTokens += usage.inputTokenDetails?.noCacheTokens ?? 0;
728
- totalCacheReadTokens += usage.inputTokenDetails?.cacheReadTokens ?? 0;
729
- totalCacheWriteTokens += usage.inputTokenDetails?.cacheWriteTokens ?? 0;
730
- totalTextTokens += usage.outputTokenDetails?.textTokens ?? 0;
731
- totalReasoningTokens += usage.outputTokenDetails?.reasoningTokens ?? 0;
768
+ const inputDetails = usage.inputTokenDetails;
769
+ if (inputDetails) {
770
+ totalNoCacheTokens += inputDetails.noCacheTokens ?? 0;
771
+ totalCacheReadTokens += inputDetails.cacheReadTokens ?? 0;
772
+ totalCacheWriteTokens += inputDetails.cacheWriteTokens ?? 0;
773
+ } else if (usage.inputTokens !== void 0) {
774
+ totalNoCacheTokens += usage.inputTokens;
775
+ }
776
+ const outputDetails = usage.outputTokenDetails;
777
+ if (outputDetails) {
778
+ totalTextTokens += outputDetails.textTokens ?? 0;
779
+ totalReasoningTokens += outputDetails.reasoningTokens ?? 0;
780
+ } else if (usage.outputTokens !== void 0) {
781
+ totalTextTokens += usage.outputTokens;
782
+ }
732
783
  requestCount++;
733
784
  },
734
785
  getTotalUsage() {
735
- const inputTokens = totalNoCacheTokens + totalCacheReadTokens;
786
+ const inputTokens = totalNoCacheTokens + totalCacheReadTokens + totalCacheWriteTokens;
736
787
  const outputTokens = totalTextTokens + totalReasoningTokens;
737
788
  return {
738
789
  inputTokens,
@@ -751,8 +802,7 @@ function createCostTracker(options) {
751
802
  },
752
803
  getTotalCost() {
753
804
  return calculateCost({
754
- provider,
755
- modelId,
805
+ model,
756
806
  usage: this.getTotalUsage(),
757
807
  customPricing
758
808
  });
@@ -774,8 +824,7 @@ async function calculateStreamCost(streamResult, options) {
774
824
  const result = await streamResult;
775
825
  const usage = result.usage;
776
826
  const cost = calculateCost({
777
- provider: options.provider,
778
- modelId: options.modelId,
827
+ model: options.model,
779
828
  usage,
780
829
  customPricing: options.customPricing
781
830
  });
package/dist/index.mjs CHANGED
@@ -589,6 +589,7 @@ function getAllSupportedModels() {
589
589
  }
590
590
 
591
591
  // src/calculator.ts
592
+ var TOKENS_PER_MILLION = 1e6;
592
593
  function getEffectivePricing(pricing, inputTokens) {
593
594
  const threshold = pricing.longContextThreshold ?? 2e5;
594
595
  const isLongContext = inputTokens > threshold && pricing.longContextInputPer1MTokens !== void 0;
@@ -611,26 +612,66 @@ function getEffectivePricing(pricing, inputTokens) {
611
612
  isLongContext: false
612
613
  };
613
614
  }
615
+ function getUsageTokenDetails(usage) {
616
+ const inputDetails = usage.inputTokenDetails;
617
+ const outputDetails = usage.outputTokenDetails;
618
+ let noCacheTokens = inputDetails?.noCacheTokens ?? 0;
619
+ let cacheReadTokens = inputDetails?.cacheReadTokens ?? 0;
620
+ let cacheWriteTokens = inputDetails?.cacheWriteTokens ?? 0;
621
+ let textTokens = outputDetails?.textTokens ?? 0;
622
+ let reasoningTokens = outputDetails?.reasoningTokens ?? 0;
623
+ if (!inputDetails && usage.inputTokens !== void 0) {
624
+ noCacheTokens = usage.inputTokens;
625
+ }
626
+ if (!outputDetails && usage.outputTokens !== void 0) {
627
+ textTokens = usage.outputTokens;
628
+ }
629
+ const totalInputTokens = usage.inputTokens ?? noCacheTokens + cacheReadTokens + cacheWriteTokens;
630
+ return {
631
+ noCacheTokens,
632
+ cacheReadTokens,
633
+ cacheWriteTokens,
634
+ textTokens,
635
+ reasoningTokens,
636
+ totalInputTokens
637
+ };
638
+ }
639
+ function costFromTokens(tokens, per1MTokens) {
640
+ return tokens / TOKENS_PER_MILLION * per1MTokens;
641
+ }
614
642
  function calculateCost(options) {
615
- const { provider, modelId, usage, customPricing } = options;
616
- const pricing = customPricing ?? getModelPricing(provider, modelId);
643
+ const { model, usage, customPricing } = options;
644
+ const pricing = customPricing ?? getModelPricingByModelId(model);
617
645
  if (!pricing) {
618
646
  throw new Error(
619
- `Unknown model: ${provider}/${modelId}. Use customPricing option or add the model to prices.ts`
647
+ `Unknown model: ${model}. Use customPricing option or add the model to prices.ts`
620
648
  );
621
649
  }
622
- const noCacheTokens = usage.inputTokenDetails?.noCacheTokens ?? 0;
623
- const cacheReadTokens = usage.inputTokenDetails?.cacheReadTokens ?? 0;
624
- const cacheWriteTokens = usage.inputTokenDetails?.cacheWriteTokens ?? 0;
625
- const textTokens = usage.outputTokenDetails?.textTokens ?? 0;
626
- const reasoningTokens = usage.outputTokenDetails?.reasoningTokens ?? 0;
627
- const totalInputTokens = usage.inputTokens ?? noCacheTokens + cacheReadTokens;
628
- const effectivePricing = getEffectivePricing(pricing, totalInputTokens);
629
- const inputCost = noCacheTokens / 1e6 * effectivePricing.inputPer1MTokens;
630
- const outputCost = textTokens / 1e6 * effectivePricing.outputPer1MTokens;
631
- const cacheReadCost = cacheReadTokens / 1e6 * effectivePricing.cacheReadPer1MTokens;
632
- const cacheWriteCost = cacheWriteTokens / 1e6 * effectivePricing.cacheWritePer1MTokens;
633
- const reasoningCost = reasoningTokens / 1e6 * effectivePricing.reasoningPer1MTokens;
650
+ const usageDetails = getUsageTokenDetails(usage);
651
+ const effectivePricing = getEffectivePricing(
652
+ pricing,
653
+ usageDetails.totalInputTokens
654
+ );
655
+ const inputCost = costFromTokens(
656
+ usageDetails.noCacheTokens,
657
+ effectivePricing.inputPer1MTokens
658
+ );
659
+ const outputCost = costFromTokens(
660
+ usageDetails.textTokens,
661
+ effectivePricing.outputPer1MTokens
662
+ );
663
+ const cacheReadCost = costFromTokens(
664
+ usageDetails.cacheReadTokens,
665
+ effectivePricing.cacheReadPer1MTokens
666
+ );
667
+ const cacheWriteCost = costFromTokens(
668
+ usageDetails.cacheWriteTokens,
669
+ effectivePricing.cacheWritePer1MTokens
670
+ );
671
+ const reasoningCost = costFromTokens(
672
+ usageDetails.reasoningTokens,
673
+ effectivePricing.reasoningPer1MTokens
674
+ );
634
675
  const totalCost = inputCost + outputCost + cacheReadCost + cacheWriteCost + reasoningCost;
635
676
  return {
636
677
  inputCost: roundToMicroDollars(inputCost),
@@ -675,7 +716,7 @@ function formatCostBreakdown(result, decimals = 6) {
675
716
 
676
717
  // src/streaming.ts
677
718
  function createCostTracker(options) {
678
- const { provider, modelId, customPricing } = options;
719
+ const { model, customPricing } = options;
679
720
  let totalNoCacheTokens = 0;
680
721
  let totalCacheReadTokens = 0;
681
722
  let totalCacheWriteTokens = 0;
@@ -684,15 +725,25 @@ function createCostTracker(options) {
684
725
  let requestCount = 0;
685
726
  return {
686
727
  addUsage(usage) {
687
- totalNoCacheTokens += usage.inputTokenDetails?.noCacheTokens ?? 0;
688
- totalCacheReadTokens += usage.inputTokenDetails?.cacheReadTokens ?? 0;
689
- totalCacheWriteTokens += usage.inputTokenDetails?.cacheWriteTokens ?? 0;
690
- totalTextTokens += usage.outputTokenDetails?.textTokens ?? 0;
691
- totalReasoningTokens += usage.outputTokenDetails?.reasoningTokens ?? 0;
728
+ const inputDetails = usage.inputTokenDetails;
729
+ if (inputDetails) {
730
+ totalNoCacheTokens += inputDetails.noCacheTokens ?? 0;
731
+ totalCacheReadTokens += inputDetails.cacheReadTokens ?? 0;
732
+ totalCacheWriteTokens += inputDetails.cacheWriteTokens ?? 0;
733
+ } else if (usage.inputTokens !== void 0) {
734
+ totalNoCacheTokens += usage.inputTokens;
735
+ }
736
+ const outputDetails = usage.outputTokenDetails;
737
+ if (outputDetails) {
738
+ totalTextTokens += outputDetails.textTokens ?? 0;
739
+ totalReasoningTokens += outputDetails.reasoningTokens ?? 0;
740
+ } else if (usage.outputTokens !== void 0) {
741
+ totalTextTokens += usage.outputTokens;
742
+ }
692
743
  requestCount++;
693
744
  },
694
745
  getTotalUsage() {
695
- const inputTokens = totalNoCacheTokens + totalCacheReadTokens;
746
+ const inputTokens = totalNoCacheTokens + totalCacheReadTokens + totalCacheWriteTokens;
696
747
  const outputTokens = totalTextTokens + totalReasoningTokens;
697
748
  return {
698
749
  inputTokens,
@@ -711,8 +762,7 @@ function createCostTracker(options) {
711
762
  },
712
763
  getTotalCost() {
713
764
  return calculateCost({
714
- provider,
715
- modelId,
765
+ model,
716
766
  usage: this.getTotalUsage(),
717
767
  customPricing
718
768
  });
@@ -734,8 +784,7 @@ async function calculateStreamCost(streamResult, options) {
734
784
  const result = await streamResult;
735
785
  const usage = result.usage;
736
786
  const cost = calculateCost({
737
- provider: options.provider,
738
- modelId: options.modelId,
787
+ model: options.model,
739
788
  usage,
740
789
  customPricing: options.customPricing
741
790
  });
@@ -1,17 +1,2 @@
1
- export type { ModelPricing, ProviderPricing } from "./types";
2
- export { openaiPricing } from "./openai";
3
- export { anthropicPricing } from "./anthropic";
4
- export { googlePricing } from "./google";
5
- export { xaiPricing } from "./xai";
6
- export { deepseekPricing } from "./deepseek";
7
- import type { ProviderPricing } from "./types";
8
- export declare const allPricing: ProviderPricing;
9
- export declare const pricingByProvider: {
10
- readonly openai: ProviderPricing;
11
- readonly anthropic: ProviderPricing;
12
- readonly google: ProviderPricing;
13
- readonly xai: ProviderPricing;
14
- readonly deepseek: ProviderPricing;
15
- };
16
- export type Provider = keyof typeof pricingByProvider;
1
+ export * from "../prices";
17
2
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/prices/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE7D,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AACnC,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAO7C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAG/C,eAAO,MAAM,UAAU,EAAE,eAMxB,CAAC;AAGF,eAAO,MAAM,iBAAiB;;;;;;CAMpB,CAAC;AAEX,MAAM,MAAM,QAAQ,GAAG,MAAM,OAAO,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/prices/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC"}
@@ -1,26 +1 @@
1
- export { openaiPricing } from "./openai";
2
- export { anthropicPricing } from "./anthropic";
3
- export { googlePricing } from "./google";
4
- export { xaiPricing } from "./xai";
5
- export { deepseekPricing } from "./deepseek";
6
- import { openaiPricing } from "./openai";
7
- import { anthropicPricing } from "./anthropic";
8
- import { googlePricing } from "./google";
9
- import { xaiPricing } from "./xai";
10
- import { deepseekPricing } from "./deepseek";
11
- // Combined pricing for all providers
12
- export const allPricing = {
13
- ...openaiPricing,
14
- ...anthropicPricing,
15
- ...googlePricing,
16
- ...xaiPricing,
17
- ...deepseekPricing,
18
- };
19
- // Provider name to pricing map
20
- export const pricingByProvider = {
21
- openai: openaiPricing,
22
- anthropic: anthropicPricing,
23
- google: googlePricing,
24
- xai: xaiPricing,
25
- deepseek: deepseekPricing,
26
- };
1
+ export * from "../prices";
@@ -9,14 +9,12 @@ export interface CostTracker {
9
9
  reset(): void;
10
10
  }
11
11
  export interface CreateCostTrackerOptions {
12
- provider: string;
13
- modelId: string;
12
+ model: string;
14
13
  customPricing?: ModelPricing;
15
14
  }
16
15
  export declare function createCostTracker(options: CreateCostTrackerOptions): CostTracker;
17
16
  export interface StreamCostOptions {
18
- provider: string;
19
- modelId: string;
17
+ model: string;
20
18
  customPricing?: ModelPricing;
21
19
  onCost?: (cost: CostBreakdown, usage: LanguageModelUsage) => void;
22
20
  }
@@ -1 +1 @@
1
- {"version":3,"file":"streaming.d.ts","sourceRoot":"","sources":["../src/streaming.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,IAAI,CAAC;AACxC,OAAO,EAAiB,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7C,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAC1C,aAAa,IAAI,kBAAkB,CAAC;IACpC,YAAY,IAAI,aAAa,CAAC;IAC9B,eAAe,IAAI,MAAM,CAAC;IAC1B,KAAK,IAAI,IAAI,CAAC;CACf;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,YAAY,CAAC;CAC9B;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,WAAW,CAsEhF;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,YAAY,CAAC;IAC7B,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC;CACnE;AAED,wBAAsB,mBAAmB,CAAC,CAAC,SAAS;IAAE,KAAK,EAAE,kBAAkB,CAAA;CAAE,EAC/E,YAAY,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EAC5B,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,aAAa,GAAG;IAAE,KAAK,EAAE,kBAAkB,CAAA;CAAE,CAAC,CAmBxD"}
1
+ {"version":3,"file":"streaming.d.ts","sourceRoot":"","sources":["../src/streaming.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,IAAI,CAAC;AACxC,OAAO,EAAiB,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7C,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAC1C,aAAa,IAAI,kBAAkB,CAAC;IACpC,YAAY,IAAI,aAAa,CAAC;IAC9B,eAAe,IAAI,MAAM,CAAC;IAC1B,KAAK,IAAI,IAAI,CAAC;CACf;AAED,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,YAAY,CAAC;CAC9B;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,WAAW,CA2EhF;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,YAAY,CAAC;IAC7B,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC;CACnE;AAED,wBAAsB,mBAAmB,CAAC,CAAC,SAAS;IAAE,KAAK,EAAE,kBAAkB,CAAA;CAAE,EAC/E,YAAY,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EAC5B,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,aAAa,GAAG;IAAE,KAAK,EAAE,kBAAkB,CAAA;CAAE,CAAC,CAkBxD"}
package/dist/streaming.js CHANGED
@@ -1,51 +1,55 @@
1
1
  import { calculateCost } from "./calculator";
2
2
  export function createCostTracker(options) {
3
- const { provider, modelId, customPricing } = options;
4
- let totalInputTokens = 0;
5
- let totalOutputTokens = 0;
3
+ const { model, customPricing } = options;
4
+ // Track detail fields directly
5
+ let totalNoCacheTokens = 0;
6
6
  let totalCacheReadTokens = 0;
7
7
  let totalCacheWriteTokens = 0;
8
+ let totalTextTokens = 0;
8
9
  let totalReasoningTokens = 0;
9
10
  let requestCount = 0;
10
11
  return {
11
12
  addUsage(usage) {
12
- totalInputTokens += usage.inputTokens ?? 0;
13
- totalOutputTokens += usage.outputTokens ?? 0;
14
- if (usage.inputTokenDetails) {
15
- totalCacheReadTokens += usage.inputTokenDetails.cacheReadTokens ?? 0;
16
- totalCacheWriteTokens += usage.inputTokenDetails.cacheWriteTokens ?? 0;
13
+ const inputDetails = usage.inputTokenDetails;
14
+ if (inputDetails) {
15
+ totalNoCacheTokens += inputDetails.noCacheTokens ?? 0;
16
+ totalCacheReadTokens += inputDetails.cacheReadTokens ?? 0;
17
+ totalCacheWriteTokens += inputDetails.cacheWriteTokens ?? 0;
17
18
  }
18
- else if (usage.cachedInputTokens) {
19
- totalCacheReadTokens += usage.cachedInputTokens;
19
+ else if (usage.inputTokens !== undefined) {
20
+ totalNoCacheTokens += usage.inputTokens;
20
21
  }
21
- if (usage.outputTokenDetails?.reasoningTokens) {
22
- totalReasoningTokens += usage.outputTokenDetails.reasoningTokens;
22
+ const outputDetails = usage.outputTokenDetails;
23
+ if (outputDetails) {
24
+ totalTextTokens += outputDetails.textTokens ?? 0;
25
+ totalReasoningTokens += outputDetails.reasoningTokens ?? 0;
23
26
  }
24
- else if (usage.reasoningTokens) {
25
- totalReasoningTokens += usage.reasoningTokens;
27
+ else if (usage.outputTokens !== undefined) {
28
+ totalTextTokens += usage.outputTokens;
26
29
  }
27
30
  requestCount++;
28
31
  },
29
32
  getTotalUsage() {
33
+ const inputTokens = totalNoCacheTokens + totalCacheReadTokens + totalCacheWriteTokens;
34
+ const outputTokens = totalTextTokens + totalReasoningTokens;
30
35
  return {
31
- inputTokens: totalInputTokens,
32
- outputTokens: totalOutputTokens,
33
- totalTokens: totalInputTokens + totalOutputTokens,
36
+ inputTokens,
37
+ outputTokens,
38
+ totalTokens: inputTokens + outputTokens,
34
39
  inputTokenDetails: {
40
+ noCacheTokens: totalNoCacheTokens,
35
41
  cacheReadTokens: totalCacheReadTokens,
36
42
  cacheWriteTokens: totalCacheWriteTokens,
37
- noCacheTokens: totalInputTokens - totalCacheReadTokens,
38
43
  },
39
44
  outputTokenDetails: {
45
+ textTokens: totalTextTokens,
40
46
  reasoningTokens: totalReasoningTokens,
41
- textTokens: totalOutputTokens - totalReasoningTokens,
42
47
  },
43
48
  };
44
49
  },
45
50
  getTotalCost() {
46
51
  return calculateCost({
47
- provider,
48
- modelId,
52
+ model,
49
53
  usage: this.getTotalUsage(),
50
54
  customPricing,
51
55
  });
@@ -54,10 +58,10 @@ export function createCostTracker(options) {
54
58
  return requestCount;
55
59
  },
56
60
  reset() {
57
- totalInputTokens = 0;
58
- totalOutputTokens = 0;
61
+ totalNoCacheTokens = 0;
59
62
  totalCacheReadTokens = 0;
60
63
  totalCacheWriteTokens = 0;
64
+ totalTextTokens = 0;
61
65
  totalReasoningTokens = 0;
62
66
  requestCount = 0;
63
67
  },
@@ -67,8 +71,7 @@ export async function calculateStreamCost(streamResult, options) {
67
71
  const result = await streamResult;
68
72
  const usage = result.usage;
69
73
  const cost = calculateCost({
70
- provider: options.provider,
71
- modelId: options.modelId,
74
+ model: options.model,
72
75
  usage,
73
76
  customPricing: options.customPricing,
74
77
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-sdk-cost-calculator",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Cost calculator for Vercel AI SDK token usage. Supports OpenAI, Anthropic, Google, xAI (Grok), and DeepSeek with long context pricing, prompt caching, and reasoning tokens.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",