|
|
@@ -17,43 +17,51 @@ describe("Cost Utility", () => {
|
|
|
}
|
|
|
|
|
|
it("should calculate basic input/output costs correctly", () => {
|
|
|
- const cost = calculateApiCostAnthropic(mockModelInfo, 1000, 500)
|
|
|
+ const result = calculateApiCostAnthropic(mockModelInfo, 1000, 500)
|
|
|
|
|
|
// Input cost: (3.0 / 1_000_000) * 1000 = 0.003
|
|
|
// Output cost: (15.0 / 1_000_000) * 500 = 0.0075
|
|
|
// Total: 0.003 + 0.0075 = 0.0105
|
|
|
- expect(cost).toBe(0.0105)
|
|
|
+ expect(result.totalCost).toBe(0.0105)
|
|
|
+ expect(result.totalInputTokens).toBe(1000)
|
|
|
+ expect(result.totalOutputTokens).toBe(500)
|
|
|
})
|
|
|
|
|
|
it("should handle cache writes cost", () => {
|
|
|
- const cost = calculateApiCostAnthropic(mockModelInfo, 1000, 500, 2000)
|
|
|
+ const result = calculateApiCostAnthropic(mockModelInfo, 1000, 500, 2000)
|
|
|
|
|
|
// Input cost: (3.0 / 1_000_000) * 1000 = 0.003
|
|
|
// Output cost: (15.0 / 1_000_000) * 500 = 0.0075
|
|
|
// Cache writes: (3.75 / 1_000_000) * 2000 = 0.0075
|
|
|
// Total: 0.003 + 0.0075 + 0.0075 = 0.018
|
|
|
- expect(cost).toBeCloseTo(0.018, 6)
|
|
|
+ expect(result.totalCost).toBeCloseTo(0.018, 6)
|
|
|
+ expect(result.totalInputTokens).toBe(3000) // 1000 + 2000
|
|
|
+ expect(result.totalOutputTokens).toBe(500)
|
|
|
})
|
|
|
|
|
|
it("should handle cache reads cost", () => {
|
|
|
- const cost = calculateApiCostAnthropic(mockModelInfo, 1000, 500, undefined, 3000)
|
|
|
+ const result = calculateApiCostAnthropic(mockModelInfo, 1000, 500, undefined, 3000)
|
|
|
|
|
|
// Input cost: (3.0 / 1_000_000) * 1000 = 0.003
|
|
|
// Output cost: (15.0 / 1_000_000) * 500 = 0.0075
|
|
|
// Cache reads: (0.3 / 1_000_000) * 3000 = 0.0009
|
|
|
// Total: 0.003 + 0.0075 + 0.0009 = 0.0114
|
|
|
- expect(cost).toBe(0.0114)
|
|
|
+ expect(result.totalCost).toBe(0.0114)
|
|
|
+ expect(result.totalInputTokens).toBe(4000) // 1000 + 3000
|
|
|
+ expect(result.totalOutputTokens).toBe(500)
|
|
|
})
|
|
|
|
|
|
it("should handle all cost components together", () => {
|
|
|
- const cost = calculateApiCostAnthropic(mockModelInfo, 1000, 500, 2000, 3000)
|
|
|
+ const result = calculateApiCostAnthropic(mockModelInfo, 1000, 500, 2000, 3000)
|
|
|
|
|
|
// Input cost: (3.0 / 1_000_000) * 1000 = 0.003
|
|
|
// Output cost: (15.0 / 1_000_000) * 500 = 0.0075
|
|
|
// Cache writes: (3.75 / 1_000_000) * 2000 = 0.0075
|
|
|
// Cache reads: (0.3 / 1_000_000) * 3000 = 0.0009
|
|
|
// Total: 0.003 + 0.0075 + 0.0075 + 0.0009 = 0.0189
|
|
|
- expect(cost).toBe(0.0189)
|
|
|
+ expect(result.totalCost).toBe(0.0189)
|
|
|
+ expect(result.totalInputTokens).toBe(6000) // 1000 + 2000 + 3000
|
|
|
+ expect(result.totalOutputTokens).toBe(500)
|
|
|
})
|
|
|
|
|
|
it("should handle missing prices gracefully", () => {
|
|
|
@@ -63,22 +71,28 @@ describe("Cost Utility", () => {
|
|
|
supportsPromptCache: true,
|
|
|
}
|
|
|
|
|
|
- const cost = calculateApiCostAnthropic(modelWithoutPrices, 1000, 500, 2000, 3000)
|
|
|
- expect(cost).toBe(0)
|
|
|
+ const result = calculateApiCostAnthropic(modelWithoutPrices, 1000, 500, 2000, 3000)
|
|
|
+ expect(result.totalCost).toBe(0)
|
|
|
+ expect(result.totalInputTokens).toBe(6000) // 1000 + 2000 + 3000
|
|
|
+ expect(result.totalOutputTokens).toBe(500)
|
|
|
})
|
|
|
|
|
|
it("should handle zero tokens", () => {
|
|
|
- const cost = calculateApiCostAnthropic(mockModelInfo, 0, 0, 0, 0)
|
|
|
- expect(cost).toBe(0)
|
|
|
+ const result = calculateApiCostAnthropic(mockModelInfo, 0, 0, 0, 0)
|
|
|
+ expect(result.totalCost).toBe(0)
|
|
|
+ expect(result.totalInputTokens).toBe(0)
|
|
|
+ expect(result.totalOutputTokens).toBe(0)
|
|
|
})
|
|
|
|
|
|
it("should handle undefined cache values", () => {
|
|
|
- const cost = calculateApiCostAnthropic(mockModelInfo, 1000, 500)
|
|
|
+ const result = calculateApiCostAnthropic(mockModelInfo, 1000, 500)
|
|
|
|
|
|
// Input cost: (3.0 / 1_000_000) * 1000 = 0.003
|
|
|
// Output cost: (15.0 / 1_000_000) * 500 = 0.0075
|
|
|
// Total: 0.003 + 0.0075 = 0.0105
|
|
|
- expect(cost).toBe(0.0105)
|
|
|
+ expect(result.totalCost).toBe(0.0105)
|
|
|
+ expect(result.totalInputTokens).toBe(1000)
|
|
|
+ expect(result.totalOutputTokens).toBe(500)
|
|
|
})
|
|
|
|
|
|
it("should handle missing cache prices", () => {
|
|
|
@@ -88,13 +102,15 @@ describe("Cost Utility", () => {
|
|
|
cacheReadsPrice: undefined,
|
|
|
}
|
|
|
|
|
|
- const cost = calculateApiCostAnthropic(modelWithoutCachePrices, 1000, 500, 2000, 3000)
|
|
|
+ const result = calculateApiCostAnthropic(modelWithoutCachePrices, 1000, 500, 2000, 3000)
|
|
|
|
|
|
// Should only include input and output costs
|
|
|
// Input cost: (3.0 / 1_000_000) * 1000 = 0.003
|
|
|
// Output cost: (15.0 / 1_000_000) * 500 = 0.0075
|
|
|
// Total: 0.003 + 0.0075 = 0.0105
|
|
|
- expect(cost).toBe(0.0105)
|
|
|
+ expect(result.totalCost).toBe(0.0105)
|
|
|
+ expect(result.totalInputTokens).toBe(6000) // 1000 + 2000 + 3000
|
|
|
+ expect(result.totalOutputTokens).toBe(500)
|
|
|
})
|
|
|
})
|
|
|
|
|
|
@@ -110,43 +126,51 @@ describe("Cost Utility", () => {
|
|
|
}
|
|
|
|
|
|
it("should calculate basic input/output costs correctly", () => {
|
|
|
- const cost = calculateApiCostOpenAI(mockModelInfo, 1000, 500)
|
|
|
+ const result = calculateApiCostOpenAI(mockModelInfo, 1000, 500)
|
|
|
|
|
|
// Input cost: (3.0 / 1_000_000) * 1000 = 0.003
|
|
|
// Output cost: (15.0 / 1_000_000) * 500 = 0.0075
|
|
|
// Total: 0.003 + 0.0075 = 0.0105
|
|
|
- expect(cost).toBe(0.0105)
|
|
|
+ expect(result.totalCost).toBe(0.0105)
|
|
|
+ expect(result.totalInputTokens).toBe(1000)
|
|
|
+ expect(result.totalOutputTokens).toBe(500)
|
|
|
})
|
|
|
|
|
|
it("should handle cache writes cost", () => {
|
|
|
- const cost = calculateApiCostOpenAI(mockModelInfo, 3000, 500, 2000)
|
|
|
+ const result = calculateApiCostOpenAI(mockModelInfo, 3000, 500, 2000)
|
|
|
|
|
|
// Input cost: (3.0 / 1_000_000) * (3000 - 2000) = 0.003
|
|
|
// Output cost: (15.0 / 1_000_000) * 500 = 0.0075
|
|
|
// Cache writes: (3.75 / 1_000_000) * 2000 = 0.0075
|
|
|
// Total: 0.003 + 0.0075 + 0.0075 = 0.018
|
|
|
- expect(cost).toBeCloseTo(0.018, 6)
|
|
|
+ expect(result.totalCost).toBeCloseTo(0.018, 6)
|
|
|
+ expect(result.totalInputTokens).toBe(3000) // Total already includes cache
|
|
|
+ expect(result.totalOutputTokens).toBe(500)
|
|
|
})
|
|
|
|
|
|
it("should handle cache reads cost", () => {
|
|
|
- const cost = calculateApiCostOpenAI(mockModelInfo, 4000, 500, undefined, 3000)
|
|
|
+ const result = calculateApiCostOpenAI(mockModelInfo, 4000, 500, undefined, 3000)
|
|
|
|
|
|
// Input cost: (3.0 / 1_000_000) * (4000 - 3000) = 0.003
|
|
|
// Output cost: (15.0 / 1_000_000) * 500 = 0.0075
|
|
|
// Cache reads: (0.3 / 1_000_000) * 3000 = 0.0009
|
|
|
// Total: 0.003 + 0.0075 + 0.0009 = 0.0114
|
|
|
- expect(cost).toBe(0.0114)
|
|
|
+ expect(result.totalCost).toBe(0.0114)
|
|
|
+ expect(result.totalInputTokens).toBe(4000) // Total already includes cache
|
|
|
+ expect(result.totalOutputTokens).toBe(500)
|
|
|
})
|
|
|
|
|
|
it("should handle all cost components together", () => {
|
|
|
- const cost = calculateApiCostOpenAI(mockModelInfo, 6000, 500, 2000, 3000)
|
|
|
+ const result = calculateApiCostOpenAI(mockModelInfo, 6000, 500, 2000, 3000)
|
|
|
|
|
|
// Input cost: (3.0 / 1_000_000) * (6000 - 2000 - 3000) = 0.003
|
|
|
// Output cost: (15.0 / 1_000_000) * 500 = 0.0075
|
|
|
// Cache writes: (3.75 / 1_000_000) * 2000 = 0.0075
|
|
|
// Cache reads: (0.3 / 1_000_000) * 3000 = 0.0009
|
|
|
// Total: 0.003 + 0.0075 + 0.0075 + 0.0009 = 0.0189
|
|
|
- expect(cost).toBe(0.0189)
|
|
|
+ expect(result.totalCost).toBe(0.0189)
|
|
|
+ expect(result.totalInputTokens).toBe(6000) // Total already includes cache
|
|
|
+ expect(result.totalOutputTokens).toBe(500)
|
|
|
})
|
|
|
|
|
|
it("should handle missing prices gracefully", () => {
|
|
|
@@ -156,22 +180,28 @@ describe("Cost Utility", () => {
|
|
|
supportsPromptCache: true,
|
|
|
}
|
|
|
|
|
|
- const cost = calculateApiCostOpenAI(modelWithoutPrices, 1000, 500, 2000, 3000)
|
|
|
- expect(cost).toBe(0)
|
|
|
+ const result = calculateApiCostOpenAI(modelWithoutPrices, 1000, 500, 2000, 3000)
|
|
|
+ expect(result.totalCost).toBe(0)
|
|
|
+ expect(result.totalInputTokens).toBe(1000) // Total already includes cache
|
|
|
+ expect(result.totalOutputTokens).toBe(500)
|
|
|
})
|
|
|
|
|
|
it("should handle zero tokens", () => {
|
|
|
- const cost = calculateApiCostOpenAI(mockModelInfo, 0, 0, 0, 0)
|
|
|
- expect(cost).toBe(0)
|
|
|
+ const result = calculateApiCostOpenAI(mockModelInfo, 0, 0, 0, 0)
|
|
|
+ expect(result.totalCost).toBe(0)
|
|
|
+ expect(result.totalInputTokens).toBe(0)
|
|
|
+ expect(result.totalOutputTokens).toBe(0)
|
|
|
})
|
|
|
|
|
|
it("should handle undefined cache values", () => {
|
|
|
- const cost = calculateApiCostOpenAI(mockModelInfo, 1000, 500)
|
|
|
+ const result = calculateApiCostOpenAI(mockModelInfo, 1000, 500)
|
|
|
|
|
|
// Input cost: (3.0 / 1_000_000) * 1000 = 0.003
|
|
|
// Output cost: (15.0 / 1_000_000) * 500 = 0.0075
|
|
|
// Total: 0.003 + 0.0075 = 0.0105
|
|
|
- expect(cost).toBe(0.0105)
|
|
|
+ expect(result.totalCost).toBe(0.0105)
|
|
|
+ expect(result.totalInputTokens).toBe(1000)
|
|
|
+ expect(result.totalOutputTokens).toBe(500)
|
|
|
})
|
|
|
|
|
|
it("should handle missing cache prices", () => {
|
|
|
@@ -181,13 +211,15 @@ describe("Cost Utility", () => {
|
|
|
cacheReadsPrice: undefined,
|
|
|
}
|
|
|
|
|
|
- const cost = calculateApiCostOpenAI(modelWithoutCachePrices, 6000, 500, 2000, 3000)
|
|
|
+ const result = calculateApiCostOpenAI(modelWithoutCachePrices, 6000, 500, 2000, 3000)
|
|
|
|
|
|
// Should only include input and output costs
|
|
|
// Input cost: (3.0 / 1_000_000) * (6000 - 2000 - 3000) = 0.003
|
|
|
// Output cost: (15.0 / 1_000_000) * 500 = 0.0075
|
|
|
// Total: 0.003 + 0.0075 = 0.0105
|
|
|
- expect(cost).toBe(0.0105)
|
|
|
+ expect(result.totalCost).toBe(0.0105)
|
|
|
+ expect(result.totalInputTokens).toBe(6000) // Total already includes cache
|
|
|
+ expect(result.totalOutputTokens).toBe(500)
|
|
|
})
|
|
|
})
|
|
|
})
|