diff --git a/src/server/responses/combo-stream-preflight.ts b/src/server/responses/combo-stream-preflight.ts index 5cdc1b4ddb6..e6a95e518ba 100644 --- a/src/server/responses/combo-stream-preflight.ts +++ b/src/server/responses/combo-stream-preflight.ts @@ -121,7 +121,8 @@ function retryableZeroOutputTerminal(payload: unknown): boolean { if (event.type === "response.failed") return true; if (event.type !== "response.incomplete") return false; const reason = event.response?.incomplete_details?.reason; - return typeof reason === "string" && RETRYABLE_ZERO_OUTPUT_INCOMPLETE_REASONS.has(reason); + return reason === undefined + || (typeof reason === "string" && RETRYABLE_ZERO_OUTPUT_INCOMPLETE_REASONS.has(reason)); } /** diff --git a/tests/routing/combo-stream-preflight.test.ts b/tests/routing/combo-stream-preflight.test.ts index 29e6d34c3e7..a4487a4b7c3 100644 --- a/tests/routing/combo-stream-preflight.test.ts +++ b/tests/routing/combo-stream-preflight.test.ts @@ -116,6 +116,20 @@ describe("combo stream preflight", () => { } }); + test("converts a zero-output incomplete without a stated reason into a retryable failure", async () => { + for (const response of [ + { id: "r1", status: "incomplete" }, + { id: "r1", status: "incomplete", incomplete_details: null }, + ]) { + const result = await preflightComboStreamResponse(sse( + { type: "response.created", response: { id: "r1", status: "in_progress" } }, + { type: "response.incomplete", response }, + ), { model: "m1", provider: "a" }); + expect(result.kind).toBe("failed"); + expect(result.response.status).toBe(502); + } + }); + test("does not replay semantic incompletes that another provider cannot safely repair", async () => { const source = sse( { type: "response.created", response: { id: "r1", status: "in_progress" } },