Skip to content
Draft
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
12 changes: 8 additions & 4 deletions src/lib/providers/openrouter/inference-provider-id.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as z from 'zod';

export const OpenRouterInferenceProviderIdSchema = z.enum([
'alibaba',
'amazon-bedrock',
'anthropic',
'arcee-ai',
Expand Down Expand Up @@ -46,7 +47,7 @@ export const UserByokProviderIdSchema = VercelUserByokInferenceProviderIdSchema.

export type UserByokProviderId = z.infer<typeof UserByokProviderIdSchema>;

export const VercelNonUserByokInferenceProviderIdSchema = z.enum(['bedrock', 'vertex']);
export const VercelNonUserByokInferenceProviderIdSchema = z.enum(['alibaba', 'bedrock', 'vertex']);

export const VercelInferenceProviderIdSchema = VercelUserByokInferenceProviderIdSchema.or(
VercelNonUserByokInferenceProviderIdSchema
Expand Down Expand Up @@ -81,19 +82,22 @@ const modelPrefixToVercelInferenceProviderMapping = {
openai: VercelUserByokInferenceProviderIdSchema.enum.openai,
minimax: VercelUserByokInferenceProviderIdSchema.enum.minimax,
mistralai: VercelUserByokInferenceProviderIdSchema.enum.mistral,
qwen: VercelNonUserByokInferenceProviderIdSchema.enum.alibaba,
'x-ai': VercelUserByokInferenceProviderIdSchema.enum.xai,
'z-ai': VercelUserByokInferenceProviderIdSchema.enum.zai,
} as Record<string, VercelUserByokInferenceProviderId | undefined>;
} as Record<string, VercelInferenceProviderId | undefined>;

export function inferUserByokProviderForModel(model: string): UserByokProviderId | null {
return model.startsWith('mistralai/codestral')
? AutocompleteUserByokProviderIdSchema.enum.codestral
: inferVercelFirstPartyInferenceProviderForModel(model);
: (VercelUserByokInferenceProviderIdSchema.safeParse(
inferVercelFirstPartyInferenceProviderForModel(model)
).data ?? null);
}

export function inferVercelFirstPartyInferenceProviderForModel(
model: string
): VercelUserByokInferenceProviderId | null {
): VercelInferenceProviderId | null {
return model.startsWith('openai/gpt-oss')
? null
: (modelPrefixToVercelInferenceProviderMapping[model.split('/')[0]] ?? null);
Expand Down
33 changes: 9 additions & 24 deletions src/lib/providers/vercel.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import type { BYOKResult } from '@/lib/byok';
import { kiloFreeModels } from '@/lib/models';
import { kiloFreeModels, preferredModels } from '@/lib/models';
import { isAnthropicModel } from '@/lib/providers/anthropic';
import { getGatewayErrorRate } from '@/lib/providers/gateway-error-rate';
import { minimax_m25_free_model } from '@/lib/providers/minimax';
import {
AutocompleteUserByokProviderIdSchema,
inferVercelFirstPartyInferenceProviderForModel,
Expand All @@ -15,7 +14,6 @@ import type {
VercelInferenceProviderConfig,
VercelProviderConfig,
} from '@/lib/providers/openrouter/types';
import { zai_glm5_free_model } from '@/lib/providers/zai';
import * as crypto from 'crypto';

// EMERGENCY SWITCH
Expand All @@ -24,22 +22,6 @@ import * as crypto from 'crypto';
// Only use when OpenRouter is down and automatic failover is not working adequately.
const ENABLE_UNIVERSAL_VERCEL_ROUTING = false;

const VERCEL_ROUTING_ALLOW_LIST = [
'arcee-ai/trinity-large-preview:free',
'google/gemini-3-pro-preview',
'google/gemini-3-flash-preview',
'minimax/minimax-m2.1',
minimax_m25_free_model.public_id,
'minimax/minimax-m2.5',
'openai/gpt-5.2',
'openai/gpt-5.2-codex',
'x-ai/grok-code-fast-1',
'z-ai/glm-4.7',
zai_glm5_free_model.public_id,
'z-ai/glm-5',
// TODO: test and add anthropic, kat-coder, kimi, mistral, qwen models
];

const ERROR_RATE_THRESHOLD = 0.5;

function getRandomNumberLessThan100(randomSeed: string) {
Expand Down Expand Up @@ -77,13 +59,18 @@ export async function shouldRouteToVercel(
return false;
}

if (ENABLE_UNIVERSAL_VERCEL_ROUTING && isOpenRouterModel(requestedModel)) {
if (!isOpenRouterModel(requestedModel)) {
console.debug(`[shouldRouteToVercel] model not available on the gateways`);
return false;
}

if (ENABLE_UNIVERSAL_VERCEL_ROUTING) {
console.debug(`[shouldRouteToVercel] universal Vercel routing is enabled`);
return true;
}

if (!VERCEL_ROUTING_ALLOW_LIST.includes(requestedModel)) {
console.debug(`[shouldRouteToVercel] model not on the allow list for Vercel routing`);
if (!preferredModels.includes(requestedModel)) {
console.debug(`[shouldRouteToVercel] only recommended models are tested for Vercel routing`);
return false;
}

Expand All @@ -108,10 +95,8 @@ function convertProviderOptions(

const vercelModelIdMapping = {
'arcee-ai/trinity-large-preview:free': 'arcee-ai/trinity-large-preview',
'google/gemini-3-flash-preview': 'google/gemini-3-flash',
'mistralai/codestral-2508': 'mistral/codestral',
'mistralai/devstral-2512': 'mistral/devstral-2',
'mistralai/devstral-2512:free': 'mistral/devstral-2',
} as Record<string, string>;

export function applyVercelSettings(
Expand Down