Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions apps/web/src/lib/ai-gateway/models.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ describe('isFreeModel', () => {
expect(gpt_5_6_sol_stealth_model.internal_id).toBe('openai/gpt-5.6-sol:optimized');
expect(gpt_5_6_sol_stealth_model.gateway).toBe('martian');
expect(getInferenceProvider(gpt_5_6_sol_stealth_model)?.slug).toBe('stealth');
expect(gpt_5_6_sol_stealth_model.pricing).toEqual([
expect(gpt_5_6_sol_stealth_model.pricing?.tiers).toEqual([
{
start_context_length: 0,
pricing: {
Expand All @@ -147,9 +147,9 @@ describe('isFreeModel', () => {
test('all Kilo exclusive models should have either no pricing or valid ordered pricing tiers', () => {
for (const model of kiloExclusiveModels) {
if (model.pricing) {
expect(model.pricing[0].start_context_length).toBe(0);
expect(model.pricing.tiers[0].start_context_length).toBe(0);
let previousStartContextLength = -1;
for (const tier of model.pricing) {
for (const tier of model.pricing.tiers) {
expect(typeof tier.pricing.prompt_per_million).toBe('number');
expect(typeof tier.pricing.completion_per_million).toBe('number');
expect(tier.start_context_length).toBeGreaterThan(previousStartContextLength);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,19 @@ const makeUsage = (overrides: Partial<JustTheCostsUsageStats> = {}): JustTheCost
...overrides,
});

const fallbackOnlyModel = {
...claude_opus_4_7_stealth_model,
pricing: claude_opus_4_7_stealth_model.pricing && {
...claude_opus_4_7_stealth_model.pricing,
fallbackOnly: true,
},
};

describe('calculateKiloExclusiveCost_mUsd with stealth Claude Opus 4.7', () => {
test('uses the 20% lower flat price for uncached tokens', () => {
const result = calculateKiloExclusiveCost_mUsd(
claude_opus_4_7_stealth_model,
makeUsage({ inputTokens: 100_000, outputTokens: 10_000 })
makeUsage({ inputTokens: 100_000, outputTokens: 10_000, cost_mUsd: 999_000 })
);
expect(result).toBe(600_000);
});
Expand All @@ -34,4 +42,20 @@ describe('calculateKiloExclusiveCost_mUsd with stealth Claude Opus 4.7', () => {
);
expect(result).toBe(735_000);
});

test('uses fallback-only pricing when market cost is missing', () => {
const result = calculateKiloExclusiveCost_mUsd(
fallbackOnlyModel,
makeUsage({ inputTokens: 100_000, outputTokens: 10_000 })
);
expect(result).toBe(600_000);
});

test('preserves reported market cost with fallback-only pricing', () => {
const result = calculateKiloExclusiveCost_mUsd(
fallbackOnlyModel,
makeUsage({ inputTokens: 100_000, outputTokens: 10_000, cost_mUsd: 123_000 })
);
expect(result).toBeUndefined();
});
});
14 changes: 10 additions & 4 deletions apps/web/src/lib/ai-gateway/processUsage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1188,11 +1188,14 @@ export function parseMicrodollarUsageFromString(
export function calculateKiloExclusiveCost_mUsd(
model: KiloExclusiveModel,
usage: JustTheCostsUsageStats
): number {
): number | undefined {
const pricing = model?.pricing;
if (!pricing) {
return 0;
}
if (pricing.fallbackOnly && usage.cost_mUsd > 0) {
return undefined;
}
const uncachedInputTokens = usage.inputTokens - usage.cacheHitTokens - usage.cacheWriteTokens;
if (uncachedInputTokens < 0) {
captureMessage('SUSPICIOUS: negative uncached input tokens', {
Expand All @@ -1209,7 +1212,7 @@ export function calculateKiloExclusiveCost_mUsd(
cacheHitTokens: usage.cacheHitTokens,
cacheWriteTokens: usage.cacheWriteTokens,
},
pricing
pricing.tiers
)
);
}
Expand Down Expand Up @@ -1288,8 +1291,11 @@ export async function processTokenData(

const kiloExclusiveModel = findKiloExclusiveModel(usageContext.requested_model);
if (kiloExclusiveModel?.pricing) {
usageStats.market_cost = usageStats.cost_mUsd;
usageStats.cost_mUsd = calculateKiloExclusiveCost_mUsd(kiloExclusiveModel, usageStats);
const exclusiveCost_mUsd = calculateKiloExclusiveCost_mUsd(kiloExclusiveModel, usageStats);
if (exclusiveCost_mUsd !== undefined) {
usageStats.market_cost = usageStats.cost_mUsd;
usageStats.cost_mUsd = exclusiveCost_mUsd;
}
}

const customCost_mUsd = calculateCustomCost_mUsd(usageContext.requested_model, usageStats);
Expand Down
8 changes: 4 additions & 4 deletions apps/web/src/lib/ai-gateway/providers/anthropic.constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export const claude_opus_4_8_stealth_model: KiloExclusiveModel = {
max_completion_tokens: 128_000,
gateway: 'martian',
flags: ['reasoning', 'vision', 'stealth', 'requires-data-collection'],
pricing: CLAUDE_OPUS_STEALTH_PRICING,
pricing: { tiers: CLAUDE_OPUS_STEALTH_PRICING },
inference_provider_restriction: [],
};

Expand All @@ -56,7 +56,7 @@ export const claude_opus_4_7_stealth_model: KiloExclusiveModel = {
max_completion_tokens: 128_000,
gateway: 'martian',
flags: ['reasoning', 'vision', 'stealth', 'requires-data-collection'],
pricing: CLAUDE_OPUS_STEALTH_PRICING,
pricing: { tiers: CLAUDE_OPUS_STEALTH_PRICING },
inference_provider_restriction: [],
};

Expand All @@ -83,7 +83,7 @@ export const claude_sonnet_4_6_stealth_model: KiloExclusiveModel = {
max_completion_tokens: 64_000,
gateway: 'martian',
flags: ['reasoning', 'vision', 'stealth', 'requires-data-collection'],
pricing: CLAUDE_SONNET_STEALTH_PRICING,
pricing: { tiers: CLAUDE_SONNET_STEALTH_PRICING },
inference_provider_restriction: [],
};

Expand All @@ -98,7 +98,7 @@ export const claude_opus_4_6_stealth_model: KiloExclusiveModel = {
max_completion_tokens: 128_000,
gateway: 'martian',
flags: ['reasoning', 'vision', 'stealth', 'requires-data-collection'],
pricing: CLAUDE_OPUS_STEALTH_PRICING,
pricing: { tiers: CLAUDE_OPUS_STEALTH_PRICING },
inference_provider_restriction: [],
};

Expand Down
44 changes: 24 additions & 20 deletions apps/web/src/lib/ai-gateway/providers/deepseek.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,19 @@ export const deepseek_v4_pro_discounted_model: KiloExclusiveModel = {
max_completion_tokens: 384000,
gateway: 'openrouter',
flags: ['reasoning', 'requires-data-collection', 'vercel-routing'],
pricing: [
{
start_context_length: 0,
pricing: {
prompt_per_million: 0.435,
completion_per_million: 0.87,
input_cache_read_per_million: 0.003625,
input_cache_write_per_million: null,
pricing: {
tiers: [
{
start_context_length: 0,
pricing: {
prompt_per_million: 0.435,
completion_per_million: 0.87,
input_cache_read_per_million: 0.003625,
input_cache_write_per_million: null,
},
},
},
],
],
},
inference_provider_restriction: ['deepseek'],
};

Expand All @@ -40,17 +42,19 @@ const deepseek_v4_flash_discounted_model: KiloExclusiveModel = {
max_completion_tokens: 384000,
gateway: 'openrouter',
flags: ['reasoning', 'requires-data-collection', 'vercel-routing'],
pricing: [
{
start_context_length: 0,
pricing: {
prompt_per_million: 0.14,
completion_per_million: 0.28,
input_cache_read_per_million: 0.0028,
input_cache_write_per_million: null,
pricing: {
tiers: [
{
start_context_length: 0,
pricing: {
prompt_per_million: 0.14,
completion_per_million: 0.28,
input_cache_read_per_million: 0.0028,
input_cache_write_per_million: null,
},
},
},
],
],
},
inference_provider_restriction: ['deepseek'],
};

Expand Down
22 changes: 18 additions & 4 deletions apps/web/src/lib/ai-gateway/providers/kilo-exclusive-model.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,24 @@ describe('convertFromKiloExclusiveModel', () => {
it('only exposes the cheapest pricing tier in model metadata', () => {
const model = makeModel({
internal_id: 'vendor/x',
pricing: [
{ start_context_length: 0, pricing: pricing(1) },
{ start_context_length: 100, pricing: pricing(2) },
],
pricing: {
tiers: [
{ start_context_length: 0, pricing: pricing(1) },
{ start_context_length: 100, pricing: pricing(2) },
],
},
});

expect(convertFromKiloExclusiveModel(model).pricing.prompt).toBe('0.000001000000');
});

it('exposes fallback-only pricing in model metadata', () => {
const model = makeModel({
internal_id: 'vendor/x',
pricing: {
fallbackOnly: true,
tiers: [{ start_context_length: 0, pricing: pricing(1) }],
},
});

expect(convertFromKiloExclusiveModel(model).pricing.prompt).toBe('0.000001000000');
Expand Down
10 changes: 8 additions & 2 deletions apps/web/src/lib/ai-gateway/providers/kilo-exclusive-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ export type PricingTier = {

export type PricingTiers = readonly [PricingTier, ...PricingTier[]];

export type KiloExclusivePricing = {
tiers: PricingTiers;
/** Only use these tiers when the upstream response does not report a positive market cost. */
fallbackOnly?: boolean;
};

export function calculateCost_mUsd(usage: Usage, pricingTiers: PricingTiers): number {
if (pricingTiers[0].start_context_length !== 0) {
throw new Error('The first pricing tier must start at context length 0');
Expand Down Expand Up @@ -75,7 +81,7 @@ export type KiloExclusiveModel = {
flags: KiloExclusiveModelFlag[];
gateway: ProviderId;
internal_id: string;
pricing: PricingTiers | null;
pricing: KiloExclusivePricing | null;
/**
* Upstream inference providers this model may be routed to; empty means no
* restriction. Only honored by the OpenRouter and Vercel AI Gateway upstreams.
Expand Down Expand Up @@ -207,7 +213,7 @@ function formatPricePerMillionAsPerToken(price: number | null | undefined): stri
}

export function convertFromKiloExclusiveModel(model: KiloExclusiveModel) {
const cheapestPricing = model.pricing?.[0].pricing;
const cheapestPricing = model.pricing?.tiers[0].pricing;
const isFree = !model.pricing;
return {
id: model.public_id,
Expand Down
38 changes: 20 additions & 18 deletions apps/web/src/lib/ai-gateway/providers/openai-exclusive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,27 @@ export const gpt_5_6_sol_stealth_model: KiloExclusiveModel = {
max_completion_tokens: 128_000,
gateway: 'martian',
flags: ['reasoning', 'vision', 'stealth', 'requires-data-collection'],
pricing: [
{
start_context_length: 0,
pricing: {
prompt_per_million: 4,
completion_per_million: 24,
input_cache_read_per_million: 0.4,
input_cache_write_per_million: 5,
pricing: {
tiers: [
{
start_context_length: 0,
pricing: {
prompt_per_million: 4,
completion_per_million: 24,
input_cache_read_per_million: 0.4,
input_cache_write_per_million: 5,
},
},
},
{
start_context_length: 272_000,
pricing: {
prompt_per_million: 8,
completion_per_million: 36,
input_cache_read_per_million: 0.8,
input_cache_write_per_million: 10,
{
start_context_length: 272_000,
pricing: {
prompt_per_million: 8,
completion_per_million: 36,
input_cache_read_per_million: 0.8,
input_cache_write_per_million: 10,
},
},
},
],
],
},
inference_provider_restriction: [],
};
Original file line number Diff line number Diff line change
Expand Up @@ -50,17 +50,19 @@ function dataCollectionExclusiveModel(
inference_provider_restriction: KiloExclusiveModel['inference_provider_restriction']
): KiloExclusiveModel {
const model = freeExclusiveModel(public_id, inference_provider_restriction);
model.pricing = [
{
start_context_length: 0,
pricing: {
prompt_per_million: 1,
completion_per_million: 1,
input_cache_read_per_million: null,
input_cache_write_per_million: null,
model.pricing = {
tiers: [
{
start_context_length: 0,
pricing: {
prompt_per_million: 1,
completion_per_million: 1,
input_cache_read_per_million: null,
input_cache_write_per_million: null,
},
},
},
];
],
};
model.flags = ['requires-data-collection'];
return model;
}
Expand Down Expand Up @@ -191,17 +193,19 @@ describe('applyFreeEndpointDataPolicy', () => {
const disabled = freeExclusiveModel('example/model:free', []);
disabled.status = 'disabled';
const paid = freeExclusiveModel('example/model:discounted', []);
paid.pricing = [
{
start_context_length: 0,
pricing: {
prompt_per_million: 1,
completion_per_million: 1,
input_cache_read_per_million: null,
input_cache_write_per_million: null,
paid.pricing = {
tiers: [
{
start_context_length: 0,
pricing: {
prompt_per_million: 1,
completion_per_million: 1,
input_cache_read_per_million: null,
input_cache_write_per_million: null,
},
},
},
];
],
};

applyFreeEndpointDataPolicy({
providerModelData: [{ provider: { slug: 'novita' }, models: [model] }],
Expand Down
Loading