ai-retry 0.6.0 → 0.7.0
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 +168 -95
- package/dist/index.d.ts +8 -4
- package/dist/index.js +8 -5
- package/dist/retryables/index.d.ts +1 -1
- package/dist/retryables/index.js +1 -1
- package/dist/{types-DhGbwiB4.d.ts → types-CfE400mD.d.ts} +1 -1
- package/dist/{utils-BlCGaP0E.js → utils-DsvLGk6a.js} +5 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -40,7 +40,8 @@ import { createRetryable } from 'ai-retry';
|
|
|
40
40
|
|
|
41
41
|
// Create a retryable model
|
|
42
42
|
const retryableModel = createRetryable({
|
|
43
|
-
|
|
43
|
+
// Base model
|
|
44
|
+
model: openai('gpt-4-mini'),
|
|
44
45
|
retries: [
|
|
45
46
|
// Retry strategies and fallbacks...
|
|
46
47
|
],
|
|
@@ -74,7 +75,8 @@ import { createRetryable } from 'ai-retry';
|
|
|
74
75
|
|
|
75
76
|
// Create a retryable model
|
|
76
77
|
const retryableModel = createRetryable({
|
|
77
|
-
|
|
78
|
+
// Base model
|
|
79
|
+
model: openai.textEmbedding('text-embedding-3-large'),
|
|
78
80
|
retries: [
|
|
79
81
|
// Retry strategies and fallbacks...
|
|
80
82
|
],
|
|
@@ -89,6 +91,165 @@ const result = await embed({
|
|
|
89
91
|
console.log(result.embedding);
|
|
90
92
|
```
|
|
91
93
|
|
|
94
|
+
### Retryables
|
|
95
|
+
|
|
96
|
+
The objects passed to the `retries` are called retryables and control the retry behavior. We can distinguish between two types of retryables:
|
|
97
|
+
|
|
98
|
+
- **Static retryables** are simply models instances (language or embedding) that will always be used when an error occurs. This is also called a fallback model.
|
|
99
|
+
- **Dynamic retryables** are functions that receive the current attempt context (error/result and previous attempts) and decide whether to retry with a different model based on custom logic.
|
|
100
|
+
|
|
101
|
+
You can think of `retries` as a big `if-else` block, where each dynamic retryable is an `if` condition that can match a certain error/result condition, and static retryables are the `else` branches that match all other conditions. The analogy is not perfect, because the order of retryables matters because `retries` are evaluated in order until one matches:
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
import { openai } from '@ai-sdk/openai';
|
|
105
|
+
import { generateText, streamText } from 'ai';
|
|
106
|
+
import { createRetryable } from 'ai-retry';
|
|
107
|
+
|
|
108
|
+
const retryableModel = createRetryable({
|
|
109
|
+
// Base model
|
|
110
|
+
model: openai('gpt-4-mini'),
|
|
111
|
+
// Retryables are evaluated in order
|
|
112
|
+
retries: [
|
|
113
|
+
// Dynamic retryable that matches only certain errors
|
|
114
|
+
(context) => {
|
|
115
|
+
return context.current.error.statusCode === 429
|
|
116
|
+
? { model: openai('gpt-3.5-turbo') } // Retry with this model
|
|
117
|
+
: undefined; // Skip to next retryable
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
// Static retryable that always matches (fallback)
|
|
121
|
+
anthropic('claude-3-haiku-20240307'),
|
|
122
|
+
// Same as:
|
|
123
|
+
// { model: anthropic('claude-3-haiku-20240307'), maxAttempts: 1 }
|
|
124
|
+
],
|
|
125
|
+
});
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
In this example, if the base model fails with a 429 error, it will retry with `gpt-4`. In any other error case, it will fallback to `gpt-3.5-turbo`. If the order would be reversed, the static retryable would catch all errors first, and the dynamic retryable would never be reached.
|
|
129
|
+
|
|
130
|
+
#### Fallbacks
|
|
131
|
+
|
|
132
|
+
If you don't need precise error matching with custom logic and just want to fallback to different models on any error, you can simply provide a list of models.
|
|
133
|
+
|
|
134
|
+
> [!NOTE]
|
|
135
|
+
> Use the object syntax `{ model: openai('gpt-4') }` if you need to provide additional options like `maxAttempts`, `delay`, etc.
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
import { openai } from '@ai-sdk/openai';
|
|
139
|
+
import { generateText, streamText } from 'ai';
|
|
140
|
+
import { createRetryable } from 'ai-retry';
|
|
141
|
+
|
|
142
|
+
const retryableModel = createRetryable({
|
|
143
|
+
// Base model
|
|
144
|
+
model: openai('gpt-4-mini'),
|
|
145
|
+
// List of fallback models
|
|
146
|
+
retries: [
|
|
147
|
+
openai('gpt-3.5-turbo'), // Fallback for first error
|
|
148
|
+
// Same as:
|
|
149
|
+
// { model: openai('gpt-3.5-turbo'), maxAttempts: 1 },
|
|
150
|
+
|
|
151
|
+
anthropic('claude-3-haiku-20240307'), // Fallback for second error
|
|
152
|
+
// Same as:
|
|
153
|
+
// { model: anthropic('claude-3-haiku-20240307'), maxAttempts: 1 },
|
|
154
|
+
],
|
|
155
|
+
});
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
In this example, if the base model fails, it will retry with `gpt-3.5-turbo`. If that also fails, it will retry with `claude-3-haiku-20240307`. If that fails again, the whole retry process stops and a `RetryError` is thrown.
|
|
159
|
+
|
|
160
|
+
#### Custom
|
|
161
|
+
|
|
162
|
+
If you need more control over when to retry and which model to use, you can create your own custom retryable. This function is called with a context object containing the current attempt (error or result) and all previous attempts and needs to return a retry model or `undefined` to skip to the next retryable. The object you return from the retryable function is the same as the one you provide in the `retries` array.
|
|
163
|
+
|
|
164
|
+
> [!NOTE]
|
|
165
|
+
> You can return additional options like `maxAttempts`, `delay`, etc. along with the model.
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
import { anthropic } from '@ai-sdk/anthropic';
|
|
169
|
+
import { openai } from '@ai-sdk/openai';
|
|
170
|
+
import { APICallError } from 'ai';
|
|
171
|
+
import { createRetryable, isErrorAttempt } from 'ai-retry';
|
|
172
|
+
import type { Retryable } from 'ai-retry';
|
|
173
|
+
|
|
174
|
+
// Custom retryable that retries on rate limit errors (429)
|
|
175
|
+
const rateLimitRetry: Retryable = (context) => {
|
|
176
|
+
// Only handle error attempts
|
|
177
|
+
if (isErrorAttempt(context.current)) {
|
|
178
|
+
// Get the error from the current attempt
|
|
179
|
+
const { error } = context.current;
|
|
180
|
+
|
|
181
|
+
// Check for rate limit error
|
|
182
|
+
if (APICallError.isInstance(error) && error.statusCode === 429) {
|
|
183
|
+
// Retry with a different model
|
|
184
|
+
return { model: anthropic('claude-3-haiku-20240307') };
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Skip to next retryable
|
|
189
|
+
return undefined;
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
const retryableModel = createRetryable({
|
|
193
|
+
// Base model
|
|
194
|
+
model: openai('gpt-4-mini'),
|
|
195
|
+
retries: [
|
|
196
|
+
// Use custom rate limit retryable
|
|
197
|
+
rateLimitRetry
|
|
198
|
+
|
|
199
|
+
// Other retryables...
|
|
200
|
+
],
|
|
201
|
+
});
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
In this example, if the base model fails with a 429 error, it will retry with `claude-3-haiku-20240307`. For any other error, it will skip to the next retryable (if any) or throw the original error.
|
|
205
|
+
|
|
206
|
+
#### All Retries Failed
|
|
207
|
+
|
|
208
|
+
If all retry attempts failed, a `RetryError` is thrown containing all individual errors.
|
|
209
|
+
If no retry was attempted (e.g. because all retryables returned `undefined`), the original error is thrown directly.
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
import { RetryError } from 'ai';
|
|
213
|
+
|
|
214
|
+
const retryableModel = createRetryable({
|
|
215
|
+
// Base model = first attempt
|
|
216
|
+
model: azure('gpt-4-mini'),
|
|
217
|
+
retries: [
|
|
218
|
+
// Fallback model 1 = Second attempt
|
|
219
|
+
openai('gpt-3.5-turbo'),
|
|
220
|
+
// Fallback model 2 = Third attempt
|
|
221
|
+
anthropic('claude-3-haiku-20240307')
|
|
222
|
+
],
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
try {
|
|
226
|
+
const result = await generateText({
|
|
227
|
+
model: retryableModel,
|
|
228
|
+
prompt: 'Hello world!',
|
|
229
|
+
});
|
|
230
|
+
} catch (error) {
|
|
231
|
+
// RetryError is an official AI SDK error
|
|
232
|
+
if (error instanceof RetryError) {
|
|
233
|
+
console.error('All retry attempts failed:', error.errors);
|
|
234
|
+
} else {
|
|
235
|
+
console.error('Request failed:', error);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Errors are tracked per unique model (provider + modelId). That means on the first error, it will retry with `gpt-3.5-turbo`. If that also fails, it will retry with `claude-3-haiku-20240307`. If that fails again, the whole retry process stops and a `RetryError` is thrown.
|
|
241
|
+
|
|
242
|
+
### Built-in Retryables
|
|
243
|
+
|
|
244
|
+
There are several built-in dynamic retryables available for common use cases:
|
|
245
|
+
|
|
246
|
+
- [`contentFilterTriggered`](./src/retryables/content-filter-triggered.ts): Content filter was triggered based on the prompt or completion.
|
|
247
|
+
- [`requestTimeout`](./src/retryables/request-timeout.ts): Request timeout occurred.
|
|
248
|
+
- [`requestNotRetryable`](./src/retryables/request-not-retryable.ts): Request failed with a non-retryable error.
|
|
249
|
+
- [`retryAfterDelay`](./src/retryables/retry-after-delay.ts): Retry with delay and exponential backoff and respect `retry-after` headers.
|
|
250
|
+
- [`serviceOverloaded`](./src/retryables/service-overloaded.ts): Response with status code 529 (service overloaded).
|
|
251
|
+
- Use this retryable to handle Anthropic's overloaded errors.
|
|
252
|
+
|
|
92
253
|
#### Content Filter
|
|
93
254
|
|
|
94
255
|
Automatically switch to a different model when content filtering blocks your request.
|
|
@@ -195,82 +356,6 @@ const retryableModel = createRetryable({
|
|
|
195
356
|
|
|
196
357
|
By default, if a [`retry-after-ms`](https://learn.microsoft.com/en-us/azure/ai-foundry/openai/how-to/provisioned-get-started#what-should--i-do-when-i-receive-a-429-response) or [`retry-after`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Retry-After) header is present in the response, it will be prioritized over the configured delay. The delay from the header will be capped at 60 seconds for safety.
|
|
197
358
|
|
|
198
|
-
#### Fallbacks
|
|
199
|
-
|
|
200
|
-
If you always want to fallback to a different model on any error, you can simply provide a list of models.
|
|
201
|
-
|
|
202
|
-
```typescript
|
|
203
|
-
const retryableModel = createRetryable({
|
|
204
|
-
model: azure('gpt-4'),
|
|
205
|
-
retries: [
|
|
206
|
-
openai('gpt-4'),
|
|
207
|
-
anthropic('claude-3-haiku-20240307')
|
|
208
|
-
],
|
|
209
|
-
});
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
#### Custom
|
|
213
|
-
|
|
214
|
-
Create your own retryables for specific use cases:
|
|
215
|
-
|
|
216
|
-
```typescript
|
|
217
|
-
import { anthropic } from '@ai-sdk/anthropic';
|
|
218
|
-
import { openai } from '@ai-sdk/openai';
|
|
219
|
-
import { APICallError } from 'ai';
|
|
220
|
-
import { createRetryable, isErrorAttempt } from 'ai-retry';
|
|
221
|
-
import type { Retryable } from 'ai-retry';
|
|
222
|
-
|
|
223
|
-
const rateLimitRetry: Retryable = (context) => {
|
|
224
|
-
if (isErrorAttempt(context.current)) {
|
|
225
|
-
const { error } = context.current;
|
|
226
|
-
|
|
227
|
-
if (APICallError.isInstance(error) && error.statusCode === 429) {
|
|
228
|
-
return { model: anthropic('claude-3-haiku-20240307') };
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
return undefined;
|
|
233
|
-
};
|
|
234
|
-
|
|
235
|
-
const retryableModel = createRetryable({
|
|
236
|
-
model: openai('gpt-4'),
|
|
237
|
-
retries: [
|
|
238
|
-
rateLimitRetry
|
|
239
|
-
],
|
|
240
|
-
});
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
#### All Retries Failed
|
|
244
|
-
|
|
245
|
-
If all retry attempts failed, a `RetryError` is thrown containing all individual errors.
|
|
246
|
-
If no retry was attempted (e.g. because all retryables returned `undefined`), the original error is thrown directly.
|
|
247
|
-
|
|
248
|
-
```typescript
|
|
249
|
-
import { RetryError } from 'ai';
|
|
250
|
-
|
|
251
|
-
const retryableModel = createRetryable({
|
|
252
|
-
model: azure('gpt-4'),
|
|
253
|
-
retries: [
|
|
254
|
-
openai('gpt-4'),
|
|
255
|
-
anthropic('claude-3-haiku-20240307')
|
|
256
|
-
],
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
try {
|
|
260
|
-
const result = await generateText({
|
|
261
|
-
model: retryableModel,
|
|
262
|
-
prompt: 'Hello world!',
|
|
263
|
-
});
|
|
264
|
-
} catch (error) {
|
|
265
|
-
// RetryError is an official AI SDK error
|
|
266
|
-
if (error instanceof RetryError) {
|
|
267
|
-
console.error('All retry attempts failed:', error.errors);
|
|
268
|
-
} else {
|
|
269
|
-
console.error('Request failed:', error);
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
```
|
|
273
|
-
|
|
274
359
|
### Options
|
|
275
360
|
|
|
276
361
|
#### Retry Delays
|
|
@@ -282,10 +367,10 @@ const retryableModel = createRetryable({
|
|
|
282
367
|
model: openai('gpt-4'),
|
|
283
368
|
retries: [
|
|
284
369
|
// Retry model 3 times with fixed 2s delay
|
|
285
|
-
|
|
370
|
+
{ model: openai('gpt-4'), delay: 2000, maxAttempts: 3 },
|
|
286
371
|
|
|
287
372
|
// Or retry with exponential backoff (2s, 4s, 8s)
|
|
288
|
-
|
|
373
|
+
{ model: openai('gpt-4'), delay: 2000, backoffFactor: 2, maxAttempts: 3 },
|
|
289
374
|
],
|
|
290
375
|
});
|
|
291
376
|
|
|
@@ -322,7 +407,7 @@ const retryableModel = createRetryable({
|
|
|
322
407
|
// Try this once
|
|
323
408
|
anthropic('claude-3-haiku-20240307'),
|
|
324
409
|
// Try this one more time (initial + 1 retry)
|
|
325
|
-
|
|
410
|
+
{ model: openai('gpt-4'), maxAttempts: 2 },
|
|
326
411
|
// Already tried, won't be retried again
|
|
327
412
|
anthropic('claude-3-haiku-20240307')
|
|
328
413
|
],
|
|
@@ -340,7 +425,7 @@ const retryableModel = createRetryable({
|
|
|
340
425
|
model: openai('gpt-5'),
|
|
341
426
|
retries: [
|
|
342
427
|
// Use different provider options for the retry
|
|
343
|
-
|
|
428
|
+
{
|
|
344
429
|
model: openai('gpt-4o-2024-08-06'),
|
|
345
430
|
providerOptions: {
|
|
346
431
|
openai: {
|
|
@@ -348,7 +433,7 @@ const retryableModel = createRetryable({
|
|
|
348
433
|
structuredOutputs: false,
|
|
349
434
|
},
|
|
350
435
|
},
|
|
351
|
-
}
|
|
436
|
+
},
|
|
352
437
|
],
|
|
353
438
|
});
|
|
354
439
|
|
|
@@ -396,18 +481,6 @@ Errors during streaming requests can occur in two ways:
|
|
|
396
481
|
|
|
397
482
|
In the second case, errors during stream processing will not always be retried, because the stream might have already emitted some actual content and the consumer might have processed it. Retrying will be stopped as soon as the first content chunk (e.g. types of `text-delta`, `tool-call`, etc.) is emitted. The type of chunks considered as content are the same as the ones that are passed to [onChunk()](https://github.com/vercel/ai/blob/1fe4bd4144bff927f5319d9d206e782a73979ccb/packages/ai/src/generate-text/stream-text.ts#L684-L697).
|
|
398
483
|
|
|
399
|
-
### Retryables
|
|
400
|
-
|
|
401
|
-
A retryable is a function that receives the current attempt and determines whether to retry with a different model based on the error/result and any previous attempts.
|
|
402
|
-
There are several built-in retryables:
|
|
403
|
-
|
|
404
|
-
- [`contentFilterTriggered`](./src/retryables/content-filter-triggered.ts): Content filter was triggered based on the prompt or completion.
|
|
405
|
-
- [`requestTimeout`](./src/retryables/request-timeout.ts): Request timeout occurred.
|
|
406
|
-
- [`requestNotRetryable`](./src/retryables/request-not-retryable.ts): Request failed with a non-retryable error.
|
|
407
|
-
- [`retryAfterDelay`](./src/retryables/retry-after-delay.ts): Retry with delay and exponential backoff and respect `retry-after` headers.
|
|
408
|
-
- [`serviceOverloaded`](./src/retryables/service-overloaded.ts): Response with status code 529 (service overloaded).
|
|
409
|
-
- Use this retryable to handle Anthropic's overloaded errors.
|
|
410
|
-
|
|
411
484
|
### API Reference
|
|
412
485
|
|
|
413
486
|
#### `createRetryable(options: RetryableModelOptions): LanguageModelV2 | EmbeddingModelV2`
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { a as LanguageModelV2Generate, c as Retry, d as RetryErrorAttempt, f as RetryResultAttempt, h as RetryableOptions, i as LanguageModelV2, l as RetryAttempt, m as RetryableModelOptions, n as EmbeddingModelV2CallOptions, o as LanguageModelV2Stream, p as Retryable, r as EmbeddingModelV2Embed, s as Retries, t as EmbeddingModelV2, u as RetryContext } from "./types-
|
|
1
|
+
import { a as LanguageModelV2Generate, c as Retry, d as RetryErrorAttempt, f as RetryResultAttempt, h as RetryableOptions, i as LanguageModelV2, l as RetryAttempt, m as RetryableModelOptions, n as EmbeddingModelV2CallOptions, o as LanguageModelV2Stream, p as Retryable, r as EmbeddingModelV2Embed, s as Retries, t as EmbeddingModelV2, u as RetryContext } from "./types-CfE400mD.js";
|
|
2
2
|
import * as _ai_sdk_provider0 from "@ai-sdk/provider";
|
|
3
3
|
import { LanguageModelV2 as LanguageModelV2$1, LanguageModelV2StreamPart } from "@ai-sdk/provider";
|
|
4
4
|
|
|
5
5
|
//#region src/create-retryable-model.d.ts
|
|
6
|
-
declare function createRetryable<MODEL extends LanguageModelV2>(options: RetryableModelOptions<MODEL>): LanguageModelV2;
|
|
7
|
-
declare function createRetryable<MODEL extends EmbeddingModelV2>(options: RetryableModelOptions<MODEL>): EmbeddingModelV2;
|
|
6
|
+
declare function createRetryable<MODEL$1 extends LanguageModelV2>(options: RetryableModelOptions<MODEL$1>): LanguageModelV2;
|
|
7
|
+
declare function createRetryable<MODEL$1 extends EmbeddingModelV2>(options: RetryableModelOptions<MODEL$1>): EmbeddingModelV2;
|
|
8
8
|
//#endregion
|
|
9
9
|
//#region src/get-model-key.d.ts
|
|
10
10
|
/**
|
|
@@ -66,5 +66,9 @@ declare const isStreamContentPart: (part: LanguageModelV2StreamPart) => part is
|
|
|
66
66
|
type: "raw";
|
|
67
67
|
rawValue: unknown;
|
|
68
68
|
};
|
|
69
|
+
/**
|
|
70
|
+
* Type guard to check if a value is a Retry object (has a model property with a MODEL)
|
|
71
|
+
*/
|
|
72
|
+
declare const isRetry: <MODEL extends LanguageModelV2$1 | EmbeddingModelV2>(value: unknown) => value is Retry<MODEL>;
|
|
69
73
|
//#endregion
|
|
70
|
-
export { EmbeddingModelV2, EmbeddingModelV2CallOptions, EmbeddingModelV2Embed, LanguageModelV2, LanguageModelV2Generate, LanguageModelV2Stream, Retries, Retry, RetryAttempt, RetryContext, RetryErrorAttempt, RetryResultAttempt, Retryable, RetryableModelOptions, RetryableOptions, createRetryable, getModelKey, isEmbeddingModelV2, isErrorAttempt, isGenerateResult, isLanguageModelV2, isModelV2, isObject, isResultAttempt, isStreamContentPart, isStreamResult, isString };
|
|
74
|
+
export { EmbeddingModelV2, EmbeddingModelV2CallOptions, EmbeddingModelV2Embed, LanguageModelV2, LanguageModelV2Generate, LanguageModelV2Stream, Retries, Retry, RetryAttempt, RetryContext, RetryErrorAttempt, RetryResultAttempt, Retryable, RetryableModelOptions, RetryableOptions, createRetryable, getModelKey, isEmbeddingModelV2, isErrorAttempt, isGenerateResult, isLanguageModelV2, isModelV2, isObject, isResultAttempt, isRetry, isStreamContentPart, isStreamResult, isString };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as isModelV2, c as
|
|
1
|
+
import { a as isModelV2, c as isRetry, d as isString, i as isLanguageModelV2, l as isStreamContentPart, n as isErrorAttempt, o as isObject, r as isGenerateResult, s as isResultAttempt, t as isEmbeddingModelV2, u as isStreamResult } from "./utils-DsvLGk6a.js";
|
|
2
2
|
import { delay } from "@ai-sdk/provider-utils";
|
|
3
3
|
import { getErrorMessage } from "@ai-sdk/provider";
|
|
4
4
|
import { RetryError } from "ai";
|
|
@@ -35,15 +35,18 @@ function countModelAttempts(model, attempts) {
|
|
|
35
35
|
async function findRetryModel(retries, context) {
|
|
36
36
|
/**
|
|
37
37
|
* Filter retryables based on attempt type:
|
|
38
|
-
* - Result-based attempts: Only consider function retryables (skip plain models)
|
|
39
|
-
* - Error-based attempts: Consider all retryables (functions + plain models)
|
|
38
|
+
* - Result-based attempts: Only consider function retryables (skip plain models and static Retry objects)
|
|
39
|
+
* - Error-based attempts: Consider all retryables (functions + plain models + static Retry objects)
|
|
40
40
|
*/
|
|
41
41
|
const applicableRetries = isResultAttempt(context.current) ? retries.filter((retry) => typeof retry === "function") : retries;
|
|
42
42
|
/**
|
|
43
43
|
* Iterate through the applicable retryables to find a model to retry with
|
|
44
44
|
*/
|
|
45
45
|
for (const retry of applicableRetries) {
|
|
46
|
-
|
|
46
|
+
let retryModel;
|
|
47
|
+
if (typeof retry === "function") retryModel = await retry(context);
|
|
48
|
+
else if (isRetry(retry)) retryModel = retry;
|
|
49
|
+
else retryModel = { model: retry };
|
|
47
50
|
if (retryModel) {
|
|
48
51
|
/**
|
|
49
52
|
* The model key uniquely identifies a model instance (provider + modelId)
|
|
@@ -485,4 +488,4 @@ function createRetryable(options) {
|
|
|
485
488
|
}
|
|
486
489
|
|
|
487
490
|
//#endregion
|
|
488
|
-
export { createRetryable, getModelKey, isEmbeddingModelV2, isErrorAttempt, isGenerateResult, isLanguageModelV2, isModelV2, isObject, isResultAttempt, isStreamContentPart, isStreamResult, isString };
|
|
491
|
+
export { createRetryable, getModelKey, isEmbeddingModelV2, isErrorAttempt, isGenerateResult, isLanguageModelV2, isModelV2, isObject, isResultAttempt, isRetry, isStreamContentPart, isStreamResult, isString };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { h as RetryableOptions, i as LanguageModelV2, p as Retryable, t as EmbeddingModelV2 } from "../types-
|
|
1
|
+
import { h as RetryableOptions, i as LanguageModelV2, p as Retryable, t as EmbeddingModelV2 } from "../types-CfE400mD.js";
|
|
2
2
|
|
|
3
3
|
//#region src/retryables/content-filter-triggered.d.ts
|
|
4
4
|
|
package/dist/retryables/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as isErrorAttempt, o as isObject, s as isResultAttempt
|
|
1
|
+
import { d as isString, n as isErrorAttempt, o as isObject, s as isResultAttempt } from "../utils-DsvLGk6a.js";
|
|
2
2
|
import { isAbortError } from "@ai-sdk/provider-utils";
|
|
3
3
|
import { APICallError } from "ai";
|
|
4
4
|
|
|
@@ -61,7 +61,7 @@ type Retry<MODEL extends LanguageModelV2$1 | EmbeddingModelV2$1> = {
|
|
|
61
61
|
* A function that determines whether to retry with a different model based on the current attempt and all previous attempts.
|
|
62
62
|
*/
|
|
63
63
|
type Retryable<MODEL extends LanguageModelV2$1 | EmbeddingModelV2$1> = (context: RetryContext<MODEL>) => Retry<MODEL> | Promise<Retry<MODEL>> | undefined;
|
|
64
|
-
type Retries<MODEL extends LanguageModelV2$1 | EmbeddingModelV2$1> = Array<Retryable<MODEL> | MODEL>;
|
|
64
|
+
type Retries<MODEL extends LanguageModelV2$1 | EmbeddingModelV2$1> = Array<Retryable<MODEL> | Retry<MODEL> | MODEL>;
|
|
65
65
|
type RetryableOptions<MODEL extends LanguageModelV2$1 | EmbeddingModelV2$1> = Partial<Omit<Retry<MODEL>, 'model'>>;
|
|
66
66
|
type LanguageModelV2Generate = Awaited<ReturnType<LanguageModelV2$1['doGenerate']>>;
|
|
67
67
|
type LanguageModelV2Stream = Awaited<ReturnType<LanguageModelV2$1['doStream']>>;
|
|
@@ -26,6 +26,10 @@ function isResultAttempt(attempt) {
|
|
|
26
26
|
const isStreamContentPart = (part) => {
|
|
27
27
|
return part.type === "text-delta" || part.type === "reasoning-delta" || part.type === "source" || part.type === "tool-call" || part.type === "tool-result" || part.type === "tool-input-start" || part.type === "tool-input-delta" || part.type === "raw";
|
|
28
28
|
};
|
|
29
|
+
/**
|
|
30
|
+
* Type guard to check if a value is a Retry object (has a model property with a MODEL)
|
|
31
|
+
*/
|
|
32
|
+
const isRetry = (value) => isObject(value) && "model" in value && isModelV2(value.model);
|
|
29
33
|
|
|
30
34
|
//#endregion
|
|
31
|
-
export { isModelV2 as a,
|
|
35
|
+
export { isModelV2 as a, isRetry as c, isString as d, isLanguageModelV2 as i, isStreamContentPart as l, isErrorAttempt as n, isObject as o, isGenerateResult as r, isResultAttempt as s, isEmbeddingModelV2 as t, isStreamResult as u };
|