TypeScript 61.9%
HTML 37.2%
SQL 0.7%
1import { describe, expect, it, vi, beforeEach } from 'vitest';2import { z } from 'zod';3import { estimateUsd, priceFor, addUsage, ZERO_USAGE } from './pricing.js';4import { ModelRouter } from './router.js';5import { AiNotConfiguredError, type ModelProvider, type Role } from './types.js';6import { recentCosts, setCostSink, recordCost } from './costs.js';7import { identifyCollectible, IdentificationSchema } from './helpers/identify.js';89describe('pricing', () => {10 it('estimates usd from the price table', () => {11 expect(priceFor('claude-opus-5')?.input).toBe(5);12 expect(estimateUsd('claude-haiku-4-5', { inputTokens: 1_000_000, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0 })).toBe(1);13 expect(estimateUsd('claude-opus-5', { inputTokens: 0, outputTokens: 1000, cacheReadTokens: 1_000_000, cacheWriteTokens: 0 })).toBeCloseTo(0.025 + 0.5, 5);14 expect(estimateUsd('unknown-local-model', { ...ZERO_USAGE, inputTokens: 5000 })).toBe(0);15 expect(addUsage(ZERO_USAGE, { inputTokens: 1, outputTokens: 2, cacheReadTokens: 3, cacheWriteTokens: 4 }).cacheWriteTokens).toBe(4);16 });17});1819describe('router', () => {20 it('reports not configured without keys', () => {21 const r = new ModelRouter({ persistCosts: false });22 expect(r.configured).toBe(false);23 expect(() => r.providerFor('research')).toThrow(AiNotConfiguredError);24 expect(r.table().every((t) => t.provider === null)).toBe(true);25 });26 it('routes roles and honours overrides', () => {27 const r = new ModelRouter({ anthropicApiKey: 'sk-test', openaiApiKey: 'sk-openai', overrides: { research: 'anthropic:claude-opus-5', classify: 'claude-haiku-4-5', embed: 'openai:text-embedding-3-small' }, persistCosts: false });28 expect(r.providerFor('research').id).toBe('anthropic');29 expect(r.modelFor('research')).toBe('claude-opus-5');30 expect(r.modelFor('normalize')).toBe('claude-haiku-4-5');31 expect(r.providerFor('embed').id).toBe('openai');32 expect(r.modelFor('vision')).toBe('claude-opus-5');33 const table = r.table();34 expect(table.find((t) => t.role === 'embed')?.provider).toBe('openai');35 });36 it('embeddings unavailable with Anthropic only', () => {37 const r = new ModelRouter({ anthropicApiKey: 'sk-test', persistCosts: false });38 expect(r.supports('embed')).toBe(false);39 expect(() => r.providerFor('embed')).toThrow(/embeddings/);40 });41});4243describe('cost sink', () => {44 beforeEach(() => setCostSink(null));45 it('records and buffers events', async () => {46 const sink = vi.fn();47 setCostSink(sink);48 await recordCost({ provider: 'anthropic', model: 'claude-haiku-4-5', role: 'classify', usage: ZERO_USAGE, usdEst: 0.001 });49 expect(sink).toHaveBeenCalledTimes(1);50 expect(recentCosts().at(-1)?.role).toBe('classify');51 });52});5354function fakeProvider(data: unknown): ModelProvider {55 return {56 id: 'fake',57 supports: () => true,58 modelFor: () => 'fake-model',59 complete: async () => ({ text: '', model: 'fake-model', provider: 'fake', usage: ZERO_USAGE, usdEst: 0, stopReason: 'end_turn', refusal: null }),60 stream: async function* () {},61 runTools: async function* () {},62 extract: async <T,>(_role: Role, req: { schema: z.ZodType<T> }) => {63 const parsed = req.schema.parse(data);64 return { data: parsed, confidence: (parsed as { confidence?: number }).confidence ?? 1, model: 'fake-model', provider: 'fake', usage: ZERO_USAGE, usdEst: 0 };65 },66 vision: async <T,>(req: { schema: z.ZodType<T> }) => ({ data: req.schema.parse(data), confidence: 0.9, model: 'fake-model', provider: 'fake', usage: ZERO_USAGE, usdEst: 0 }),67 embed: async () => ({ vectors: [], model: 'fake', provider: 'fake', dimensions: 0, usdEst: 0 }),68 };69}7071describe('identifyCollectible', () => {72 it('validates schema and rejects unknown categories', async () => {73 const guess = IdentificationSchema.parse({74 categorySlug: 'not_a_real_slug',75 name: 'Charizard',76 brand: null,77 franchise: 'Pokémon',78 set: 'Base Set',79 number: '4/102',80 year: 1999,81 variant: '1st Edition Holo',82 language: 'English',83 grader: 'psa',84 grade: '10',85 certificationNumber: null,86 conditionNotes: null,87 likelyGradeRange: null,88 confidence: 0.82,89 rationale: 'Holo foil, 1st edition stamp visible',90 searchQueries: ['Charizard Base Set 1st Edition 4/102'],91 warnings: [],92 });93 const res = await identifyCollectible({ text: '1999 Pokemon Base Set Charizard 1st Edition PSA 10', provider: fakeProvider(guess) });94 expect(res.data.categorySlug).toBeNull();95 expect(res.data.warnings[0]).toMatch(/unknown category/);96 expect(res.confidence).toBeCloseTo(0.82);97 });98 it('requires input', async () => {99 await expect(identifyCollectible({ provider: fakeProvider({}) })).rejects.toThrow(/provide images or text/);100 });101});102