- commit
- d58f880
- parent
- 1bddb21
- author
- im_wower
- date
- 2026-03-28 02:09:55 +0800 CST
fix: keep buffered SSE full_text text-only
2 files changed,
+58,
-9
+44,
-1
1@@ -1472,6 +1472,20 @@ function createBrowserBridgeStub() {
2 "",
3 "event: completion",
4 'data: {"type":"completion","completion":"world"}',
5+ "",
6+ "event: completion",
7+ 'data: {"type":"completion","completion":"","id":"chatcompl_01-buffered","stop":"\\n\\nHuman:","log_id":"log_01-buffered","messageLimit":{"type":"within_limit","resetsAt":"2026-03-28T00:00:00.000Z"}}',
8+ ""
9+ ].join("\n")
10+ });
11+ }
12+
13+ if (input.path === "/backend-api/conversation-buffered-smoke") {
14+ return buildApiResponse({
15+ id: input.id,
16+ body: [
17+ "event: message",
18+ 'data: {"message":{"id":"msg-chatgpt-buffered-1","author":{"role":"assistant"},"content":{"content_type":"text","parts":["Buffered ChatGPT answer"]}}}',
19 ""
20 ].join("\n")
21 });
22@@ -2738,13 +2752,41 @@ test("handleConductorHttpRequest serves the migrated local business endpoints fr
23 assert.equal(bufferedSsePayload.data.request_mode, "api_request");
24 assert.equal(bufferedSsePayload.data.proxy.path, "/api/stream-buffered-smoke");
25 assert.equal(bufferedSsePayload.data.response.content_type, "text/event-stream");
26- assert.equal(bufferedSsePayload.data.response.events.length, 2);
27+ assert.equal(bufferedSsePayload.data.response.events.length, 3);
28 assert.equal(bufferedSsePayload.data.response.events[0].event, "completion");
29 assert.equal(bufferedSsePayload.data.response.events[0].data.type, "completion");
30 assert.equal(bufferedSsePayload.data.response.events[0].data.completion, "Hello ");
31 assert.equal(bufferedSsePayload.data.response.events[1].data.completion, "world");
32+ assert.equal(bufferedSsePayload.data.response.events[2].data.completion, "");
33+ assert.equal(bufferedSsePayload.data.response.events[2].data.id, "chatcompl_01-buffered");
34+ assert.equal(bufferedSsePayload.data.response.events[2].data.stop, "\n\nHuman:");
35 assert.equal(bufferedSsePayload.data.response.full_text, "Hello world");
36
37+ const chatgptBufferedSseResponse = await handleConductorHttpRequest(
38+ {
39+ body: JSON.stringify({
40+ platform: "chatgpt",
41+ method: "GET",
42+ path: "/backend-api/conversation-buffered-smoke",
43+ requestId: "browser-chatgpt-buffered-sse-123"
44+ }),
45+ method: "POST",
46+ path: "/v1/browser/request"
47+ },
48+ localApiContext
49+ );
50+ assert.equal(chatgptBufferedSseResponse.status, 200);
51+ const chatgptBufferedSsePayload = parseJsonBody(chatgptBufferedSseResponse);
52+ assert.equal(chatgptBufferedSsePayload.data.request_mode, "api_request");
53+ assert.equal(chatgptBufferedSsePayload.data.proxy.path, "/backend-api/conversation-buffered-smoke");
54+ assert.equal(chatgptBufferedSsePayload.data.response.content_type, "text/event-stream");
55+ assert.equal(chatgptBufferedSsePayload.data.response.events[0].event, "message");
56+ assert.equal(
57+ chatgptBufferedSsePayload.data.response.events[0].data.message.content.parts[0],
58+ "Buffered ChatGPT answer"
59+ );
60+ assert.equal(chatgptBufferedSsePayload.data.response.full_text, "Buffered ChatGPT answer");
61+
62 const chatgptBufferedResponse = await handleConductorHttpRequest(
63 {
64 body: JSON.stringify({
65@@ -3206,6 +3248,7 @@ test("handleConductorHttpRequest serves the migrated local business endpoints fr
66 "apiRequest:GET:/api/organizations/org-1/chat_conversations",
67 "apiRequest:POST:/api/organizations/org-1/chat_conversations/conv-1/completion",
68 "apiRequest:GET:/api/stream-buffered-smoke",
69+ "apiRequest:GET:/backend-api/conversation-buffered-smoke",
70 "apiRequest:GET:/backend-api/models",
71 "apiRequest:GET:/api/organizations",
72 "apiRequest:GET:/api/organizations/org-1/chat_conversations",
+14,
-8
1@@ -1392,6 +1392,18 @@ function isLikelyBufferedSseText(value: string): boolean {
2 return prefixedLineCount > 0;
3 }
4
5+const BUFFERED_SSE_TEXT_PATH_KEYS = [
6+ "text",
7+ "value",
8+ "content",
9+ "message",
10+ "markdown",
11+ "completion",
12+ "delta",
13+ "parts",
14+ "choices"
15+] as const;
16+
17 function extractBufferedSseTextFragments(value: JsonValue | null): string[] {
18 if (typeof value === "string") {
19 return value === "" ? [] : [value];
20@@ -1405,16 +1417,10 @@ function extractBufferedSseTextFragments(value: JsonValue | null): string[] {
21 return [];
22 }
23
24- const directKeys = ["text", "value", "content", "message", "markdown", "completion"];
25- const directValues = directKeys.flatMap((fieldName) =>
26+ // Only follow fields that are known to contain text or wrap nested text.
27+ return BUFFERED_SSE_TEXT_PATH_KEYS.flatMap((fieldName) =>
28 extractBufferedSseTextFragments(value[fieldName] as JsonValue)
29 );
30-
31- if (directValues.length > 0) {
32- return directValues;
33- }
34-
35- return Object.values(value).flatMap((entry) => extractBufferedSseTextFragments(entry as JsonValue));
36 }
37
38 function parseBufferedSseProxyBody(body: string): JsonObject | null {