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.
This commit is contained in:
1 parent
e2cc7e1c26
commit
c6df5d350f
1 file changed
+13
@@ -478,6 +478,7 @@ interface Props {
|
|||||||
try {
|
try {
|
||||||
const chunk = JSON.parse(data);
|
const chunk = JSON.parse(data);
|
||||||
const delta = chunk.choices?.[0]?.delta?.content;
|
const delta = chunk.choices?.[0]?.delta?.content;
|
||||||
|
const finishReason = chunk.choices?.[0]?.finish_reason;
|
||||||
if (typeof delta === "string") {
|
if (typeof delta === "string") {
|
||||||
const sanitizedDelta = sanitizeMessageText(delta);
|
const sanitizedDelta = sanitizeMessageText(delta);
|
||||||
tokenCount++;
|
tokenCount++;
|
||||||
@@ -485,12 +486,24 @@ interface Props {
|
|||||||
fullContent += sanitizedDelta.text;
|
fullContent += sanitizedDelta.text;
|
||||||
streamContentAccRef.current = fullContent;
|
streamContentAccRef.current = fullContent;
|
||||||
}
|
}
|
||||||
|
if (finishReason) {
|
||||||
|
const parsed = parseAssistantResponse(fullContent);
|
||||||
|
setStreamContent(parsed.content);
|
||||||
|
setStreamReasoning(parsed.reasoning);
|
||||||
|
setStreamThinkingOpen(parsed.thinkingOpen);
|
||||||
|
}
|
||||||
if (chunk.usage) usage = chunk.usage;
|
if (chunk.usage) usage = chunk.usage;
|
||||||
} catch (chunkErr) {
|
} catch (chunkErr) {
|
||||||
devLog.logStreamChunk(line, null, null, `Parse error: ${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 {
|
} else {
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
const rawNonStream = data.choices?.[0]?.message?.content || "";
|
const rawNonStream = data.choices?.[0]?.message?.content || "";
|
||||||
|
|||||||
Reference in new issue
Block a user