ai 7.0.112 → 7.0.114

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.
Files changed (105) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +6 -6
  3. package/dist/index.d.ts +16 -0
  4. package/dist/index.js +378 -256
  5. package/dist/index.js.map +1 -1
  6. package/dist/internal/index.d.ts +2 -1
  7. package/dist/internal/index.js +182 -78
  8. package/dist/internal/index.js.map +1 -1
  9. package/docs/02-foundations/02-providers-and-models.mdx +3 -0
  10. package/docs/02-foundations/03-prompts.mdx +1 -1
  11. package/docs/02-foundations/04-tools.mdx +2 -2
  12. package/docs/02-foundations/06-provider-options.mdx +11 -11
  13. package/docs/02-getting-started/00-choosing-a-provider.mdx +4 -4
  14. package/docs/02-getting-started/02-nextjs-app-router.mdx +3 -3
  15. package/docs/02-getting-started/03-nextjs-pages-router.mdx +3 -3
  16. package/docs/02-getting-started/04-svelte.mdx +7 -7
  17. package/docs/02-getting-started/05-nuxt.mdx +7 -7
  18. package/docs/02-getting-started/06-nodejs.mdx +3 -3
  19. package/docs/02-getting-started/07-expo.mdx +3 -3
  20. package/docs/02-getting-started/08-tanstack-start.mdx +3 -3
  21. package/docs/02-getting-started/09-coding-agents.mdx +1 -1
  22. package/docs/03-agents/03-workflows.mdx +2 -2
  23. package/docs/03-agents/04-loop-control.mdx +1 -1
  24. package/docs/03-agents/05-configuring-call-options.mdx +4 -2
  25. package/docs/03-agents/06-memory.mdx +2 -2
  26. package/docs/03-agents/06-policy-tool-approvals.mdx +2 -2
  27. package/docs/03-agents/06-tool-approvals.mdx +16 -0
  28. package/docs/03-agents/07-workflow-agent.mdx +11 -11
  29. package/docs/03-agents/08-terminal-ui.mdx +2 -2
  30. package/docs/03-ai-sdk-core/05-generating-text.mdx +2 -2
  31. package/docs/03-ai-sdk-core/17-mcp-apps.mdx +1 -1
  32. package/docs/03-ai-sdk-core/20-prompt-engineering.mdx +1 -1
  33. package/docs/03-ai-sdk-core/26-reasoning.mdx +13 -12
  34. package/docs/03-ai-sdk-core/31-reranking.mdx +12 -10
  35. package/docs/03-ai-sdk-core/32-evaluation.mdx +1 -1
  36. package/docs/03-ai-sdk-core/35-image-generation.mdx +2 -2
  37. package/docs/03-ai-sdk-core/37-speech.mdx +8 -6
  38. package/docs/03-ai-sdk-core/39-file-uploads.mdx +1 -1
  39. package/docs/03-ai-sdk-core/41-skill-uploads.mdx +1 -1
  40. package/docs/03-ai-sdk-core/42-batch.mdx +1 -1
  41. package/docs/03-ai-sdk-core/45-provider-management.mdx +21 -21
  42. package/docs/03-ai-sdk-core/60-telemetry.mdx +1 -1
  43. package/docs/03-ai-sdk-core/65-devtools.mdx +3 -3
  44. package/docs/03-ai-sdk-core/65-lifecycle-callbacks.mdx +1 -1
  45. package/docs/04-ai-sdk-ui/02-chatbot.mdx +3 -3
  46. package/docs/04-ai-sdk-ui/03-chatbot-message-persistence.mdx +3 -3
  47. package/docs/04-ai-sdk-ui/03-chatbot-resume-streams.mdx +1 -1
  48. package/docs/05-ai-sdk-rsc/02-streaming-react-components.mdx +5 -5
  49. package/docs/05-ai-sdk-rsc/04-multistep-interfaces.mdx +1 -1
  50. package/docs/05-ai-sdk-rsc/06-loading-state.mdx +1 -1
  51. package/docs/05-ai-sdk-rsc/10-migrating-to-ui.mdx +3 -3
  52. package/docs/07-reference/01-ai-sdk-core/01-generate-text.mdx +5 -3
  53. package/docs/07-reference/01-ai-sdk-core/02-stream-text.mdx +5 -3
  54. package/docs/07-reference/01-ai-sdk-core/06-rerank.mdx +5 -5
  55. package/docs/07-reference/01-ai-sdk-core/11-transcribe.mdx +1 -1
  56. package/docs/07-reference/01-ai-sdk-core/12-generate-speech.mdx +3 -3
  57. package/docs/07-reference/01-ai-sdk-core/16-tool-loop-agent.mdx +4 -2
  58. package/docs/07-reference/01-ai-sdk-core/20-start-batch.mdx +1 -1
  59. package/docs/07-reference/01-ai-sdk-core/32-validate-ui-messages.mdx +18 -0
  60. package/docs/07-reference/01-ai-sdk-core/40-provider-registry.mdx +1 -1
  61. package/docs/07-reference/01-ai-sdk-core/42-custom-provider.mdx +4 -4
  62. package/docs/07-reference/01-ai-sdk-core/60-wrap-language-model.mdx +1 -1
  63. package/docs/07-reference/01-ai-sdk-core/61-wrap-image-model.mdx +1 -1
  64. package/docs/07-reference/02-ai-sdk-ui/50-direct-chat-transport.mdx +3 -3
  65. package/docs/07-reference/03-ai-sdk-rsc/01-stream-ui.mdx +1 -1
  66. package/docs/07-reference/04-ai-sdk-workflow/01-workflow-agent.mdx +8 -8
  67. package/docs/07-reference/06-ai-sdk-tui/01-run-agent-tui.mdx +1 -1
  68. package/docs/09-troubleshooting/11-use-chat-custom-request-options.mdx +3 -3
  69. package/docs/09-troubleshooting/13-repeated-assistant-messages.mdx +2 -2
  70. package/docs/09-troubleshooting/17-use-chat-stale-body-data.mdx +1 -1
  71. package/docs/09-troubleshooting/70-high-memory-usage-with-images.mdx +2 -2
  72. package/package.json +11 -11
  73. package/src/embed/embed-many.ts +18 -2
  74. package/src/evaluate/evaluate.ts +1 -10
  75. package/src/generate-speech/generate-speech.ts +15 -4
  76. package/src/generate-speech/generated-audio-file.ts +0 -8
  77. package/src/generate-text/execute-tools-from-stream.ts +0 -2
  78. package/src/generate-text/generate-text.ts +1 -0
  79. package/src/generate-text/generated-file.ts +0 -8
  80. package/src/generate-text/invoke-tool-callbacks-from-stream.ts +9 -8
  81. package/src/generate-text/output.ts +0 -2
  82. package/src/generate-text/parse-tool-call.ts +38 -25
  83. package/src/generate-text/restricted-telemetry-dispatcher.ts +6 -58
  84. package/src/generate-text/stream-text.ts +1 -0
  85. package/src/generate-text/to-response-messages.ts +7 -0
  86. package/src/generate-text/tool-call.ts +26 -0
  87. package/src/generate-text/validate-tool-approvals.ts +39 -3
  88. package/src/generate-video/generate-video.ts +0 -2
  89. package/src/middleware/extract-reasoning-middleware.ts +1 -1
  90. package/src/middleware/wrap-embedding-model.ts +9 -1
  91. package/src/model/get-embedding-model-provider-options-transformer.ts +17 -0
  92. package/src/prompt/content-part.ts +3 -0
  93. package/src/prompt/standardize-prompt.ts +2 -0
  94. package/src/registry/custom-provider.ts +12 -5
  95. package/src/telemetry/create-telemetry-dispatcher.ts +58 -6
  96. package/src/telemetry/filter-included-context.ts +57 -2
  97. package/src/ui/chat.ts +108 -17
  98. package/src/ui/convert-to-model-messages.ts +8 -0
  99. package/src/ui/direct-chat-transport.ts +2 -0
  100. package/src/ui/process-ui-message-stream.ts +6 -0
  101. package/src/ui/ui-messages.ts +10 -0
  102. package/src/ui/validate-ui-messages.ts +98 -132
  103. package/src/ui-message-stream/to-ui-message-chunk.ts +7 -0
  104. package/src/ui-message-stream/ui-message-chunks.ts +2 -0
  105. package/src/util/write-to-server-response.ts +0 -2
@@ -78,12 +78,4 @@ export class DefaultGeneratedFile implements GeneratedFile {
78
78
 
79
79
  export class DefaultGeneratedFileWithType extends DefaultGeneratedFile {
80
80
  readonly type = 'file';
81
-
82
- constructor(options: {
83
- data: string | Uint8Array;
84
- mediaType: string;
85
- providerMetadata?: Record<string, JSONObject>;
86
- }) {
87
- super(options);
88
- }
89
81
  }
@@ -35,7 +35,7 @@ export function invokeToolCallbacksFromStream<TOOLS extends ToolSet>({
35
35
  string,
36
36
  {
37
37
  toolName: string;
38
- validatedContext: Promise<unknown> | undefined;
38
+ validatedContexts: Record<string, Promise<unknown> | undefined>;
39
39
  }
40
40
  > = createIdMap();
41
41
 
@@ -48,22 +48,23 @@ export function invokeToolCallbacksFromStream<TOOLS extends ToolSet>({
48
48
  }): Promise<unknown> => {
49
49
  const ongoingToolCall = ongoingToolCalls[toolCallId];
50
50
 
51
- if (ongoingToolCall?.validatedContext != null) {
52
- return ongoingToolCall.validatedContext;
51
+ const validatedContext = ongoingToolCall?.validatedContexts[toolName];
52
+ if (validatedContext != null) {
53
+ return validatedContext;
53
54
  }
54
55
 
55
56
  const tool = getOwn(tools, toolName);
56
- const validatedContext = validateToolContext({
57
+ const newValidatedContext = validateToolContext({
57
58
  toolName,
58
59
  context: getOwn(toolsContext, toolName),
59
60
  contextSchema: tool?.contextSchema,
60
61
  });
61
62
 
62
63
  if (ongoingToolCall != null) {
63
- ongoingToolCall.validatedContext = validatedContext;
64
+ ongoingToolCall.validatedContexts[toolName] = newValidatedContext;
64
65
  }
65
66
 
66
- return validatedContext;
67
+ return newValidatedContext;
67
68
  };
68
69
 
69
70
  return stream.pipeThrough(
@@ -80,7 +81,7 @@ export function invokeToolCallbacksFromStream<TOOLS extends ToolSet>({
80
81
  case 'tool-input-start': {
81
82
  ongoingToolCalls[chunk.id] = {
82
83
  toolName: chunk.toolName,
83
- validatedContext: undefined,
84
+ validatedContexts: createIdMap(),
84
85
  };
85
86
 
86
87
  const tool = getOwn(tools, chunk.toolName);
@@ -120,7 +121,7 @@ export function invokeToolCallbacksFromStream<TOOLS extends ToolSet>({
120
121
  }
121
122
 
122
123
  case 'tool-call': {
123
- const toolName = ongoingToolCalls[chunk.toolCallId]?.toolName;
124
+ const toolName = chunk.toolName;
124
125
  const tool = getOwn(tools, toolName);
125
126
 
126
127
  if (!chunk.invalid && tool?.onInputAvailable != null) {
@@ -487,8 +487,6 @@ function getArrayLengthValidationError({
487
487
  cause: `elements array must contain at most ${maxItems} items`,
488
488
  });
489
489
  }
490
-
491
- return undefined;
492
490
  }
493
491
 
494
492
  /**
@@ -12,7 +12,12 @@ import { NoSuchToolError } from '../error/no-such-tool-error';
12
12
  import { ToolCallRepairError } from '../error/tool-call-repair-error';
13
13
  import type { Instructions } from '../prompt';
14
14
  import { getOwn } from '../util/get-own';
15
- import type { DynamicToolCall, TypedToolCall } from './tool-call';
15
+ import {
16
+ getToolCallInputSchemaInput,
17
+ setToolCallInputSchemaInput,
18
+ type DynamicToolCall,
19
+ type TypedToolCall,
20
+ } from './tool-call';
16
21
  import type { ToolCallRepairFunction } from './tool-call-repair-function';
17
22
  import type { ToolInputRefinement } from './tool-input-refinement';
18
23
 
@@ -167,7 +172,7 @@ async function waitForPromiseWithAbortSignal<T>({
167
172
  });
168
173
  }
169
174
 
170
- async function refineParsedToolCallInput<TOOLS extends ToolSet>({
175
+ export async function refineParsedToolCallInput<TOOLS extends ToolSet>({
171
176
  toolCall,
172
177
  refineToolInput,
173
178
  }: {
@@ -180,10 +185,15 @@ async function refineParsedToolCallInput<TOOLS extends ToolSet>({
180
185
  return toolCall;
181
186
  }
182
187
 
183
- return {
188
+ const refinedToolCall = {
184
189
  ...toolCall,
185
190
  input: await refine(toolCall.input as InferToolInput<TOOLS[keyof TOOLS]>),
186
191
  } as TypedToolCall<TOOLS>;
192
+
193
+ const inputSchemaInput = getToolCallInputSchemaInput(toolCall);
194
+ return inputSchemaInput == null
195
+ ? refinedToolCall
196
+ : setToolCallInputSchemaInput(refinedToolCall, inputSchemaInput.value);
187
197
  }
188
198
 
189
199
  async function parseProviderExecutedDynamicToolCall(
@@ -253,26 +263,29 @@ async function doParseToolCall<TOOLS extends ToolSet>({
253
263
  });
254
264
  }
255
265
 
256
- return tool.type === 'dynamic'
257
- ? {
258
- type: 'tool-call',
259
- toolCallId: toolCall.toolCallId,
260
- toolName: toolCall.toolName,
261
- input: parseResult.value,
262
- providerExecuted: toolCall.providerExecuted,
263
- providerMetadata: toolCall.providerMetadata,
264
- ...(tool.metadata != null ? { toolMetadata: tool.metadata } : {}),
265
- dynamic: true,
266
- title: tool.title,
267
- }
268
- : {
269
- type: 'tool-call',
270
- toolCallId: toolCall.toolCallId,
271
- toolName,
272
- input: parseResult.value,
273
- providerExecuted: toolCall.providerExecuted,
274
- providerMetadata: toolCall.providerMetadata,
275
- ...(tool.metadata != null ? { toolMetadata: tool.metadata } : {}),
276
- title: tool.title,
277
- };
266
+ return setToolCallInputSchemaInput(
267
+ tool.type === 'dynamic'
268
+ ? {
269
+ type: 'tool-call',
270
+ toolCallId: toolCall.toolCallId,
271
+ toolName: toolCall.toolName,
272
+ input: parseResult.value,
273
+ providerExecuted: toolCall.providerExecuted,
274
+ providerMetadata: toolCall.providerMetadata,
275
+ ...(tool.metadata != null ? { toolMetadata: tool.metadata } : {}),
276
+ dynamic: true,
277
+ title: tool.title,
278
+ }
279
+ : {
280
+ type: 'tool-call',
281
+ toolCallId: toolCall.toolCallId,
282
+ toolName,
283
+ input: parseResult.value,
284
+ providerExecuted: toolCall.providerExecuted,
285
+ providerMetadata: toolCall.providerMetadata,
286
+ ...(tool.metadata != null ? { toolMetadata: tool.metadata } : {}),
287
+ title: tool.title,
288
+ },
289
+ parseResult.rawValue,
290
+ );
278
291
  }
@@ -1,10 +1,9 @@
1
- import type {
2
- Context,
3
- InferToolContext,
4
- InferToolSetContext,
5
- ToolSet,
6
- } from '@ai-sdk/provider-utils';
7
- import { filterIncludedContext } from '../telemetry/filter-included-context';
1
+ import type { Context, ToolSet } from '@ai-sdk/provider-utils';
2
+ import {
3
+ filterIncludedContext,
4
+ filterToolContext,
5
+ filterToolsContext,
6
+ } from '../telemetry/filter-included-context';
8
7
  import { createTelemetryDispatcher } from '../telemetry/create-telemetry-dispatcher';
9
8
  import type { TelemetryDispatcher } from '../telemetry/telemetry';
10
9
  import type {
@@ -98,57 +97,6 @@ function restrictStepResult<
98
97
  });
99
98
  }
100
99
 
101
- /**
102
- * Returns a shallow copy of the tools context with only top-level properties
103
- * marked for telemetry inclusion for each tool.
104
- */
105
- function filterToolsContext<TOOLS extends ToolSet>({
106
- toolsContext,
107
- includeToolsContext,
108
- }: {
109
- toolsContext: InferToolSetContext<TOOLS>;
110
- includeToolsContext: IncludedToolsContext<TOOLS>;
111
- }): InferToolSetContext<TOOLS> {
112
- if (includeToolsContext == null) {
113
- return {} as InferToolSetContext<TOOLS>;
114
- }
115
-
116
- return Object.fromEntries(
117
- Object.entries(toolsContext).map(([toolName, toolContext]) => [
118
- toolName,
119
- filterToolContext({
120
- toolName,
121
- toolContext,
122
- includeToolsContext,
123
- }),
124
- ]),
125
- ) as InferToolSetContext<TOOLS>;
126
- }
127
-
128
- function filterToolContext<TOOLS extends ToolSet>({
129
- toolName,
130
- toolContext,
131
- includeToolsContext,
132
- }: {
133
- toolName: string;
134
- toolContext: unknown;
135
- includeToolsContext: IncludedToolsContext<TOOLS>;
136
- }) {
137
- const includeToolContext = (
138
- includeToolsContext as
139
- | Record<
140
- string,
141
- IncludedContext<InferToolContext<TOOLS[typeof toolName]>>
142
- >
143
- | undefined
144
- )?.[toolName];
145
-
146
- return filterIncludedContext({
147
- context: toolContext as InferToolContext<TOOLS[typeof toolName]>,
148
- includeContext: includeToolContext,
149
- });
150
- }
151
-
152
100
  /**
153
101
  * Creates a telemetry dispatcher that only includes configured runtime context
154
102
  * properties in text-generation lifecycle events before dispatching them.
@@ -2046,6 +2046,7 @@ class DefaultStreamTextResult<
2046
2046
  toolsContext,
2047
2047
  runtimeContext,
2048
2048
  toolApprovalSecret: experimental_toolApprovalSecret,
2049
+ refineToolInput,
2049
2050
  });
2050
2051
 
2051
2052
  const localDeniedToolApprovals = [
@@ -6,8 +6,10 @@ import type {
6
6
  } from '../prompt';
7
7
  import { createToolModelOutput } from '../prompt/create-tool-model-output';
8
8
  import { getOwn } from '../util/get-own';
9
+ import { isDeepEqualData } from '../util/is-deep-equal-data';
9
10
  import type { ContentPart } from './content-part';
10
11
  import type { ToolSet } from '@ai-sdk/provider-utils';
12
+ import { getToolCallInputSchemaInput } from './tool-call';
11
13
 
12
14
  /**
13
15
  * Converts the result of a `generateText` or `streamText` call to a list of response messages.
@@ -129,6 +131,7 @@ export async function toResponseMessages<TOOLS extends ToolSet>({
129
131
  break;
130
132
  }
131
133
  case 'tool-approval-request':
134
+ const inputSchemaInput = getToolCallInputSchemaInput(part.toolCall);
132
135
  content.push({
133
136
  type: 'tool-approval-request',
134
137
  approvalId: part.approvalId,
@@ -136,6 +139,10 @@ export async function toResponseMessages<TOOLS extends ToolSet>({
136
139
  ...(part.reason != null ? { reason: part.reason } : {}),
137
140
  isAutomatic: part.isAutomatic,
138
141
  ...(part.signature != null ? { signature: part.signature } : {}),
142
+ ...(inputSchemaInput != null &&
143
+ !isDeepEqualData(inputSchemaInput.value, part.toolCall.input)
144
+ ? { inputSchemaInput: inputSchemaInput.value }
145
+ : {}),
139
146
  });
140
147
  break;
141
148
  }
@@ -3,6 +3,8 @@ import type { InferToolInput, ToolSet } from '@ai-sdk/provider-utils';
3
3
  import type { ProviderMetadata } from '../types';
4
4
  import type { ValueOf } from '../util/value-of';
5
5
 
6
+ const inputSchemaInputSymbol = Symbol('ai-sdk-tool-call-input-schema-input');
7
+
6
8
  type BaseToolCall = {
7
9
  type: 'tool-call';
8
10
  toolCallId: string;
@@ -58,3 +60,27 @@ export type DynamicToolCall = BaseToolCall & {
58
60
  export type TypedToolCall<TOOLS extends ToolSet> =
59
61
  | StaticToolCall<TOOLS>
60
62
  | DynamicToolCall;
63
+
64
+ export function setToolCallInputSchemaInput<TOOLS extends ToolSet>(
65
+ toolCall: TypedToolCall<TOOLS>,
66
+ inputSchemaInput: unknown,
67
+ ): TypedToolCall<TOOLS> {
68
+ Object.defineProperty(toolCall, inputSchemaInputSymbol, {
69
+ value: inputSchemaInput,
70
+ });
71
+ return toolCall;
72
+ }
73
+
74
+ export function getToolCallInputSchemaInput<TOOLS extends ToolSet>(
75
+ toolCall: TypedToolCall<TOOLS>,
76
+ ): { value: unknown } | undefined {
77
+ return inputSchemaInputSymbol in toolCall
78
+ ? {
79
+ value: (
80
+ toolCall as TypedToolCall<TOOLS> & {
81
+ [inputSchemaInputSymbol]: unknown;
82
+ }
83
+ )[inputSchemaInputSymbol],
84
+ }
85
+ : undefined;
86
+ }
@@ -10,10 +10,13 @@ import {
10
10
  import { InvalidToolApprovalSignatureError } from '../error/invalid-tool-approval-signature-error';
11
11
  import { InvalidToolInputError } from '../error/invalid-tool-input-error';
12
12
  import { getOwn } from '../util/get-own';
13
+ import { isDeepEqualData } from '../util/is-deep-equal-data';
13
14
  import type { CollectedToolApprovals } from './collect-tool-approvals';
15
+ import { refineParsedToolCallInput } from './parse-tool-call';
14
16
  import { resolveToolApproval } from './resolve-tool-approval';
15
17
  import { verifyToolApprovalSignature } from './tool-approval-signature';
16
18
  import type { ToolApprovalConfiguration } from './tool-approval-configuration';
19
+ import type { ToolInputRefinement } from './tool-input-refinement';
17
20
 
18
21
  /**
19
22
  * Re-validates approved tool approvals reconstructed from client-supplied
@@ -31,6 +34,7 @@ export async function validateApprovedToolApprovals<
31
34
  toolsContext,
32
35
  runtimeContext,
33
36
  toolApprovalSecret,
37
+ refineToolInput,
34
38
  }: {
35
39
  approvedToolApprovals: Array<CollectedToolApprovals<TOOLS>>;
36
40
  tools: TOOLS | undefined;
@@ -39,6 +43,7 @@ export async function validateApprovedToolApprovals<
39
43
  toolsContext: InferToolSetContext<TOOLS>;
40
44
  runtimeContext: RUNTIME_CONTEXT;
41
45
  toolApprovalSecret?: string | Uint8Array;
46
+ refineToolInput?: ToolInputRefinement<TOOLS>;
42
47
  }): Promise<{
43
48
  approvedToolApprovals: Array<CollectedToolApprovals<TOOLS>>;
44
49
  deniedToolApprovals: Array<CollectedToolApprovals<TOOLS>>;
@@ -53,7 +58,7 @@ export async function validateApprovedToolApprovals<
53
58
  > = [];
54
59
 
55
60
  for (const approval of approvedToolApprovals) {
56
- const { toolCall, approvalRequest } = approval;
61
+ const { approvalRequest, toolCall } = approval;
57
62
  // Look up the tool by own property only: `toolName` comes from
58
63
  // client-supplied history, so a name matching an inherited object property
59
64
  // (e.g. `constructor`, `toString`) must resolve to "no such tool" rather
@@ -88,18 +93,49 @@ export async function validateApprovedToolApprovals<
88
93
  }
89
94
 
90
95
  if (isExecutableTool(tool) && tool.inputSchema != null) {
96
+ const hasInputSchemaInput = Object.prototype.hasOwnProperty.call(
97
+ approvalRequest,
98
+ 'inputSchemaInput',
99
+ );
91
100
  const validation = await safeValidateTypes({
92
- value: toolCall.input,
101
+ value: hasInputSchemaInput
102
+ ? approvalRequest.inputSchemaInput
103
+ : toolCall.input,
93
104
  schema: asSchema(tool.inputSchema),
94
105
  });
95
106
 
107
+ let validationError: unknown;
96
108
  if (!validation.success) {
109
+ validationError = validation.error;
110
+ } else {
111
+ try {
112
+ const revalidatedToolCall = await refineParsedToolCallInput({
113
+ toolCall: {
114
+ ...toolCall,
115
+ input: validation.value,
116
+ },
117
+ refineToolInput,
118
+ });
119
+
120
+ // Revalidation must never change the operation that was approved,
121
+ // including when older or projected history omits the schema input.
122
+ if (!isDeepEqualData(revalidatedToolCall.input, toolCall.input)) {
123
+ validationError = new Error(
124
+ 'Approved tool input does not match the validated schema output.',
125
+ );
126
+ }
127
+ } catch (error) {
128
+ validationError = error;
129
+ }
130
+ }
131
+
132
+ if (validationError != null) {
97
133
  invalid.push({
98
134
  ...approval,
99
135
  error: new InvalidToolInputError({
100
136
  toolName: toolCall.toolName,
101
137
  toolInput: JSON.stringify(toolCall.input),
102
- cause: validation.error,
138
+ cause: validationError,
103
139
  }),
104
140
  });
105
141
  continue;
@@ -890,8 +890,6 @@ function normalizeImageData(
890
890
  data: bytes,
891
891
  };
892
892
  }
893
-
894
- return undefined;
895
893
  }
896
894
 
897
895
  /**
@@ -24,7 +24,7 @@ export function extractReasoningMiddleware({
24
24
  startWithReasoning?: boolean;
25
25
  }): LanguageModelMiddleware {
26
26
  const openingTag = `<${tagName}>`;
27
- const closingTag = `<\/${tagName}>`;
27
+ const closingTag = `</${tagName}>`;
28
28
 
29
29
  return {
30
30
  specificationVersion: 'v4',
@@ -7,12 +7,17 @@ import type {
7
7
  import {
8
8
  asArray,
9
9
  EXPERIMENTAL_EMBEDDING_MODEL_MAX_INPUT_BYTES_PER_CALL,
10
+ EXPERIMENTAL_EMBEDDING_MODEL_PROVIDER_OPTIONS_TRANSFORMER,
10
11
  } from '@ai-sdk/provider-utils';
11
12
  import { asEmbeddingModelV4 } from '../model/as-embedding-model-v4';
12
13
  import {
13
14
  getEmbeddingModelMaxInputBytesPerCall,
14
15
  type EmbeddingModelWithMaxInputBytesPerCall,
15
16
  } from '../model/get-embedding-model-max-input-bytes-per-call';
17
+ import {
18
+ getEmbeddingModelProviderOptionsTransformer,
19
+ type EmbeddingModelWithProviderOptionsTransformer,
20
+ } from '../model/get-embedding-model-provider-options-transformer';
16
21
  import type { EmbeddingModelMiddleware } from '../types';
17
22
 
18
23
  /**
@@ -63,7 +68,8 @@ const doWrap = ({
63
68
  middleware: EmbeddingModelMiddleware;
64
69
  modelId?: string;
65
70
  providerId?: string;
66
- }): EmbeddingModelWithMaxInputBytesPerCall => {
71
+ }): EmbeddingModelWithMaxInputBytesPerCall &
72
+ EmbeddingModelWithProviderOptionsTransformer => {
67
73
  async function doTransform({
68
74
  params,
69
75
  }: {
@@ -80,6 +86,8 @@ const doWrap = ({
80
86
  overrideMaxEmbeddingsPerCall?.({ model }) ?? model.maxEmbeddingsPerCall,
81
87
  [EXPERIMENTAL_EMBEDDING_MODEL_MAX_INPUT_BYTES_PER_CALL]:
82
88
  getEmbeddingModelMaxInputBytesPerCall(model),
89
+ [EXPERIMENTAL_EMBEDDING_MODEL_PROVIDER_OPTIONS_TRANSFORMER]:
90
+ getEmbeddingModelProviderOptionsTransformer(model),
83
91
  supportsParallelCalls:
84
92
  overrideSupportsParallelCalls?.({ model }) ?? model.supportsParallelCalls,
85
93
  async doEmbed(
@@ -0,0 +1,17 @@
1
+ import type { EmbeddingModelV4 } from '@ai-sdk/provider';
2
+ import {
3
+ EXPERIMENTAL_EMBEDDING_MODEL_PROVIDER_OPTIONS_TRANSFORMER,
4
+ type EmbeddingModelProviderOptionsTransformer,
5
+ } from '@ai-sdk/provider-utils';
6
+
7
+ export type EmbeddingModelWithProviderOptionsTransformer = EmbeddingModelV4 & {
8
+ readonly [EXPERIMENTAL_EMBEDDING_MODEL_PROVIDER_OPTIONS_TRANSFORMER]?: EmbeddingModelProviderOptionsTransformer;
9
+ };
10
+
11
+ export function getEmbeddingModelProviderOptionsTransformer(
12
+ model: EmbeddingModelV4,
13
+ ) {
14
+ return (model as EmbeddingModelWithProviderOptionsTransformer)[
15
+ EXPERIMENTAL_EMBEDDING_MODEL_PROVIDER_OPTIONS_TRANSFORMER
16
+ ];
17
+ }
@@ -284,6 +284,9 @@ export const toolApprovalRequestSchema: ZodType<ToolApprovalRequest> = z.object(
284
284
  approvalId: z.string(),
285
285
  toolCallId: z.string(),
286
286
  reason: z.string().optional(),
287
+ isAutomatic: z.boolean().optional(),
288
+ signature: z.string().optional(),
289
+ inputSchemaInput: z.unknown().optional(),
287
290
  },
288
291
  );
289
292
 
@@ -82,6 +82,8 @@ export async function standardizePrompt({
82
82
  });
83
83
  }
84
84
 
85
+ // Require explicit trust in supplied system messages to reduce prompt-injection
86
+ // risk. The opt-in permits all system messages, including instruction text.
85
87
  if (
86
88
  !allowSystemInMessages &&
87
89
  messages.some(message => message.role === 'system')
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  type Experimental_EvaluationModelV4 as EvaluationModelV4,
3
3
  type EmbeddingModelV4,
4
+ type Experimental_VideoModelV3,
4
5
  type Experimental_VideoModelV4,
5
6
  type FilesV4,
6
7
  type ImageModelV4,
@@ -35,6 +36,12 @@ import type { SpeechModel } from '../types/speech-model';
35
36
  import type { TranscriptionModel } from '../types/transcription-model';
36
37
  import type { VideoModel } from '../types/video-model';
37
38
 
39
+ type ProviderWithOptionalVideoModel = {
40
+ videoModel?: (
41
+ modelId: string,
42
+ ) => Experimental_VideoModelV3 | Experimental_VideoModelV4;
43
+ };
44
+
38
45
  /**
39
46
  * Creates a custom provider with specified language models, text embedding models, image models, transcription models, speech models, file APIs, skill APIs, and an optional fallback provider.
40
47
  *
@@ -247,11 +254,11 @@ export function customProvider<
247
254
  return resolveVideoModel(videoModels[modelId]);
248
255
  }
249
256
 
250
- // TODO AI SDK v7
251
- // @ts-expect-error - videoModel support is experimental
252
- const videoModel = fallbackProvider?.videoModel;
253
- if (videoModel) {
254
- return videoModel(modelId);
257
+ const provider = fallbackProviderArg as
258
+ | ProviderWithOptionalVideoModel
259
+ | undefined;
260
+ if (provider?.videoModel) {
261
+ return resolveVideoModel(provider.videoModel(modelId));
255
262
  }
256
263
 
257
264
  throw new NoSuchModelError({ modelId, modelType: 'videoModel' });
@@ -1,5 +1,10 @@
1
- import { asArray } from '@ai-sdk/provider-utils';
1
+ import { asArray, type Context } from '@ai-sdk/provider-utils';
2
2
  import type { Callback } from '../util/callback';
3
+ import {
4
+ filterIncludedContext,
5
+ filterToolContext,
6
+ filterToolsContext,
7
+ } from './filter-included-context';
3
8
  import { mergeCallbacks } from '../util/merge-callbacks';
4
9
  import type {
5
10
  InferTelemetryEvent,
@@ -41,14 +46,59 @@ function augmentEvent<EVENT>(
41
46
  event: EVENT,
42
47
  telemetry: Pick<
43
48
  TelemetryOptions,
44
- 'recordInputs' | 'recordOutputs' | 'functionId'
49
+ | 'recordInputs'
50
+ | 'recordOutputs'
51
+ | 'functionId'
52
+ | 'includeRuntimeContext'
53
+ | 'includeToolsContext'
45
54
  >,
55
+ filterContext = false,
46
56
  ): InferTelemetryEvent<EVENT> {
47
- return Object.assign(
57
+ const augmentedEvent = Object.assign(
48
58
  Object.create(Object.getPrototypeOf(event)),
49
59
  event,
50
- telemetry,
60
+ {
61
+ recordInputs: telemetry.recordInputs,
62
+ recordOutputs: telemetry.recordOutputs,
63
+ functionId: telemetry.functionId,
64
+ },
51
65
  );
66
+
67
+ if (
68
+ filterContext &&
69
+ event != null &&
70
+ typeof event === 'object' &&
71
+ 'runtimeContext' in event
72
+ ) {
73
+ augmentedEvent.runtimeContext = filterIncludedContext({
74
+ context: event.runtimeContext as Context,
75
+ includeContext: telemetry.includeRuntimeContext,
76
+ });
77
+ }
78
+
79
+ if (filterContext && event != null && typeof event === 'object') {
80
+ if ('toolsContext' in event) {
81
+ augmentedEvent.toolsContext = filterToolsContext({
82
+ toolsContext: event.toolsContext as Record<string, Context>,
83
+ includeToolsContext: telemetry.includeToolsContext,
84
+ });
85
+ } else if (
86
+ 'toolContext' in event &&
87
+ event.toolContext != null &&
88
+ 'toolCall' in event &&
89
+ event.toolCall != null &&
90
+ typeof event.toolCall === 'object' &&
91
+ 'toolName' in event.toolCall
92
+ ) {
93
+ augmentedEvent.toolContext = filterToolContext({
94
+ toolName: event.toolCall.toolName as string,
95
+ toolContext: event.toolContext,
96
+ includeToolsContext: telemetry.includeToolsContext,
97
+ });
98
+ }
99
+ }
100
+
101
+ return augmentedEvent;
52
102
  }
53
103
 
54
104
  /**
@@ -86,6 +136,8 @@ export function createTelemetryDispatcher({
86
136
  recordInputs: telemetry?.recordInputs,
87
137
  recordOutputs: telemetry?.recordOutputs,
88
138
  functionId: telemetry?.functionId,
139
+ includeRuntimeContext: telemetry?.includeRuntimeContext,
140
+ includeToolsContext: telemetry?.includeToolsContext,
89
141
  };
90
142
 
91
143
  const mergeTelemetryCallback = <KEY extends TelemetryCallbackKey>(
@@ -127,7 +179,7 @@ export function createTelemetryDispatcher({
127
179
  await runWithTracingChannelSpan(
128
180
  {
129
181
  type,
130
- event: augmentEvent(event, telemetryMetadata),
182
+ event: augmentEvent(event, telemetryMetadata, true),
131
183
  },
132
184
  execute,
133
185
  ),
@@ -136,7 +188,7 @@ export function createTelemetryDispatcher({
136
188
  openTelemetryChannelSpanContext({
137
189
  message: {
138
190
  type,
139
- event: augmentEvent(event, telemetryMetadata),
191
+ event: augmentEvent(event, telemetryMetadata, true),
140
192
  },
141
193
  completion,
142
194
  }),