fix(responses): handle response.done terminal events (#2142)

Treat response.done as a terminal OpenAI Responses stream event so
passthrough streams ending with response.done are not flagged incomplete
and no synthetic response.failed is emitted. Restore the data: [DONE]
sentinel for same-format Responses passthrough streams.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
rifuki
2026-06-29 16:05:29 +07:00
committed by decolua
co-authored by Cursor
parent 373850ee36
commit a9785a5f70
3 changed files with 26 additions and 5 deletions
+12 -5
View File
@@ -217,9 +217,11 @@ export function createSSEStream(options = {}) {
sseEmittedCount++;
}
// [DONE] not emitted in translate mode — some clients' SSE decoders
// fail to parse the OpenAI sentinel on Claude-format translated streams.
// message_stop already signals end-of-response; stream close handles it.
if (keepsOpenAIResponsesFormat && !streamDoneSent) {
const doneOutput = "data: [DONE]\n\n";
reqLogger?.appendConvertedChunk?.(doneOutput);
controller.enqueue(sharedEncoder.encode(doneOutput));
}
streamDoneSent = true;
if (keepsOpenAIResponsesFormat) openAIResponsesDoneSent = true;
continue;
@@ -417,8 +419,13 @@ export function createSSEStream(options = {}) {
openAIResponsesTerminalSeen = true;
}
// [DONE] not emitted in translate mode — see comment above.
// Passthrough mode still emits it for standard OpenAI clients.
if (keepsOpenAIResponsesFormat && !openAIResponsesDoneSent && !streamDoneSent) {
const doneOutput = "data: [DONE]\n\n";
reqLogger?.appendConvertedChunk?.(doneOutput);
controller.enqueue(sharedEncoder.encode(doneOutput));
openAIResponsesDoneSent = true;
streamDoneSent = true;
}
if (!hasValidUsage(state?.usage) && totalContentLength > 0) {
state.usage = estimateUsage(body, totalContentLength, sourceFormat);