ai 6.0.296 → 6.0.298

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 (37) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/index.d.mts +36 -5
  3. package/dist/index.d.ts +36 -5
  4. package/dist/index.js +187 -32
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +187 -32
  7. package/dist/index.mjs.map +1 -1
  8. package/dist/internal/index.js +1 -1
  9. package/dist/internal/index.mjs +1 -1
  10. package/docs/04-ai-sdk-ui/02-chatbot.mdx +10 -1
  11. package/docs/04-ai-sdk-ui/03-chatbot-message-persistence.mdx +8 -0
  12. package/docs/04-ai-sdk-ui/03-chatbot-resume-streams.mdx +10 -3
  13. package/docs/04-ai-sdk-ui/03-chatbot-tool-usage.mdx +10 -1
  14. package/docs/07-reference/01-ai-sdk-core/02-stream-text.mdx +1 -1
  15. package/docs/07-reference/02-ai-sdk-ui/41-create-ui-message-stream-response.mdx +7 -0
  16. package/docs/07-reference/02-ai-sdk-ui/42-pipe-ui-message-stream-to-response.mdx +7 -0
  17. package/package.json +4 -4
  18. package/src/agent/create-agent-ui-stream-response.ts +3 -0
  19. package/src/agent/pipe-agent-ui-stream-to-response.ts +3 -0
  20. package/src/embed/embed-many.ts +5 -3
  21. package/src/generate-image/generate-image.ts +7 -2
  22. package/src/generate-text/stream-text-result.ts +5 -0
  23. package/src/generate-text/stream-text.ts +4 -1
  24. package/src/generate-video/generate-video.ts +6 -4
  25. package/src/registry/provider-registry.ts +1 -1
  26. package/src/ui/chat.ts +13 -4
  27. package/src/ui/http-chat-transport.ts +27 -1
  28. package/src/ui/last-assistant-message-is-complete-with-tool-calls.ts +15 -3
  29. package/src/ui/process-ui-message-stream.ts +51 -14
  30. package/src/ui/ui-messages.ts +14 -0
  31. package/src/ui/validate-ui-messages.ts +2 -0
  32. package/src/ui-message-stream/create-sse-stream-with-keep-alive.ts +89 -0
  33. package/src/ui-message-stream/create-ui-message-stream-response.ts +7 -1
  34. package/src/ui-message-stream/pipe-ui-message-stream-to-response.ts +7 -1
  35. package/src/ui-message-stream/ui-message-stream-response-init.ts +7 -0
  36. package/src/util/get-own.ts +18 -0
  37. package/src/util/set-own.ts +16 -0
package/dist/index.mjs CHANGED
@@ -1224,7 +1224,7 @@ import {
1224
1224
  } from "@ai-sdk/provider-utils";
1225
1225
 
1226
1226
  // src/version.ts
1227
- var VERSION = true ? "6.0.296" : "0.0.0-test";
1227
+ var VERSION = true ? "6.0.298" : "0.0.0-test";
1228
1228
 
1229
1229
  // src/util/download/download.ts
1230
1230
  var download = async ({
@@ -5639,6 +5639,75 @@ function pipeTextStreamToResponse({
5639
5639
  });
5640
5640
  }
5641
5641
 
5642
+ // src/ui-message-stream/create-sse-stream-with-keep-alive.ts
5643
+ var STREAM_OPEN_COMMENT = ": stream-open\n\n";
5644
+ var KEEP_ALIVE_COMMENT = ": keep-alive\n\n";
5645
+ function createSseStreamWithKeepAlive({
5646
+ stream,
5647
+ keepAliveMs
5648
+ }) {
5649
+ if (keepAliveMs == null) {
5650
+ return stream;
5651
+ }
5652
+ if (!Number.isFinite(keepAliveMs) || keepAliveMs <= 0 || keepAliveMs > 2147483647) {
5653
+ throw new Error(
5654
+ "keepAliveMs must be a positive finite timer duration no greater than 2147483647"
5655
+ );
5656
+ }
5657
+ const reader = stream.getReader();
5658
+ let keepAliveTimeout;
5659
+ let isCancelled = false;
5660
+ const clearKeepAliveTimeout = () => {
5661
+ clearTimeout(keepAliveTimeout);
5662
+ keepAliveTimeout = void 0;
5663
+ };
5664
+ const scheduleKeepAlive = (controller) => {
5665
+ clearKeepAliveTimeout();
5666
+ keepAliveTimeout = setTimeout(() => {
5667
+ if (isCancelled) {
5668
+ return;
5669
+ }
5670
+ if (controller.desiredSize != null && controller.desiredSize > 0) {
5671
+ controller.enqueue(KEEP_ALIVE_COMMENT);
5672
+ }
5673
+ scheduleKeepAlive(controller);
5674
+ }, keepAliveMs);
5675
+ };
5676
+ return new ReadableStream({
5677
+ start(controller) {
5678
+ controller.enqueue(STREAM_OPEN_COMMENT);
5679
+ scheduleKeepAlive(controller);
5680
+ },
5681
+ pull(controller) {
5682
+ return reader.read().then(
5683
+ (result) => {
5684
+ clearKeepAliveTimeout();
5685
+ if (isCancelled) {
5686
+ return;
5687
+ }
5688
+ if (result.done) {
5689
+ controller.close();
5690
+ } else {
5691
+ controller.enqueue(result.value);
5692
+ scheduleKeepAlive(controller);
5693
+ }
5694
+ },
5695
+ (error) => {
5696
+ clearKeepAliveTimeout();
5697
+ if (!isCancelled) {
5698
+ throw error;
5699
+ }
5700
+ }
5701
+ );
5702
+ },
5703
+ async cancel(reason) {
5704
+ isCancelled = true;
5705
+ clearKeepAliveTimeout();
5706
+ await reader.cancel(reason);
5707
+ }
5708
+ });
5709
+ }
5710
+
5642
5711
  // src/ui-message-stream/json-to-sse-transform-stream.ts
5643
5712
  var JsonToSseTransformStream = class extends TransformStream {
5644
5713
  constructor() {
@@ -5671,9 +5740,13 @@ function createUIMessageStreamResponse({
5671
5740
  statusText,
5672
5741
  headers,
5673
5742
  stream,
5743
+ keepAliveMs,
5674
5744
  consumeSseStream
5675
5745
  }) {
5676
- let sseStream = stream.pipeThrough(new JsonToSseTransformStream());
5746
+ let sseStream = createSseStreamWithKeepAlive({
5747
+ stream: stream.pipeThrough(new JsonToSseTransformStream()),
5748
+ keepAliveMs
5749
+ });
5677
5750
  if (consumeSseStream) {
5678
5751
  const [stream1, stream2] = sseStream.tee();
5679
5752
  sseStream = stream1;
@@ -5925,16 +5998,43 @@ function createStreamingUIMessageState({
5925
5998
  lastMessage,
5926
5999
  messageId
5927
6000
  }) {
6001
+ var _a23;
6002
+ const message = (lastMessage == null ? void 0 : lastMessage.role) === "assistant" ? lastMessage : {
6003
+ id: messageId,
6004
+ metadata: void 0,
6005
+ role: "assistant",
6006
+ parts: []
6007
+ };
6008
+ const partialToolCalls = createIdMap();
6009
+ const lastStepStartIndex = message.parts.findLastIndex(
6010
+ (part) => part.type === "step-start"
6011
+ );
6012
+ let staticToolIndex = 0;
6013
+ for (const part of message.parts.slice(lastStepStartIndex + 1)) {
6014
+ if (!isToolUIPart(part)) {
6015
+ continue;
6016
+ }
6017
+ const index = staticToolIndex;
6018
+ if (isStaticToolUIPart(part)) {
6019
+ staticToolIndex++;
6020
+ }
6021
+ if (part.state !== "input-streaming") {
6022
+ continue;
6023
+ }
6024
+ partialToolCalls[part.toolCallId] = {
6025
+ text: (_a23 = part.rawInput) != null ? _a23 : "",
6026
+ index,
6027
+ toolName: part.type === "dynamic-tool" ? part.toolName : getStaticToolName(part),
6028
+ dynamic: part.type === "dynamic-tool",
6029
+ title: part.title,
6030
+ toolMetadata: part.toolMetadata
6031
+ };
6032
+ }
5928
6033
  return {
5929
- message: (lastMessage == null ? void 0 : lastMessage.role) === "assistant" ? lastMessage : {
5930
- id: messageId,
5931
- metadata: void 0,
5932
- role: "assistant",
5933
- parts: []
5934
- },
6034
+ message,
5935
6035
  activeTextParts: createIdMap(),
5936
6036
  activeReasoningParts: createIdMap(),
5937
- partialToolCalls: createIdMap()
6037
+ partialToolCalls
5938
6038
  };
5939
6039
  }
5940
6040
  function processUIMessageStream({
@@ -6035,7 +6135,7 @@ function processUIMessageStream({
6035
6135
  }
6036
6136
  }
6037
6137
  function updateDynamicToolPart(options, existingPart) {
6038
- var _a24, _b2;
6138
+ var _a24;
6039
6139
  const part = existingPart != null ? existingPart : getCurrentStepParts().find(
6040
6140
  (part2) => part2.type === "dynamic-tool" && part2.toolCallId === options.toolCallId
6041
6141
  );
@@ -6047,7 +6147,7 @@ function processUIMessageStream({
6047
6147
  anyPart.input = anyOptions.input;
6048
6148
  anyPart.output = anyOptions.output;
6049
6149
  anyPart.errorText = anyOptions.errorText;
6050
- anyPart.rawInput = (_a24 = anyOptions.rawInput) != null ? _a24 : anyPart.rawInput;
6150
+ anyPart.rawInput = anyOptions.rawInput;
6051
6151
  anyPart.preliminary = anyOptions.preliminary;
6052
6152
  if (options.title !== void 0) {
6053
6153
  anyPart.title = options.title;
@@ -6055,7 +6155,7 @@ function processUIMessageStream({
6055
6155
  if (options.toolMetadata !== void 0) {
6056
6156
  anyPart.toolMetadata = options.toolMetadata;
6057
6157
  }
6058
- anyPart.providerExecuted = (_b2 = anyOptions.providerExecuted) != null ? _b2 : part.providerExecuted;
6158
+ anyPart.providerExecuted = (_a24 = anyOptions.providerExecuted) != null ? _a24 : part.providerExecuted;
6059
6159
  const providerMetadata = anyOptions.providerMetadata;
6060
6160
  if (providerMetadata != null) {
6061
6161
  if (options.state === "output-available" || options.state === "output-error") {
@@ -6271,6 +6371,7 @@ function processUIMessageStream({
6271
6371
  toolName: partialToolCall.toolName,
6272
6372
  state: "input-streaming",
6273
6373
  input: partialArgs,
6374
+ rawInput: partialToolCall.text,
6274
6375
  title: partialToolCall.title,
6275
6376
  toolMetadata: partialToolCall.toolMetadata
6276
6377
  });
@@ -6280,6 +6381,7 @@ function processUIMessageStream({
6280
6381
  toolName: partialToolCall.toolName,
6281
6382
  state: "input-streaming",
6282
6383
  input: partialArgs,
6384
+ rawInput: partialToolCall.text,
6283
6385
  title: partialToolCall.title,
6284
6386
  toolMetadata: partialToolCall.toolMetadata
6285
6387
  });
@@ -6668,9 +6770,13 @@ function pipeUIMessageStreamToResponse({
6668
6770
  statusText,
6669
6771
  headers,
6670
6772
  stream,
6773
+ keepAliveMs,
6671
6774
  consumeSseStream
6672
6775
  }) {
6673
- let sseStream = stream.pipeThrough(new JsonToSseTransformStream());
6776
+ let sseStream = createSseStreamWithKeepAlive({
6777
+ stream: stream.pipeThrough(new JsonToSseTransformStream()),
6778
+ keepAliveMs
6779
+ });
6674
6780
  if (consumeSseStream) {
6675
6781
  const [stream1, stream2] = sseStream.tee();
6676
6782
  sseStream = stream1;
@@ -8834,7 +8940,7 @@ var DefaultStreamTextResult = class {
8834
8940
  sendStart = true,
8835
8941
  sendFinish = true,
8836
8942
  onError = () => "An error occurred."
8837
- // prevent leaking server error details to the client by default
8943
+ // masks errors except provider-executed tool execution errors
8838
8944
  } = {}) {
8839
8945
  let outcome = { status: "unknown" };
8840
8946
  let hasFatalFailure = false;
@@ -9883,6 +9989,7 @@ var uiMessagesSchema = lazySchema2(() => {
9883
9989
  toolMetadata: toolMetadataSchema2.optional(),
9884
9990
  state: z8.literal("input-streaming"),
9885
9991
  input: z8.unknown().optional(),
9992
+ rawInput: z8.string().optional(),
9886
9993
  providerExecuted: z8.boolean().optional(),
9887
9994
  callProviderMetadata: providerMetadataSchema.optional(),
9888
9995
  output: z8.never().optional(),
@@ -9979,6 +10086,7 @@ var uiMessagesSchema = lazySchema2(() => {
9979
10086
  providerExecuted: z8.boolean().optional(),
9980
10087
  callProviderMetadata: providerMetadataSchema.optional(),
9981
10088
  input: z8.unknown().optional(),
10089
+ rawInput: z8.string().optional(),
9982
10090
  output: z8.never().optional(),
9983
10091
  errorText: z8.never().optional(),
9984
10092
  approval: z8.never().optional()
@@ -10300,6 +10408,7 @@ async function createAgentUIStreamResponse({
10300
10408
  headers,
10301
10409
  status,
10302
10410
  statusText,
10411
+ keepAliveMs,
10303
10412
  consumeSseStream,
10304
10413
  ...options
10305
10414
  }) {
@@ -10307,6 +10416,7 @@ async function createAgentUIStreamResponse({
10307
10416
  headers,
10308
10417
  status,
10309
10418
  statusText,
10419
+ keepAliveMs,
10310
10420
  consumeSseStream,
10311
10421
  stream: await createAgentUIStream(options)
10312
10422
  });
@@ -10318,6 +10428,7 @@ async function pipeAgentUIStreamToResponse({
10318
10428
  headers,
10319
10429
  status,
10320
10430
  statusText,
10431
+ keepAliveMs,
10321
10432
  consumeSseStream,
10322
10433
  ...options
10323
10434
  }) {
@@ -10326,6 +10437,7 @@ async function pipeAgentUIStreamToResponse({
10326
10437
  headers,
10327
10438
  status,
10328
10439
  statusText,
10440
+ keepAliveMs,
10329
10441
  consumeSseStream,
10330
10442
  stream: await createAgentUIStream(options)
10331
10443
  });
@@ -10462,6 +10574,21 @@ var DefaultEmbedResult = class {
10462
10574
  }
10463
10575
  };
10464
10576
 
10577
+ // src/util/get-own.ts
10578
+ function getOwn(obj, key) {
10579
+ return obj != null && Object.hasOwn(obj, key) ? obj[key] : void 0;
10580
+ }
10581
+
10582
+ // src/util/set-own.ts
10583
+ function setOwn(object2, key, value) {
10584
+ Object.defineProperty(object2, key, {
10585
+ value,
10586
+ enumerable: true,
10587
+ configurable: true,
10588
+ writable: true
10589
+ });
10590
+ }
10591
+
10465
10592
  // src/embed/embed-many.ts
10466
10593
  import {
10467
10594
  withUserAgentSuffix as withUserAgentSuffix4
@@ -10715,10 +10842,10 @@ async function embedMany({
10715
10842
  for (const [providerName, metadata] of Object.entries(
10716
10843
  result.providerMetadata
10717
10844
  )) {
10718
- providerMetadata[providerName] = {
10719
- ...providerMetadata[providerName],
10845
+ setOwn(providerMetadata, providerName, {
10846
+ ...getOwn(providerMetadata, providerName),
10720
10847
  ...metadata
10721
- };
10848
+ });
10722
10849
  }
10723
10850
  }
10724
10851
  }
@@ -10917,10 +11044,13 @@ async function generateImage({
10917
11044
  delete providerMetadata[providerName].images;
10918
11045
  }
10919
11046
  } else {
10920
- (_b = providerMetadata[providerName]) != null ? _b : providerMetadata[providerName] = { images: [] };
10921
- providerMetadata[providerName].images.push(
11047
+ const currentEntry = (_b = getOwn(providerMetadata, providerName)) != null ? _b : {
11048
+ images: []
11049
+ };
11050
+ currentEntry.images.push(
10922
11051
  ...result.providerMetadata[providerName].images
10923
11052
  );
11053
+ setOwn(providerMetadata, providerName, currentEntry);
10924
11054
  }
10925
11055
  }
10926
11056
  }
@@ -12885,12 +13015,12 @@ async function experimental_generateVideo({
12885
13015
  for (const [providerName, metadata] of Object.entries(
12886
13016
  result.providerMetadata
12887
13017
  )) {
12888
- const existingMetadata = providerMetadata[providerName];
13018
+ const existingMetadata = getOwn(providerMetadata, providerName);
12889
13019
  if (existingMetadata != null && typeof existingMetadata === "object") {
12890
- providerMetadata[providerName] = {
13020
+ setOwn(providerMetadata, providerName, {
12891
13021
  ...existingMetadata,
12892
13022
  ...metadata
12893
- };
13023
+ });
12894
13024
  if ("videos" in existingMetadata && Array.isArray(existingMetadata.videos) && "videos" in metadata && Array.isArray(metadata.videos)) {
12895
13025
  providerMetadata[providerName].videos = [
12896
13026
  ...existingMetadata.videos,
@@ -12898,7 +13028,7 @@ async function experimental_generateVideo({
12898
13028
  ];
12899
13029
  }
12900
13030
  } else {
12901
- providerMetadata[providerName] = metadata;
13031
+ setOwn(providerMetadata, providerName, metadata);
12902
13032
  }
12903
13033
  }
12904
13034
  }
@@ -13776,7 +13906,7 @@ var DefaultProviderRegistry = class {
13776
13906
  languageModelMiddleware,
13777
13907
  imageModelMiddleware
13778
13908
  }) {
13779
- this.providers = {};
13909
+ this.providers = /* @__PURE__ */ Object.create(null);
13780
13910
  this.separator = separator;
13781
13911
  this.languageModelMiddleware = languageModelMiddleware;
13782
13912
  this.imageModelMiddleware = imageModelMiddleware;
@@ -14298,6 +14428,10 @@ import {
14298
14428
  normalizeHeaders,
14299
14429
  resolve as resolve2
14300
14430
  } from "@ai-sdk/provider-utils";
14431
+ function appendPathToUrl(url, path) {
14432
+ const queryOrFragmentStart = url.search(/[?#]/);
14433
+ return queryOrFragmentStart === -1 ? `${url}${path}` : `${url.slice(0, queryOrFragmentStart)}${path}${url.slice(queryOrFragmentStart)}`;
14434
+ }
14301
14435
  var HttpChatTransport = class {
14302
14436
  constructor({
14303
14437
  api = "/api/chat",
@@ -14372,7 +14506,7 @@ var HttpChatTransport = class {
14372
14506
  return this.processResponseStream(response.body);
14373
14507
  }
14374
14508
  async reconnectToStream(options) {
14375
- var _a23, _b, _c, _d, _e;
14509
+ var _a23, _b, _c, _d;
14376
14510
  const resolvedBody = await resolve2(this.body);
14377
14511
  const resolvedHeaders = await resolve2(this.headers);
14378
14512
  const resolvedCredentials = await resolve2(this.credentials);
@@ -14388,10 +14522,23 @@ var HttpChatTransport = class {
14388
14522
  credentials: resolvedCredentials,
14389
14523
  requestMetadata: options.metadata
14390
14524
  }));
14391
- const api = (_b = preparedRequest == null ? void 0 : preparedRequest.api) != null ? _b : `${this.api}/${options.chatId}/stream`;
14525
+ let api = preparedRequest == null ? void 0 : preparedRequest.api;
14526
+ if (api == null) {
14527
+ if (options.chatId === "." || options.chatId === "..") {
14528
+ throw new InvalidArgumentError({
14529
+ parameter: "chatId",
14530
+ value: options.chatId,
14531
+ message: 'Chat IDs must not be "." or ".." when using the default reconnect URL.'
14532
+ });
14533
+ }
14534
+ api = appendPathToUrl(
14535
+ this.api,
14536
+ `/${encodeURIComponent(options.chatId)}/stream`
14537
+ );
14538
+ }
14392
14539
  const headers = (preparedRequest == null ? void 0 : preparedRequest.headers) !== void 0 ? normalizeHeaders(preparedRequest.headers) : baseHeaders;
14393
- const credentials = (_c = preparedRequest == null ? void 0 : preparedRequest.credentials) != null ? _c : resolvedCredentials;
14394
- const fetch2 = (_d = this.fetch) != null ? _d : globalThis.fetch;
14540
+ const credentials = (_b = preparedRequest == null ? void 0 : preparedRequest.credentials) != null ? _b : resolvedCredentials;
14541
+ const fetch2 = (_c = this.fetch) != null ? _c : globalThis.fetch;
14395
14542
  const response = await fetch2(api, {
14396
14543
  method: "GET",
14397
14544
  headers,
@@ -14403,7 +14550,7 @@ var HttpChatTransport = class {
14403
14550
  }
14404
14551
  if (!response.ok) {
14405
14552
  throw new Error(
14406
- (_e = await response.text()) != null ? _e : "Failed to fetch the chat response."
14553
+ (_d = await response.text()) != null ? _d : "Failed to fetch the chat response."
14407
14554
  );
14408
14555
  }
14409
14556
  if (!response.body) {
@@ -14798,6 +14945,9 @@ var AbstractChat = class {
14798
14945
  const lastMessage = this.lastMessage;
14799
14946
  const responseMessageIndex = trigger === "submit-message" && messageId != null ? this.state.messages.findIndex((message) => message.id === messageId) : this.state.messages.length - 1;
14800
14947
  const responseMessage = responseMessageIndex === -1 ? lastMessage : this.state.messages[responseMessageIndex];
14948
+ const resumableResponseMessage = trigger === "resume-stream" && (responseMessage == null ? void 0 : responseMessage.role) === "assistant" && responseMessage.parts.some(
14949
+ (part) => isToolUIPart(part) && part.state === "input-streaming"
14950
+ ) ? this.state.snapshot(responseMessage) : void 0;
14801
14951
  const usesEarlierAssistantMessage = responseMessageIndex !== -1 && responseMessageIndex < this.state.messages.length - 1 && (responseMessage == null ? void 0 : responseMessage.role) === "assistant";
14802
14952
  let isAbort = false;
14803
14953
  let isDisconnect = false;
@@ -14806,7 +14956,7 @@ var AbstractChat = class {
14806
14956
  try {
14807
14957
  const response = {
14808
14958
  state: trigger === "resume-stream" && this.resumableStreamState != null ? this.resumableStreamState : createStreamingUIMessageState({
14809
- lastMessage: trigger === "resume-stream" || trigger === "regenerate-message" ? void 0 : this.state.snapshot(responseMessage),
14959
+ lastMessage: trigger === "resume-stream" ? resumableResponseMessage : trigger === "regenerate-message" ? void 0 : this.state.snapshot(responseMessage),
14810
14960
  messageId: this.generateId()
14811
14961
  }),
14812
14962
  abortController
@@ -15032,8 +15182,13 @@ function lastAssistantMessageIsCompleteWithToolCalls({
15032
15182
  const lastStepStartIndex = message.parts.reduce((lastIndex, part, index) => {
15033
15183
  return part.type === "step-start" ? index : lastIndex;
15034
15184
  }, -1);
15035
- const lastStepToolInvocations = message.parts.slice(lastStepStartIndex + 1).filter(isToolUIPart).filter((part) => !part.providerExecuted);
15036
- return lastStepToolInvocations.length > 0 && lastStepToolInvocations.every(
15185
+ const lastStepParts = message.parts.slice(lastStepStartIndex + 1);
15186
+ const lastStepToolInvocations = lastStepParts.filter(isToolUIPart).filter((part) => !part.providerExecuted);
15187
+ const lastToolInvocationIndex = lastStepParts.reduce(
15188
+ (lastIndex, part, index) => isToolUIPart(part) && !part.providerExecuted ? index : lastIndex,
15189
+ -1
15190
+ );
15191
+ return lastStepToolInvocations.length > 0 && !lastStepParts.slice(lastToolInvocationIndex + 1).some((part) => part.type === "text" && part.state !== "done") && lastStepToolInvocations.every(
15037
15192
  (part) => part.state === "output-available" && part.preliminary !== true || part.state === "output-error"
15038
15193
  );
15039
15194
  }