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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # ai
2
2
 
3
+ ## 6.0.227
4
+
5
+ ### Patch Changes
6
+
7
+ - 6ace546: Fix chat `onFinish` handling when overlapping requests clear the active response before a resume stream finishes.
8
+
9
+ ## 6.0.226
10
+
11
+ ### Patch Changes
12
+
13
+ - 94219a2: Allow validating assistant UI messages with empty parts so persisted errored responses remain loadable.
14
+ - b1be847: Prevent pending tool executions from enqueueing results after a model stream error closes the result stream.
15
+ - Updated dependencies [06fb54c]
16
+ - Updated dependencies [bc46977]
17
+ - @ai-sdk/provider-utils@4.0.39
18
+ - @ai-sdk/gateway@3.0.150
19
+
3
20
  ## 6.0.225
4
21
 
5
22
  ### Patch Changes
package/dist/index.js CHANGED
@@ -1282,7 +1282,7 @@ function detectMediaType({
1282
1282
  var import_provider_utils3 = require("@ai-sdk/provider-utils");
1283
1283
 
1284
1284
  // src/version.ts
1285
- var VERSION = true ? "6.0.225" : "0.0.0-test";
1285
+ var VERSION = true ? "6.0.227" : "0.0.0-test";
1286
1286
 
1287
1287
  // src/util/download/download.ts
1288
1288
  var download = async ({
@@ -6611,11 +6611,35 @@ function runToolsTransformation({
6611
6611
  onToolCallFinish
6612
6612
  }) {
6613
6613
  let toolResultsStreamController = null;
6614
+ let toolResultsStreamClosed = false;
6614
6615
  const toolResultsStream = new ReadableStream({
6615
6616
  start(controller) {
6616
6617
  toolResultsStreamController = controller;
6618
+ },
6619
+ cancel() {
6620
+ toolResultsStreamClosed = true;
6617
6621
  }
6618
6622
  });
6623
+ function enqueueToolResult(chunk) {
6624
+ if (toolResultsStreamClosed) {
6625
+ return;
6626
+ }
6627
+ try {
6628
+ toolResultsStreamController.enqueue(chunk);
6629
+ } catch (e) {
6630
+ toolResultsStreamClosed = true;
6631
+ }
6632
+ }
6633
+ function closeToolResultsStream() {
6634
+ if (toolResultsStreamClosed) {
6635
+ return;
6636
+ }
6637
+ toolResultsStreamClosed = true;
6638
+ try {
6639
+ toolResultsStreamController.close();
6640
+ } catch (e) {
6641
+ }
6642
+ }
6619
6643
  const outstandingToolResults = /* @__PURE__ */ new Set();
6620
6644
  const toolCallsByToolCallId = /* @__PURE__ */ new Map();
6621
6645
  let canClose = false;
@@ -6623,9 +6647,9 @@ function runToolsTransformation({
6623
6647
  function attemptClose() {
6624
6648
  if (canClose && outstandingToolResults.size === 0) {
6625
6649
  if (finishChunk != null) {
6626
- toolResultsStreamController.enqueue(finishChunk);
6650
+ enqueueToolResult(finishChunk);
6627
6651
  }
6628
- toolResultsStreamController.close();
6652
+ closeToolResultsStream();
6629
6653
  }
6630
6654
  }
6631
6655
  const forwardStream = new TransformStream({
@@ -6673,7 +6697,7 @@ function runToolsTransformation({
6673
6697
  case "tool-approval-request": {
6674
6698
  const toolCall = toolCallsByToolCallId.get(chunk.toolCallId);
6675
6699
  if (toolCall == null) {
6676
- toolResultsStreamController.enqueue({
6700
+ enqueueToolResult({
6677
6701
  type: "error",
6678
6702
  error: new ToolCallNotFoundForApprovalError({
6679
6703
  toolCallId: chunk.toolCallId,
@@ -6701,7 +6725,7 @@ function runToolsTransformation({
6701
6725
  toolCallsByToolCallId.set(toolCall.toolCallId, toolCall);
6702
6726
  controller.enqueue(toolCall);
6703
6727
  if (toolCall.invalid) {
6704
- toolResultsStreamController.enqueue({
6728
+ enqueueToolResult({
6705
6729
  type: "tool-error",
6706
6730
  toolCallId: toolCall.toolCallId,
6707
6731
  toolName: toolCall.toolName,
@@ -6740,7 +6764,7 @@ function runToolsTransformation({
6740
6764
  toolName: toolCall.toolName,
6741
6765
  input: toolCall.input
6742
6766
  });
6743
- toolResultsStreamController.enqueue({
6767
+ enqueueToolResult({
6744
6768
  type: "tool-approval-request",
6745
6769
  approvalId,
6746
6770
  toolCall,
@@ -6764,12 +6788,12 @@ function runToolsTransformation({
6764
6788
  onToolCallStart,
6765
6789
  onToolCallFinish,
6766
6790
  onPreliminaryToolResult: (result) => {
6767
- toolResultsStreamController.enqueue(result);
6791
+ enqueueToolResult(result);
6768
6792
  }
6769
6793
  }).then((result) => {
6770
- toolResultsStreamController.enqueue(result);
6794
+ enqueueToolResult(result);
6771
6795
  }).catch((error) => {
6772
- toolResultsStreamController.enqueue({
6796
+ enqueueToolResult({
6773
6797
  type: "error",
6774
6798
  error
6775
6799
  });
@@ -6779,7 +6803,7 @@ function runToolsTransformation({
6779
6803
  });
6780
6804
  }
6781
6805
  } catch (error) {
6782
- toolResultsStreamController.enqueue({ type: "error", error });
6806
+ enqueueToolResult({ type: "error", error });
6783
6807
  }
6784
6808
  break;
6785
6809
  }
@@ -6787,7 +6811,7 @@ function runToolsTransformation({
6787
6811
  const toolName = chunk.toolName;
6788
6812
  const toolCall = toolCallsByToolCallId.get(chunk.toolCallId);
6789
6813
  if (chunk.isError) {
6790
- toolResultsStreamController.enqueue({
6814
+ enqueueToolResult({
6791
6815
  type: "tool-error",
6792
6816
  toolCallId: chunk.toolCallId,
6793
6817
  toolName,
@@ -9437,7 +9461,19 @@ var uiMessagesSchema = (0, import_provider_utils24.lazySchema)(
9437
9461
  })
9438
9462
  })
9439
9463
  ])
9440
- ).nonempty("Message must contain at least one part")
9464
+ )
9465
+ }).superRefine((message, context2) => {
9466
+ if (message.role !== "assistant" && message.parts.length === 0) {
9467
+ context2.addIssue({
9468
+ origin: "array",
9469
+ code: "too_small",
9470
+ minimum: 1,
9471
+ inclusive: true,
9472
+ input: message.parts,
9473
+ path: ["parts"],
9474
+ message: "Message must contain at least one part"
9475
+ });
9476
+ }
9441
9477
  })
9442
9478
  ).nonempty("Messages array must not be empty")
9443
9479
  )
@@ -13801,7 +13837,7 @@ var AbstractChat = class {
13801
13837
  body,
13802
13838
  messageId
13803
13839
  }) {
13804
- var _a22, _b, _c;
13840
+ var _a22, _b;
13805
13841
  let resumeStream;
13806
13842
  if (trigger === "resume-stream") {
13807
13843
  try {
@@ -13828,18 +13864,20 @@ var AbstractChat = class {
13828
13864
  let isAbort = false;
13829
13865
  let isDisconnect = false;
13830
13866
  let isError = false;
13867
+ let activeResponse;
13831
13868
  try {
13832
- const activeResponse = {
13869
+ const response = {
13833
13870
  state: createStreamingUIMessageState({
13834
13871
  lastMessage: this.state.snapshot(lastMessage),
13835
13872
  messageId: this.generateId()
13836
13873
  }),
13837
13874
  abortController: new AbortController()
13838
13875
  };
13839
- activeResponse.abortController.signal.addEventListener("abort", () => {
13876
+ activeResponse = response;
13877
+ response.abortController.signal.addEventListener("abort", () => {
13840
13878
  isAbort = true;
13841
13879
  });
13842
- this.activeResponse = activeResponse;
13880
+ this.activeResponse = response;
13843
13881
  let stream;
13844
13882
  if (trigger === "resume-stream") {
13845
13883
  stream = resumeStream;
@@ -13847,7 +13885,7 @@ var AbstractChat = class {
13847
13885
  stream = await this.transport.sendMessages({
13848
13886
  chatId: this.id,
13849
13887
  messages: this.state.messages,
13850
- abortSignal: activeResponse.abortController.signal,
13888
+ abortSignal: response.abortController.signal,
13851
13889
  metadata,
13852
13890
  headers,
13853
13891
  body,
@@ -13859,18 +13897,18 @@ var AbstractChat = class {
13859
13897
  // serialize the job execution to avoid race conditions:
13860
13898
  this.jobExecutor.run(
13861
13899
  () => job({
13862
- state: activeResponse.state,
13900
+ state: response.state,
13863
13901
  write: () => {
13864
13902
  var _a23;
13865
13903
  this.setStatus({ status: "streaming" });
13866
- const replaceLastMessage = activeResponse.state.message.id === ((_a23 = this.lastMessage) == null ? void 0 : _a23.id);
13904
+ const replaceLastMessage = response.state.message.id === ((_a23 = this.lastMessage) == null ? void 0 : _a23.id);
13867
13905
  if (replaceLastMessage) {
13868
13906
  this.state.replaceMessage(
13869
13907
  this.state.messages.length - 1,
13870
- activeResponse.state.message
13908
+ response.state.message
13871
13909
  );
13872
13910
  } else {
13873
- this.state.pushMessage(activeResponse.state.message);
13911
+ this.state.pushMessage(response.state.message);
13874
13912
  }
13875
13913
  }
13876
13914
  })
@@ -13909,23 +13947,27 @@ var AbstractChat = class {
13909
13947
  this.setStatus({ status: "error", error: err });
13910
13948
  } finally {
13911
13949
  try {
13912
- (_b = this.onFinish) == null ? void 0 : _b.call(this, {
13913
- message: this.activeResponse.state.message,
13914
- messages: this.state.messages,
13915
- isAbort,
13916
- isDisconnect,
13917
- isError,
13918
- finishReason: (_a22 = this.activeResponse) == null ? void 0 : _a22.state.finishReason
13919
- });
13950
+ if (activeResponse) {
13951
+ (_a22 = this.onFinish) == null ? void 0 : _a22.call(this, {
13952
+ message: activeResponse.state.message,
13953
+ messages: this.state.messages,
13954
+ isAbort,
13955
+ isDisconnect,
13956
+ isError,
13957
+ finishReason: activeResponse.state.finishReason
13958
+ });
13959
+ }
13920
13960
  } catch (err) {
13921
13961
  console.error(err);
13922
13962
  }
13923
- this.activeResponse = void 0;
13963
+ if (this.activeResponse === activeResponse) {
13964
+ this.activeResponse = void 0;
13965
+ }
13924
13966
  }
13925
13967
  if (!isError && await this.shouldSendAutomatically()) {
13926
13968
  await this.makeRequest({
13927
13969
  trigger: "submit-message",
13928
- messageId: (_c = this.lastMessage) == null ? void 0 : _c.id,
13970
+ messageId: (_b = this.lastMessage) == null ? void 0 : _b.id,
13929
13971
  metadata,
13930
13972
  headers,
13931
13973
  body