From c6df5d350fd1a4e42956e9777ae9d785a0292cf5 Mon Sep 17 00:00:00 2001 From: Evandro Fonseca Junior Date: Sat, 4 Apr 2026 02:31:40 -0300 Subject: [PATCH] fix(ui): prevent UI from dropping partial chunks during stream tail parsing Added a catch-all parsing step at the very end of the streaming loop, and within the flushed chunk loop, so any straggler text that wasn't accompanied by a finish_reason chunk or was buffered in streamDecoder.flush() is properly parsed into visible content before the DB insert. --- tauri-app/src/components/ChatView.tsx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tauri-app/src/components/ChatView.tsx b/tauri-app/src/components/ChatView.tsx index 9cd20e2..e455a5b 100644 --- a/tauri-app/src/components/ChatView.tsx +++ b/tauri-app/src/components/ChatView.tsx @@ -478,6 +478,7 @@ interface Props { try { const chunk = JSON.parse(data); const delta = chunk.choices?.[0]?.delta?.content; + const finishReason = chunk.choices?.[0]?.finish_reason; if (typeof delta === "string") { const sanitizedDelta = sanitizeMessageText(delta); tokenCount++; @@ -485,12 +486,24 @@ interface Props { fullContent += sanitizedDelta.text; streamContentAccRef.current = fullContent; } + if (finishReason) { + const parsed = parseAssistantResponse(fullContent); + setStreamContent(parsed.content); + setStreamReasoning(parsed.reasoning); + setStreamThinkingOpen(parsed.thinkingOpen); + } if (chunk.usage) usage = chunk.usage; } catch (chunkErr) { devLog.logStreamChunk(line, null, null, `Parse error: ${chunkErr}`); } } } + + // Final safety parsing step to ensure UI states match DB right before saving + const parsed = parseAssistantResponse(fullContent); + setStreamContent(parsed.content); + setStreamReasoning(parsed.reasoning); + setStreamThinkingOpen(parsed.thinkingOpen); } else { const data = await res.json(); const rawNonStream = data.choices?.[0]?.message?.content || "";