wulf-pulse/lib/services/llm/pricing.test.ts

86 lines
2.6 KiB
TypeScript
Raw Normal View History

import { describe, it, expect } from 'vitest';
import { estimateCostUsd, PRICING } from './pricing';
import { HAIKU, SONNET, OPUS } from './models';
describe('PRICING', () => {
it('has rows for all three analyzer models', () => {
expect(PRICING[HAIKU]).toBeDefined();
expect(PRICING[SONNET]).toBeDefined();
expect(PRICING[OPUS]).toBeDefined();
});
it('output is more expensive than input on every model', () => {
for (const m of [HAIKU, SONNET, OPUS] as const) {
expect(PRICING[m].output).toBeGreaterThan(PRICING[m].input);
}
});
it('cache_read is much cheaper than uncached input', () => {
for (const m of [HAIKU, SONNET, OPUS] as const) {
expect(PRICING[m].cacheRead).toBeLessThan(PRICING[m].input);
}
});
});
describe('estimateCostUsd', () => {
it('charges Haiku $1/1M input + $5/1M output', () => {
// 1,000,000 input + 1,000,000 output = $1 + $5 = $6
expect(
estimateCostUsd(HAIKU, { input_tokens: 1_000_000, output_tokens: 1_000_000 })
).toBe(6);
});
it('charges Sonnet $3/1M input + $15/1M output', () => {
expect(
estimateCostUsd(SONNET, { input_tokens: 1_000_000, output_tokens: 1_000_000 })
).toBe(18);
});
it('charges Opus $5/1M input + $25/1M output', () => {
expect(
estimateCostUsd(OPUS, { input_tokens: 1_000_000, output_tokens: 1_000_000 })
).toBe(30);
});
it('charges cache_read at the discounted rate', () => {
// 1M cache_read at Haiku's $0.10 = $0.10
const cost = estimateCostUsd(HAIKU, {
input_tokens: 0,
output_tokens: 0,
cache_read_input_tokens: 1_000_000,
});
expect(cost).toBeCloseTo(0.1, 4);
});
it('charges cache_creation at the 1.25x premium', () => {
// 1M cache_write at Haiku's $1.25 = $1.25
const cost = estimateCostUsd(HAIKU, {
input_tokens: 0,
output_tokens: 0,
cache_creation_input_tokens: 1_000_000,
});
expect(cost).toBeCloseTo(1.25, 4);
});
it('rounds to 4 decimals (matches DB column)', () => {
const cost = estimateCostUsd(HAIKU, { input_tokens: 1, output_tokens: 1 });
// 1 input @ $1/M = $0.000001 ≈ rounds to 0.0000
expect(cost.toString().split('.')[1]?.length ?? 0).toBeLessThanOrEqual(4);
});
it('returns 0 for zero usage', () => {
expect(
estimateCostUsd(OPUS, { input_tokens: 0, output_tokens: 0 })
).toBe(0);
});
it('produces a realistic ticket-analysis cost for a typical Stage 1 call', () => {
// ~10K input tokens, ~500 output tokens on Haiku ≈ $0.013
const cost = estimateCostUsd(HAIKU, {
input_tokens: 10_000,
output_tokens: 500,
});
expect(cost).toBeCloseTo(0.0125, 4);
});
});