Skip to content

Commit ccb089c

Browse files
committed
feat: add robust error handling for GPT-5 previous_response_id failures
- Automatically retry without previous_response_id when it's not found (400 error) - Clear stored lastResponseId to prevent reusing stale IDs - Handle errors in both SDK and SSE fallback paths - Log warnings when retrying to help with debugging
1 parent 9d27ffc commit ccb089c

File tree

1 file changed

+88
-2
lines changed

1 file changed

+88
-2
lines changed

src/api/providers/openai-native.ts

Lines changed: 88 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,8 +221,52 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio
221221
yield outChunk
222222
}
223223
}
224-
} catch (_sdkErr) {
225-
// Fallback to manual SSE via fetch to maintain functionality with custom base URLs or older SDKs
224+
} catch (sdkErr: any) {
225+
// Check if this is a 400 error about previous_response_id not found
226+
const errorMessage = sdkErr?.message || sdkErr?.error?.message || ""
227+
const is400Error = sdkErr?.status === 400 || sdkErr?.response?.status === 400
228+
const isPreviousResponseError =
229+
errorMessage.includes("Previous response") || errorMessage.includes("not found")
230+
231+
if (is400Error && requestBody.previous_response_id && isPreviousResponseError) {
232+
// Log the error and retry without the previous_response_id
233+
console.warn(
234+
`[GPT-5] Previous response ID not found (${requestBody.previous_response_id}), retrying without it`,
235+
)
236+
237+
// Remove the problematic previous_response_id and retry
238+
const retryRequestBody = { ...requestBody }
239+
delete retryRequestBody.previous_response_id
240+
241+
// Clear the stored lastResponseId to prevent using it again
242+
this.lastResponseId = undefined
243+
244+
try {
245+
// Retry with the SDK
246+
const retryStream = (await (this.client as any).responses.create(
247+
retryRequestBody,
248+
)) as AsyncIterable<any>
249+
250+
if (typeof (retryStream as any)[Symbol.asyncIterator] !== "function") {
251+
// If SDK fails, fall back to SSE
252+
yield* this.makeGpt5ResponsesAPIRequest(retryRequestBody, model, metadata)
253+
return
254+
}
255+
256+
for await (const event of retryStream) {
257+
for await (const outChunk of this.processGpt5Event(event, model)) {
258+
yield outChunk
259+
}
260+
}
261+
return
262+
} catch (retryErr) {
263+
// If retry also fails, fall back to SSE
264+
yield* this.makeGpt5ResponsesAPIRequest(retryRequestBody, model, metadata)
265+
return
266+
}
267+
}
268+
269+
// For other errors, fallback to manual SSE via fetch
226270
yield* this.makeGpt5ResponsesAPIRequest(requestBody, model, metadata)
227271
}
228272
}
@@ -315,6 +359,48 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio
315359
errorDetails = errorText
316360
}
317361

362+
// Check if this is a 400 error about previous_response_id not found
363+
const isPreviousResponseError =
364+
errorDetails.includes("Previous response") || errorDetails.includes("not found")
365+
366+
if (response.status === 400 && requestBody.previous_response_id && isPreviousResponseError) {
367+
// Log the error and retry without the previous_response_id
368+
console.warn(
369+
`[GPT-5 SSE] Previous response ID not found (${requestBody.previous_response_id}), retrying without it`,
370+
)
371+
372+
// Remove the problematic previous_response_id and retry
373+
const retryRequestBody = { ...requestBody }
374+
delete retryRequestBody.previous_response_id
375+
376+
// Clear the stored lastResponseId to prevent using it again
377+
this.lastResponseId = undefined
378+
379+
// Retry the request without the previous_response_id
380+
const retryResponse = await fetch(url, {
381+
method: "POST",
382+
headers: {
383+
"Content-Type": "application/json",
384+
Authorization: `Bearer ${apiKey}`,
385+
Accept: "text/event-stream",
386+
},
387+
body: JSON.stringify(retryRequestBody),
388+
})
389+
390+
if (!retryResponse.ok) {
391+
// If retry also fails, throw the original error
392+
throw new Error(`GPT-5 API retry failed (${retryResponse.status})`)
393+
}
394+
395+
if (!retryResponse.body) {
396+
throw new Error("No response body from Responses API retry")
397+
}
398+
399+
// Handle the successful retry response
400+
yield* this.handleGpt5StreamResponse(retryResponse.body, model)
401+
return
402+
}
403+
318404
// Provide user-friendly error messages based on status code
319405
switch (response.status) {
320406
case 400:

0 commit comments

Comments
 (0)