Skip to content

Commit a320291

Browse files
fix(byok): skip Vercel BYOK for Kilo-exclusive models (#3001)
* feat(byok): exclude Kilo-exclusive models from user BYOK Kilo-exclusive models must always be served through Kilo's own providers and never through a user's BYOK key. This change: - Adds isKiloExclusiveModel helper - Skips BYOK lookup (direct and Vercel) in getProvider for Kilo-exclusive models - Filters Kilo-exclusive models out of the listSupportedModels response used by the BYOK selection screen * refactor(byok): only skip Vercel BYOK for Kilo-exclusive models Direct BYOK is unaffected — it targets dedicated OpenAI-compatible providers by model ID prefix and does not overlap with Kilo-exclusive models. Expanded the comment to explain why Vercel is incompatible: the Vercel AI Gateway speaks upstream-native API shapes, whereas Kilo-exclusive models live behind generic OpenAI-compatible endpoints with our own request/response transforms. * refactor(byok): move Kilo-exclusive check into checkVercelBYOK Pushes the filter down to where it belongs and clarifies that the core incompatibility is reasoning: the Vercel AI Gateway normalizes reasoning to upstream-native shapes, whereas Kilo-exclusive models go through generic OpenAI-compatible endpoints with transforms we apply ourselves. * fix(byok): exclude disabled models from isKiloExclusiveModel Matches the convention used by findKiloExclusiveModel and isKiloExclusiveFreeModel: disabled exclusive models shouldn't be treated as Kilo-exclusive for routing/filtering purposes. * docs(byok): drop 'transforms we apply ourselves' from comment --------- Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
1 parent f0649ef commit a320291

3 files changed

Lines changed: 14 additions & 1 deletion

File tree

apps/web/src/lib/ai-gateway/models.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ export function isKiloExclusiveFreeModel(model: string): boolean {
8282
);
8383
}
8484

85+
export function isKiloExclusiveModel(model: string): boolean {
86+
return kiloExclusiveModels.some(m => m.public_id === model && m.status !== 'disabled');
87+
}
88+
8589
export const kiloExclusiveModels = [
8690
gemma_4_26b_a4b_it_free_model,
8791
minimax_m25_free_model,

apps/web/src/lib/ai-gateway/providers/get-provider.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { GatewayRequest } from '@/lib/ai-gateway/providers/openrouter/types';
22
import { shouldRouteToVercel } from '@/lib/ai-gateway/providers/vercel';
3-
import { kiloExclusiveModels } from '@/lib/ai-gateway/models';
3+
import { isKiloExclusiveModel, kiloExclusiveModels } from '@/lib/ai-gateway/models';
44
import {
55
getBYOKforOrganization,
66
getBYOKforUser,
@@ -132,6 +132,13 @@ async function checkVercelBYOK(
132132
organizationId: string | undefined
133133
): Promise<BYOKResult[] | null> {
134134
if (isAnonymousContext(user)) return null;
135+
// Kilo-exclusive models are not routable through Vercel BYOK. Reasoning in particular
136+
// breaks: the Vercel AI Gateway normalizes reasoning to each provider's upstream-native
137+
// shape, whereas our Kilo-exclusive models are served through generic OpenAI-compatible
138+
// endpoints (Martian, direct Alibaba, etc.) where that normalization doesn't apply and the
139+
// response ends up corrupted. Skip the Vercel BYOK lookup entirely and let the caller fall
140+
// through to the model's declared gateway.
141+
if (isKiloExclusiveModel(requestedModel)) return null;
135142
const modelProviders = await getModelUserByokProviders(requestedModel);
136143
if (modelProviders.length === 0) return null;
137144
return organizationId

apps/web/src/routers/byok-router.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import { decryptByokRow } from '@/lib/ai-gateway/byok';
3434
import type { GatewayProviderOptions } from '@ai-sdk/gateway';
3535
import { mapModelIdToVercel } from '@/lib/ai-gateway/providers/vercel/mapModelIdToVercel';
3636
import { isCodestralModel } from '@/lib/ai-gateway/providers/mistral';
37+
import { isKiloExclusiveModel } from '@/lib/ai-gateway/models';
3738
import DIRECT_BYOK_PROVIDERS from '@/lib/ai-gateway/providers/direct-byok/direct-byok-definitions';
3839
import {
3940
createAiSdkProvider,
@@ -106,6 +107,7 @@ async function fetchSupportedModels(): Promise<Record<string, string[]>> {
106107
result['codestral'] = ['Codestral (mistralai/codestral-2508)'];
107108

108109
for (const openRouterModel of Object.values(openRouterModelMetadata)) {
110+
if (isKiloExclusiveModel(openRouterModel.id)) continue;
109111
const vercelModel = vercelModelMetadata[mapModelIdToVercel(openRouterModel.id, false)];
110112
if (!vercelModel) continue;
111113
if (isCodestralModel(vercelModel.id)) continue;

0 commit comments

Comments
 (0)