mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
fix(llm): cap codex retry delays
This commit is contained in:
@@ -304,4 +304,40 @@ describe("streamOpenAICodexResponses transport", () => {
|
||||
expect(setTimeoutSpy).toHaveBeenCalledWith(expect.any(Function), 1000);
|
||||
},
|
||||
);
|
||||
|
||||
it("caps oversized Retry-After delays before sleeping", async () => {
|
||||
const fetchMock = vi
|
||||
.fn<typeof fetch>()
|
||||
.mockResolvedValueOnce(
|
||||
new Response("rate limited", {
|
||||
status: 429,
|
||||
headers: { "retry-after": String(Number.MAX_SAFE_INTEGER) },
|
||||
}),
|
||||
)
|
||||
.mockRejectedValueOnce(new Error("usage limit: stop after retry delay"));
|
||||
vi.stubGlobal("fetch", fetchMock);
|
||||
const setTimeoutSpy = vi
|
||||
.spyOn(globalThis, "setTimeout")
|
||||
.mockImplementation((callback: TimerHandler) => {
|
||||
if (typeof callback === "function") {
|
||||
callback();
|
||||
}
|
||||
return 0 as unknown as ReturnType<typeof setTimeout>;
|
||||
});
|
||||
|
||||
const stream = streamOpenAICodexResponses(model, context, {
|
||||
apiKey: createJwt({
|
||||
"https://api.openai.com/auth": {
|
||||
chatgpt_account_id: "acct-1",
|
||||
},
|
||||
}),
|
||||
transport: "sse",
|
||||
});
|
||||
|
||||
const result = await stream.result();
|
||||
|
||||
expect(result.stopReason).toBe("error");
|
||||
expect(fetchMock).toHaveBeenCalledTimes(2);
|
||||
expect(setTimeoutSpy).toHaveBeenCalledWith(expect.any(Function), MAX_TIMER_TIMEOUT_MS);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -20,7 +20,7 @@ if (typeof process !== "undefined" && (process.versions?.node || process.version
|
||||
});
|
||||
}
|
||||
|
||||
import { resolveTimerTimeoutMs } from "../../shared/number-coercion.js";
|
||||
import { resolveTimerTimeoutMs, clampTimerTimeoutMs } from "../../shared/number-coercion.js";
|
||||
import { getEnvApiKey } from "../env-api-keys.js";
|
||||
import { clampThinkingLevel } from "../model-utils.js";
|
||||
import { registerSessionResourceCleanup } from "../session-resources.js";
|
||||
@@ -343,7 +343,7 @@ export const streamOpenAICodexResponses: StreamFunction<
|
||||
const trimmedRetryAfterMs = retryAfterMs.trim();
|
||||
const millis = Number(trimmedRetryAfterMs);
|
||||
if (/^\d+(?:\.\d+)?$/.test(trimmedRetryAfterMs) && Number.isFinite(millis)) {
|
||||
delayMs = Math.max(0, millis);
|
||||
delayMs = clampTimerTimeoutMs(millis, 0) ?? delayMs;
|
||||
}
|
||||
} else {
|
||||
const retryAfter = response.headers.get("retry-after");
|
||||
@@ -351,11 +351,11 @@ export const streamOpenAICodexResponses: StreamFunction<
|
||||
const trimmedRetryAfter = retryAfter.trim();
|
||||
const seconds = Number(trimmedRetryAfter);
|
||||
if (/^\d+$/.test(trimmedRetryAfter) && Number.isFinite(seconds)) {
|
||||
delayMs = Math.max(0, seconds * 1000);
|
||||
delayMs = clampTimerTimeoutMs(seconds * 1000, 0) ?? delayMs;
|
||||
} else if (RETRY_AFTER_HTTP_DATE_RE.test(trimmedRetryAfter)) {
|
||||
const date = Date.parse(trimmedRetryAfter);
|
||||
if (!Number.isNaN(date)) {
|
||||
delayMs = Math.max(0, date - Date.now());
|
||||
delayMs = clampTimerTimeoutMs(date - Date.now(), 0) ?? delayMs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user