ai 6.0.312 → 6.0.313

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.
@@ -164,7 +164,7 @@ function detectMediaType({
164
164
  var import_provider_utils2 = require("@ai-sdk/provider-utils");
165
165
 
166
166
  // src/version.ts
167
- var VERSION = true ? "6.0.312" : "0.0.0-test";
167
+ var VERSION = true ? "6.0.313" : "0.0.0-test";
168
168
 
169
169
  // src/util/download/download.ts
170
170
  var download = async ({
@@ -144,7 +144,7 @@ import {
144
144
  } from "@ai-sdk/provider-utils";
145
145
 
146
146
  // src/version.ts
147
- var VERSION = true ? "6.0.312" : "0.0.0-test";
147
+ var VERSION = true ? "6.0.313" : "0.0.0-test";
148
148
 
149
149
  // src/util/download/download.ts
150
150
  var download = async ({
@@ -142,6 +142,7 @@ try {
142
142
  | [OpenAI](/providers/ai-sdk-providers/openai#speech-models) | `tts-1-hd` |
143
143
  | [OpenAI](/providers/ai-sdk-providers/openai#speech-models) | `gpt-4o-mini-tts` |
144
144
  | [Mistral](/providers/ai-sdk-providers/mistral#speech-models) | `voxtral-mini-tts-2603` |
145
+ | [Mistral](/providers/ai-sdk-providers/mistral#speech-models) | `voxtral-mini-tts-3-0` |
145
146
  | [Azure Speech](/providers/ai-sdk-providers/azure#mai-voice) | `mai-voice-2.1-flash` |
146
147
  | [Azure Speech](/providers/ai-sdk-providers/azure#mai-voice) | `mai-voice-2.1` |
147
148
  | [Azure Speech](/providers/ai-sdk-providers/azure#mai-voice) | `mai-voice-2-flash` |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai",
3
- "version": "6.0.312",
3
+ "version": "6.0.313",
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,7 +45,7 @@
45
45
  },
46
46
  "dependencies": {
47
47
  "@opentelemetry/api": "^1.9.0",
48
- "@ai-sdk/gateway": "3.0.219",
48
+ "@ai-sdk/gateway": "3.0.220",
49
49
  "@ai-sdk/provider": "3.0.19",
50
50
  "@ai-sdk/provider-utils": "4.0.62"
51
51
  },
@@ -73,6 +73,7 @@ export function collectToolApprovals<TOOLS extends ToolSet>({
73
73
 
74
74
  const approvedToolApprovals: Array<CollectedToolApprovals<TOOLS>> = [];
75
75
  const deniedToolApprovals: Array<CollectedToolApprovals<TOOLS>> = [];
76
+ const collectedToolCallIds = new Set<string>();
76
77
 
77
78
  const approvalResponses = lastMessage.content.filter(
78
79
  part => part.type === 'tool-approval-response',
@@ -99,6 +100,15 @@ export function collectToolApprovals<TOOLS extends ToolSet>({
99
100
  });
100
101
  }
101
102
 
103
+ // Only the first response for a tool call is collected. Later responses
104
+ // (replays, conflicting decisions, or responses to another approval of the
105
+ // same call) would otherwise execute the tool twice or both execute and
106
+ // deny it.
107
+ if (collectedToolCallIds.has(toolCall.toolCallId)) {
108
+ continue;
109
+ }
110
+ collectedToolCallIds.add(toolCall.toolCallId);
111
+
102
112
  const approval: CollectedToolApprovals<TOOLS> = {
103
113
  approvalRequest,
104
114
  approvalResponse,
@@ -161,42 +161,95 @@ export function pruneMessages({
161
161
  return message;
162
162
  }
163
163
 
164
- return {
165
- ...message,
166
- content: message.content.filter(part => {
167
- // keep non-tool parts:
168
- if (
169
- part.type !== 'tool-call' &&
170
- part.type !== 'tool-result' &&
171
- part.type !== 'tool-approval-request' &&
172
- part.type !== 'tool-approval-response'
173
- ) {
174
- return true;
164
+ const keepParts = message.content.map(part => {
165
+ // keep non-tool parts:
166
+ if (
167
+ part.type !== 'tool-call' &&
168
+ part.type !== 'tool-result' &&
169
+ part.type !== 'tool-approval-request' &&
170
+ part.type !== 'tool-approval-response'
171
+ ) {
172
+ return true;
173
+ }
174
+
175
+ // keep parts that are associated with a tool call or approval that needs to be kept:
176
+ if (
177
+ ((part.type === 'tool-call' || part.type === 'tool-result') &&
178
+ keptToolCallIds.has(part.toolCallId)) ||
179
+ ((part.type === 'tool-approval-request' ||
180
+ part.type === 'tool-approval-response') &&
181
+ keptApprovalIds.has(part.approvalId))
182
+ ) {
183
+ return true;
184
+ }
185
+
186
+ // keep parts that are not associated with a tool that should be removed:
187
+ const partToolName =
188
+ part.type === 'tool-call' || part.type === 'tool-result'
189
+ ? part.toolName
190
+ : approvalIdToToolName.get(part.approvalId);
191
+
192
+ return (
193
+ toolCall.tools != null &&
194
+ partToolName != null &&
195
+ !toolCall.tools.includes(partToolName)
196
+ );
197
+ });
198
+
199
+ // Consecutive reasoning parts can belong to the same provider item.
200
+ // Remove the whole group when its following content was pruned.
201
+ if (message.role === 'assistant') {
202
+ for (
203
+ let reasoningIndex = 0;
204
+ reasoningIndex < message.content.length;
205
+ reasoningIndex++
206
+ ) {
207
+ const part = message.content[reasoningIndex];
208
+ if (part.type !== 'reasoning') {
209
+ continue;
210
+ }
211
+
212
+ let reasoningEndIndex = reasoningIndex + 1;
213
+ while (reasoningEndIndex < message.content.length) {
214
+ const nextPart = message.content[reasoningEndIndex];
215
+ if (nextPart.type !== 'reasoning') {
216
+ break;
217
+ }
218
+ reasoningEndIndex++;
219
+ }
220
+
221
+ let followingPartIndex = reasoningEndIndex;
222
+ let hasFollowingPart = false;
223
+ let hasKeptFollowingPart = false;
224
+
225
+ while (followingPartIndex < message.content.length) {
226
+ const followingPart = message.content[followingPartIndex];
227
+ if (followingPart.type === 'reasoning') {
228
+ break;
229
+ }
230
+
231
+ hasFollowingPart = true;
232
+ hasKeptFollowingPart ||= keepParts[followingPartIndex];
233
+ followingPartIndex++;
175
234
  }
176
235
 
177
- // keep parts that are associated with a tool call or approval that needs to be kept:
178
- if (
179
- ((part.type === 'tool-call' || part.type === 'tool-result') &&
180
- keptToolCallIds.has(part.toolCallId)) ||
181
- ((part.type === 'tool-approval-request' ||
182
- part.type === 'tool-approval-response') &&
183
- keptApprovalIds.has(part.approvalId))
184
- ) {
185
- return true;
236
+ if (hasFollowingPart && !hasKeptFollowingPart) {
237
+ for (
238
+ let index = reasoningIndex;
239
+ index < reasoningEndIndex;
240
+ index++
241
+ ) {
242
+ keepParts[index] = false;
243
+ }
186
244
  }
187
245
 
188
- // keep parts that are not associated with a tool that should be removed:
189
- const partToolName =
190
- part.type === 'tool-call' || part.type === 'tool-result'
191
- ? part.toolName
192
- : approvalIdToToolName.get(part.approvalId);
193
-
194
- return (
195
- toolCall.tools != null &&
196
- partToolName != null &&
197
- !toolCall.tools.includes(partToolName)
198
- );
199
- }),
246
+ reasoningIndex = followingPartIndex - 1;
247
+ }
248
+ }
249
+
250
+ return {
251
+ ...message,
252
+ content: message.content.filter((_, index) => keepParts[index]),
200
253
  } as AssistantModelMessage | ToolModelMessage;
201
254
  });
202
255
  }
@@ -253,6 +253,7 @@ export function processUIMessageStream<UI_MESSAGE extends UIMessage>({
253
253
 
254
254
  if (part != null) {
255
255
  part.state = options.state;
256
+ anyPart.type = `tool-${options.toolName}`;
256
257
  anyPart.input = anyOptions.input;
257
258
  anyPart.output = anyOptions.output;
258
259
  anyPart.errorText = anyOptions.errorText;