From bf29ab1e0e01370c3b94de85ddb1814b03651e92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Fri, 26 Jun 2026 09:30:08 +0200 Subject: [PATCH] fix(insights): cancel the Coach tool-loop provider calls on disconnect Thread the request abort signal through runCoachToolLoop into each per-round completion so a mid-generation client disconnect tears down the upstream call instead of paying the full token cost. Completes the no-tools-path wiring to cover the tool-retrieval path as well. Regenerate the OpenAPI spec for the trimmed OCR-capability reason enum. --- docs/api/openapi.yaml | 1 - src/app/api/insights/chat/route.ts | 3 +++ src/lib/ai/coach/tools/loop.ts | 4 ++++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/api/openapi.yaml b/docs/api/openapi.yaml index befef0a1b..a4e4dbcec 100644 --- a/docs/api/openapi.yaml +++ b/docs/api/openapi.yaml @@ -19630,7 +19630,6 @@ components: - type: string enum: - no-provider - - text-only-model - enable-local-ocr - type: "null" pdfSupported: diff --git a/src/app/api/insights/chat/route.ts b/src/app/api/insights/chat/route.ts index f418a1c7e..341476274 100644 --- a/src/app/api/insights/chat/route.ts +++ b/src/app/api/insights/chat/route.ts @@ -549,6 +549,9 @@ Reply now as the assistant, in ${locale === "de" ? "German" : "English"}. Fetch temperature: AI_BUDGETS.coach.temperature, maxTokens: AI_BUDGETS.coach.maxTokens, fallbackWindow: effectiveScope?.window, + // v1.20.1 — thread the abort signal so a mid-generation disconnect tears + // down the per-round provider calls instead of paying the full cost. + signal: request.signal, }); result = loop.result; workingProviderType = loop.workingProviderType; diff --git a/src/lib/ai/coach/tools/loop.ts b/src/lib/ai/coach/tools/loop.ts index 216c29b96..1f0dfb1d6 100644 --- a/src/lib/ai/coach/tools/loop.ts +++ b/src/lib/ai/coach/tools/loop.ts @@ -58,6 +58,8 @@ export async function runCoachToolLoop(args: { maxTokens?: number; fallbackWindow?: CoachScopeWindow; ledger?: ProviderHealthLedger; + /** Aborts the per-round provider calls on client disconnect. */ + signal?: AbortSignal; }): Promise { const { userId, @@ -68,6 +70,7 @@ export async function runCoachToolLoop(args: { maxTokens, fallbackWindow, ledger, + signal, } = args; const messages: AiMessage[] = [...args.messages]; @@ -92,6 +95,7 @@ export async function runCoachToolLoop(args: { messages, temperature, maxTokens, + signal, ...(offerTools ? { tools, toolChoice: "auto" as const } : { toolChoice: "none" as const }),