ai-retry 0.0.1 → 0.0.2
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 +22 -0
- package/dist/retryables/index.d.ts +31 -2
- package/dist/retryables/index.js +52 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
<a href="https://www.npmjs.com/package/ai-retry" alt="ai-retry"><img src="https://img.shields.io/npm/dt/ai-retry?label=ai-retry"></a> <a href="https://github.com/zirkelc/ai-retry/actions/workflows/ci.yml" alt="CI"><img src="https://img.shields.io/github/actions/workflow/status/zirkelc/ai-retry/ci.yml?branch=main"></a>
|
|
2
|
+
|
|
1
3
|
# ai-retry: Retry and fallback mechanisms for AI SDK
|
|
2
4
|
|
|
3
5
|
Automatically handle API failures, content filtering and timeouts by switching between different AI models.
|
|
@@ -118,6 +120,24 @@ const result = await generateText({
|
|
|
118
120
|
});
|
|
119
121
|
```
|
|
120
122
|
|
|
123
|
+
#### Service Overloaded
|
|
124
|
+
|
|
125
|
+
Handle service overload errors (HTTP code 529) by switching to a provider.
|
|
126
|
+
|
|
127
|
+
> [!NOTE]
|
|
128
|
+
> For Anthropic specifically, use `anthropicServiceOverloaded` instead as Anthropic sometimes returns HTTP 200 OK with an error payload rather than the standard HTTP 529.
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
import { serviceOverloaded } from 'ai-retry/retryables';
|
|
132
|
+
|
|
133
|
+
const retryableModel = createRetryable({
|
|
134
|
+
model: azure('gpt-4'),
|
|
135
|
+
retries: [
|
|
136
|
+
serviceOverloaded(openai('gpt-4')), // Switch to OpenAI if Azure is overloaded
|
|
137
|
+
],
|
|
138
|
+
});
|
|
139
|
+
```
|
|
140
|
+
|
|
121
141
|
#### Request Not Retryable
|
|
122
142
|
|
|
123
143
|
Handle cases where the base model fails with a non-retryable error.
|
|
@@ -240,6 +260,8 @@ There are several built-in retryables:
|
|
|
240
260
|
- [`contentFilterTriggered`](./src/retryables/content-filter-triggered.ts): Content filter was triggered based on the prompt or completion.
|
|
241
261
|
- [`requestTimeout`](./src/retryables/request-timeout.ts): Request timeout occurred.
|
|
242
262
|
- [`requestNotRetryable`](./src/retryables/request-not-retryable.ts): Request failed with a non-retryable error.
|
|
263
|
+
- [`serviceOverloaded`](./src/retryables/service-overloaded.ts): Response with status code 529 (service overloaded).
|
|
264
|
+
- [`anthropicServiceOverloaded`](./src/retryables/anthropic-service-overloaded.ts): Anthropic-specific overloaded error handling for both HTTP 529 and 200 OK responses with overloaded error payloads.
|
|
243
265
|
|
|
244
266
|
By default, each retryable will only attempt to retry once per model to avoid infinite loops. You can customize this behavior by returning a `maxAttempts` value from your retryable function.
|
|
245
267
|
|
|
@@ -1,8 +1,31 @@
|
|
|
1
1
|
import { RetryModel, Retryable } from "../create-retryable-model-DzDFqgQO.js";
|
|
2
2
|
import { LanguageModelV2 } from "@ai-sdk/provider";
|
|
3
3
|
|
|
4
|
-
//#region src/retryables/
|
|
4
|
+
//#region src/retryables/anthropic-service-overloaded.d.ts
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Type for Anthropic error responses.
|
|
8
|
+
*
|
|
9
|
+
* @see https://docs.claude.com/en/api/errors#error-shapes
|
|
10
|
+
*/
|
|
11
|
+
type AnthropicErrorResponse = {
|
|
12
|
+
type: 'error';
|
|
13
|
+
error: {
|
|
14
|
+
type: string;
|
|
15
|
+
message: string;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Fallback if Anthropic returns an "overloaded" error with HTTP 200.
|
|
20
|
+
*
|
|
21
|
+
* ```
|
|
22
|
+
* HTTP 200 OK
|
|
23
|
+
* {"type":"error","error":{"type":"overloaded_error","message":"Overloaded"}}
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
declare function anthropicServiceOverloaded(model: LanguageModelV2, options?: Omit<RetryModel, 'model'>): Retryable;
|
|
27
|
+
//#endregion
|
|
28
|
+
//#region src/retryables/content-filter-triggered.d.ts
|
|
6
29
|
/**
|
|
7
30
|
* Fallback to a different model if the content filter was triggered.
|
|
8
31
|
*/
|
|
@@ -24,4 +47,10 @@ declare function requestTimeout(model: LanguageModelV2, options?: Omit<RetryMode
|
|
|
24
47
|
//#region src/retryables/response-schema-mismatch.d.ts
|
|
25
48
|
declare function responseSchemaMismatch(model: LanguageModelV2, options?: Omit<RetryModel, 'model'>): Retryable;
|
|
26
49
|
//#endregion
|
|
27
|
-
|
|
50
|
+
//#region src/retryables/service-overloaded.d.ts
|
|
51
|
+
/**
|
|
52
|
+
* Fallback to a different model if the provider returns a HTTP 529 error.
|
|
53
|
+
*/
|
|
54
|
+
declare function serviceOverloaded(model: LanguageModelV2, options?: Omit<RetryModel, 'model'>): Retryable;
|
|
55
|
+
//#endregion
|
|
56
|
+
export { AnthropicErrorResponse, anthropicServiceOverloaded, contentFilterTriggered, requestNotRetryable, requestTimeout, responseSchemaMismatch, serviceOverloaded };
|
package/dist/retryables/index.js
CHANGED
|
@@ -6,6 +6,38 @@ import { APICallError, NoObjectGeneratedError, TypeValidationError } from "ai";
|
|
|
6
6
|
const isObject = (value) => typeof value === "object" && value !== null;
|
|
7
7
|
const isString = (value) => typeof value === "string";
|
|
8
8
|
|
|
9
|
+
//#endregion
|
|
10
|
+
//#region src/retryables/anthropic-service-overloaded.ts
|
|
11
|
+
/**
|
|
12
|
+
* Fallback if Anthropic returns an "overloaded" error with HTTP 200.
|
|
13
|
+
*
|
|
14
|
+
* ```
|
|
15
|
+
* HTTP 200 OK
|
|
16
|
+
* {"type":"error","error":{"type":"overloaded_error","message":"Overloaded"}}
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
function anthropicServiceOverloaded(model, options) {
|
|
20
|
+
return (context) => {
|
|
21
|
+
const { current } = context;
|
|
22
|
+
if (isErrorAttempt(current)) {
|
|
23
|
+
const { error } = current;
|
|
24
|
+
if (APICallError.isInstance(error) && error.statusCode === 529) return {
|
|
25
|
+
model,
|
|
26
|
+
maxAttempts: 1,
|
|
27
|
+
...options
|
|
28
|
+
};
|
|
29
|
+
if (APICallError.isInstance(error) && error.statusCode === 200) try {
|
|
30
|
+
const responseBody = JSON.parse(error.responseBody ?? "");
|
|
31
|
+
if (responseBody.error && isObject(responseBody.error) && isString(responseBody.error.type) && responseBody.error.type === "overloaded_error") return {
|
|
32
|
+
model,
|
|
33
|
+
maxAttempts: 1,
|
|
34
|
+
...options
|
|
35
|
+
};
|
|
36
|
+
} catch {}
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
9
41
|
//#endregion
|
|
10
42
|
//#region src/retryables/content-filter-triggered.ts
|
|
11
43
|
/**
|
|
@@ -89,4 +121,23 @@ function responseSchemaMismatch(model, options) {
|
|
|
89
121
|
}
|
|
90
122
|
|
|
91
123
|
//#endregion
|
|
92
|
-
|
|
124
|
+
//#region src/retryables/service-overloaded.ts
|
|
125
|
+
/**
|
|
126
|
+
* Fallback to a different model if the provider returns a HTTP 529 error.
|
|
127
|
+
*/
|
|
128
|
+
function serviceOverloaded(model, options) {
|
|
129
|
+
return (context) => {
|
|
130
|
+
const { current } = context;
|
|
131
|
+
if (isErrorAttempt(current)) {
|
|
132
|
+
const { error } = current;
|
|
133
|
+
if (APICallError.isInstance(error) && error.statusCode === 529) return {
|
|
134
|
+
model,
|
|
135
|
+
maxAttempts: 1,
|
|
136
|
+
...options
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
//#endregion
|
|
143
|
+
export { anthropicServiceOverloaded, contentFilterTriggered, requestNotRetryable, requestTimeout, responseSchemaMismatch, serviceOverloaded };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-retry",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"description": "AI SDK Retry",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"ai": "5.x"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
+
"@ai-sdk/anthropic": "^2.0.18",
|
|
36
37
|
"@ai-sdk/azure": "^2.0.30",
|
|
37
38
|
"@ai-sdk/openai": "^2.0.30",
|
|
38
39
|
"@arethetypeswrong/cli": "^0.18.2",
|