From ec646ed7b1b016de785eefee724e51f4c9690a07 Mon Sep 17 00:00:00 2001 From: Tofik Hasanov Date: Sun, 26 Jul 2026 17:59:36 -0400 Subject: [PATCH] fix(app): use the GA gemini-3.1-flash-lite slug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `google/gemini-3.1-flash-lite-preview` no longer exists: the AI Gateway retires `-preview` aliases when a model goes GA. Two paths referenced it. rerank-suggestions.ts calls the gateway directly for risk/vendor -> task auto-link reranking. Both callers in run-linkage.ts catch the 404 and fall back to raw cosine, so the breakage was silent — suggestions quietly regressed to the pre-reranker precision this module exists to fix. Added a regression test asserting the requested slug is GA, not a preview alias. The automation chat `modelId` values are inert (the enterprise-api chat route hardcodes its own model and ignores the body field), but they are updated so the two repos do not disagree on which model is in use. --- .../workflow/workflow-visualizer-simple.tsx | 2 +- .../[automationId]/hooks/use-chat-handlers.ts | 6 +++--- apps/app/src/lib/rerank-suggestions.spec.ts | 16 ++++++++++++++++ apps/app/src/lib/rerank-suggestions.ts | 7 ++++++- 4 files changed, 26 insertions(+), 5 deletions(-) diff --git a/apps/app/src/app/(app)/[orgId]/tasks/[taskId]/automation/[automationId]/components/workflow/workflow-visualizer-simple.tsx b/apps/app/src/app/(app)/[orgId]/tasks/[taskId]/automation/[automationId]/components/workflow/workflow-visualizer-simple.tsx index f3ee55700e..773ecd5f9a 100644 --- a/apps/app/src/app/(app)/[orgId]/tasks/[taskId]/automation/[automationId]/components/workflow/workflow-visualizer-simple.tsx +++ b/apps/app/src/app/(app)/[orgId]/tasks/[taskId]/automation/[automationId]/components/workflow/workflow-visualizer-simple.tsx @@ -229,7 +229,7 @@ Please fix the automation script to resolve this error.`; { text: errorMessage }, { body: { - modelId: 'google/gemini-3.1-flash-lite-preview', + modelId: 'google/gemini-3.1-flash-lite', reasoningEffort: 'high', orgId, taskId, diff --git a/apps/app/src/app/(app)/[orgId]/tasks/[taskId]/automation/[automationId]/hooks/use-chat-handlers.ts b/apps/app/src/app/(app)/[orgId]/tasks/[taskId]/automation/[automationId]/hooks/use-chat-handlers.ts index 8b71aeda6b..f4e282864a 100644 --- a/apps/app/src/app/(app)/[orgId]/tasks/[taskId]/automation/[automationId]/hooks/use-chat-handlers.ts +++ b/apps/app/src/app/(app)/[orgId]/tasks/[taskId]/automation/[automationId]/hooks/use-chat-handlers.ts @@ -74,7 +74,7 @@ export function useChatHandlers({ { text }, { body: { - modelId: 'google/gemini-3.1-flash-lite-preview', + modelId: 'google/gemini-3.1-flash-lite', reasoningEffort: 'high', orgId, taskId, @@ -96,7 +96,7 @@ export function useChatHandlers({ }, { body: { - modelId: 'google/gemini-3.1-flash-lite-preview', + modelId: 'google/gemini-3.1-flash-lite', reasoningEffort: 'high', orgId, taskId, @@ -120,7 +120,7 @@ export function useChatHandlers({ }, { body: { - modelId: 'google/gemini-3.1-flash-lite-preview', + modelId: 'google/gemini-3.1-flash-lite', reasoningEffort: 'high', orgId, taskId, diff --git a/apps/app/src/lib/rerank-suggestions.spec.ts b/apps/app/src/lib/rerank-suggestions.spec.ts index 0bf69a5256..ac111c3a0a 100644 --- a/apps/app/src/lib/rerank-suggestions.spec.ts +++ b/apps/app/src/lib/rerank-suggestions.spec.ts @@ -80,6 +80,22 @@ describe('rerankSuggestions', () => { expect(byId.tsk_c).toBe(0); }); + // Regression: the reranker was pinned to `google/gemini-3.1-flash-lite-preview`. The + // gateway retires `-preview` aliases on GA, so every call 404'd — and because both + // callers in run-linkage.ts catch and fall back to cosine, nothing surfaced the failure. + it('requests a GA model slug, never a -preview alias', async () => { + generateObjectMock.mockResolvedValueOnce({ object: { scores: [] } }); + + await rerankSuggestions({ + source: { kind: 'risk', title: 't', description: 'd' }, + candidates: [{ id: 'tsk_a', title: 'A', description: 'a', cosineScore: 0.5 }], + }); + + const { model } = generateObjectMock.mock.calls[0][0]; + expect(model.modelId).toBe('google/gemini-3.1-flash-lite'); + expect(model.modelId).not.toMatch(/-preview$/); + }); + it('assigns 0 to candidates the LLM omits', async () => { generateObjectMock.mockResolvedValueOnce({ object: { scores: [{ id: 'tsk_a', score: 8 }] }, diff --git a/apps/app/src/lib/rerank-suggestions.ts b/apps/app/src/lib/rerank-suggestions.ts index f9cd37692c..98542fd2fa 100644 --- a/apps/app/src/lib/rerank-suggestions.ts +++ b/apps/app/src/lib/rerank-suggestions.ts @@ -43,7 +43,12 @@ const gateway = createGatewayProvider({ baseURL: process.env.AI_GATEWAY_BASE_URL, }); -const RERANK_MODEL = 'google/gemini-3.1-flash-lite-preview' as const; +/** + * GA slug. Never pin a `-preview` alias here: the gateway retires it once the model + * goes GA, and every rerank call then 404s. Both callers in `run-linkage.ts` swallow that + * into a cosine-only fallback, so the failure is silent — suggestion quality just degrades. + */ +const RERANK_MODEL = 'google/gemini-3.1-flash-lite' as const; const SYSTEM_PROMPT = `You are a GRC analyst evaluating which compliance tasks would meaningfully reduce a specific risk or vendor exposure.