fix(agents): keep proxied streams working when SSE data lines omit the space (#129905)

This commit is contained in:
KevinZhou
2026-08-26 15:10:52 +08:00
committed by GitHub
parent 95bbc0ac05
commit da7bad79cf
2 changed files with 48 additions and 2 deletions
+44
View File
@@ -182,6 +182,50 @@ describe("streamProxy", () => {
});
});
it("accepts data lines without a space after the colon", async () => {
// The SSE spec makes the space optional; proxies emitting `data:{...}`
// must not have their events silently dropped.
const proxyEvents = [
{ type: "text_start", contentIndex: 0, contentSignature: "sig" },
{ type: "text_delta", contentIndex: 0, delta: "Working..." },
{ type: "text_end", contentIndex: 0 },
{ type: "done", reason: "stop", usage },
];
const body = [
`data:${JSON.stringify(proxyEvents[0])}`,
"",
`data: ${JSON.stringify(proxyEvents[1])}`,
"",
`data:${JSON.stringify(proxyEvents[2])}`,
"",
`data:${JSON.stringify(proxyEvents[3])}`,
"",
].join("\n");
vi.stubGlobal(
"fetch",
vi.fn(async () => responseFromText(body)),
);
const stream = streamProxy(model, context, {
authToken: "token",
proxyUrl: "https://proxy.example",
});
const events = [];
for await (const event of stream) {
events.push(event);
}
expect(events.map((event) => event.type)).toEqual([
"text_start",
"text_delta",
"text_end",
"done",
]);
await expect(stream.result()).resolves.toMatchObject({
content: [{ type: "text", text: "Working..." }],
});
});
it("delays tool argument previews while preserving exact terminal arguments", async () => {
const initialContent = "a".repeat(128);
const checkpointContent = "b".repeat(400);
+4 -2
View File
@@ -356,10 +356,12 @@ export function streamProxy(
const toolArgumentPreviewSchedules = new Map<number, ToolArgumentPreviewSchedule>();
const processSseLine = (line: string) => {
if (!line.startsWith("data: ")) {
// The SSE spec makes the space after "data:" optional; accept both
// `data:{...}` and `data: {...}`, mirroring provider-transport-fetch.
if (!line.startsWith("data:")) {
return;
}
const data = line.slice(6).trim();
const data = line.slice("data:".length).trim();
if (!data) {
return;
}