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
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
} from '@/lib/ai-gateway/providers/apply-provider-specific-logic';
import type { GatewayRequest } from '@/lib/ai-gateway/providers/openrouter/types';
import type { ProviderId } from '@/lib/ai-gateway/providers/types';
import { OPENROUTER_GPT56_PROMO_MODEL_IDS } from '@/lib/ai-gateway/providers/openai';

function makeRequest(model: string, models?: string[]): GatewayRequest {
return {
Expand Down Expand Up @@ -60,12 +59,24 @@ describe('applyGatewayModelsFallback', () => {
});

describe('applyPreferredProvider', () => {
it.each(OPENROUTER_GPT56_PROMO_MODEL_IDS)('prefers OpenAI for promo model %s', model => {
it.each(['openai/gpt-5.6-terra', 'openai/o3', 'gpt-5.5'])(
'prefers OpenAI for OpenAI model %s',
model => {
const request = makeRequest(model);

applyPreferredProvider(model, request.body);

expect(request.body.provider).toEqual({ order: ['openai'] });
}
);

it('does not set a provider order for GPT-OSS', () => {
const model = 'openai/gpt-oss-120b';
const request = makeRequest(model);

applyPreferredProvider(model, request.body);

expect(request.body.provider).toEqual({ order: ['openai'] });
expect(request.body.provider).toBeUndefined();
});

it('does not set a provider order for Fable', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ import {
} from '@/lib/ai-gateway/providers/openrouter/request-helpers';
import { isQwenExplicitCacheModel, isQwenModel } from '@/lib/ai-gateway/providers/qwen';
import { isFreeModel } from '@/lib/ai-gateway/is-free-model';
import { isOpenRouterGpt56PromoModel } from '@/lib/ai-gateway/providers/openai';
import { isOpenAiModel } from '@/lib/ai-gateway/providers/openai';

export function getPreferredProviderOrder(requestedModel: string): string[] {
if (isOpenRouterGpt56PromoModel(requestedModel)) {
if (isOpenAiModel(requestedModel)) {
return [OpenRouterInferenceProviderIdSchema.enum.openai];
}
if (isClaudeModel(requestedModel) && !isFableModel(requestedModel)) {
Expand Down
4 changes: 2 additions & 2 deletions apps/web/src/lib/ai-gateway/providers/openai.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ export const GPT_MINI_CURRENT_MODEL_ID = 'openai/gpt-5.4-mini';

export const GPT_MINI_CURRENT_VERCEL_MODEL_ID = GPT_MINI_CURRENT_MODEL_ID;

// OpenRouter BYOK must be disabled for these models so requests use the discounted endpoint.
export const ENABLE_OPENROUTER_GPT56_PROMO = true;
// OpenAI BYOK must be disabled on the OpenRouter website before enabling this flag.
export const ENABLE_OPENROUTER_GPT56_PROMO = false;

export const OPENROUTER_GPT56_PROMO_MODEL_IDS = [
'openai/gpt-5.6-terra',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,16 @@ describe('OpenRouter GPT-5.6 promotion', () => {
discount: 0.5,
};

it.each(OPENROUTER_GPT56_PROMO_MODEL_IDS)('preserves discounted pricing for %s', modelId => {
expect(getModelDisplayPricing(modelId, discountedPricing)).toBe(discountedPricing);
});
it.each(OPENROUTER_GPT56_PROMO_MODEL_IDS)(
'undoes discounted pricing while the promotion is disabled for %s',
modelId => {
expect(getModelDisplayPricing(modelId, discountedPricing)).toEqual({
prompt: '0.000002000000',
completion: '0.000008000000',
input_cache_read: '0.000000200000',
});
}
);

it('continues to undo endpoint discounts for other models', () => {
expect(getModelDisplayPricing('openai/gpt-5.6-sol', discountedPricing)).toEqual({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,23 +159,23 @@ describe('formatName', () => {
expect(formatName(model, NOT_PREFERRED)).toBe('OpenRouter Test Model ($$$$)');
});

it.each(OPENROUTER_GPT56_PROMO_MODEL_IDS)('prefers the 50% off marker for %s', modelId => {
it.each(OPENROUTER_GPT56_PROMO_MODEL_IDS)('does not show the disabled promo for %s', modelId => {
const recentlyCreated = Math.floor(Date.now() / 1000) - 24 * 3600;
const model = buildModel({
id: modelId,
created: recentlyCreated,
expiration_date: '2026-07-01',
pricing: { prompt: '0.00001', completion: '0', discount: 0.5 },
});
expect(formatName(model, 0)).toBe('Test Model (50% off)');
expect(formatName(model, 0)).toBe('Test Model ($$$$)');
});

it('takes the promo percentage from endpoint metadata', () => {
it('does not show the disabled promo percentage from endpoint metadata', () => {
const model = buildModel({
id: OPENROUTER_GPT56_PROMO_MODEL_IDS[0],
pricing: { prompt: '0.00001', completion: '0', discount: 0.375 },
});
expect(formatName(model, NOT_PREFERRED)).toBe('Test Model (37.5% off)');
expect(formatName(model, NOT_PREFERRED)).toBe('Test Model ($$$$)');
});
});

Expand Down
23 changes: 1 addition & 22 deletions apps/web/src/lib/ai-gateway/providers/vercel/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import { describe, it, expect, jest } from '@jest/globals';
import { describe, it, expect } from '@jest/globals';
import {
convertProviderOptions,
getAnthropicProviderOptionsForVercel,
getVercelInferenceProvidersExcludingIgnored,
hasCompatibleVercelInferenceProvider,
passesVercelRoutingPercentage,
shouldRouteToVercel,
} from '@/lib/ai-gateway/providers/vercel';
import { getRandomNumber } from '@/lib/ai-gateway/getRandomNumber';
import type { GatewayRequest } from '@/lib/ai-gateway/providers/openrouter/types';
import { OPENROUTER_GPT56_PROMO_MODEL_IDS } from '@/lib/ai-gateway/providers/openai';

describe('getAnthropicProviderOptionsForVercel', () => {
it('maps chat completion verbosity to Anthropic effort', () => {
Expand Down Expand Up @@ -156,22 +154,3 @@ describe('passesVercelRoutingPercentage', () => {
expect(seedsInFinalBucket.some(seed => !passesVercelRoutingPercentage(seed, 99.9))).toBe(true);
});
});

describe('OpenRouter GPT-5.6 promotion', () => {
it.each(OPENROUTER_GPT56_PROMO_MODEL_IDS)('does not route %s to Vercel', async model => {
const debugSpy = jest.spyOn(console, 'debug').mockImplementation(() => {});
const request: GatewayRequest = {
kind: 'chat_completions',
body: {
model,
messages: [{ role: 'user', content: 'hello' }],
},
};

await expect(shouldRouteToVercel(model, request, 'promo-test')).resolves.toBe(false);
expect(debugSpy).toHaveBeenCalledWith(
`[shouldRouteToVercel] routing ${model} to OpenRouter for the GPT-5.6 promotion`
);
debugSpy.mockRestore();
});
});