ai 6.0.229 → 6.0.231

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.
@@ -152,7 +152,7 @@ function detectMediaType({
152
152
  var import_provider_utils2 = require("@ai-sdk/provider-utils");
153
153
 
154
154
  // src/version.ts
155
- var VERSION = true ? "6.0.229" : "0.0.0-test";
155
+ var VERSION = true ? "6.0.231" : "0.0.0-test";
156
156
 
157
157
  // src/util/download/download.ts
158
158
  var download = async ({
@@ -132,7 +132,7 @@ import {
132
132
  } from "@ai-sdk/provider-utils";
133
133
 
134
134
  // src/version.ts
135
- var VERSION = true ? "6.0.229" : "0.0.0-test";
135
+ var VERSION = true ? "6.0.231" : "0.0.0-test";
136
136
 
137
137
  // src/util/download/download.ts
138
138
  var download = async ({
@@ -723,7 +723,7 @@ The following tool input lifecycle hooks are available:
723
723
  - **`onInputDelta`**: Called for each chunk of text as the input is streamed
724
724
  - **`onInputAvailable`**: Called when the complete input is available and validated
725
725
 
726
- `onInputStart` and `onInputDelta` are only called in streaming contexts (when using `streamText`). They are not called when using `generateText`.
726
+ `onInputStart` is always called before `onInputAvailable`, including when using `generateText`. `onInputDelta` is only called in streaming contexts (when using `streamText`).
727
727
 
728
728
  ### Example
729
729
 
@@ -146,7 +146,7 @@ export const weatherTool = tool({
146
146
  isOptional: true,
147
147
  type: '(options: ToolExecutionOptions) => void | PromiseLike<void>',
148
148
  description:
149
- 'Optional function that is called when the argument streaming starts. Only called when the tool is used in a streaming context.',
149
+ 'Optional function that is called when the model starts generating the tool input. In non-streaming contexts, it is called immediately before onInputAvailable.',
150
150
  },
151
151
  {
152
152
  name: 'onInputDelta',
@@ -131,7 +131,7 @@ export const customTool = dynamicTool({
131
131
  isOptional: true,
132
132
  type: '(options: ToolExecutionOptions) => void | PromiseLike<void>',
133
133
  description:
134
- 'Optional function that is called when the argument streaming starts. Only called when the tool is used in a streaming context.'
134
+ 'Optional function that is called when the model starts generating the tool input. In non-streaming contexts, it is called immediately before onInputAvailable.'
135
135
  },
136
136
  {
137
137
  name: 'onInputDelta',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai",
3
- "version": "6.0.229",
3
+ "version": "6.0.231",
4
4
  "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.",
5
5
  "license": "Apache-2.0",
6
6
  "sideEffects": false,
@@ -45,9 +45,9 @@
45
45
  },
46
46
  "dependencies": {
47
47
  "@opentelemetry/api": "^1.9.0",
48
- "@ai-sdk/gateway": "3.0.152",
49
48
  "@ai-sdk/provider": "3.0.14",
50
- "@ai-sdk/provider-utils": "4.0.39"
49
+ "@ai-sdk/provider-utils": "4.0.40",
50
+ "@ai-sdk/gateway": "3.0.154"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@edge-runtime/vm": "^5.0.0",
@@ -0,0 +1,19 @@
1
+ import type { ToolSet } from './tool-set';
2
+
3
+ export function filterActiveTools<TOOLS extends ToolSet>({
4
+ tools,
5
+ activeTools,
6
+ }: {
7
+ tools: TOOLS | undefined;
8
+ activeTools: Array<keyof TOOLS> | undefined;
9
+ }): TOOLS | undefined {
10
+ if (tools == null || activeTools == null) {
11
+ return tools;
12
+ }
13
+
14
+ return Object.fromEntries(
15
+ Object.entries(tools).filter(([name]) =>
16
+ activeTools.includes(name as keyof TOOLS),
17
+ ),
18
+ ) as TOOLS;
19
+ }
@@ -67,6 +67,7 @@ import type { ContentPart } from './content-part';
67
67
  import { executeToolCall } from './execute-tool-call';
68
68
  import { extractReasoningContent } from './extract-reasoning-content';
69
69
  import { extractTextContent } from './extract-text-content';
70
+ import { filterActiveTools } from './filter-active-tools';
70
71
  import type { GenerateTextResult } from './generate-text-result';
71
72
  import { DefaultGeneratedFile } from './generated-file';
72
73
  import { isApprovalNeeded } from './is-approval-needed';
@@ -684,6 +685,10 @@ export async function generateText<
684
685
  >();
685
686
 
686
687
  do {
688
+ if (steps.length > 0) {
689
+ mergedAbortSignal?.throwIfAborted();
690
+ }
691
+
687
692
  // Set up step timeout if configured
688
693
  const stepTimeoutId = setAbortTimeout({
689
694
  abortController: stepAbortController,
@@ -724,6 +729,10 @@ export async function generateText<
724
729
 
725
730
  const stepActiveTools =
726
731
  prepareStepResult?.activeTools ?? activeTools;
732
+ const stepToolSet = filterActiveTools({
733
+ tools,
734
+ activeTools: stepActiveTools,
735
+ });
727
736
 
728
737
  const { toolChoice: stepToolChoice, tools: stepTools } =
729
738
  await prepareToolsAndToolChoice({
@@ -916,7 +925,7 @@ export async function generateText<
916
925
  .map(toolCall =>
917
926
  parseToolCall({
918
927
  toolCall,
919
- tools,
928
+ tools: stepToolSet,
920
929
  repairToolCall,
921
930
  system,
922
931
  messages: stepInputMessages,
@@ -934,7 +943,7 @@ export async function generateText<
934
943
  continue; // ignore invalid tool calls
935
944
  }
936
945
 
937
- const tool = tools?.[toolCall.toolName];
946
+ const tool = stepToolSet?.[toolCall.toolName];
938
947
 
939
948
  if (tool == null) {
940
949
  // ignore tool calls for tools that are not available,
@@ -942,7 +951,16 @@ export async function generateText<
942
951
  continue;
943
952
  }
944
953
 
945
- if (tool?.onInputAvailable != null) {
954
+ if (tool.onInputStart != null) {
955
+ await tool.onInputStart({
956
+ toolCallId: toolCall.toolCallId,
957
+ messages: stepInputMessages,
958
+ abortSignal: mergedAbortSignal,
959
+ experimental_context,
960
+ });
961
+ }
962
+
963
+ if (tool.onInputAvailable != null) {
946
964
  await tool.onInputAvailable({
947
965
  input: toolCall.input,
948
966
  toolCallId: toolCall.toolCallId,
@@ -1002,7 +1020,7 @@ export async function generateText<
1002
1020
  toolCall => !toolCall.providerExecuted,
1003
1021
  );
1004
1022
 
1005
- if (tools != null) {
1023
+ if (stepToolSet != null) {
1006
1024
  clientToolOutputs.push(
1007
1025
  ...(await executeTools({
1008
1026
  toolCalls: clientToolCalls.filter(
@@ -1010,7 +1028,7 @@ export async function generateText<
1010
1028
  !toolCall.invalid &&
1011
1029
  toolApprovalRequests[toolCall.toolCallId] == null,
1012
1030
  ),
1013
- tools,
1031
+ tools: stepToolSet,
1014
1032
  tracer,
1015
1033
  telemetry,
1016
1034
  messages: stepInputMessages,
@@ -1038,7 +1056,7 @@ export async function generateText<
1038
1056
  // the client tool's result is sent back.
1039
1057
  for (const toolCall of stepToolCalls) {
1040
1058
  if (!toolCall.providerExecuted) continue;
1041
- const tool = tools?.[toolCall.toolName];
1059
+ const tool = stepToolSet?.[toolCall.toolName];
1042
1060
  if (tool?.type === 'provider' && tool.supportsDeferredResults) {
1043
1061
  // Check if this tool call already has a result in the current response
1044
1062
  const hasResultInResponse = currentModelResponse.content.some(
@@ -1067,14 +1085,14 @@ export async function generateText<
1067
1085
  toolCalls: stepToolCalls,
1068
1086
  toolOutputs: clientToolOutputs,
1069
1087
  toolApprovalRequests: Object.values(toolApprovalRequests),
1070
- tools,
1088
+ tools: stepToolSet,
1071
1089
  });
1072
1090
 
1073
1091
  // append to messages for potential next step:
1074
1092
  responseMessages.push(
1075
1093
  ...(await toResponseMessages({
1076
1094
  content: stepContent,
1077
- tools,
1095
+ tools: stepToolSet,
1078
1096
  })),
1079
1097
  );
1080
1098
 
@@ -95,6 +95,7 @@ import type {
95
95
  } from './callback-events';
96
96
  import type { ContentPart } from './content-part';
97
97
  import { executeToolCall } from './execute-tool-call';
98
+ import { filterActiveTools } from './filter-active-tools';
98
99
  import { text, type Output } from './output';
99
100
  import type {
100
101
  InferCompleteOutput,
@@ -882,6 +883,7 @@ class DefaultStreamTextResult<
882
883
  let recordedWarnings: Array<CallWarning> = [];
883
884
  const recordedSteps: StepResult<TOOLS>[] = [];
884
885
  let recordedNoOutputError: NoOutputGeneratedError | undefined;
886
+ let currentStepToolSet = tools;
885
887
 
886
888
  // Track provider-executed tool calls that support deferred results
887
889
  // (e.g., code_execution in programmatic tool calling scenarios).
@@ -1081,7 +1083,7 @@ class DefaultStreamTextResult<
1081
1083
  if (part.type === 'finish-step') {
1082
1084
  const stepMessages = await toResponseMessages({
1083
1085
  content: recordedContent,
1084
- tools,
1086
+ tools: currentStepToolSet,
1085
1087
  });
1086
1088
 
1087
1089
  // Add step information (after response messages are updated):
@@ -1641,6 +1643,11 @@ class DefaultStreamTextResult<
1641
1643
 
1642
1644
  const stepActiveTools =
1643
1645
  prepareStepResult?.activeTools ?? activeTools;
1646
+ const stepToolSet = filterActiveTools({
1647
+ tools,
1648
+ activeTools: stepActiveTools,
1649
+ });
1650
+ currentStepToolSet = stepToolSet;
1644
1651
 
1645
1652
  const { toolChoice: stepToolChoice, tools: stepTools } =
1646
1653
  await prepareToolsAndToolChoice({
@@ -1759,7 +1766,7 @@ class DefaultStreamTextResult<
1759
1766
  );
1760
1767
 
1761
1768
  const streamWithToolResults = runToolsTransformation({
1762
- tools,
1769
+ tools: stepToolSet,
1763
1770
  generatorStream: stream,
1764
1771
  tracer,
1765
1772
  telemetry,
@@ -1967,7 +1974,7 @@ class DefaultStreamTextResult<
1967
1974
  case 'tool-input-start': {
1968
1975
  activeToolCallToolNames[chunk.id] = chunk.toolName;
1969
1976
 
1970
- const tool = tools?.[chunk.toolName];
1977
+ const tool = stepToolSet?.[chunk.toolName];
1971
1978
  if (tool?.onInputStart != null) {
1972
1979
  await tool.onInputStart({
1973
1980
  toolCallId: chunk.id,
@@ -1993,7 +2000,7 @@ class DefaultStreamTextResult<
1993
2000
 
1994
2001
  case 'tool-input-delta': {
1995
2002
  const toolName = activeToolCallToolNames[chunk.id];
1996
- const tool = tools?.[toolName];
2003
+ const tool = stepToolSet?.[toolName];
1997
2004
 
1998
2005
  if (tool?.onInputDelta != null) {
1999
2006
  await tool.onInputDelta({
@@ -2167,7 +2174,7 @@ class DefaultStreamTextResult<
2167
2174
  // the client tool's result is sent back.
2168
2175
  for (const toolCall of stepToolCalls) {
2169
2176
  if (toolCall.providerExecuted !== true) continue;
2170
- const tool = tools?.[toolCall.toolName];
2177
+ const tool = stepToolSet?.[toolCall.toolName];
2171
2178
  if (
2172
2179
  tool?.type === 'provider' &&
2173
2180
  tool.supportsDeferredResults
@@ -2220,7 +2227,7 @@ class DefaultStreamTextResult<
2220
2227
  content:
2221
2228
  // use transformed content to create the messages for the next step:
2222
2229
  recordedSteps[recordedSteps.length - 1].content,
2223
- tools,
2230
+ tools: stepToolSet,
2224
2231
  })),
2225
2232
  );
2226
2233
 
@@ -21,29 +21,29 @@ const toolMetadataSchema: z.ZodType<JSONObject> = z.record(
21
21
  );
22
22
 
23
23
  export const uiMessageChunkSchema = lazySchema(() =>
24
- zodSchema(
24
+ zodSchema<UIMessageChunk>(
25
25
  z.union([
26
- z.strictObject({
26
+ z.looseObject({
27
27
  type: z.literal('text-start'),
28
28
  id: z.string(),
29
29
  providerMetadata: providerMetadataSchema.optional(),
30
30
  }),
31
- z.strictObject({
31
+ z.looseObject({
32
32
  type: z.literal('text-delta'),
33
33
  id: z.string(),
34
34
  delta: z.string(),
35
35
  providerMetadata: providerMetadataSchema.optional(),
36
36
  }),
37
- z.strictObject({
37
+ z.looseObject({
38
38
  type: z.literal('text-end'),
39
39
  id: z.string(),
40
40
  providerMetadata: providerMetadataSchema.optional(),
41
41
  }),
42
- z.strictObject({
42
+ z.looseObject({
43
43
  type: z.literal('error'),
44
44
  errorText: z.string(),
45
45
  }),
46
- z.strictObject({
46
+ z.looseObject({
47
47
  type: z.literal('tool-input-start'),
48
48
  toolCallId: z.string(),
49
49
  toolName: z.string(),
@@ -53,12 +53,12 @@ export const uiMessageChunkSchema = lazySchema(() =>
53
53
  dynamic: z.boolean().optional(),
54
54
  title: z.string().optional(),
55
55
  }),
56
- z.strictObject({
56
+ z.looseObject({
57
57
  type: z.literal('tool-input-delta'),
58
58
  toolCallId: z.string(),
59
59
  inputTextDelta: z.string(),
60
60
  }),
61
- z.strictObject({
61
+ z.looseObject({
62
62
  type: z.literal('tool-input-available'),
63
63
  toolCallId: z.string(),
64
64
  toolName: z.string(),
@@ -69,7 +69,7 @@ export const uiMessageChunkSchema = lazySchema(() =>
69
69
  dynamic: z.boolean().optional(),
70
70
  title: z.string().optional(),
71
71
  }),
72
- z.strictObject({
72
+ z.looseObject({
73
73
  type: z.literal('tool-input-error'),
74
74
  toolCallId: z.string(),
75
75
  toolName: z.string(),
@@ -81,13 +81,13 @@ export const uiMessageChunkSchema = lazySchema(() =>
81
81
  errorText: z.string(),
82
82
  title: z.string().optional(),
83
83
  }),
84
- z.strictObject({
84
+ z.looseObject({
85
85
  type: z.literal('tool-approval-request'),
86
86
  approvalId: z.string(),
87
87
  toolCallId: z.string(),
88
88
  signature: z.string().optional(),
89
89
  }),
90
- z.strictObject({
90
+ z.looseObject({
91
91
  type: z.literal('tool-output-available'),
92
92
  toolCallId: z.string(),
93
93
  output: z.unknown(),
@@ -97,7 +97,7 @@ export const uiMessageChunkSchema = lazySchema(() =>
97
97
  dynamic: z.boolean().optional(),
98
98
  preliminary: z.boolean().optional(),
99
99
  }),
100
- z.strictObject({
100
+ z.looseObject({
101
101
  type: z.literal('tool-output-error'),
102
102
  toolCallId: z.string(),
103
103
  errorText: z.string(),
@@ -106,34 +106,34 @@ export const uiMessageChunkSchema = lazySchema(() =>
106
106
  toolMetadata: toolMetadataSchema.optional(),
107
107
  dynamic: z.boolean().optional(),
108
108
  }),
109
- z.strictObject({
109
+ z.looseObject({
110
110
  type: z.literal('tool-output-denied'),
111
111
  toolCallId: z.string(),
112
112
  }),
113
- z.strictObject({
113
+ z.looseObject({
114
114
  type: z.literal('reasoning-start'),
115
115
  id: z.string(),
116
116
  providerMetadata: providerMetadataSchema.optional(),
117
117
  }),
118
- z.strictObject({
118
+ z.looseObject({
119
119
  type: z.literal('reasoning-delta'),
120
120
  id: z.string(),
121
121
  delta: z.string(),
122
122
  providerMetadata: providerMetadataSchema.optional(),
123
123
  }),
124
- z.strictObject({
124
+ z.looseObject({
125
125
  type: z.literal('reasoning-end'),
126
126
  id: z.string(),
127
127
  providerMetadata: providerMetadataSchema.optional(),
128
128
  }),
129
- z.strictObject({
129
+ z.looseObject({
130
130
  type: z.literal('source-url'),
131
131
  sourceId: z.string(),
132
132
  url: z.string(),
133
133
  title: z.string().optional(),
134
134
  providerMetadata: providerMetadataSchema.optional(),
135
135
  }),
136
- z.strictObject({
136
+ z.looseObject({
137
137
  type: z.literal('source-document'),
138
138
  sourceId: z.string(),
139
139
  mediaType: z.string(),
@@ -141,13 +141,13 @@ export const uiMessageChunkSchema = lazySchema(() =>
141
141
  filename: z.string().optional(),
142
142
  providerMetadata: providerMetadataSchema.optional(),
143
143
  }),
144
- z.strictObject({
144
+ z.looseObject({
145
145
  type: z.literal('file'),
146
146
  url: z.string(),
147
147
  mediaType: z.string(),
148
148
  providerMetadata: providerMetadataSchema.optional(),
149
149
  }),
150
- z.strictObject({
150
+ z.looseObject({
151
151
  type: z.custom<`data-${string}`>(
152
152
  (value): value is `data-${string}` =>
153
153
  typeof value === 'string' && value.startsWith('data-'),
@@ -157,18 +157,18 @@ export const uiMessageChunkSchema = lazySchema(() =>
157
157
  data: z.unknown(),
158
158
  transient: z.boolean().optional(),
159
159
  }),
160
- z.strictObject({
160
+ z.looseObject({
161
161
  type: z.literal('start-step'),
162
162
  }),
163
- z.strictObject({
163
+ z.looseObject({
164
164
  type: z.literal('finish-step'),
165
165
  }),
166
- z.strictObject({
166
+ z.looseObject({
167
167
  type: z.literal('start'),
168
168
  messageId: z.string().optional(),
169
169
  messageMetadata: z.unknown().optional(),
170
170
  }),
171
- z.strictObject({
171
+ z.looseObject({
172
172
  type: z.literal('finish'),
173
173
  finishReason: z
174
174
  .enum([
@@ -182,11 +182,11 @@ export const uiMessageChunkSchema = lazySchema(() =>
182
182
  .optional(),
183
183
  messageMetadata: z.unknown().optional(),
184
184
  }),
185
- z.strictObject({
185
+ z.looseObject({
186
186
  type: z.literal('abort'),
187
187
  reason: z.string().optional(),
188
188
  }),
189
- z.strictObject({
189
+ z.looseObject({
190
190
  type: z.literal('message-metadata'),
191
191
  messageMetadata: z.unknown(),
192
192
  }),