ai 6.0.225 → 6.0.227

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.225" : "0.0.0-test";
155
+ var VERSION = true ? "6.0.227" : "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.225" : "0.0.0-test";
135
+ var VERSION = true ? "6.0.227" : "0.0.0-test";
136
136
 
137
137
  // src/util/download/download.ts
138
138
  var download = async ({
@@ -156,6 +156,7 @@ try {
156
156
  | [OpenAI](/providers/ai-sdk-providers/openai#speech-models) | `tts-1` |
157
157
  | [OpenAI](/providers/ai-sdk-providers/openai#speech-models) | `tts-1-hd` |
158
158
  | [OpenAI](/providers/ai-sdk-providers/openai#speech-models) | `gpt-4o-mini-tts` |
159
+ | [Mistral](/providers/ai-sdk-providers/mistral#speech-models) | `voxtral-mini-tts-2603` |
159
160
  | [ElevenLabs](/providers/ai-sdk-providers/elevenlabs#speech-models) | `eleven_v3` |
160
161
  | [ElevenLabs](/providers/ai-sdk-providers/elevenlabs#speech-models) | `eleven_multilingual_v2` |
161
162
  | [ElevenLabs](/providers/ai-sdk-providers/elevenlabs#speech-models) | `eleven_flash_v2_5` |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai",
3
- "version": "6.0.225",
3
+ "version": "6.0.227",
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.149",
48
+ "@ai-sdk/gateway": "3.0.150",
49
49
  "@ai-sdk/provider": "3.0.14",
50
- "@ai-sdk/provider-utils": "4.0.38"
50
+ "@ai-sdk/provider-utils": "4.0.39"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@edge-runtime/vm": "^5.0.0",
@@ -160,14 +160,44 @@ export function runToolsTransformation<TOOLS extends ToolSet>({
160
160
  let toolResultsStreamController: ReadableStreamDefaultController<
161
161
  SingleRequestTextStreamPart<TOOLS>
162
162
  > | null = null;
163
+ let toolResultsStreamClosed = false;
163
164
  const toolResultsStream = new ReadableStream<
164
165
  SingleRequestTextStreamPart<TOOLS>
165
166
  >({
166
167
  start(controller) {
167
168
  toolResultsStreamController = controller;
168
169
  },
170
+ cancel() {
171
+ toolResultsStreamClosed = true;
172
+ },
169
173
  });
170
174
 
175
+ function enqueueToolResult(chunk?: SingleRequestTextStreamPart<TOOLS>) {
176
+ if (toolResultsStreamClosed) {
177
+ return;
178
+ }
179
+
180
+ try {
181
+ toolResultsStreamController!.enqueue(chunk);
182
+ } catch {
183
+ toolResultsStreamClosed = true;
184
+ }
185
+ }
186
+
187
+ function closeToolResultsStream() {
188
+ if (toolResultsStreamClosed) {
189
+ return;
190
+ }
191
+
192
+ toolResultsStreamClosed = true;
193
+
194
+ try {
195
+ toolResultsStreamController!.close();
196
+ } catch {
197
+ // suppress errors when the stream has been closed
198
+ }
199
+ }
200
+
171
201
  // keep track of outstanding tool results for stream closing:
172
202
  const outstandingToolResults = new Set<string>();
173
203
 
@@ -187,10 +217,10 @@ export function runToolsTransformation<TOOLS extends ToolSet>({
187
217
  // are received to ensure that the frontend receives tool results before a message
188
218
  // finish event arrives.
189
219
  if (finishChunk != null) {
190
- toolResultsStreamController!.enqueue(finishChunk);
220
+ enqueueToolResult(finishChunk);
191
221
  }
192
222
 
193
- toolResultsStreamController!.close();
223
+ closeToolResultsStream();
194
224
  }
195
225
  }
196
226
 
@@ -255,7 +285,7 @@ export function runToolsTransformation<TOOLS extends ToolSet>({
255
285
  case 'tool-approval-request': {
256
286
  const toolCall = toolCallsByToolCallId.get(chunk.toolCallId);
257
287
  if (toolCall == null) {
258
- toolResultsStreamController!.enqueue({
288
+ enqueueToolResult({
259
289
  type: 'error',
260
290
  error: new ToolCallNotFoundForApprovalError({
261
291
  toolCallId: chunk.toolCallId,
@@ -288,7 +318,7 @@ export function runToolsTransformation<TOOLS extends ToolSet>({
288
318
  controller.enqueue(toolCall);
289
319
 
290
320
  if (toolCall.invalid) {
291
- toolResultsStreamController!.enqueue({
321
+ enqueueToolResult({
292
322
  type: 'tool-error',
293
323
  toolCallId: toolCall.toolCallId,
294
324
  toolName: toolCall.toolName,
@@ -338,7 +368,7 @@ export function runToolsTransformation<TOOLS extends ToolSet>({
338
368
  input: toolCall.input,
339
369
  });
340
370
 
341
- toolResultsStreamController!.enqueue({
371
+ enqueueToolResult({
342
372
  type: 'tool-approval-request',
343
373
  approvalId,
344
374
  toolCall,
@@ -368,14 +398,14 @@ export function runToolsTransformation<TOOLS extends ToolSet>({
368
398
  onToolCallStart,
369
399
  onToolCallFinish,
370
400
  onPreliminaryToolResult: result => {
371
- toolResultsStreamController!.enqueue(result);
401
+ enqueueToolResult(result);
372
402
  },
373
403
  })
374
404
  .then(result => {
375
- toolResultsStreamController!.enqueue(result);
405
+ enqueueToolResult(result);
376
406
  })
377
407
  .catch(error => {
378
- toolResultsStreamController!.enqueue({
408
+ enqueueToolResult({
379
409
  type: 'error',
380
410
  error,
381
411
  });
@@ -386,7 +416,7 @@ export function runToolsTransformation<TOOLS extends ToolSet>({
386
416
  });
387
417
  }
388
418
  } catch (error) {
389
- toolResultsStreamController!.enqueue({ type: 'error', error });
419
+ enqueueToolResult({ type: 'error', error });
390
420
  }
391
421
 
392
422
  break;
@@ -397,7 +427,7 @@ export function runToolsTransformation<TOOLS extends ToolSet>({
397
427
  const toolCall = toolCallsByToolCallId.get(chunk.toolCallId);
398
428
 
399
429
  if (chunk.isError) {
400
- toolResultsStreamController!.enqueue({
430
+ enqueueToolResult({
401
431
  type: 'tool-error',
402
432
  toolCallId: chunk.toolCallId,
403
433
  toolName,
package/src/ui/chat.ts CHANGED
@@ -651,9 +651,10 @@ export abstract class AbstractChat<UI_MESSAGE extends UIMessage> {
651
651
  let isAbort = false;
652
652
  let isDisconnect = false;
653
653
  let isError = false;
654
+ let activeResponse: ActiveResponse<UI_MESSAGE> | undefined;
654
655
 
655
656
  try {
656
- const activeResponse = {
657
+ const response = {
657
658
  state: createStreamingUIMessageState({
658
659
  lastMessage: this.state.snapshot(lastMessage),
659
660
  messageId: this.generateId(),
@@ -661,11 +662,13 @@ export abstract class AbstractChat<UI_MESSAGE extends UIMessage> {
661
662
  abortController: new AbortController(),
662
663
  } as ActiveResponse<UI_MESSAGE>;
663
664
 
664
- activeResponse.abortController.signal.addEventListener('abort', () => {
665
+ activeResponse = response;
666
+
667
+ response.abortController.signal.addEventListener('abort', () => {
665
668
  isAbort = true;
666
669
  });
667
670
 
668
- this.activeResponse = activeResponse;
671
+ this.activeResponse = response;
669
672
 
670
673
  let stream: ReadableStream<UIMessageChunk>;
671
674
 
@@ -675,7 +678,7 @@ export abstract class AbstractChat<UI_MESSAGE extends UIMessage> {
675
678
  stream = await this.transport.sendMessages({
676
679
  chatId: this.id,
677
680
  messages: this.state.messages,
678
- abortSignal: activeResponse.abortController.signal,
681
+ abortSignal: response.abortController.signal,
679
682
  metadata,
680
683
  headers,
681
684
  body,
@@ -693,21 +696,21 @@ export abstract class AbstractChat<UI_MESSAGE extends UIMessage> {
693
696
  // serialize the job execution to avoid race conditions:
694
697
  this.jobExecutor.run(() =>
695
698
  job({
696
- state: activeResponse.state,
699
+ state: response.state,
697
700
  write: () => {
698
701
  // streaming is set on first write (before it should be "submitted")
699
702
  this.setStatus({ status: 'streaming' });
700
703
 
701
704
  const replaceLastMessage =
702
- activeResponse.state.message.id === this.lastMessage?.id;
705
+ response.state.message.id === this.lastMessage?.id;
703
706
 
704
707
  if (replaceLastMessage) {
705
708
  this.state.replaceMessage(
706
709
  this.state.messages.length - 1,
707
- activeResponse.state.message,
710
+ response.state.message,
708
711
  );
709
712
  } else {
710
- this.state.pushMessage(activeResponse.state.message);
713
+ this.state.pushMessage(response.state.message);
711
714
  }
712
715
  },
713
716
  }),
@@ -757,19 +760,23 @@ export abstract class AbstractChat<UI_MESSAGE extends UIMessage> {
757
760
  this.setStatus({ status: 'error', error: err as Error });
758
761
  } finally {
759
762
  try {
760
- this.onFinish?.({
761
- message: this.activeResponse!.state.message,
762
- messages: this.state.messages,
763
- isAbort,
764
- isDisconnect,
765
- isError,
766
- finishReason: this.activeResponse?.state.finishReason,
767
- });
763
+ if (activeResponse) {
764
+ this.onFinish?.({
765
+ message: activeResponse.state.message,
766
+ messages: this.state.messages,
767
+ isAbort,
768
+ isDisconnect,
769
+ isError,
770
+ finishReason: activeResponse.state.finishReason,
771
+ });
772
+ }
768
773
  } catch (err) {
769
774
  console.error(err);
770
775
  }
771
776
 
772
- this.activeResponse = undefined;
777
+ if (this.activeResponse === activeResponse) {
778
+ this.activeResponse = undefined;
779
+ }
773
780
  }
774
781
 
775
782
  // automatically send the message if the sendAutomaticallyWhen function returns true
@@ -32,12 +32,12 @@ const uiMessagesSchema = lazySchema(() =>
32
32
  zodSchema(
33
33
  z
34
34
  .array(
35
- z.object({
36
- id: z.string(),
37
- role: z.enum(['system', 'user', 'assistant']),
38
- metadata: z.unknown().optional(),
39
- parts: z
40
- .array(
35
+ z
36
+ .object({
37
+ id: z.string(),
38
+ role: z.enum(['system', 'user', 'assistant']),
39
+ metadata: z.unknown().optional(),
40
+ parts: z.array(
41
41
  z.union([
42
42
  z.object({
43
43
  type: z.literal('text'),
@@ -323,9 +323,21 @@ const uiMessagesSchema = lazySchema(() =>
323
323
  }),
324
324
  }),
325
325
  ]),
326
- )
327
- .nonempty('Message must contain at least one part'),
328
- }),
326
+ ),
327
+ })
328
+ .superRefine((message, context) => {
329
+ if (message.role !== 'assistant' && message.parts.length === 0) {
330
+ context.addIssue({
331
+ origin: 'array',
332
+ code: 'too_small',
333
+ minimum: 1,
334
+ inclusive: true,
335
+ input: message.parts,
336
+ path: ['parts'],
337
+ message: 'Message must contain at least one part',
338
+ });
339
+ }
340
+ }),
329
341
  )
330
342
  .nonempty('Messages array must not be empty'),
331
343
  ),