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..a8b81f8755 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]) => ({
@@ -92,6 +92,9 @@ const DIRECT_BYOK_PROVIDERS_LIST = Object.entries(DIRECT_BYOK_PROVIDERS_META).ma
const BYOK_PROVIDERS = [...DIRECT_BYOK_PROVIDERS_LIST, ...VERCEL_BYOK_PROVIDERS].toSorted((a, b) =>
a.name.localeCompare(b.name)
);
+const ADD_BYOK_PROVIDERS = BYOK_PROVIDERS.filter(
+ provider => provider.id !== DirectUserByokInferenceProviderIdSchema.enum.codestral
+);
function BYOKDescription({ showsCodingPlanKey = false }: { showsCodingPlanKey?: boolean }) {
return (
@@ -604,7 +607,7 @@ export function BYOKKeysManager({ organizationId }: BYOKKeysManagerProps) {
- {BYOK_PROVIDERS.map(provider => {
+ {(editingKeyId ? BYOK_PROVIDERS : ADD_BYOK_PROVIDERS).map(provider => {
const isDisabled = !editingKeyId && hasExistingKey(provider.id);
return (
{
- 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(