ai-retry 1.6.0 → 1.6.1
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/README.md
CHANGED
|
@@ -782,7 +782,9 @@ const retryableModel = createRetryable({
|
|
|
782
782
|
|
|
783
783
|
#### Timeouts
|
|
784
784
|
|
|
785
|
-
When a retry specifies a `timeout` value, a fresh `AbortSignal.timeout()` is created for that retry attempt,
|
|
785
|
+
When a retry specifies a `timeout` value, a fresh `AbortSignal.timeout()` is created for that retry attempt. If the original `abortSignal` is still alive, the fresh deadline is composed with it via `AbortSignal.any()` so user cancellation still works mid-retry. If the original signal is already aborted (for example it carried a request-level deadline that already fired), it is dropped so the retry runs against the fresh deadline alone.
|
|
786
|
+
|
|
787
|
+
If the original `abortSignal` is already aborted at the time of retry and the chosen retry does **not** supply a `timeout`, ai-retry rethrows the original error rather than firing a misleading retry against the dead signal. `onError` still fires for observability, but `onRetry` is skipped. Setting `retry.timeout` is the explicit opt-in for retrying past an aborted signal.
|
|
786
788
|
|
|
787
789
|
```typescript
|
|
788
790
|
const retryableModel = createRetryable({
|
|
@@ -925,7 +927,7 @@ The following options can be overridden:
|
|
|
925
927
|
|
|
926
928
|
#### Dynamic Call Options
|
|
927
929
|
|
|
928
|
-
You can also override call options dynamically from inside the `onRetry` callback, instead of declaring them statically on the retry object. This is useful when the override depends on something only known at runtime, like the prompt that just failed, the model that's about to be tried next, or the error that triggered the retry. The overrides apply to the upcoming retry attempt only, and can change the same fields as the static `options` on a retry
|
|
930
|
+
You can also override call options dynamically from inside the `onRetry` callback, instead of declaring them statically on the retry object. This is useful when the override depends on something only known at runtime, like the prompt that just failed, the model that's about to be tried next, or the error that triggered the retry. The overrides apply to the upcoming retry attempt only, and can change the same fields as the static `options` on a retry. The callback may also be `async` if computing the override needs to do work (e.g. fetching a fresh credential).
|
|
929
931
|
|
|
930
932
|
A common use case is sanitizing provider-scoped metadata when falling back to a different provider, for example stripping `providerOptions.azure.itemId` references from the previous prompt before retrying on OpenAI:
|
|
931
933
|
|
|
@@ -1090,7 +1092,7 @@ interface RetryableModelOptions<
|
|
|
1090
1092
|
- `disabled`: Disable all retry logic. Can be a boolean or function returning boolean. Default: `false` (retries enabled).
|
|
1091
1093
|
- `reset`: Controls when to reset back to the base model after a successful retry. Default: `after-request`.
|
|
1092
1094
|
- `onError`: Callback invoked when an error occurs.
|
|
1093
|
-
- `onRetry`: Callback invoked before attempting a retry. May optionally return an `OnRetryOverrides` object (or a `Promise` of one) to override `options.*`
|
|
1095
|
+
- `onRetry`: Callback invoked before attempting a retry. May optionally return an `OnRetryOverrides` object (or a `Promise` of one) to override `options.*` for the upcoming attempt only. See [Dynamic Call Options via `onRetry`](#dynamic-call-options-via-onretry).
|
|
1094
1096
|
- `onSuccess`: Callback invoked after a successful request. Receives the model that handled the request and all previous attempts.
|
|
1095
1097
|
|
|
1096
1098
|
#### `Reset`
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as RetryResultAttempt, C as Result, D as RetryCallOptions, E as RetryAttempt, F as SuccessContext, M as RetryableModelOptions, N as RetryableOptions, O as RetryContext, P as SuccessAttempt, S as ResolvedModel, T as Retry, _ as OnRetryOverrides, a as EmbeddingModelRetryCallOptions, b as ResolvableLanguageModel, c as ImageModelCallOptions, d as LanguageModel, f as LanguageModelCallOptions, g as LanguageModelStreamPart, h as LanguageModelStream, i as EmbeddingModelEmbed, j as Retryable, k as RetryErrorAttempt, l as ImageModelGenerate, m as LanguageModelRetryCallOptions, n as EmbeddingModel, o as GatewayLanguageModelId, p as LanguageModelGenerate, r as EmbeddingModelCallOptions, s as ImageModel, t as CallOptions, u as ImageModelRetryCallOptions, v as ProviderOptions, w as Retries, x as ResolvableModel, y as Reset } from "./types-
|
|
1
|
+
import { A as RetryResultAttempt, C as Result, D as RetryCallOptions, E as RetryAttempt, F as SuccessContext, M as RetryableModelOptions, N as RetryableOptions, O as RetryContext, P as SuccessAttempt, S as ResolvedModel, T as Retry, _ as OnRetryOverrides, a as EmbeddingModelRetryCallOptions, b as ResolvableLanguageModel, c as ImageModelCallOptions, d as LanguageModel, f as LanguageModelCallOptions, g as LanguageModelStreamPart, h as LanguageModelStream, i as EmbeddingModelEmbed, j as Retryable, k as RetryErrorAttempt, l as ImageModelGenerate, m as LanguageModelRetryCallOptions, n as EmbeddingModel, o as GatewayLanguageModelId, p as LanguageModelGenerate, r as EmbeddingModelCallOptions, s as ImageModel, t as CallOptions, u as ImageModelRetryCallOptions, v as ProviderOptions, w as Retries, x as ResolvableModel, y as Reset } from "./types-CRKV-hdW.mjs";
|
|
2
2
|
import * as _ai_sdk_provider0 from "@ai-sdk/provider";
|
|
3
3
|
|
|
4
4
|
//#region src/create-retryable-model.d.ts
|
package/dist/index.mjs
CHANGED
|
@@ -197,14 +197,18 @@ function resolveProviderOptions(base, currentRetry, onRetryOverrides) {
|
|
|
197
197
|
/**
|
|
198
198
|
* Resolve `abortSignal` for the upcoming attempt.
|
|
199
199
|
*
|
|
200
|
-
* If
|
|
201
|
-
*
|
|
202
|
-
*
|
|
200
|
+
* If `currentRetry.timeout` is set, a fresh `AbortSignal.timeout(...)` is
|
|
201
|
+
* created. When the base signal is still alive, the fresh deadline is
|
|
202
|
+
* composed with it via `AbortSignal.any` so the user can still cancel
|
|
203
|
+
* mid-retry. When the base is already aborted, it is dropped so the retry
|
|
204
|
+
* runs against the fresh deadline alone. Without a retry timeout, the base
|
|
205
|
+
* is preserved unchanged.
|
|
203
206
|
*/
|
|
204
|
-
function resolveAbortSignal(base, currentRetry
|
|
205
|
-
if (
|
|
206
|
-
|
|
207
|
-
return base;
|
|
207
|
+
function resolveAbortSignal(base, currentRetry) {
|
|
208
|
+
if (currentRetry?.timeout === void 0) return base;
|
|
209
|
+
const fresh = AbortSignal.timeout(currentRetry.timeout);
|
|
210
|
+
if (base !== void 0 && !base.aborted) return AbortSignal.any([base, fresh]);
|
|
211
|
+
return fresh;
|
|
208
212
|
}
|
|
209
213
|
/**
|
|
210
214
|
* Merge call options for the upcoming language model retry attempt.
|
|
@@ -231,7 +235,7 @@ function mergeLanguageModelCallOptions(input) {
|
|
|
231
235
|
seed: overrideOptions.seed ?? retryOptions.seed ?? callOptions.seed,
|
|
232
236
|
headers: overrideOptions.headers ?? retryOptions.headers ?? callOptions.headers,
|
|
233
237
|
providerOptions: resolveProviderOptions(callOptions.providerOptions, currentRetry, onRetryOverrides),
|
|
234
|
-
abortSignal: resolveAbortSignal(callOptions.abortSignal, currentRetry
|
|
238
|
+
abortSignal: resolveAbortSignal(callOptions.abortSignal, currentRetry)
|
|
235
239
|
};
|
|
236
240
|
}
|
|
237
241
|
/**
|
|
@@ -246,7 +250,7 @@ function mergeEmbeddingModelCallOptions(input) {
|
|
|
246
250
|
values: overrideOptions.values ?? retryOptions.values ?? callOptions.values,
|
|
247
251
|
headers: overrideOptions.headers ?? retryOptions.headers ?? callOptions.headers,
|
|
248
252
|
providerOptions: resolveProviderOptions(callOptions.providerOptions, currentRetry, onRetryOverrides),
|
|
249
|
-
abortSignal: resolveAbortSignal(callOptions.abortSignal, currentRetry
|
|
253
|
+
abortSignal: resolveAbortSignal(callOptions.abortSignal, currentRetry)
|
|
250
254
|
};
|
|
251
255
|
}
|
|
252
256
|
/**
|
|
@@ -264,7 +268,7 @@ function mergeImageModelCallOptions(input) {
|
|
|
264
268
|
seed: overrideOptions.seed ?? retryOptions.seed ?? callOptions.seed,
|
|
265
269
|
headers: overrideOptions.headers ?? retryOptions.headers ?? callOptions.headers,
|
|
266
270
|
providerOptions: resolveProviderOptions(callOptions.providerOptions, currentRetry, onRetryOverrides),
|
|
267
|
-
abortSignal: resolveAbortSignal(callOptions.abortSignal, currentRetry
|
|
271
|
+
abortSignal: resolveAbortSignal(callOptions.abortSignal, currentRetry)
|
|
268
272
|
};
|
|
269
273
|
}
|
|
270
274
|
|
|
@@ -331,9 +335,15 @@ var RetryableEmbeddingModel = class extends BaseRetryableModel {
|
|
|
331
335
|
callOptions: retryCallOptions
|
|
332
336
|
};
|
|
333
337
|
} catch (error) {
|
|
334
|
-
if (isAbortError(error)) throw error;
|
|
335
338
|
const { retryModel, attempt } = await this.handleError(error, attempts, retryCallOptions);
|
|
336
339
|
attempts.push(attempt);
|
|
340
|
+
/**
|
|
341
|
+
* If the inbound abort signal is already aborted and the chosen
|
|
342
|
+
* retry does not supply a fresh deadline, the retry would die
|
|
343
|
+
* instantly with the same abort. Rethrow rather than fire a
|
|
344
|
+
* misleading retry against a dead signal.
|
|
345
|
+
*/
|
|
346
|
+
if (input.callOptions.abortSignal?.aborted && retryModel.timeout === void 0) throw error;
|
|
337
347
|
if (retryModel.delay) {
|
|
338
348
|
/**
|
|
339
349
|
* Calculate exponential backoff delay based on the number of attempts for this specific model.
|
|
@@ -474,11 +484,15 @@ var RetryableImageModel = class extends BaseRetryableModel {
|
|
|
474
484
|
callOptions: retryCallOptions
|
|
475
485
|
};
|
|
476
486
|
} catch (error) {
|
|
477
|
-
/** Don't retry if user manually aborted the request. */
|
|
478
|
-
/** TimeoutError from AbortSignal.timeout() will still be handled by retry handlers. */
|
|
479
|
-
if (isAbortError(error)) throw error;
|
|
480
487
|
const { retryModel, attempt } = await this.handleError(error, attempts, retryCallOptions);
|
|
481
488
|
attempts.push(attempt);
|
|
489
|
+
/**
|
|
490
|
+
* If the inbound abort signal is already aborted and the chosen
|
|
491
|
+
* retry does not supply a fresh deadline, the retry would die
|
|
492
|
+
* instantly with the same abort. Rethrow rather than fire a
|
|
493
|
+
* misleading retry against a dead signal.
|
|
494
|
+
*/
|
|
495
|
+
if (input.callOptions.abortSignal?.aborted && retryModel.timeout === void 0) throw error;
|
|
482
496
|
if (retryModel.delay) {
|
|
483
497
|
/**
|
|
484
498
|
* Calculate exponential backoff delay based on the number of attempts for this specific model.
|
|
@@ -650,9 +664,15 @@ var RetryableLanguageModel = class extends BaseRetryableModel {
|
|
|
650
664
|
callOptions: retryCallOptions
|
|
651
665
|
};
|
|
652
666
|
} catch (error) {
|
|
653
|
-
if (isAbortError(error)) throw error;
|
|
654
667
|
const { retryModel, attempt } = await this.handleError(error, attempts, retryCallOptions);
|
|
655
668
|
attempts.push(attempt);
|
|
669
|
+
/**
|
|
670
|
+
* If the inbound abort signal is already aborted and the chosen
|
|
671
|
+
* retry does not supply a fresh deadline, the retry would die
|
|
672
|
+
* instantly with the same abort. Rethrow rather than fire a
|
|
673
|
+
* misleading retry against a dead signal.
|
|
674
|
+
*/
|
|
675
|
+
if (input.callOptions.abortSignal?.aborted && retryModel.timeout === void 0) throw error;
|
|
656
676
|
if (retryModel.delay) {
|
|
657
677
|
/**
|
|
658
678
|
* Calculate exponential backoff delay based on the number of attempts for this specific model.
|
|
@@ -825,6 +845,13 @@ var RetryableLanguageModel = class extends BaseRetryableModel {
|
|
|
825
845
|
* Save the attempt
|
|
826
846
|
*/
|
|
827
847
|
attempts.push(attempt);
|
|
848
|
+
/**
|
|
849
|
+
* If the inbound abort signal is already aborted and the chosen
|
|
850
|
+
* retry does not supply a fresh deadline, the retry would die
|
|
851
|
+
* instantly with the same abort. Rethrow rather than fire a
|
|
852
|
+
* misleading retry against a dead signal.
|
|
853
|
+
*/
|
|
854
|
+
if (callOptions.abortSignal?.aborted && retryModel.timeout === void 0) throw error;
|
|
828
855
|
if (retryModel.delay) {
|
|
829
856
|
/**
|
|
830
857
|
* Calculate exponential backoff delay based on the number of attempts for this specific model.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { O as RetryContext, T as Retry, b as ResolvableLanguageModel, j as Retryable, n as EmbeddingModel, p as LanguageModelGenerate, s as ImageModel } from "../../types-
|
|
1
|
+
import { O as RetryContext, T as Retry, b as ResolvableLanguageModel, j as Retryable, n as EmbeddingModel, p as LanguageModelGenerate, s as ImageModel } from "../../types-CRKV-hdW.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/retryables/experimental/condition.d.ts
|
|
4
4
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { N as RetryableOptions, b as ResolvableLanguageModel, j as Retryable, n as EmbeddingModel, s as ImageModel } from "../types-
|
|
1
|
+
import { N as RetryableOptions, b as ResolvableLanguageModel, j as Retryable, n as EmbeddingModel, s as ImageModel } from "../types-CRKV-hdW.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/retryables/content-filter-triggered.d.ts
|
|
4
4
|
/**
|
|
@@ -34,7 +34,7 @@ type RetryCallOptions<MODEL extends LanguageModel | EmbeddingModel | ImageModel>
|
|
|
34
34
|
/**
|
|
35
35
|
* Override returned by `onRetry` to influence the upcoming retry attempt.
|
|
36
36
|
*/
|
|
37
|
-
type OnRetryOverrides<MODEL extends LanguageModel | EmbeddingModel | ImageModel> = Pick<Retry<MODEL>, 'options'
|
|
37
|
+
type OnRetryOverrides<MODEL extends LanguageModel | EmbeddingModel | ImageModel> = Pick<Retry<MODEL>, 'options'>;
|
|
38
38
|
/**
|
|
39
39
|
* Maps a model type to its call options type.
|
|
40
40
|
*/
|