| // Helpers for OpenAI Responses API streaming termination + event framing | |
| import { FORMATS } from "../translator/formats.js"; | |
| import { formatSSE } from "./streamHelpers.js"; | |
| // Responses API events that signal the stream has reached a terminal state | |
| const OPENAI_RESPONSES_TERMINAL_EVENTS = new Set([ | |
| "response.completed", | |
| "response.failed", | |
| "error" | |
| ]); | |
| export function getOpenAIResponsesEventName(eventName, chunk) { | |
| if (eventName) return eventName; | |
| if (chunk && typeof chunk.type === "string") return chunk.type; | |
| return null; | |
| } | |
| export function isOpenAIResponsesTerminalEvent(eventName, chunk) { | |
| const type = getOpenAIResponsesEventName(eventName, chunk); | |
| if (OPENAI_RESPONSES_TERMINAL_EVENTS.has(type)) return true; | |
| const status = chunk?.response?.status; | |
| return status === "completed" || status === "failed"; | |
| } | |
| const sharedEncoder = new TextEncoder(); | |
| // Encoded response.failed + [DONE] payload for aborted/stalled Responses passthrough streams | |
| export function buildAbortedResponsesTerminalBytes() { | |
| return sharedEncoder.encode(`${formatIncompleteOpenAIResponsesStreamFailure()}data: [DONE]\n\n`); | |
| } | |
| // Synthesize a response.failed event for streams that close without a terminal event | |
| export function formatIncompleteOpenAIResponsesStreamFailure() { | |
| return formatSSE({ | |
| event: "response.failed", | |
| data: { | |
| type: "response.failed", | |
| response: { | |
| id: `resp_${Date.now()}`, | |
| status: "failed", | |
| error: { | |
| type: "stream_error", | |
| code: "stream_disconnected", | |
| message: "stream closed before response.completed" | |
| } | |
| } | |
| } | |
| }, FORMATS.OPENAI_RESPONSES); | |
| } | |