feat(FN-3817): fix chat delta spacing in legacy streaming API

Fixes chat streaming delta spacing to preserve proper whitespace, adding regression tests for legacy chat stream handlers and the createChatStreamHandlers factory. A changeset was created for the `@runfusion/fusion` package.

Fusion-Task-Id: FN-3817
This commit is contained in:
Fusion
2026-05-11 00:49:25 -07:00
committed by gsxdsm
parent 1cb961becb
commit d0a7fe3667
4 changed files with 117 additions and 0 deletions

View File

@@ -139,6 +139,65 @@ describe("streamChatResponse SSE parser", () => {
expect(onError).toHaveBeenCalledWith("Timed out waiting for first response event");
vi.useRealTimers();
});
it.each([
{
name: "leading-space second delta",
chunks: [
"event: text\n",
"data: \"Hello.\"\n\n",
"event: text\n",
"data: \" World.\"\n\n",
],
},
{
name: "space-trailing first delta",
chunks: [
"event: text\n",
"data: \"Hello. \"\n\n",
"event: text\n",
"data: \"World.\"\n\n",
],
},
{
name: "empty delta between spaced chunks",
chunks: [
"event: text\n",
"data: \"Hello.\"\n\n",
"event: text\n",
"data: \"\"\n\n",
"event: text\n",
"data: \" World.\"\n\n",
],
},
{
name: "chunk boundary mid-json of second delta",
chunks: [
"event: text\ndata: \"Hello.\"\n\nevent: text\ndata: \"",
" World.\"\n\n",
],
},
{
name: "chunk boundary inside leading space on data line",
chunks: [
"event: text\ndata: \"Hello.\"\n\nevent: text\ndata: \" ",
"World.\"\n\n",
],
},
])("preserves whitespace at SSE delta boundaries: $name", async ({ chunks }) => {
vi.spyOn(globalThis, "fetch").mockResolvedValue(new Response(createChunkedStream(chunks), { status: 200 }));
const textChunks: string[] = [];
streamChatResponse("s-1", "hi", {
onText: (data) => textChunks.push(data),
onError: vi.fn(),
});
await vi.waitFor(() => {
expect(textChunks.join("")).toBe("Hello. World.");
});
});
});
describe("attachChatStream", () => {

View File

@@ -8580,6 +8580,8 @@ export function streamChatResponse(
currentEvent = line.slice(6).trim();
} else if (line.startsWith("data:")) {
const value = line.slice(5);
// Strip only the optional SSE protocol delimiter-space after `data:`.
// Payload whitespace (including JSON-string leading spaces) must stay verbatim.
currentDataLines.push(value.startsWith(" ") ? value.slice(1) : value);
} else if (line === "") {
const currentData = currentDataLines.join("\n");
@@ -8780,6 +8782,8 @@ export function attachChatStream(
currentEvent = line.slice(6).trim();
} else if (line.startsWith("data:")) {
const value = line.slice(5);
// Strip only the optional SSE protocol delimiter-space after `data:`.
// Payload whitespace (including JSON-string leading spaces) must stay verbatim.
currentDataLines.push(value.startsWith(" ") ? value.slice(1) : value);
} else if (line === "") {
const currentData = currentDataLines.join("\n");