From b3b90834ea163c74b004635ac7715025ff6bb2e4 Mon Sep 17 00:00:00 2001 From: dolphin Date: Mon, 3 Aug 2026 20:48:19 +0800 Subject: [PATCH] fix(chat): render a throttled file-parse failure as the red card MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The busy notice offered a Retry button, but the turn is already lost by then — the attachment never made it into the prompt, so retrying just re-runs against the same throttled OCR service. Route `file_parse_busy` to the red failure card like every other terminal outcome; it keeps its own "service is busy" wording and the "view details" disclosure, and the user re-sends from the input box. Model-side throttling (12046) is untouched and still gets the calm notice. --- src/frontend/client/src/components/ChatErrorCard.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/frontend/client/src/components/ChatErrorCard.tsx b/src/frontend/client/src/components/ChatErrorCard.tsx index e43ded385..0b9094c55 100644 --- a/src/frontend/client/src/components/ChatErrorCard.tsx +++ b/src/frontend/client/src/components/ChatErrorCard.tsx @@ -52,11 +52,15 @@ const KNOWN_TYPES = new Set([ // they get the calm neutral ServiceBusyNotice (+ optional retry) rather than the red // failure card — a rate limit is the model vendor's availability blip, not a fault. // Mirrors the classifier's RETRYABLE bucket. +// +// `file_parse_busy` is deliberately NOT here despite being recoverable: the turn is +// already lost (the attachment never made it into the prompt), so a Retry button +// would re-run against the same throttled service. It keeps its own "busy" wording +// but renders as the red card, and the user re-sends from the input box. const TRANSIENT_TYPES = new Set([ 'rate_limit', 'network_timeout', 'service_unavailable', - 'file_parse_busy', ]); /** Would this failure render as the calm busy notice rather than the red card?