From 7022b698e70829ca7c93df421af237b338ed3dff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Sat, 3 Oct 2026 18:04:09 +0200 Subject: [PATCH] fix(ai): forget the remembered working provider when the chain is saved The in-memory memo of the last provider that answered reorders the chain for up to an hour. Saving a new chain now drops it for that account, so a provider the person removed or disabled no longer leads the chain they just arranged. --- .../api/insights/provider-chain/__tests__/put.test.ts | 9 +++++++++ .../api/insights/provider-chain/__tests__/route.test.ts | 1 + src/app/api/insights/provider-chain/route.ts | 6 +++++- src/lib/ai/provider-runner.ts | 9 +++++++++ 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/app/api/insights/provider-chain/__tests__/put.test.ts b/src/app/api/insights/provider-chain/__tests__/put.test.ts index 7721d1d46..510fa5fe7 100644 --- a/src/app/api/insights/provider-chain/__tests__/put.test.ts +++ b/src/app/api/insights/provider-chain/__tests__/put.test.ts @@ -61,8 +61,14 @@ vi.mock("@/lib/logging/context", () => ({ annotate: vi.fn(), })); +vi.mock("@/lib/ai/provider-runner", () => ({ + getLastWorkingProvider: vi.fn(), + forgetLastWorkingProvider: vi.fn(), +})); + import { PUT } from "../route"; import { prisma } from "@/lib/db"; +import { forgetLastWorkingProvider } from "@/lib/ai/provider-runner"; import { annotate } from "@/lib/logging/context"; interface Envelope { @@ -108,6 +114,9 @@ describe("PUT /api/insights/provider-chain", () => { ], }); expect(annotate).toHaveBeenCalled(); + // The remembered working provider would reorder the chain the person + // just arranged; a save drops it for this account. + expect(forgetLastWorkingProvider).toHaveBeenCalledWith("u-1"); }); it("rejects unknown provider types with 422", async () => { diff --git a/src/app/api/insights/provider-chain/__tests__/route.test.ts b/src/app/api/insights/provider-chain/__tests__/route.test.ts index fff8209ea..efb66afab 100644 --- a/src/app/api/insights/provider-chain/__tests__/route.test.ts +++ b/src/app/api/insights/provider-chain/__tests__/route.test.ts @@ -30,6 +30,7 @@ vi.mock("@/lib/ai/provider", () => ({ vi.mock("@/lib/ai/provider-runner", () => ({ getLastWorkingProvider: vi.fn(), + forgetLastWorkingProvider: vi.fn(), })); vi.mock("@/lib/logging/context", () => ({ diff --git a/src/app/api/insights/provider-chain/route.ts b/src/app/api/insights/provider-chain/route.ts index b5afc4379..8ea535990 100644 --- a/src/app/api/insights/provider-chain/route.ts +++ b/src/app/api/insights/provider-chain/route.ts @@ -10,7 +10,10 @@ import { } from "@/lib/api-response"; import { annotate } from "@/lib/logging/context"; import { resolveProviderChain } from "@/lib/ai/provider"; -import { getLastWorkingProvider } from "@/lib/ai/provider-runner"; +import { + forgetLastWorkingProvider, + getLastWorkingProvider, +} from "@/lib/ai/provider-runner"; import { prisma } from "@/lib/db"; import { parseProviderChain, @@ -149,6 +152,7 @@ export const PUT = apiHandler(async (request: NextRequest) => { where: { id: user.id }, data: { aiProviderChain: normalised }, }); + forgetLastWorkingProvider(user.id); annotate({ meta: { diff --git a/src/lib/ai/provider-runner.ts b/src/lib/ai/provider-runner.ts index 37270e54f..7bf914106 100644 --- a/src/lib/ai/provider-runner.ts +++ b/src/lib/ai/provider-runner.ts @@ -98,6 +98,15 @@ export function getLastWorkingProvider( return entry.providerType; } +/** + * Drop one user's "last working provider" memo. Called when the person saves + * a new chain: the memo reorders the chain they just arranged, and a provider + * they removed or disabled must not keep leading it for up to an hour. + */ +export function forgetLastWorkingProvider(userId: string): void { + lastWorkingCache.delete(userId); +} + function rememberWorkingProvider( userId: string, providerType: ProviderChainType,