fix: use full OpenRouter model IDs in pricing lookup
MODEL_PRICING keys were 'gpt-oss-120b' but the actual model string from env is 'openai/gpt-oss-120b'. The lookup always missed, so calculateCost returned 0 for every call. Updated keys to match the full OpenRouter model identifiers. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -69,12 +69,12 @@ describe('llmConfig', () => {
|
||||
|
||||
describe('MODEL_PRICING', () => {
|
||||
it('has free pricing for trinity models', () => {
|
||||
const pricing = MODEL_PRICING['recursal/trinity-large'];
|
||||
const pricing = MODEL_PRICING['arcee-ai/trinity-large-preview:free'];
|
||||
expect(pricing).toEqual({ inputPerToken: 0, outputPerToken: 0 });
|
||||
});
|
||||
|
||||
it('has correct pricing for gpt-oss-120b', () => {
|
||||
const pricing = MODEL_PRICING['gpt-oss-120b'];
|
||||
const pricing = MODEL_PRICING['openai/gpt-oss-120b'];
|
||||
expect(pricing.inputPerToken).toBeCloseTo(0.000000039, 12);
|
||||
expect(pricing.outputPerToken).toBeCloseTo(0.00000019, 12);
|
||||
});
|
||||
@@ -82,11 +82,11 @@ describe('MODEL_PRICING', () => {
|
||||
|
||||
describe('calculateCost', () => {
|
||||
it('returns 0 for free model', () => {
|
||||
expect(calculateCost('recursal/trinity-large', 1000, 500)).toBe(0);
|
||||
expect(calculateCost('arcee-ai/trinity-large-preview:free', 1000, 500)).toBe(0);
|
||||
});
|
||||
|
||||
it('calculates cost for paid model', () => {
|
||||
const cost = calculateCost('gpt-oss-120b', 1000, 500);
|
||||
const cost = calculateCost('openai/gpt-oss-120b', 1000, 500);
|
||||
expect(cost).toBeCloseTo(0.000134, 8);
|
||||
});
|
||||
|
||||
|
||||
@@ -29,8 +29,8 @@ export interface ModelPricing {
|
||||
}
|
||||
|
||||
export const MODEL_PRICING: Record<string, ModelPricing> = {
|
||||
'recursal/trinity-large': { inputPerToken: 0, outputPerToken: 0 },
|
||||
'gpt-oss-120b': { inputPerToken: 0.039 / 1_000_000, outputPerToken: 0.19 / 1_000_000 },
|
||||
'arcee-ai/trinity-large-preview:free': { inputPerToken: 0, outputPerToken: 0 },
|
||||
'openai/gpt-oss-120b': { inputPerToken: 0.039 / 1_000_000, outputPerToken: 0.19 / 1_000_000 },
|
||||
};
|
||||
|
||||
export function calculateCost(model: string, inputTokens: number, outputTokens: number): number {
|
||||
|
||||
@@ -50,7 +50,7 @@ describe('llmStatsService', () => {
|
||||
|
||||
it('records a successful call and retrieves stats', () => {
|
||||
const service = setup();
|
||||
service.record('socialNarration', 100, 50, 'gpt-oss-120b', 0, false, 42);
|
||||
service.record('socialNarration', 100, 50, 'openai/gpt-oss-120b', 0, false, 42);
|
||||
|
||||
const stats = service.getStats();
|
||||
expect(stats.types).toHaveLength(1);
|
||||
@@ -64,8 +64,8 @@ describe('llmStatsService', () => {
|
||||
|
||||
it('tracks retries and failures', () => {
|
||||
const service = setup();
|
||||
service.record('socialNarration', 100, 50, 'gpt-oss-120b', 2, false, 1);
|
||||
service.record('socialNarration', 100, 50, 'gpt-oss-120b', 0, true, 2);
|
||||
service.record('socialNarration', 100, 50, 'openai/gpt-oss-120b', 2, false, 1);
|
||||
service.record('socialNarration', 100, 50, 'openai/gpt-oss-120b', 0, true, 2);
|
||||
|
||||
const stats = service.getStats();
|
||||
expect(stats.types[0].retryCount).toBe(1);
|
||||
@@ -76,8 +76,8 @@ describe('llmStatsService', () => {
|
||||
|
||||
it('calculates min/max/avg cost', () => {
|
||||
const service = setup();
|
||||
service.record('backstoryAndDesires', 100, 50, 'recursal/trinity-large', 0, false, 1);
|
||||
service.record('backstoryAndDesires', 1000, 500, 'gpt-oss-120b', 0, false, 2);
|
||||
service.record('backstoryAndDesires', 100, 50, 'arcee-ai/trinity-large-preview:free', 0, false, 1);
|
||||
service.record('backstoryAndDesires', 1000, 500, 'openai/gpt-oss-120b', 0, false, 2);
|
||||
|
||||
const stats = service.getStats();
|
||||
const bs = stats.types.find(t => t.templateName === 'backstoryAndDesires')!;
|
||||
@@ -91,7 +91,7 @@ describe('llmStatsService', () => {
|
||||
it('respects tracking toggle', () => {
|
||||
const service = setup();
|
||||
service.setTrackingEnabled(false);
|
||||
service.record('socialNarration', 100, 50, 'gpt-oss-120b', 0, false, 1);
|
||||
service.record('socialNarration', 100, 50, 'openai/gpt-oss-120b', 0, false, 1);
|
||||
|
||||
const stats = service.getStats();
|
||||
expect(stats.totalCount).toBe(0);
|
||||
@@ -100,11 +100,11 @@ describe('llmStatsService', () => {
|
||||
|
||||
it('returns friendly labels', () => {
|
||||
const service = setup();
|
||||
service.record('backstoryAndDesires', 100, 50, 'recursal/trinity-large', 0, false, 1);
|
||||
service.record('socialNarration', 100, 50, 'recursal/trinity-large', 0, false, 2);
|
||||
service.record('batchedThoughts', 100, 50, 'recursal/trinity-large', 0, false, 3);
|
||||
service.record('desireGeneration', 100, 50, 'recursal/trinity-large', 0, false, 4);
|
||||
service.record('invention', 100, 50, 'recursal/trinity-large', 0, false, 5);
|
||||
service.record('backstoryAndDesires', 100, 50, 'arcee-ai/trinity-large-preview:free', 0, false, 1);
|
||||
service.record('socialNarration', 100, 50, 'arcee-ai/trinity-large-preview:free', 0, false, 2);
|
||||
service.record('batchedThoughts', 100, 50, 'arcee-ai/trinity-large-preview:free', 0, false, 3);
|
||||
service.record('desireGeneration', 100, 50, 'arcee-ai/trinity-large-preview:free', 0, false, 4);
|
||||
service.record('invention', 100, 50, 'arcee-ai/trinity-large-preview:free', 0, false, 5);
|
||||
|
||||
const stats = service.getStats();
|
||||
const labels = stats.types.map(t => t.label);
|
||||
|
||||
Reference in New Issue
Block a user