diff --git a/apps/web/src/app/api/fim/completions/route.ts b/apps/web/src/app/api/fim/completions/route.ts index dfb1181756..3a6e501a87 100644 --- a/apps/web/src/app/api/fim/completions/route.ts +++ b/apps/web/src/app/api/fim/completions/route.ts @@ -25,6 +25,7 @@ import { readDb } from '@/lib/drizzle'; import { debugSaveProxyRequest } from '@/lib/debugUtils'; import { sentryLogger } from '@/lib/utils.server'; import { getBYOKforOrganization, getBYOKforUser } from '@/lib/ai-gateway/byok'; +import type { UserByokProviderId } from '@/lib/ai-gateway/providers/openrouter/inference-provider-id'; // Mistral exposes FIM on two separate, key-incompatible endpoints: // - https://api.mistral.ai (La Plateforme, paid tier keys) @@ -153,11 +154,12 @@ export async function POST(request: NextRequest) { // Extract properties for usage context const promptInfo = extractFimPromptInfo(requestBody); - const byokProviderKey = fimProvider === 'mistral' ? 'codestral' : 'inception'; + const byokProviderKeys: UserByokProviderId[] = + fimProvider === 'mistral' ? ['codestral', 'mistral'] : ['inception']; const userByok = organizationId - ? await getBYOKforOrganization(readDb, organizationId, [byokProviderKey]) - : await getBYOKforUser(readDb, user.id, [byokProviderKey]); + ? await getBYOKforOrganization(readDb, organizationId, byokProviderKeys) + : await getBYOKforUser(readDb, user.id, byokProviderKeys); const usageContext: MicrodollarUsageContext = { api_kind: 'fim_completions', @@ -232,7 +234,9 @@ export async function POST(request: NextRequest) { } const systemKey = getSystemApiKey(fimProvider); - const userByokEntry = userByok?.at(0); + const userByokEntry = byokProviderKeys + .map(providerId => userByok?.find(entry => entry.providerId === providerId)) + .find(entry => entry !== undefined); const apiKey = userByokEntry?.decryptedAPIKey ?? systemKey; const upstreamUrl = resolveFimUpstreamUrl(fimProvider, userByokEntry?.providerId === 'codestral'); diff --git a/apps/web/src/components/organizations/byok/BYOKKeysManager.tsx b/apps/web/src/components/organizations/byok/BYOKKeysManager.tsx index a9ac567c38..e5d73eb24c 100644 --- a/apps/web/src/components/organizations/byok/BYOKKeysManager.tsx +++ b/apps/web/src/components/organizations/byok/BYOKKeysManager.tsx @@ -70,7 +70,7 @@ const VERCEL_BYOK_PROVIDER_NAMES = { fireworks: 'Fireworks', google: 'Google AI Studio', minimax: 'MiniMax', - mistral: 'Mistral AI (other models)', + mistral: 'Mistral AI', moonshotai: 'Moonshot AI', novita: 'Novita', perplexity: 'Perplexity', @@ -81,7 +81,7 @@ const VERCEL_BYOK_PROVIDER_NAMES = { const VERCEL_BYOK_PROVIDERS = [ ...Object.entries(VERCEL_BYOK_PROVIDER_NAMES).map(([id, name]) => ({ id, name })), - { id: DirectUserByokInferenceProviderIdSchema.enum.codestral, name: 'Mistral AI (Codestral)' }, + { id: DirectUserByokInferenceProviderIdSchema.enum.codestral, name: 'Legacy Codestral-only key' }, ]; const DIRECT_BYOK_PROVIDERS_LIST = Object.entries(DIRECT_BYOK_PROVIDERS_META).map(([id, name]) => ({ diff --git a/apps/web/src/lib/ai-gateway/byok/index.ts b/apps/web/src/lib/ai-gateway/byok/index.ts index 01b18b11b0..c2d3a15cc0 100644 --- a/apps/web/src/lib/ai-gateway/byok/index.ts +++ b/apps/web/src/lib/ai-gateway/byok/index.ts @@ -15,15 +15,12 @@ import type { BYOKResult } from '@/lib/ai-gateway/providers/types'; import { getVercelModelsMetadata } from '@/lib/ai-gateway/providers/gateway-models-cache'; export async function getModelUserByokProviders(modelId: string): Promise { - if (isCodestralModel(modelId)) { - return ['codestral']; - } const vercelModelMetadata = await getVercelModelsMetadata(); if (Object.keys(vercelModelMetadata).length === 0) { console.error('[getModelUserByokProviders] no Vercel model metadata in the database'); return []; } - const providers = + const providers: UserByokProviderId[] = vercelModelMetadata[mapModelIdToVercel(modelId, false)]?.endpoints .map(ep => VercelUserByokInferenceProviderIdSchema.safeParse(ep.provider_name ?? ep.tag).data) .filter(providerId => providerId !== undefined) ?? []; @@ -31,6 +28,9 @@ export async function getModelUserByokProviders(modelId: string): Promise> { if (isKiloExclusiveModel(openRouterModel.id)) continue; const vercelModel = vercelModelMetadata[mapModelIdToVercel(openRouterModel.id, false)]; if (!vercelModel) continue; - if (isCodestralModel(vercelModel.id)) continue; if (vercelModel.type !== 'language') continue; for (const endpoint of vercelModel.endpoints) { const providerParsed = VercelUserByokInferenceProviderIdSchema.safeParse(