ai 5.0.0-beta.19 → 5.0.0-beta.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # ai
2
2
 
3
+ ## 5.0.0-beta.20
4
+
5
+ ### Patch Changes
6
+
7
+ - 4c8f834: feat: automatically respect rate limit headers in retry logic
8
+
9
+ Added automatic support for respecting rate limit headers (`retry-after-ms` and `retry-after`) in the SDK's retry logic. When these headers are present and contain reasonable values (0-60 seconds), the retry mechanism will use the server-specified delay instead of exponential backoff. This matches the behavior of Anthropic and OpenAI client SDKs and improves rate limit handling without requiring any API changes.
10
+
3
11
  ## 5.0.0-beta.19
4
12
 
5
13
  ### Patch Changes
package/dist/bin/ai.js CHANGED
@@ -1349,7 +1349,33 @@ var RetryError = class extends import_provider3.AISDKError {
1349
1349
  _a3 = symbol3;
1350
1350
 
1351
1351
  // src/util/retry-with-exponential-backoff.ts
1352
- var retryWithExponentialBackoff = ({
1352
+ function getRetryDelay(error, exponentialBackoffDelay) {
1353
+ const headers = error.responseHeaders;
1354
+ if (!headers)
1355
+ return exponentialBackoffDelay;
1356
+ let timeoutMillis;
1357
+ const retryAfterMs = headers["retry-after-ms"];
1358
+ if (retryAfterMs) {
1359
+ const timeoutMs = parseFloat(retryAfterMs);
1360
+ if (!Number.isNaN(timeoutMs)) {
1361
+ timeoutMillis = timeoutMs;
1362
+ }
1363
+ }
1364
+ const retryAfter = headers["retry-after"];
1365
+ if (retryAfter && timeoutMillis === void 0) {
1366
+ const timeoutSeconds = parseFloat(retryAfter);
1367
+ if (!Number.isNaN(timeoutSeconds)) {
1368
+ timeoutMillis = timeoutSeconds * 1e3;
1369
+ } else {
1370
+ timeoutMillis = Date.parse(retryAfter) - Date.now();
1371
+ }
1372
+ }
1373
+ if (timeoutMillis !== void 0 && 0 <= timeoutMillis && timeoutMillis < 60 * 1e3) {
1374
+ return timeoutMillis;
1375
+ }
1376
+ return exponentialBackoffDelay;
1377
+ }
1378
+ var retryWithExponentialBackoffRespectingRetryHeaders = ({
1353
1379
  maxRetries = 2,
1354
1380
  initialDelayInMs = 2e3,
1355
1381
  backoffFactor = 2
@@ -1383,7 +1409,8 @@ async function _retryWithExponentialBackoff(f, {
1383
1409
  });
1384
1410
  }
1385
1411
  if (error instanceof Error && import_provider4.APICallError.isInstance(error) && error.isRetryable === true && tryNumber <= maxRetries) {
1386
- await (0, import_provider_utils3.delay)(delayInMs);
1412
+ const actualDelay = getRetryDelay(error, delayInMs);
1413
+ await (0, import_provider_utils3.delay)(actualDelay);
1387
1414
  return _retryWithExponentialBackoff(
1388
1415
  f,
1389
1416
  { maxRetries, delayInMs: backoffFactor * delayInMs, backoffFactor },
@@ -1424,7 +1451,9 @@ function prepareRetries({
1424
1451
  const maxRetriesResult = maxRetries != null ? maxRetries : 2;
1425
1452
  return {
1426
1453
  maxRetries: maxRetriesResult,
1427
- retry: retryWithExponentialBackoff({ maxRetries: maxRetriesResult })
1454
+ retry: retryWithExponentialBackoffRespectingRetryHeaders({
1455
+ maxRetries: maxRetriesResult
1456
+ })
1428
1457
  };
1429
1458
  }
1430
1459