diff --git a/typescript/src/model.ts b/typescript/src/model.ts index f20df5d8..c4988bc7 100644 --- a/typescript/src/model.ts +++ b/typescript/src/model.ts @@ -422,7 +422,7 @@ function getRetryDelayMs(response: Response, defaultMs: number, maxMs: number): const retryAfter = response.headers.get("retry-after"); if (retryAfter) { const seconds = parseInt(retryAfter, 10); - if (!isNaN(seconds)) { + if (Number.isFinite(seconds) && seconds >= 0) { return Math.min(seconds * 1000, maxMs); } } diff --git a/typescript/tests/model.test.mjs b/typescript/tests/model.test.mjs index d8417ac5..b3a75816 100644 --- a/typescript/tests/model.test.mjs +++ b/typescript/tests/model.test.mjs @@ -247,6 +247,30 @@ describe("createOpenAILanguageModel (Chat Completions API)", () => { assert.equal(result.data, "OK after 503 retry"); assert.equal(capturedRequests.length, 2, "Expected 2 requests: initial + 1 retry"); }); + + test("uses the configured pause for a negative retry-after header", async () => { + setupFetch([ + makeErrorResponse(429, "Too Many Requests", -1000), + makeChatCompletionsResponse("OK after retry"), + ]); + const model = createOpenAILanguageModel("sk-test", "gpt-4"); + model.retryMaxAttempts = 3; + model.retryPauseMs = 1000; + const scheduledDelays = []; + const originalSetTimeout = globalThis.setTimeout; + globalThis.setTimeout = (callback, delay, ...args) => { + scheduledDelays.push(delay); + queueMicrotask(() => callback(...args)); + }; + try { + const result = await model.complete("test"); + assert.equal(result.success, true); + assert.equal(result.data, "OK after retry"); + assert.deepEqual(scheduledDelays, [1000]); + } finally { + globalThis.setTimeout = originalSetTimeout; + } + }); }); // ---------------------------------------------------------------------------