@sema-agent/core
Version:
Stateless, task-oriented AI agent core
64 lines (63 loc) • 2.27 kB
JavaScript
const MAX_BACKOFF_MS = 32_000;
const JITTER_FRACTION = 0.25;
const MAX_HEADER_WAIT_MS = 60_000;
const RATE_LIMIT_STATUS = 429;
export function parseRetryAfter(res) {
const h = res?.headers?.get?.("retry-after");
if (!h)
return undefined;
const secs = Number(h);
if (Number.isFinite(secs))
return Math.max(0, secs * 1000);
const date = Date.parse(h);
if (Number.isFinite(date))
return Math.max(0, date - Date.now());
return undefined;
}
export function parseRateLimitReset(res) {
const at = readUnifiedResetEpochMs(res?.headers);
if (at === undefined)
return undefined;
const ms = at - Date.now();
return ms > 0 ? ms : undefined;
}
export function readUnifiedResetEpochMs(headers) {
const h = headers?.get?.("anthropic-ratelimit-unified-reset");
if (!h)
return undefined;
const epochSecs = Number(h);
if (!Number.isFinite(epochSecs) || epochSecs <= 0)
return undefined;
return Math.round(epochSecs * 1000);
}
function clampHint(rawMs) {
return rawMs > MAX_HEADER_WAIT_MS ? { ms: MAX_HEADER_WAIT_MS, rawMs } : { ms: rawMs };
}
export function providerWaitHint(res) {
const hints = [];
const retryAfter = parseRetryAfter(res);
if (retryAfter !== undefined)
hints.push(clampHint(retryAfter));
if (res?.status === RATE_LIMIT_STATUS) {
const reset = parseRateLimitReset(res);
if (reset !== undefined)
hints.push(clampHint(reset));
}
if (hints.length === 0)
return undefined;
return hints.reduce((largest, next) => {
if (next.ms !== largest.ms)
return next.ms > largest.ms ? next : largest;
return (next.rawMs ?? next.ms) > (largest.rawMs ?? largest.ms) ? next : largest;
});
}
function providerWaitHintMs(res) {
return providerWaitHint(res)?.ms;
}
export const FAST_MAX_BACKOFF_MS = 1_000;
export function retryBackoffMs(baseDelayMs, attempt, res, rand = Math.random, maxBackoffMs = MAX_BACKOFF_MS) {
const exp = Math.min(maxBackoffMs, baseDelayMs * 2 ** attempt);
const computed = Math.round(exp + rand() * JITTER_FRACTION * exp);
const hint = providerWaitHintMs(res);
return hint === undefined ? computed : Math.max(hint, computed);
}