From 51964edff7a1a59d1a2059aca57b52ff8b657ab9 Mon Sep 17 00:00:00 2001 From: Alexej Wolff Date: Thu, 7 May 2026 01:01:07 +0200 Subject: [PATCH] fix: add buffer for SSE stream parsing to prevent truncated words --- src/services/deepseek.ts | 52 +++++++++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/src/services/deepseek.ts b/src/services/deepseek.ts index 945d5eb..b973906 100644 --- a/src/services/deepseek.ts +++ b/src/services/deepseek.ts @@ -112,29 +112,53 @@ export async function sendMessageStream( const decoder = new TextDecoder(); let fullContent = ""; + let buffer = ""; // Buffer for incomplete lines while (true) { const { done, value } = await reader.read(); if (done) break; - const chunk = decoder.decode(value, { stream: true }); - const lines = chunk.split("\n").filter((line) => line.trim() !== ""); + // Append new data to buffer + buffer += decoder.decode(value, { stream: true }); + + // Process complete lines only + const lines = buffer.split("\n"); + // Keep last incomplete line in buffer + buffer = lines.pop() || ""; for (const line of lines) { - if (line.startsWith("data: ")) { - const data = line.slice(6); - if (data === "[DONE]") continue; + const trimmed = line.trim(); + if (!trimmed || !trimmed.startsWith("data: ")) continue; + + const data = trimmed.slice(6); + if (data === "[DONE]") continue; - try { - const parsed = JSON.parse(data); - const content = parsed.choices?.[0]?.delta?.content || ""; - if (content) { - fullContent += content; - onChunk(content); - } - } catch { - // Ignore parse errors + try { + const parsed = JSON.parse(data); + const content = parsed.choices?.[0]?.delta?.content || ""; + if (content) { + fullContent += content; + onChunk(content); } + } catch { + // Incomplete JSON - will be handled in next chunk + } + } + } + + // Process any remaining buffer + if (buffer.trim().startsWith("data: ")) { + const data = buffer.trim().slice(6); + if (data !== "[DONE]") { + try { + const parsed = JSON.parse(data); + const content = parsed.choices?.[0]?.delta?.content || ""; + if (content) { + fullContent += content; + onChunk(content); + } + } catch { + // Ignore final parse error } } }