diff --git a/apps/web/src/app/api/openrouter/models/[provider]/[model]/endpoints/route.test.ts b/apps/web/src/app/api/openrouter/models/[provider]/[model]/endpoints/route.test.ts index f74394e1b3..3ad812c24e 100644 --- a/apps/web/src/app/api/openrouter/models/[provider]/[model]/endpoints/route.test.ts +++ b/apps/web/src/app/api/openrouter/models/[provider]/[model]/endpoints/route.test.ts @@ -89,10 +89,10 @@ describe('GET /api/openrouter/models/[provider]/[model]/endpoints', () => { test('returns 404 for unavailable models without reading cached metadata', async () => { mockedGetOpenRouterModelsMetadataFromDatabase.mockClear(); - const modelId = 'openai/gpt-oss-20b:free'; + const modelId = 'google/gemma-4-31b-it:free'; const response = await GET(request(modelId), { - params: Promise.resolve({ provider: 'openai', model: 'gpt-oss-20b:free' }), + params: Promise.resolve({ provider: 'google', model: 'gemma-4-31b-it:free' }), }); expect(response.status).toBe(404); diff --git a/apps/web/src/lib/ai-gateway/providers/openrouter/free-endpoint-data-policy.test.ts b/apps/web/src/lib/ai-gateway/providers/openrouter/free-endpoint-data-policy.test.ts index a6982da457..6a0ccc4854 100644 --- a/apps/web/src/lib/ai-gateway/providers/openrouter/free-endpoint-data-policy.test.ts +++ b/apps/web/src/lib/ai-gateway/providers/openrouter/free-endpoint-data-policy.test.ts @@ -217,14 +217,14 @@ describe('applyFreeEndpointDataPolicy', () => { }); test('ignores unavailable OpenRouter and exclusive free models', () => { - const freeVariant = offering('openai/gpt-oss-20b', true); - const model = offering('openai/gpt-oss-20b'); + const freeVariant = offering('google/gemma-4-31b-it', true); + const model = offering('google/gemma-4-31b-it'); const providerModelData = [{ provider: { slug: 'darkbloom' }, models: [freeVariant, model] }]; applyFreeEndpointDataPolicy({ providerModelData, openRouterFreeEndpoints: getOpenRouterFreeEndpoints(providerModelData), - kiloExclusiveModels: [freeExclusiveModel('openai/gpt-oss-20b:free', [])], + kiloExclusiveModels: [freeExclusiveModel('google/gemma-4-31b-it:free', [])], }); expect(freeVariant.endpoint?.data_policy).toEqual({ training: false, retainsPrompts: false }); diff --git a/apps/web/src/lib/ai-gateway/unavailable-models.test.ts b/apps/web/src/lib/ai-gateway/unavailable-models.test.ts index 0b152a4270..de3c08b1a6 100644 --- a/apps/web/src/lib/ai-gateway/unavailable-models.test.ts +++ b/apps/web/src/lib/ai-gateway/unavailable-models.test.ts @@ -6,19 +6,30 @@ import { describe('unavailable models', () => { test('keeps exact matching for request rejection', () => { - expect(isUnavailableModel('openai/gpt-oss-20b:free')).toBe(true); + expect(isUnavailableModel('google/gemma-4-26b-a4b-it:free')).toBe(true); expect(isUnavailableModel('sakana/fugu-ultra')).toBe(false); expect(isUnavailableModel('google/gemma-4-31b-it:free')).toBe(true); - expect(isUnavailableModel('openai/gpt-oss-20b')).toBe(false); - expect(isUnavailableModel('tencent/hy3:free')).toBe(true); - expect(isUnavailableModel('tencent/hy3')).toBe(false); + expect(isUnavailableModel('google/gemma-4-26b-a4b-it')).toBe(false); + expect(isUnavailableModel('z-ai/glm-5.2:free')).toBe(true); + expect(isUnavailableModel('z-ai/glm-5.2')).toBe(false); }); test('matches normalized families for provider metadata', () => { - expect(familyHasUnavailableFreeModel('openai/gpt-oss-20b:free')).toBe(true); - expect(familyHasUnavailableFreeModel('openai/gpt-oss-20b')).toBe(true); + expect(familyHasUnavailableFreeModel('google/gemma-4-26b-a4b-it:free')).toBe(true); + expect(familyHasUnavailableFreeModel('google/gemma-4-26b-a4b-it')).toBe(true); expect(familyHasUnavailableFreeModel('cohere/north-mini-code')).toBe(false); - expect(familyHasUnavailableFreeModel('tencent/hy3:free')).toBe(true); - expect(familyHasUnavailableFreeModel('tencent/hy3')).toBe(true); + expect(familyHasUnavailableFreeModel('z-ai/glm-5.2:free')).toBe(true); + expect(familyHasUnavailableFreeModel('z-ai/glm-5.2')).toBe(true); + }); + + test.each([ + 'nvidia/nemotron-3-nano-30b-a3b:free', + 'nvidia/nemotron-nano-12b-v2-vl:free', + 'nvidia/nemotron-nano-9b-v2:free', + 'openai/gpt-oss-20b:free', + 'tencent/hy3:free', + ])('does not explicitly block delisted model %s', modelId => { + expect(isUnavailableModel(modelId)).toBe(false); + expect(familyHasUnavailableFreeModel(modelId)).toBe(false); }); }); diff --git a/apps/web/src/lib/ai-gateway/unavailable-models.ts b/apps/web/src/lib/ai-gateway/unavailable-models.ts index c8a465fbee..78eccef008 100644 --- a/apps/web/src/lib/ai-gateway/unavailable-models.ts +++ b/apps/web/src/lib/ai-gateway/unavailable-models.ts @@ -3,11 +3,6 @@ import { normalizeModelId } from '@/lib/ai-gateway/model-utils'; const unavailableModelIds: ReadonlySet = new Set([ 'google/gemma-4-26b-a4b-it:free', // usable through kilo-auto 'google/gemma-4-31b-it:free', - 'nvidia/nemotron-3-nano-30b-a3b:free', - 'nvidia/nemotron-nano-12b-v2-vl:free', - 'nvidia/nemotron-nano-9b-v2:free', - 'openai/gpt-oss-20b:free', - 'tencent/hy3:free', 'z-ai/glm-5.2:free', ]);