1- import { calculateApiCost } from "../cost"
1+ import { calculateApiCostAnthropic , calculateApiCostOpenAI } from "../cost"
22import { ModelInfo } from "../../shared/api"
33
44describe ( "Cost Utility" , ( ) => {
5- describe ( "calculateApiCost " , ( ) => {
5+ describe ( "calculateApiCostAnthropic " , ( ) => {
66 const mockModelInfo : ModelInfo = {
77 maxTokens : 8192 ,
88 contextWindow : 200_000 ,
@@ -14,7 +14,7 @@ describe("Cost Utility", () => {
1414 }
1515
1616 it ( "should calculate basic input/output costs correctly" , ( ) => {
17- const cost = calculateApiCost ( mockModelInfo , 1000 , 500 )
17+ const cost = calculateApiCostAnthropic ( mockModelInfo , 1000 , 500 )
1818
1919 // Input cost: (3.0 / 1_000_000) * 1000 = 0.003
2020 // Output cost: (15.0 / 1_000_000) * 500 = 0.0075
@@ -23,7 +23,7 @@ describe("Cost Utility", () => {
2323 } )
2424
2525 it ( "should handle cache writes cost" , ( ) => {
26- const cost = calculateApiCost ( mockModelInfo , 1000 , 500 , 2000 )
26+ const cost = calculateApiCostAnthropic ( mockModelInfo , 1000 , 500 , 2000 )
2727
2828 // Input cost: (3.0 / 1_000_000) * 1000 = 0.003
2929 // Output cost: (15.0 / 1_000_000) * 500 = 0.0075
@@ -33,7 +33,7 @@ describe("Cost Utility", () => {
3333 } )
3434
3535 it ( "should handle cache reads cost" , ( ) => {
36- const cost = calculateApiCost ( mockModelInfo , 1000 , 500 , undefined , 3000 )
36+ const cost = calculateApiCostAnthropic ( mockModelInfo , 1000 , 500 , undefined , 3000 )
3737
3838 // Input cost: (3.0 / 1_000_000) * 1000 = 0.003
3939 // Output cost: (15.0 / 1_000_000) * 500 = 0.0075
@@ -43,7 +43,7 @@ describe("Cost Utility", () => {
4343 } )
4444
4545 it ( "should handle all cost components together" , ( ) => {
46- const cost = calculateApiCost ( mockModelInfo , 1000 , 500 , 2000 , 3000 )
46+ const cost = calculateApiCostAnthropic ( mockModelInfo , 1000 , 500 , 2000 , 3000 )
4747
4848 // Input cost: (3.0 / 1_000_000) * 1000 = 0.003
4949 // Output cost: (15.0 / 1_000_000) * 500 = 0.0075
@@ -60,17 +60,17 @@ describe("Cost Utility", () => {
6060 supportsPromptCache : true ,
6161 }
6262
63- const cost = calculateApiCost ( modelWithoutPrices , 1000 , 500 , 2000 , 3000 )
63+ const cost = calculateApiCostAnthropic ( modelWithoutPrices , 1000 , 500 , 2000 , 3000 )
6464 expect ( cost ) . toBe ( 0 )
6565 } )
6666
6767 it ( "should handle zero tokens" , ( ) => {
68- const cost = calculateApiCost ( mockModelInfo , 0 , 0 , 0 , 0 )
68+ const cost = calculateApiCostAnthropic ( mockModelInfo , 0 , 0 , 0 , 0 )
6969 expect ( cost ) . toBe ( 0 )
7070 } )
7171
7272 it ( "should handle undefined cache values" , ( ) => {
73- const cost = calculateApiCost ( mockModelInfo , 1000 , 500 )
73+ const cost = calculateApiCostAnthropic ( mockModelInfo , 1000 , 500 )
7474
7575 // Input cost: (3.0 / 1_000_000) * 1000 = 0.003
7676 // Output cost: (15.0 / 1_000_000) * 500 = 0.0075
@@ -85,7 +85,7 @@ describe("Cost Utility", () => {
8585 cacheReadsPrice : undefined ,
8686 }
8787
88- const cost = calculateApiCost ( modelWithoutCachePrices , 1000 , 500 , 2000 , 3000 )
88+ const cost = calculateApiCostAnthropic ( modelWithoutCachePrices , 1000 , 500 , 2000 , 3000 )
8989
9090 // Should only include input and output costs
9191 // Input cost: (3.0 / 1_000_000) * 1000 = 0.003
@@ -94,4 +94,97 @@ describe("Cost Utility", () => {
9494 expect ( cost ) . toBe ( 0.0105 )
9595 } )
9696 } )
97+
98+ describe ( "calculateApiCostOpenAI" , ( ) => {
99+ const mockModelInfo : ModelInfo = {
100+ maxTokens : 8192 ,
101+ contextWindow : 200_000 ,
102+ supportsPromptCache : true ,
103+ inputPrice : 3.0 , // $3 per million tokens
104+ outputPrice : 15.0 , // $15 per million tokens
105+ cacheWritesPrice : 3.75 , // $3.75 per million tokens
106+ cacheReadsPrice : 0.3 , // $0.30 per million tokens
107+ }
108+
109+ it ( "should calculate basic input/output costs correctly" , ( ) => {
110+ const cost = calculateApiCostOpenAI ( mockModelInfo , 1000 , 500 )
111+
112+ // Input cost: (3.0 / 1_000_000) * 1000 = 0.003
113+ // Output cost: (15.0 / 1_000_000) * 500 = 0.0075
114+ // Total: 0.003 + 0.0075 = 0.0105
115+ expect ( cost ) . toBe ( 0.0105 )
116+ } )
117+
118+ it ( "should handle cache writes cost" , ( ) => {
119+ const cost = calculateApiCostOpenAI ( mockModelInfo , 3000 , 500 , 2000 )
120+
121+ // Input cost: (3.0 / 1_000_000) * (3000 - 2000) = 0.003
122+ // Output cost: (15.0 / 1_000_000) * 500 = 0.0075
123+ // Cache writes: (3.75 / 1_000_000) * 2000 = 0.0075
124+ // Total: 0.003 + 0.0075 + 0.0075 = 0.018
125+ expect ( cost ) . toBeCloseTo ( 0.018 , 6 )
126+ } )
127+
128+ it ( "should handle cache reads cost" , ( ) => {
129+ const cost = calculateApiCostOpenAI ( mockModelInfo , 4000 , 500 , undefined , 3000 )
130+
131+ // Input cost: (3.0 / 1_000_000) * (4000 - 3000) = 0.003
132+ // Output cost: (15.0 / 1_000_000) * 500 = 0.0075
133+ // Cache reads: (0.3 / 1_000_000) * 3000 = 0.0009
134+ // Total: 0.003 + 0.0075 + 0.0009 = 0.0114
135+ expect ( cost ) . toBe ( 0.0114 )
136+ } )
137+
138+ it ( "should handle all cost components together" , ( ) => {
139+ const cost = calculateApiCostOpenAI ( mockModelInfo , 6000 , 500 , 2000 , 3000 )
140+
141+ // Input cost: (3.0 / 1_000_000) * (6000 - 2000 - 3000) = 0.003
142+ // Output cost: (15.0 / 1_000_000) * 500 = 0.0075
143+ // Cache writes: (3.75 / 1_000_000) * 2000 = 0.0075
144+ // Cache reads: (0.3 / 1_000_000) * 3000 = 0.0009
145+ // Total: 0.003 + 0.0075 + 0.0075 + 0.0009 = 0.0189
146+ expect ( cost ) . toBe ( 0.0189 )
147+ } )
148+
149+ it ( "should handle missing prices gracefully" , ( ) => {
150+ const modelWithoutPrices : ModelInfo = {
151+ maxTokens : 8192 ,
152+ contextWindow : 200_000 ,
153+ supportsPromptCache : true ,
154+ }
155+
156+ const cost = calculateApiCostOpenAI ( modelWithoutPrices , 1000 , 500 , 2000 , 3000 )
157+ expect ( cost ) . toBe ( 0 )
158+ } )
159+
160+ it ( "should handle zero tokens" , ( ) => {
161+ const cost = calculateApiCostOpenAI ( mockModelInfo , 0 , 0 , 0 , 0 )
162+ expect ( cost ) . toBe ( 0 )
163+ } )
164+
165+ it ( "should handle undefined cache values" , ( ) => {
166+ const cost = calculateApiCostOpenAI ( mockModelInfo , 1000 , 500 )
167+
168+ // Input cost: (3.0 / 1_000_000) * 1000 = 0.003
169+ // Output cost: (15.0 / 1_000_000) * 500 = 0.0075
170+ // Total: 0.003 + 0.0075 = 0.0105
171+ expect ( cost ) . toBe ( 0.0105 )
172+ } )
173+
174+ it ( "should handle missing cache prices" , ( ) => {
175+ const modelWithoutCachePrices : ModelInfo = {
176+ ...mockModelInfo ,
177+ cacheWritesPrice : undefined ,
178+ cacheReadsPrice : undefined ,
179+ }
180+
181+ const cost = calculateApiCostOpenAI ( modelWithoutCachePrices , 6000 , 500 , 2000 , 3000 )
182+
183+ // Should only include input and output costs
184+ // Input cost: (3.0 / 1_000_000) * (6000 - 2000 - 3000) = 0.003
185+ // Output cost: (15.0 / 1_000_000) * 500 = 0.0075
186+ // Total: 0.003 + 0.0075 = 0.0105
187+ expect ( cost ) . toBe ( 0.0105 )
188+ } )
189+ } )
97190} )
0 commit comments