handle openai websocket previous_response_not_found error

fixes #6931
This commit is contained in:
David Brailovsky
2026-07-22 10:26:24 +00:00
parent a5afc3f171
commit c5dcb26000
2 changed files with 238 additions and 6 deletions
+20 -6
View File
@@ -67,6 +67,7 @@ const REQUEST_COMPRESSION_ZSTD_LEVEL = 3;
const CODEX_TOOL_CALL_PROVIDERS = new Set(["openai", "openai-codex", "opencode"]);
const WEBSOCKET_MESSAGE_TOO_BIG_CLOSE_CODE = 1009;
const WEBSOCKET_CONNECTION_LIMIT_REACHED_CODE = "websocket_connection_limit_reached";
const PREVIOUS_RESPONSE_NOT_FOUND_CODE = "previous_response_not_found";
const CODEX_RESPONSE_STATUSES = new Set<CodexResponseStatus>([
"completed",
@@ -273,6 +274,7 @@ export const stream: StreamFunction<"openai-codex-responses", OpenAICodexRespons
const httpTimeoutMs = normalizeTimeoutMs(options?.timeoutMs);
const websocketConnectTimeoutMs = normalizeTimeoutMs(options?.websocketConnectTimeoutMs);
const transport = options?.transport || "auto";
let startEmitted = false;
const websocketDisabledForSession = transport !== "sse" && isWebSocketSseFallbackActive(options?.sessionId);
if (websocketDisabledForSession) {
recordWebSocketSseFallback(options?.sessionId);
@@ -281,6 +283,7 @@ export const stream: StreamFunction<"openai-codex-responses", OpenAICodexRespons
if (transport !== "sse" && !websocketDisabledForSession) {
let websocketStarted = false;
let retriedWebSocketConnectionLimit = false;
let retriedMissingWebSocketContinuation = false;
while (true) {
websocketStarted = false;
try {
@@ -293,6 +296,10 @@ export const stream: StreamFunction<"openai-codex-responses", OpenAICodexRespons
model,
() => {
websocketStarted = true;
if (!startEmitted) {
startEmitted = true;
stream.push({ type: "start", partial: output });
}
},
httpTimeoutMs,
websocketConnectTimeoutMs,
@@ -312,6 +319,11 @@ export const stream: StreamFunction<"openai-codex-responses", OpenAICodexRespons
} catch (error) {
const aborted = options?.signal?.aborted;
const connectionLimitBeforeStart = !websocketStarted && isWebSocketConnectionLimitReachedError(error);
const previousResponseNotFound = isPreviousResponseNotFoundError(error);
if (!aborted && previousResponseNotFound && !retriedMissingWebSocketContinuation) {
retriedMissingWebSocketContinuation = true;
continue;
}
if (!aborted && connectionLimitBeforeStart && !retriedWebSocketConnectionLimit) {
retriedWebSocketConnectionLimit = true;
continue;
@@ -432,7 +444,10 @@ export const stream: StreamFunction<"openai-codex-responses", OpenAICodexRespons
throw new Error("No response body");
}
stream.push({ type: "start", partial: output });
if (!startEmitted) {
startEmitted = true;
stream.push({ type: "start", partial: output });
}
await processStream(response, output, stream, model, options);
if (options?.signal?.aborted) {
@@ -636,6 +651,10 @@ function isWebSocketConnectionLimitReachedError(error: unknown): boolean {
return error instanceof CodexApiError && error.code === WEBSOCKET_CONNECTION_LIMIT_REACHED_CODE;
}
function isPreviousResponseNotFoundError(error: unknown): boolean {
return error instanceof CodexApiError && error.code === PREVIOUS_RESPONSE_NOT_FOUND_CODE;
}
function extractCodexEventError(event: Record<string, unknown>): { code?: string; message?: string } {
const nested = event.error && typeof event.error === "object" ? (event.error as Record<string, unknown>) : undefined;
return {
@@ -1358,8 +1377,6 @@ function buildCachedWebSocketRequestBody(entry: CachedWebSocketConnection, body:
async function* startWebSocketOutputOnFirstEvent(
events: AsyncIterable<ResponseStreamEvent>,
output: AssistantMessage,
stream: AssistantMessageEventStream,
onStart: () => void,
): AsyncGenerator<ResponseStreamEvent> {
let started = false;
@@ -1367,7 +1384,6 @@ async function* startWebSocketOutputOnFirstEvent(
if (!started) {
started = true;
onStart();
stream.push({ type: "start", partial: output });
}
yield event;
}
@@ -1422,8 +1438,6 @@ async function processWebSocketStream(
await processResponsesStream(
startWebSocketOutputOnFirstEvent(
mapCodexEvents(parseWebSocket(socket, options?.signal, idleTimeoutMs)),
output,
stream,
onStart,
),
output,