ai 7.0.11 → 7.0.13

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.
@@ -214,8 +214,8 @@ try {
214
214
  | [Deepgram](/providers/ai-sdk-providers/deepgram#transcription-models) | `nova-2` (+ variants) |
215
215
  | [Deepgram](/providers/ai-sdk-providers/deepgram#transcription-models) | `nova-3` (+ variants) |
216
216
  | [Gladia](/providers/ai-sdk-providers/gladia#transcription-models) | `default` |
217
- | [AssemblyAI](/providers/ai-sdk-providers/assemblyai#transcription-models) | `best` |
218
- | [AssemblyAI](/providers/ai-sdk-providers/assemblyai#transcription-models) | `nano` |
217
+ | [AssemblyAI](/providers/ai-sdk-providers/assemblyai#transcription-models) | `universal-3-5-pro` |
218
+ | [AssemblyAI](/providers/ai-sdk-providers/assemblyai#transcription-models) | `universal-3-pro` |
219
219
  | [Fal](/providers/ai-sdk-providers/fal#transcription-models) | `whisper` |
220
220
  | [Fal](/providers/ai-sdk-providers/fal#transcription-models) | `wizper` |
221
221
  | [Google Vertex](/providers/ai-sdk-providers/google-vertex#transcription-models) | `chirp_2` |
@@ -106,6 +106,11 @@ It also contains the following helper functions:
106
106
  description: 'Creates a client for connecting to MCP servers.',
107
107
  href: '/docs/reference/ai-sdk-core/create-mcp-client',
108
108
  },
109
+ {
110
+ title: 'validateJSONRPCMessage()',
111
+ description: 'Validates unknown values as MCP JSON-RPC messages.',
112
+ href: '/docs/reference/ai-sdk-core/validate-json-rpc-message',
113
+ },
109
114
  {
110
115
  title: 'MCP Apps',
111
116
  description:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai",
3
- "version": "7.0.11",
3
+ "version": "7.0.13",
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.8",
45
+ "@ai-sdk/gateway": "4.0.10",
46
46
  "@ai-sdk/provider": "4.0.1",
47
- "@ai-sdk/provider-utils": "5.0.3"
47
+ "@ai-sdk/provider-utils": "5.0.4"
48
48
  },
49
49
  "devDependencies": {
50
50
  "@edge-runtime/vm": "^5.0.0",
@@ -19,6 +19,7 @@ export async function toResponseMessages<TOOLS extends ToolSet>({
19
19
  tools: TOOLS | undefined;
20
20
  }): Promise<Array<AssistantModelMessage | ToolModelMessage>> {
21
21
  const responseMessages: Array<AssistantModelMessage | ToolModelMessage> = [];
22
+ const toolCallOrder = new Map<string, number>();
22
23
 
23
24
  const content: AssistantContent = [];
24
25
  for (const part of inputContent) {
@@ -79,6 +80,9 @@ export async function toResponseMessages<TOOLS extends ToolSet>({
79
80
  });
80
81
  break;
81
82
  case 'tool-call':
83
+ if (!toolCallOrder.has(part.toolCallId)) {
84
+ toolCallOrder.set(part.toolCallId, toolCallOrder.size);
85
+ }
82
86
  content.push({
83
87
  type: 'tool-call',
84
88
  toolCallId: part.toolCallId,
@@ -204,9 +208,49 @@ export async function toResponseMessages<TOOLS extends ToolSet>({
204
208
  if (toolResultContent.length > 0) {
205
209
  responseMessages.push({
206
210
  role: 'tool',
207
- content: toolResultContent,
211
+ content: sortToolResultContentByToolCallOrder({
212
+ toolResultContent,
213
+ toolCallOrder,
214
+ }),
208
215
  });
209
216
  }
210
217
 
211
218
  return responseMessages;
212
219
  }
220
+
221
+ function sortToolResultContentByToolCallOrder({
222
+ toolResultContent,
223
+ toolCallOrder,
224
+ }: {
225
+ toolResultContent: ToolContent;
226
+ toolCallOrder: Map<string, number>;
227
+ }): ToolContent {
228
+ const sortedToolResults = toolResultContent
229
+ .filter(part => part.type === 'tool-result')
230
+ .map((part, index) => ({ part, index }))
231
+ .sort((a, b) => {
232
+ const aOrder = toolCallOrder.get(a.part.toolCallId);
233
+ const bOrder = toolCallOrder.get(b.part.toolCallId);
234
+
235
+ if (aOrder == null && bOrder == null) {
236
+ return a.index - b.index;
237
+ }
238
+
239
+ if (aOrder == null) {
240
+ return 1;
241
+ }
242
+
243
+ if (bOrder == null) {
244
+ return -1;
245
+ }
246
+
247
+ return aOrder - bOrder || a.index - b.index;
248
+ })
249
+ .map(({ part }) => part);
250
+
251
+ let toolResultIndex = 0;
252
+
253
+ return toolResultContent.map(part =>
254
+ part.type === 'tool-result' ? sortedToolResults[toolResultIndex++] : part,
255
+ );
256
+ }
@@ -15,6 +15,10 @@ function defaultTransform(text: string): string {
15
15
  .trim();
16
16
  }
17
17
 
18
+ function stripMarkdownCodeFenceSuffix(text: string): string {
19
+ return text.replace(/\n?```\s*$/, '').trimEnd();
20
+ }
21
+
18
22
  /**
19
23
  * Middleware that extracts JSON from text content by stripping
20
24
  * markdown code fences and other formatting.
@@ -169,10 +173,15 @@ export function extractJsonMiddleware(options?: {
169
173
  remaining = transform(remaining);
170
174
  } else if (block.prefixStripped) {
171
175
  // strip suffix since prefix already handled
172
- remaining = remaining.replace(/\n?```\s*$/, '').trimEnd();
173
- } else {
174
- // Apply full transform (handles both prefix and suffix)
176
+ remaining = stripMarkdownCodeFenceSuffix(remaining);
177
+ } else if (block.phase === 'prefix') {
178
+ // No text has streamed yet, so the full transform is safe.
175
179
  remaining = transform(remaining);
180
+ } else {
181
+ // Only strip the suffix. Since earlier text may already have
182
+ // streamed, trimming the remaining suffix would remove valid
183
+ // leading whitespace at the stream boundary.
184
+ remaining = stripMarkdownCodeFenceSuffix(remaining);
176
185
  }
177
186
 
178
187
  if (remaining.length > 0) {