ai 7.0.42 → 7.0.44

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.
@@ -85,7 +85,7 @@ import {
85
85
  } from "@ai-sdk/provider-utils";
86
86
 
87
87
  // src/version.ts
88
- var VERSION = true ? "7.0.42" : "0.0.0-test";
88
+ var VERSION = true ? "7.0.44" : "0.0.0-test";
89
89
 
90
90
  // src/util/download/download.ts
91
91
  var download = async ({
@@ -0,0 +1,246 @@
1
+ ---
2
+ title: Code Mode
3
+ description: Let models orchestrate AI SDK tools with sandboxed JavaScript and TypeScript.
4
+ ---
5
+
6
+ # Code Mode
7
+
8
+ Code mode lets a model write JavaScript or TypeScript that calls your AI SDK
9
+ tools. The generated code runs in an isolated QuickJS sandbox and returns a JSON-serializable result.
10
+
11
+ Instead of calling tools one at a time, a model can use code mode to:
12
+
13
+ - call independent tools concurrently
14
+ - transform and combine tool results
15
+ - filter large tool responses before returning them to the model
16
+ - use JavaScript control flow for multi-step operations
17
+
18
+ Code mode is provided by the `@ai-sdk/code-mode` package.
19
+
20
+ <Note type="warning">
21
+ Code mode is experimental and its APIs may change in future releases. It
22
+ requires Node.js 22 or newer and is not available in browser or edge runtimes.
23
+ </Note>
24
+
25
+ ## Installation
26
+
27
+ ```bash
28
+ pnpm add ai @ai-sdk/code-mode zod
29
+ ```
30
+
31
+ ## Using Code Mode with `generateText`
32
+
33
+ Define your tools in one tool set and use `experimental_toolCallers` to select
34
+ which tools code mode can call:
35
+
36
+ ```ts
37
+ import { experimental_codeModeTool as codeModeTool } from '@ai-sdk/code-mode';
38
+ import { generateText, isStepCount, tool } from 'ai';
39
+ import { z } from 'zod';
40
+
41
+ const getInventory = tool({
42
+ description: 'Get available inventory for a product.',
43
+ inputSchema: z.object({
44
+ productId: z.string(),
45
+ }),
46
+ outputSchema: z.object({
47
+ productId: z.string(),
48
+ availableUnits: z.number(),
49
+ }),
50
+ execute: async ({ productId }) => ({
51
+ productId,
52
+ availableUnits: 42,
53
+ }),
54
+ });
55
+
56
+ const getDemand = tool({
57
+ description: 'Get requested units for a product.',
58
+ inputSchema: z.object({
59
+ productId: z.string(),
60
+ }),
61
+ outputSchema: z.object({
62
+ productId: z.string(),
63
+ requestedUnits: z.number(),
64
+ }),
65
+ execute: async ({ productId }) => ({
66
+ productId,
67
+ requestedUnits: 31,
68
+ }),
69
+ });
70
+
71
+ const tools = {
72
+ code_mode: codeModeTool({
73
+ executionPolicy: {
74
+ timeoutMs: 30_000,
75
+ },
76
+ }),
77
+ getInventory,
78
+ getDemand,
79
+ } as const;
80
+
81
+ const result = await generateText({
82
+ model: __MODEL__,
83
+ tools,
84
+ experimental_toolCallers: ({ code_mode }) => ({
85
+ getInventory: [code_mode],
86
+ getDemand: [code_mode],
87
+ }),
88
+ stopWhen: isStepCount(10),
89
+ prompt: 'Compare inventory and demand for product sku_123.',
90
+ });
91
+ ```
92
+
93
+ The keys returned by `experimental_toolCallers` are the tools being governed.
94
+ The values identify their allowed callers. In this example, `getInventory` and
95
+ `getDemand` are available through `code_mode`, but they are not exposed to the
96
+ model as directly callable tools. Include `'direct'` when a tool should also be
97
+ callable directly:
98
+
99
+ ```ts
100
+ experimental_toolCallers: ({ code_mode }) => ({
101
+ getInventory: ['direct', code_mode],
102
+ });
103
+ ```
104
+
105
+ Tools without an `experimental_toolCallers` entry keep their existing direct
106
+ tool-calling behavior.
107
+
108
+ The code mode tool description includes TypeScript signatures generated from
109
+ the input and output schemas of its allowed tools. Descriptions,
110
+ `inputExamples`, and precise schemas help the model write correct code.
111
+
112
+ For the example above, the model can generate a program like:
113
+
114
+ ```ts
115
+ const [inventory, demand] = await Promise.all([
116
+ tools.getInventory({ productId: 'sku_123' }),
117
+ tools.getDemand({ productId: 'sku_123' }),
118
+ ]);
119
+
120
+ return {
121
+ sufficient: inventory.availableUnits >= demand.requestedUnits,
122
+ remaining: inventory.availableUnits - demand.requestedUnits,
123
+ };
124
+ ```
125
+
126
+ Each provided tool is available through the global `tools` object. Tool names
127
+ that are not valid JavaScript identifiers use bracket notation:
128
+
129
+ ```ts
130
+ const user = await tools['lookup-user']({ userId: 'user_123' });
131
+ return { id: user.id, plan: user.plan };
132
+ ```
133
+
134
+ ## Writing Code Mode Programs
135
+
136
+ Generated programs support:
137
+
138
+ - JavaScript and type-stripped TypeScript
139
+ - top-level `await` and `return`
140
+ - standard JavaScript control flow and data transformations
141
+ - `Promise.all` for concurrent tool calls
142
+ - `JSON.parse` and `JSON.stringify`
143
+ - `console.log`, `console.info`, `console.debug`, and `console.error`
144
+
145
+ Every tool call is asynchronous and must be awaited or otherwise observed.
146
+ Returning while tool calls are still detached fails the invocation and aborts
147
+ the outstanding work.
148
+
149
+ Programs and tool inputs and outputs cross the sandbox boundary as JSON. Return
150
+ only JSON-serializable values. TypeScript support is limited to removing type
151
+ syntax; code mode does not perform type checking or provide a full TypeScript
152
+ compiler.
153
+
154
+ ## Direct Execution
155
+
156
+ Use `experimental_runCodeMode` when you want to execute a program directly
157
+ instead of exposing code mode to a model:
158
+
159
+ ```ts
160
+ import { experimental_runCodeMode as runCodeMode } from '@ai-sdk/code-mode';
161
+
162
+ const result = await runCodeMode({
163
+ js: `
164
+ const inventory = await tools.getInventory({
165
+ productId: 'sku_123',
166
+ });
167
+
168
+ return {
169
+ productId: inventory.productId,
170
+ available: inventory.availableUnits > 0,
171
+ };
172
+ `,
173
+ tools: { getInventory },
174
+ });
175
+ ```
176
+
177
+ `runCodeMode` returns the value returned by the program. It uses the same
178
+ sandbox and execution limits as the AI SDK tool.
179
+
180
+ ## Execution Limits
181
+
182
+ Every invocation has limits for runtime, memory, source size, results, tool
183
+ payloads, console output, and tool calls. Override them with
184
+ `executionPolicy`:
185
+
186
+ ```ts
187
+ const codeMode = codeModeTool({
188
+ executionPolicy: {
189
+ timeoutMs: 30_000,
190
+ memoryLimitBytes: 64 * 1024 * 1024,
191
+ maxResultBytes: 1024 * 1024,
192
+ maxBridgeRequests: 100,
193
+ maxInFlightBridgeRequests: 10,
194
+ },
195
+ });
196
+ ```
197
+
198
+ The available limits are:
199
+
200
+ - `timeoutMs`: total execution time
201
+ - `memoryLimitBytes`: QuickJS memory
202
+ - `maxStackSizeBytes`: QuickJS stack
203
+ - `maxSourceBytes`: generated source code
204
+ - `maxResultBytes`: returned result
205
+ - `maxConsoleOutputBytes`: combined console output
206
+ - `maxToolInputBytes`: input for each tool call
207
+ - `maxToolOutputBytes`: output from each tool call
208
+ - `maxBridgeRequests`: total tool calls
209
+ - `maxInFlightBridgeRequests`: concurrent tool calls
210
+
211
+ Use `experimental_setMaxWorkers` to set a process-wide cap on concurrent code
212
+ mode workers:
213
+
214
+ ```ts
215
+ import { experimental_setMaxWorkers as setMaxWorkers } from '@ai-sdk/code-mode';
216
+
217
+ setMaxWorkers(4);
218
+ ```
219
+
220
+ Without an explicit cap, code mode chooses one based on available memory, up to
221
+ 32 workers.
222
+
223
+ ## Isolation and Tool Access
224
+
225
+ Each invocation receives a fresh QuickJS context. Sandboxed code cannot access:
226
+
227
+ - Node.js globals such as `process`, `require`, or `module`
228
+ - the host file system or module loader
229
+ - `fetch`, WebCrypto, or performance APIs
230
+ - `eval` or dynamic `Function` construction
231
+
232
+ Network or system access must be implemented in a tool and explicitly provided
233
+ to code mode.
234
+
235
+ <Note type="warning">
236
+ Treat the sandbox as defense in depth. Generated code and tool arguments are
237
+ untrusted. Tools execute in your host application, outside the QuickJS
238
+ sandbox, and every capability exposed by a provided tool is available to the
239
+ generated program. Enforce authorization and validate inputs inside each tool.
240
+ </Note>
241
+
242
+ Tool input schemas are validated before their `execute` functions run. Abort
243
+ signals and AI SDK tool execution context are forwarded to nested tool calls.
244
+
245
+ Code mode does not currently support approval flows for nested tool calls.
246
+ Tools that require approval are rejected instead of being executed.
@@ -653,7 +653,7 @@ Called after the provider response has been normalized and parsed, before local
653
653
  {
654
654
  name: 'modelId',
655
655
  type: 'string',
656
- description: 'Model identifier for this model call.',
656
+ description: 'Provider-returned model identifier for this model call.',
657
657
  },
658
658
  {
659
659
  name: 'finishReason',
@@ -28,6 +28,12 @@ description: Learn about AI SDK Core.
28
28
  description: 'Learn how to do tool calling with AI SDK Core.',
29
29
  href: '/docs/ai-sdk-core/tools-and-tool-calling',
30
30
  },
31
+ {
32
+ title: 'Code Mode',
33
+ description:
34
+ 'Learn how models can orchestrate tools with sandboxed JavaScript and TypeScript.',
35
+ href: '/docs/ai-sdk-core/code-mode',
36
+ },
31
37
  {
32
38
  title: 'Realtime',
33
39
  description: 'Learn how to build realtime voice conversations.',
@@ -578,6 +578,13 @@ To see `generateText` in action, check out [these examples](#examples).
578
578
  description:
579
579
  "Approval configuration for this call. Pass a `GenericToolApprovalFunction` to handle all tool calls in one callback with `toolCall`, `tools`, `toolsContext`, `messages`, and `runtimeContext`, or pass a per-tool object where each key can be a status (`'not-applicable'`, `'approved'`, `'denied'`, or `'user-approval'`), an object form such as `{ type: 'denied', reason: 'blocked by policy' }`, or a `SingleToolApprovalFunction` that receives the tool input and options `toolCallId`, `messages`, `toolContext`, and `runtimeContext` (same shape as tool execution options without `abortSignal`, with `context` renamed to `toolContext`). The `RUNTIME_CONTEXT` type parameter matches the call's `runtimeContext`. A `GenericToolApprovalFunction` or `SingleToolApprovalFunction` may return `undefined` for the same effect as `'not-applicable'`. `'not-applicable'` is the default execution path and runs the tool without approval metadata. Use `'approved'`, `'denied'`, or their object forms when you want explicit automatic approval request/response parts in the output. Automatic approvals and denials can include a `reason`, which is forwarded to the emitted approval response. This setting takes precedence over a tool's `needsApproval` default.",
580
580
  },
581
+ {
582
+ name: 'experimental_toolCallers',
583
+ type: 'Experimental_ToolCallers<TOOLS>',
584
+ isOptional: true,
585
+ description:
586
+ "Configures which caller tools may invoke each tool. The callback receives typed references for caller-capable tools in the `tools` set and returns an object keyed by callee tool name. Include `'direct'` to keep a configured tool directly callable by the model. Local-only callees are hidden from direct model calls and bound to their local caller for each generation step. Provider caller references are translated to provider-native allowed-caller options. Tools without an entry keep their existing direct tool-calling behavior.",
587
+ },
581
588
  {
582
589
  name: 'experimental_refineToolInput',
583
590
  type: 'ToolInputRefinement<TOOLS>',
@@ -1406,7 +1413,8 @@ To see `generateText` in action, check out [these examples](#examples).
1406
1413
  {
1407
1414
  name: 'modelId',
1408
1415
  type: 'string',
1409
- description: 'The specific model identifier for this model call.',
1416
+ description:
1417
+ 'The provider-returned model identifier for this model call.',
1410
1418
  },
1411
1419
  {
1412
1420
  name: 'finishReason',
@@ -2390,7 +2390,8 @@ To see `streamText` in action, check out [these examples](#examples).
2390
2390
  {
2391
2391
  name: 'modelId',
2392
2392
  type: 'string',
2393
- description: 'The specific model identifier for this model call.',
2393
+ description:
2394
+ 'The provider-returned model identifier for this model call.',
2394
2395
  },
2395
2396
  {
2396
2397
  name: 'finishReason',
@@ -162,6 +162,13 @@ It currently does not support accepting notifications from an MCP server, and cu
162
162
  },
163
163
  ],
164
164
  },
165
+ {
166
+ name: 'initializationOptions',
167
+ type: 'RequestOptions',
168
+ isOptional: true,
169
+ description:
170
+ 'Optional signal and timeout settings that bound transport startup and the initialize request. A timeout or abort closes the transport and rejects createMCPClient.',
171
+ },
165
172
  {
166
173
  name: 'clientName',
167
174
  type: 'string',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai",
3
- "version": "7.0.42",
3
+ "version": "7.0.44",
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.32",
45
+ "@ai-sdk/gateway": "4.0.33",
46
46
  "@ai-sdk/provider": "4.0.4",
47
- "@ai-sdk/provider-utils": "5.0.15"
47
+ "@ai-sdk/provider-utils": "5.0.16"
48
48
  },
49
49
  "devDependencies": {
50
50
  "@edge-runtime/vm": "^5.0.0",
@@ -55,7 +55,7 @@
55
55
  "tsx": "^4.22.0",
56
56
  "typescript": "5.8.3",
57
57
  "zod": "3.25.76",
58
- "@ai-sdk/test-server": "2.0.0",
58
+ "@ai-sdk/test-server": "2.0.1",
59
59
  "@vercel/ai-tsconfig": "0.0.0"
60
60
  },
61
61
  "peerDependencies": {
@@ -104,6 +104,11 @@ import { toResponseMessages } from './to-response-messages';
104
104
  import type { ToolApprovalConfiguration } from './tool-approval-configuration';
105
105
  import type { ToolApprovalRequestOutput } from './tool-approval-request-output';
106
106
  import type { ToolApprovalResponseOutput } from './tool-approval-response-output';
107
+ import {
108
+ prepareToolsForToolCallers,
109
+ resolveToolCallerConfiguration,
110
+ type Experimental_ToolCallers,
111
+ } from './tool-caller-configuration';
107
112
  import type { TypedToolCall } from './tool-call';
108
113
  import type { ToolCallRepairFunction } from './tool-call-repair-function';
109
114
  import type { TypedToolError } from './tool-error';
@@ -242,6 +247,7 @@ export async function generateText<
242
247
  experimental_sandbox: sandbox,
243
248
  output,
244
249
  toolApproval,
250
+ experimental_toolCallers,
245
251
  experimental_toolApprovalSecret,
246
252
  experimental_telemetry,
247
253
  telemetry = experimental_telemetry,
@@ -358,6 +364,11 @@ export async function generateText<
358
364
  */
359
365
  toolApproval?: ToolApprovalConfiguration<TOOLS, RUNTIME_CONTEXT>;
360
366
 
367
+ /**
368
+ * Configures which caller tools may invoke each tool.
369
+ */
370
+ experimental_toolCallers?: Experimental_ToolCallers<NoInfer<TOOLS>>;
371
+
361
372
  /**
362
373
  * Secret for HMAC-signing tool approval requests. When set, the server
363
374
  * signs each approval request at issuance and verifies the signature when
@@ -560,6 +571,10 @@ export async function generateText<
560
571
  };
561
572
 
562
573
  const model = resolveLanguageModel(modelArg);
574
+ const resolvedToolCallers = resolveToolCallerConfiguration({
575
+ tools,
576
+ toolCallers: experimental_toolCallers,
577
+ });
563
578
  const stopConditions = asArray(stopWhen);
564
579
  const resolvedOnStart = onStart ?? experimental_onStart;
565
580
  const resolvedOnStepStart = onStepStart ?? experimental_onStepStart;
@@ -863,10 +878,20 @@ export async function generateText<
863
878
  tools,
864
879
  activeTools: prepareStepResult?.activeTools ?? activeTools,
865
880
  });
881
+ const {
882
+ executionTools: stepExecutionTools,
883
+ modelTools: stepModelTools,
884
+ } = prepareToolsForToolCallers({
885
+ tools: stepActiveTools,
886
+ toolCallers: resolvedToolCallers,
887
+ });
866
888
  const stepToolOrder = prepareStepResult?.toolOrder ?? toolOrder;
867
889
 
868
890
  const stepTools = await prepareTools({
869
- tools: stepActiveTools,
891
+ tools: stepModelTools as ActiveToolSubset<
892
+ TOOLS,
893
+ ActiveTools<NoInfer<TOOLS>>
894
+ >,
870
895
  toolOrder: stepToolOrder as ToolOrder<
871
896
  ActiveToolSubset<TOOLS, ActiveTools<NoInfer<TOOLS>>>
872
897
  >,
@@ -994,7 +1019,7 @@ export async function generateText<
994
1019
  .map(toolCall =>
995
1020
  parseToolCall({
996
1021
  toolCall,
997
- tools,
1022
+ tools: stepExecutionTools as TOOLS,
998
1023
  repairToolCall,
999
1024
  refineToolInput,
1000
1025
  instructions: stepInstructions,
@@ -1025,7 +1050,7 @@ export async function generateText<
1025
1050
  event: {
1026
1051
  callId,
1027
1052
  provider: stepModel.provider,
1028
- modelId: stepModel.modelId,
1053
+ modelId: currentModelResponse.response.modelId,
1029
1054
  finishReason: currentModelResponse.finishReason.unified,
1030
1055
  usage: stepUsage,
1031
1056
  content: modelCallContent,
@@ -1062,7 +1087,7 @@ export async function generateText<
1062
1087
  continue; // ignore invalid tool calls
1063
1088
  }
1064
1089
 
1065
- const tool = getOwn(tools, toolCall.toolName);
1090
+ const tool = getOwn(stepExecutionTools, toolCall.toolName);
1066
1091
 
1067
1092
  if (tool == null) {
1068
1093
  // ignore tool calls for tools that are not available,
@@ -1090,7 +1115,7 @@ export async function generateText<
1090
1115
  }
1091
1116
 
1092
1117
  const toolApprovalStatus = await resolveToolApproval({
1093
- tools,
1118
+ tools: stepExecutionTools as TOOLS,
1094
1119
  toolApproval,
1095
1120
  toolCall,
1096
1121
  messages: stepMessages,
@@ -1199,14 +1224,14 @@ export async function generateText<
1199
1224
  );
1200
1225
  const toolExecutionMs: Record<string, number> = {};
1201
1226
 
1202
- if (tools != null) {
1227
+ if (stepExecutionTools != null) {
1203
1228
  const toolExecutionResults = await executeTools({
1204
1229
  toolCalls: clientToolCalls.filter(
1205
1230
  toolCall =>
1206
1231
  !toolCall.invalid &&
1207
1232
  !blockedToolCallIds.has(toolCall.toolCallId),
1208
1233
  ),
1209
- tools,
1234
+ tools: stepExecutionTools as TOOLS,
1210
1235
  callId,
1211
1236
  messages: stepMessages,
1212
1237
  abortSignal: mergedAbortSignal,
@@ -1268,7 +1293,7 @@ export async function generateText<
1268
1293
  // the client tool's result is sent back.
1269
1294
  for (const toolCall of stepToolCalls) {
1270
1295
  if (!toolCall.providerExecuted) continue;
1271
- const tool = getOwn(tools, toolCall.toolName);
1296
+ const tool = getOwn(stepExecutionTools, toolCall.toolName);
1272
1297
  if (tool?.type === 'provider' && tool.supportsDeferredResults) {
1273
1298
  // Check if this tool call already has a result in the current response
1274
1299
  const hasResultInResponse = currentModelResponse.content.some(
@@ -80,6 +80,10 @@ export type {
80
80
  ToolApprovalConfiguration,
81
81
  ToolApprovalStatus,
82
82
  } from './tool-approval-configuration';
83
+ export type {
84
+ Experimental_ToolCallerReference,
85
+ Experimental_ToolCallers,
86
+ } from './tool-caller-configuration';
83
87
  export { detectToolDrift, fingerprintTools } from './tool-fingerprint';
84
88
  export type { ToolApprovalRequestOutput } from './tool-approval-request-output';
85
89
  export type { ToolApprovalResponseOutput } from './tool-approval-response-output';
@@ -422,6 +422,7 @@ function createLanguageModelV4StreamPartToLanguageModelStreamPartTransform<
422
422
  const textPartIndexes = new Map<string, number>();
423
423
  const reasoningPartIndexes = new Map<string, number>();
424
424
  let responseId = generateId();
425
+ let responseModelId = modelId;
425
426
  let timeToFirstOutputMs: number | undefined;
426
427
  let previousOutputChunkTimestampMs: number | undefined;
427
428
  const timeBetweenOutputChunksMs: number[] = [];
@@ -590,7 +591,7 @@ function createLanguageModelV4StreamPartToLanguageModelStreamPartTransform<
590
591
  event: {
591
592
  callId,
592
593
  provider,
593
- modelId,
594
+ modelId: responseModelId,
594
595
  finishReason: chunk.finishReason.unified,
595
596
  usage,
596
597
  content: modelCallContent,
@@ -739,6 +740,7 @@ function createLanguageModelV4StreamPartToLanguageModelStreamPartTransform<
739
740
 
740
741
  case 'response-metadata': {
741
742
  responseId = chunk.id ?? responseId;
743
+ responseModelId = chunk.modelId ?? responseModelId;
742
744
 
743
745
  controller.enqueue({
744
746
  type: 'model-call-response-metadata',