Skip to content

Commit e6d1478

Browse files
Merge pull request #5580 from zyxue/zyxue-patch-1
handle `data:[DONE]` without space properly
2 parents 0ed58f4 + ad37da6 commit e6d1478

File tree

3 files changed

+74
-2
lines changed

3 files changed

+74
-2
lines changed

core/llm/stream.test.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { Readable } from "stream";
2+
import { streamSse } from "./stream";
3+
4+
function createMockResponse(sseLines: string[]): Response {
5+
// Create a Readable stream that emits the SSE lines
6+
const stream = new Readable({
7+
read() {
8+
for (const line of sseLines) {
9+
this.push(line + "\n\n");
10+
}
11+
this.push(null); // End of stream
12+
}
13+
}) as any;
14+
15+
// Minimal Response mock
16+
return {
17+
status: 200,
18+
body: stream,
19+
text: async () => "",
20+
} as unknown as Response;
21+
}
22+
23+
describe("streamSse", () => {
24+
it("yields parsed SSE data objects that ends with `data:[DONE]`", async () => {
25+
const sseLines = [
26+
'data: {"foo": "bar"}',
27+
'data: {"baz": 42}',
28+
'data:[DONE]'
29+
];
30+
const response = createMockResponse(sseLines);
31+
32+
const results = [];
33+
for await (const data of streamSse(response)) {
34+
results.push(data);
35+
}
36+
37+
expect(results).toEqual([
38+
{ foo: "bar" },
39+
{ baz: 42 }
40+
]);
41+
});
42+
43+
it("yields parsed SSE data objects that ends with `data: [DONE]` (with a space before [DONE]", async () => {
44+
const sseLines = [
45+
'data: {"foo": "bar"}',
46+
'data: {"baz": 42}',
47+
'data: [DONE]'
48+
];
49+
const response = createMockResponse(sseLines);
50+
51+
const results = [];
52+
for await (const data of streamSse(response)) {
53+
results.push(data);
54+
}
55+
56+
expect(results).toEqual([
57+
{ foo: "bar" },
58+
{ baz: 42 }
59+
]);
60+
});
61+
62+
it("throws on malformed JSON", async () => {
63+
const sseLines = [
64+
'data: {"foo": "bar"',
65+
'data:[DONE]'
66+
];
67+
const response = createMockResponse(sseLines);
68+
69+
const iterator = streamSse(response)[Symbol.asyncIterator]();
70+
await expect(iterator.next()).rejects.toThrow(/Malformed JSON/);
71+
});
72+
});

core/llm/stream.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ function parseDataLine(line: string): any {
5858
}
5959

6060
function parseSseLine(line: string): { done: boolean; data: any } {
61-
if (line.startsWith("data: [DONE]")) {
61+
if (line.startsWith("data:[DONE]") || line.startsWith("data: [DONE]")) {
6262
return { done: true, data: undefined };
6363
}
6464
if (line.startsWith("data:")) {

packages/fetch/src/stream.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ function parseDataLine(line: string): any {
5858
}
5959

6060
function parseSseLine(line: string): { done: boolean; data: any } {
61-
if (line.startsWith("data: [DONE]")) {
61+
if (line.startsWith("data:[DONE]") || line.startsWith("data: [DONE]")) {
6262
return { done: true, data: undefined };
6363
}
6464
if (line.startsWith("data:")) {

0 commit comments

Comments
 (0)