ai 7.0.9 → 7.0.10
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 +9 -0
- package/dist/index.js +25 -71
- package/dist/index.js.map +1 -1
- package/dist/internal/index.d.ts +1 -3
- package/dist/internal/index.js +17 -63
- package/dist/internal/index.js.map +1 -1
- package/docs/03-ai-sdk-core/16-mcp-tools.mdx +28 -0
- package/docs/03-ai-sdk-harnesses/02-harness-agent.mdx +4 -0
- package/docs/03-ai-sdk-harnesses/03-tools.mdx +49 -0
- package/docs/03-ai-sdk-harnesses/05-harness-adapters.mdx +7 -7
- package/docs/07-reference/01-ai-sdk-core/23-create-mcp-client.mdx +7 -0
- package/docs/08-migration-guides/23-migration-guide-7-0.mdx +19 -0
- package/package.json +3 -3
- package/src/util/prepare-retries.ts +2 -4
- package/src/util/retry-with-exponential-backoff.ts +27 -95
|
@@ -203,6 +203,34 @@ This hook is called before the SDK fetches authorization server metadata, so a
|
|
|
203
203
|
rejected URL is not requested. It is optional and does not change existing OAuth
|
|
204
204
|
flows unless you implement it.
|
|
205
205
|
|
|
206
|
+
### Retrying Transient Tool Failures
|
|
207
|
+
|
|
208
|
+
MCP tool calls can fail for transient transport reasons, such as rate limits,
|
|
209
|
+
temporary overload, or gateway timeouts. You can opt into automatic retries for
|
|
210
|
+
`tools/call` requests by passing `maxRetries` when creating the client:
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
const mcpClient = await createMCPClient({
|
|
214
|
+
transport: {
|
|
215
|
+
type: 'http',
|
|
216
|
+
url: 'https://your-server.com/mcp',
|
|
217
|
+
},
|
|
218
|
+
maxRetries: 2,
|
|
219
|
+
});
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Retries are disabled by default. Built-in retry matching is intended for
|
|
223
|
+
transient HTTP and network failures only. JSON-RPC application errors, such as
|
|
224
|
+
invalid tool arguments, are surfaced immediately without retrying. Successful
|
|
225
|
+
MCP tool responses with `isError: true` are also returned to the model without
|
|
226
|
+
retrying.
|
|
227
|
+
|
|
228
|
+
<Note type="warning">
|
|
229
|
+
Only enable retries for MCP tools where retrying is safe. Retrying
|
|
230
|
+
non-idempotent tools, such as tools that send emails or create records, can
|
|
231
|
+
duplicate side effects.
|
|
232
|
+
</Note>
|
|
233
|
+
|
|
206
234
|
### Closing the MCP Client
|
|
207
235
|
|
|
208
236
|
After initialization, you should close the MCP client based on your usage pattern:
|
|
@@ -345,6 +345,10 @@ console.log(preparation.identity);
|
|
|
345
345
|
- `id`: optional stable agent identifier.
|
|
346
346
|
- `instructions`: instructions applied once to a fresh session.
|
|
347
347
|
- `tools`: AI SDK tools executed by the host when the harness calls them.
|
|
348
|
+
- `activeTools`: allowlist of built-in and host-executed tools the harness can
|
|
349
|
+
call.
|
|
350
|
+
- `inactiveTools`: denylist of built-in and host-executed tools the harness
|
|
351
|
+
cannot call.
|
|
348
352
|
- `skills`: instruction bundles surfaced by the adapter.
|
|
349
353
|
- `permissionMode`: built-in tool permission mode.
|
|
350
354
|
- `toolApproval`: approval status map for host-executed tools.
|
|
@@ -91,6 +91,55 @@ const agent = new HarnessAgent({
|
|
|
91
91
|
When the harness calls `weather`, `HarnessAgent` executes the tool in your host
|
|
92
92
|
process, then submits the result back to the harness runtime.
|
|
93
93
|
|
|
94
|
+
## Tool Filtering
|
|
95
|
+
|
|
96
|
+
Use `activeTools` or `inactiveTools` on `HarnessAgent` to control which tools the
|
|
97
|
+
harness can call. Both settings accept tool names from the combined tool set:
|
|
98
|
+
the built-in tools declared by the harness adapter and the AI SDK tools passed
|
|
99
|
+
with `tools`.
|
|
100
|
+
|
|
101
|
+
`activeTools` is an allowlist:
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
const agent = new HarnessAgent({
|
|
105
|
+
harness: claudeCode,
|
|
106
|
+
sandbox: createVercelSandbox({
|
|
107
|
+
runtime: 'node24',
|
|
108
|
+
ports: [4000],
|
|
109
|
+
}),
|
|
110
|
+
tools: { weather },
|
|
111
|
+
activeTools: ['weather'],
|
|
112
|
+
});
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
`inactiveTools` is a denylist:
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
const agent = new HarnessAgent({
|
|
119
|
+
harness: claudeCode,
|
|
120
|
+
sandbox: createVercelSandbox({
|
|
121
|
+
runtime: 'node24',
|
|
122
|
+
ports: [4000],
|
|
123
|
+
}),
|
|
124
|
+
tools: { weather },
|
|
125
|
+
inactiveTools: ['bash', 'write'],
|
|
126
|
+
});
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Pass either `activeTools` or `inactiveTools`, not both. The TypeScript settings
|
|
130
|
+
type prevents combining them, and `HarnessAgent` also throws at runtime when
|
|
131
|
+
both are specified.
|
|
132
|
+
|
|
133
|
+
For host-executed tools, inactive tools are not passed to the underlying
|
|
134
|
+
harness runtime. If the runtime still attempts to call one, `HarnessAgent`
|
|
135
|
+
returns an execution-denied tool result.
|
|
136
|
+
|
|
137
|
+
For built-in tools, support depends on the harness adapter. Some adapters can
|
|
138
|
+
filter built-ins natively. Others enforce filtering through their built-in tool
|
|
139
|
+
approval mechanism by denying inactive built-in calls before they execute,
|
|
140
|
+
without emitting approval request or response stream parts. Adapters that
|
|
141
|
+
support neither mechanism throw when you filter built-in tools.
|
|
142
|
+
|
|
94
143
|
## Sandbox in Tool Execution
|
|
95
144
|
|
|
96
145
|
Host-executed tools receive the session sandbox through the same
|
|
@@ -28,10 +28,10 @@ The AI SDK includes the following harness adapters:
|
|
|
28
28
|
|
|
29
29
|
## Adapter Capabilities
|
|
30
30
|
|
|
31
|
-
| Adapter | Runtime location | Custom tools | Custom skills | Built-in tool approval |
|
|
32
|
-
| ------------------------------------------------------ | ---------------- | ------------------- | ------------------- | ---------------------- |
|
|
33
|
-
| [Claude Code](/providers/ai-sdk-harnesses/claude-code) | Sandbox bridge | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
|
|
34
|
-
| [Codex](/providers/ai-sdk-harnesses/codex) | Sandbox bridge | <Check size={18} /> | <Check size={18} /> | <Cross size={18} /> |
|
|
35
|
-
| [Deep Agents](/providers/ai-sdk-harnesses/deepagents) | Sandbox bridge | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
|
|
36
|
-
| [OpenCode](/providers/ai-sdk-harnesses/opencode) | Sandbox bridge | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
|
|
37
|
-
| [Pi](/providers/ai-sdk-harnesses/pi) | Host process | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
|
|
31
|
+
| Adapter | Runtime location | Custom tools | Custom skills | Built-in tool approval | Built-in tool filtering |
|
|
32
|
+
| ------------------------------------------------------ | ---------------- | ------------------- | ------------------- | ---------------------- | -------------------------------------- |
|
|
33
|
+
| [Claude Code](/providers/ai-sdk-harnesses/claude-code) | Sandbox bridge | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
|
|
34
|
+
| [Codex](/providers/ai-sdk-harnesses/codex) | Sandbox bridge | <Check size={18} /> | <Check size={18} /> | <Cross size={18} /> | <Cross size={18} /> |
|
|
35
|
+
| [Deep Agents](/providers/ai-sdk-harnesses/deepagents) | Sandbox bridge | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> via auto-rejection |
|
|
36
|
+
| [OpenCode](/providers/ai-sdk-harnesses/opencode) | Sandbox bridge | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> via auto-rejection |
|
|
37
|
+
| [Pi](/providers/ai-sdk-harnesses/pi) | Host process | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
|
|
@@ -187,6 +187,13 @@ It currently does not support accepting notifications from an MCP server, and cu
|
|
|
187
187
|
isOptional: true,
|
|
188
188
|
description: 'Handler for uncaught errors',
|
|
189
189
|
},
|
|
190
|
+
{
|
|
191
|
+
name: 'maxRetries',
|
|
192
|
+
type: 'number',
|
|
193
|
+
isOptional: true,
|
|
194
|
+
description:
|
|
195
|
+
'Maximum number of retries for transient MCP tool call failures. Set to 0 to disable retries. Defaults to 0. Retries are opt-in and apply to tools/call requests.',
|
|
196
|
+
},
|
|
190
197
|
{
|
|
191
198
|
name: 'initialInitializeResult',
|
|
192
199
|
type: 'InitializeResult',
|
|
@@ -1883,6 +1883,25 @@ The old names still work as deprecated aliases, but you should migrate to the ne
|
|
|
1883
1883
|
|
|
1884
1884
|
The main entry point the `google` constant, remains unchanged, so if that's all you use from the provider, no changes are required.
|
|
1885
1885
|
|
|
1886
|
+
## xAI Provider
|
|
1887
|
+
|
|
1888
|
+
### Default Model Now Uses the Responses API
|
|
1889
|
+
|
|
1890
|
+
In AI SDK 7, `xai(modelId)` (and `xai.languageModel(modelId)`) uses the xAI Responses API by default instead of the Chat Completions API. Both APIs were already available in AI SDK 6 via `xai.chat(modelId)` and `xai.responses(modelId)`; AI SDK 7 only changes which one `xai(modelId)` uses by default. To keep using the Chat Completions API, use `xai.chat(modelId)`.
|
|
1891
|
+
|
|
1892
|
+
```tsx filename="AI SDK 6"
|
|
1893
|
+
// used the Chat Completions API
|
|
1894
|
+
const model = xai('grok-4.3');
|
|
1895
|
+
```
|
|
1896
|
+
|
|
1897
|
+
```tsx filename="AI SDK 7"
|
|
1898
|
+
// now uses the Responses API
|
|
1899
|
+
const model = xai('grok-4.3');
|
|
1900
|
+
|
|
1901
|
+
// use the Chat Completions API explicitly
|
|
1902
|
+
const chatModel = xai.chat('grok-4.3');
|
|
1903
|
+
```
|
|
1904
|
+
|
|
1886
1905
|
# Migration Skill
|
|
1887
1906
|
|
|
1888
1907
|
Use the command below to add the migration skill and guide your agent
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.0.10",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "AI SDK by Vercel - build apps like ChatGPT, Claude, Gemini, and more with a single interface for any model using the Vercel AI Gateway or go direct to OpenAI, Anthropic, Google, or any other model provider.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -42,9 +42,9 @@
|
|
|
42
42
|
}
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@ai-sdk/gateway": "4.0.
|
|
45
|
+
"@ai-sdk/gateway": "4.0.8",
|
|
46
46
|
"@ai-sdk/provider": "4.0.1",
|
|
47
|
-
"@ai-sdk/provider-utils": "5.0.
|
|
47
|
+
"@ai-sdk/provider-utils": "5.0.3"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@edge-runtime/vm": "^5.0.0",
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { InvalidArgumentError } from '../error/invalid-argument-error';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
type RetryFunction,
|
|
5
|
-
} from '../util/retry-with-exponential-backoff';
|
|
2
|
+
import type { RetryFunction } from '@ai-sdk/provider-utils';
|
|
3
|
+
import { retryWithExponentialBackoffRespectingRetryHeaders } from '../util/retry-with-exponential-backoff';
|
|
6
4
|
/**
|
|
7
5
|
* Validate and prepare retries.
|
|
8
6
|
*/
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { APICallError } from '@ai-sdk/provider';
|
|
2
2
|
import { GatewayError } from '@ai-sdk/gateway';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
retryWithExponentialBackoff,
|
|
5
|
+
type RetryFunction,
|
|
6
|
+
} from '@ai-sdk/provider-utils';
|
|
4
7
|
import { RetryError } from './retry-error';
|
|
5
8
|
|
|
6
|
-
export type RetryFunction = <OUTPUT>(
|
|
7
|
-
fn: () => PromiseLike<OUTPUT>,
|
|
8
|
-
) => PromiseLike<OUTPUT>;
|
|
9
|
-
|
|
10
9
|
function getRetryDelayInMs({
|
|
11
10
|
error,
|
|
12
11
|
exponentialBackoffDelay,
|
|
@@ -62,98 +61,31 @@ function getRetryDelayInMs({
|
|
|
62
61
|
* while respecting rate limit headers (retry-after-ms and retry-after) if they are provided and reasonable (0-60 seconds).
|
|
63
62
|
* You can configure the maximum number of retries, the initial delay, and the backoff factor.
|
|
64
63
|
*/
|
|
65
|
-
export const retryWithExponentialBackoffRespectingRetryHeaders =
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
async <OUTPUT>(f: () => PromiseLike<OUTPUT>) =>
|
|
78
|
-
_retryWithExponentialBackoff(f, {
|
|
79
|
-
maxRetries,
|
|
80
|
-
delayInMs: initialDelayInMs,
|
|
81
|
-
backoffFactor,
|
|
82
|
-
abortSignal,
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
async function _retryWithExponentialBackoff<OUTPUT>(
|
|
86
|
-
f: () => PromiseLike<OUTPUT>,
|
|
87
|
-
{
|
|
64
|
+
export const retryWithExponentialBackoffRespectingRetryHeaders = ({
|
|
65
|
+
maxRetries = 2,
|
|
66
|
+
initialDelayInMs = 2000,
|
|
67
|
+
backoffFactor = 2,
|
|
68
|
+
abortSignal,
|
|
69
|
+
}: {
|
|
70
|
+
maxRetries?: number;
|
|
71
|
+
initialDelayInMs?: number;
|
|
72
|
+
backoffFactor?: number;
|
|
73
|
+
abortSignal?: AbortSignal;
|
|
74
|
+
} = {}): RetryFunction =>
|
|
75
|
+
retryWithExponentialBackoff({
|
|
88
76
|
maxRetries,
|
|
89
|
-
|
|
77
|
+
initialDelayInMs,
|
|
90
78
|
backoffFactor,
|
|
91
79
|
abortSignal,
|
|
92
|
-
|
|
93
|
-
maxRetries: number;
|
|
94
|
-
delayInMs: number;
|
|
95
|
-
backoffFactor: number;
|
|
96
|
-
abortSignal: AbortSignal | undefined;
|
|
97
|
-
},
|
|
98
|
-
errors: unknown[] = [],
|
|
99
|
-
): Promise<OUTPUT> {
|
|
100
|
-
try {
|
|
101
|
-
return await f();
|
|
102
|
-
} catch (error) {
|
|
103
|
-
if (isAbortError(error)) {
|
|
104
|
-
throw error; // don't retry when the request was aborted
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
if (maxRetries === 0) {
|
|
108
|
-
throw error; // don't wrap the error when retries are disabled
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const errorMessage = getErrorMessage(error);
|
|
112
|
-
const newErrors = [...errors, error];
|
|
113
|
-
const tryNumber = newErrors.length;
|
|
114
|
-
|
|
115
|
-
if (tryNumber > maxRetries) {
|
|
116
|
-
throw new RetryError({
|
|
117
|
-
message: `Failed after ${tryNumber} attempts. Last error: ${errorMessage}`,
|
|
118
|
-
reason: 'maxRetriesExceeded',
|
|
119
|
-
errors: newErrors,
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
if (
|
|
80
|
+
shouldRetry: error =>
|
|
124
81
|
error instanceof Error &&
|
|
125
82
|
((APICallError.isInstance(error) && error.isRetryable === true) ||
|
|
126
|
-
(GatewayError.isInstance(error) && error.isRetryable === true))
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
);
|
|
136
|
-
|
|
137
|
-
return _retryWithExponentialBackoff(
|
|
138
|
-
f,
|
|
139
|
-
{
|
|
140
|
-
maxRetries,
|
|
141
|
-
delayInMs: backoffFactor * delayInMs,
|
|
142
|
-
backoffFactor,
|
|
143
|
-
abortSignal,
|
|
144
|
-
},
|
|
145
|
-
newErrors,
|
|
146
|
-
);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
if (tryNumber === 1) {
|
|
150
|
-
throw error; // don't wrap the error when a non-retryable error occurs on the first try
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
throw new RetryError({
|
|
154
|
-
message: `Failed after ${tryNumber} attempts with non-retryable error: '${errorMessage}'`,
|
|
155
|
-
reason: 'errorNotRetryable',
|
|
156
|
-
errors: newErrors,
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
}
|
|
83
|
+
(GatewayError.isInstance(error) && error.isRetryable === true)),
|
|
84
|
+
getDelayInMs: ({ error, exponentialBackoffDelay }) =>
|
|
85
|
+
getRetryDelayInMs({
|
|
86
|
+
error: error as APICallError | GatewayError,
|
|
87
|
+
exponentialBackoffDelay,
|
|
88
|
+
}),
|
|
89
|
+
createRetryError: ({ message, reason, errors }) =>
|
|
90
|
+
new RetryError({ message, reason, errors }),
|
|
91
|
+
});
|