diff --git a/apps/web/src/app/api/openrouter/[...path]/route.test.ts b/apps/web/src/app/api/openrouter/[...path]/route.test.ts index 70e5a61990..3d65029d8b 100644 --- a/apps/web/src/app/api/openrouter/[...path]/route.test.ts +++ b/apps/web/src/app/api/openrouter/[...path]/route.test.ts @@ -784,21 +784,22 @@ describe('POST /api/openrouter/v1/chat/completions rules-engine actions', () => expect(mockedUpstreamRequest).not.toHaveBeenCalled(); }); - it.each(['google/gemma-4-26b-a4b-it:free', 'google/gemma-4-31b-it:free'])( - 'rejects the unavailable free model %s before upstream', - async modelId => { - mockedCheckFreeModelRateLimit.mockResolvedValue({ allowed: true, requestCount: 0 }); + it.each([ + 'google/gemma-4-26b-a4b-it:free', + 'google/gemma-4-31b-it:free', + 'thinkingmachines/inkling:free', + ])('rejects the unavailable free model %s before upstream', async modelId => { + mockedCheckFreeModelRateLimit.mockResolvedValue({ allowed: true, requestCount: 0 }); - const { POST } = await import('./route'); - const response = await POST(makeRequest(makeBody(modelId)) as never); + const { POST } = await import('./route'); + const response = await POST(makeRequest(makeBody(modelId)) as never); - expect(response.status).toBe(404); - expect(await response.json()).toMatchObject({ - error_type: 'unavailable_model', - }); - expect(mockedUpstreamRequest).not.toHaveBeenCalled(); - } - ); + expect(response.status).toBe(404); + expect(await response.json()).toMatchObject({ + error_type: 'unavailable_model', + }); + expect(mockedUpstreamRequest).not.toHaveBeenCalled(); + }); it('rate limits rules-engine rate-limit actions before upstream', async () => { mockedRedisGet.mockResolvedValue(cachedRulesEngineAction('rate-limit')); diff --git a/apps/web/src/lib/ai-gateway/unavailable-models.ts b/apps/web/src/lib/ai-gateway/unavailable-models.ts index aaf91676aa..917adadbe0 100644 --- a/apps/web/src/lib/ai-gateway/unavailable-models.ts +++ b/apps/web/src/lib/ai-gateway/unavailable-models.ts @@ -3,6 +3,7 @@ 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', + 'thinkingmachines/inkling:free', ]); export function isUnavailableModel(modelId: string): boolean { diff --git a/apps/web/src/tests/openrouter-models.test.ts b/apps/web/src/tests/openrouter-models.test.ts index 95bbbb9437..724037d5ac 100644 --- a/apps/web/src/tests/openrouter-models.test.ts +++ b/apps/web/src/tests/openrouter-models.test.ts @@ -283,14 +283,18 @@ describe('GET /api/openrouter/models', () => { expect(Array.isArray(responseData.data)).toBe(true); }); - test('excludes unavailable free Gemma models advertised upstream while retaining paid Gemma', async () => { + test('excludes unavailable free models advertised upstream while retaining paid Gemma', async () => { const original = mockOpenRouterModels.data.find(model => model.id === 'some-other-model'); if (!original) throw new Error('Expected catalog fixture'); const upstream = { data: [ ...mockOpenRouterModels.data, { ...original, id: 'google/gemma-4-31b-it', name: 'Google: Gemma 4 31B IT' }, - ...['google/gemma-4-26b-a4b-it:free', 'google/gemma-4-31b-it:free'].map(id => ({ + ...[ + 'google/gemma-4-26b-a4b-it:free', + 'google/gemma-4-31b-it:free', + 'thinkingmachines/inkling:free', + ].map(id => ({ ...original, id, name: id, @@ -310,6 +314,7 @@ describe('GET /api/openrouter/models', () => { expect(response.status).toBe(200); expect(modelIds).not.toContain('google/gemma-4-26b-a4b-it:free'); expect(modelIds).not.toContain('google/gemma-4-31b-it:free'); + expect(modelIds).not.toContain('thinkingmachines/inkling:free'); expect(modelIds).toContain('google/gemma-4-31b-it'); });