ai 5.0.229 → 5.0.231

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,20 @@
1
1
  # ai
2
2
 
3
+ ## 5.0.231
4
+
5
+ ### Patch Changes
6
+
7
+ - 2709314: Stop pending and active resumed chat streams after cancellation, and prevent overlapping resumptions from applying stale updates.
8
+ - Updated dependencies [b474448]
9
+ - @ai-sdk/gateway@2.0.130
10
+
11
+ ## 5.0.230
12
+
13
+ ### Patch Changes
14
+
15
+ - Updated dependencies [c524e57]
16
+ - @ai-sdk/gateway@2.0.129
17
+
3
18
  ## 5.0.229
4
19
 
5
20
  ### Patch Changes
package/dist/index.d.mts CHANGED
@@ -3094,9 +3094,10 @@ functionality that can be fully encapsulated in the provider.
3094
3094
  * @param {ReadableStream} stream - The ReadableStream to be consumed.
3095
3095
  * @returns {Promise<void>} A promise that resolves when the stream is fully consumed.
3096
3096
  */
3097
- declare function consumeStream({ stream, onError, }: {
3097
+ declare function consumeStream({ stream, onError, abortSignal, }: {
3098
3098
  stream: ReadableStream;
3099
3099
  onError?: (error: unknown) => void;
3100
+ abortSignal?: AbortSignal;
3100
3101
  }): Promise<void>;
3101
3102
 
3102
3103
  /**
@@ -3983,6 +3984,7 @@ interface ChatTransport<UI_MESSAGE extends UIMessage> {
3983
3984
  *
3984
3985
  * @param options - Configuration object containing:
3985
3986
  * @param options.chatId - Unique identifier for the chat session to reconnect to
3987
+ * @param options.abortSignal - Signal to abort the reconnection request if needed
3986
3988
  * @param options.headers - Additional HTTP headers to include in the reconnection request
3987
3989
  * @param options.body - Additional JSON properties to include in the request body
3988
3990
  * @param options.metadata - Custom metadata to attach to the request
@@ -3996,6 +3998,8 @@ interface ChatTransport<UI_MESSAGE extends UIMessage> {
3996
3998
  reconnectToStream: (options: {
3997
3999
  /** Unique identifier for the chat session to reconnect to */
3998
4000
  chatId: string;
4001
+ /** Signal to abort the reconnection request if needed */
4002
+ abortSignal?: AbortSignal;
3999
4003
  } & ChatRequestOptions) => Promise<ReadableStream<UIMessageChunk> | null>;
4000
4004
  }
4001
4005
 
@@ -4113,6 +4117,7 @@ declare abstract class AbstractChat<UI_MESSAGE extends UIMessage> {
4113
4117
  private onData?;
4114
4118
  private sendAutomaticallyWhen?;
4115
4119
  private activeResponse;
4120
+ private activeResumeRequest;
4116
4121
  private jobExecutor;
4117
4122
  constructor({ generateId, id, transport, messageMetadataSchema, dataPartSchemas, state, onError, onToolCall, onFinish, onData, sendAutomaticallyWhen, }: Omit<ChatInit<UI_MESSAGE>, 'messages'> & {
4118
4123
  state: ChatState<UI_MESSAGE>;
package/dist/index.d.ts CHANGED
@@ -3094,9 +3094,10 @@ functionality that can be fully encapsulated in the provider.
3094
3094
  * @param {ReadableStream} stream - The ReadableStream to be consumed.
3095
3095
  * @returns {Promise<void>} A promise that resolves when the stream is fully consumed.
3096
3096
  */
3097
- declare function consumeStream({ stream, onError, }: {
3097
+ declare function consumeStream({ stream, onError, abortSignal, }: {
3098
3098
  stream: ReadableStream;
3099
3099
  onError?: (error: unknown) => void;
3100
+ abortSignal?: AbortSignal;
3100
3101
  }): Promise<void>;
3101
3102
 
3102
3103
  /**
@@ -3983,6 +3984,7 @@ interface ChatTransport<UI_MESSAGE extends UIMessage> {
3983
3984
  *
3984
3985
  * @param options - Configuration object containing:
3985
3986
  * @param options.chatId - Unique identifier for the chat session to reconnect to
3987
+ * @param options.abortSignal - Signal to abort the reconnection request if needed
3986
3988
  * @param options.headers - Additional HTTP headers to include in the reconnection request
3987
3989
  * @param options.body - Additional JSON properties to include in the request body
3988
3990
  * @param options.metadata - Custom metadata to attach to the request
@@ -3996,6 +3998,8 @@ interface ChatTransport<UI_MESSAGE extends UIMessage> {
3996
3998
  reconnectToStream: (options: {
3997
3999
  /** Unique identifier for the chat session to reconnect to */
3998
4000
  chatId: string;
4001
+ /** Signal to abort the reconnection request if needed */
4002
+ abortSignal?: AbortSignal;
3999
4003
  } & ChatRequestOptions) => Promise<ReadableStream<UIMessageChunk> | null>;
4000
4004
  }
4001
4005
 
@@ -4113,6 +4117,7 @@ declare abstract class AbstractChat<UI_MESSAGE extends UIMessage> {
4113
4117
  private onData?;
4114
4118
  private sendAutomaticallyWhen?;
4115
4119
  private activeResponse;
4120
+ private activeResumeRequest;
4116
4121
  private jobExecutor;
4117
4122
  constructor({ generateId, id, transport, messageMetadataSchema, dataPartSchemas, state, onError, onToolCall, onFinish, onData, sendAutomaticallyWhen, }: Omit<ChatInit<UI_MESSAGE>, 'messages'> & {
4118
4123
  state: ChatState<UI_MESSAGE>;
package/dist/index.js CHANGED
@@ -816,7 +816,7 @@ function detectMediaType({
816
816
  var import_provider_utils2 = require("@ai-sdk/provider-utils");
817
817
 
818
818
  // src/version.ts
819
- var VERSION = true ? "5.0.229" : "0.0.0-test";
819
+ var VERSION = true ? "5.0.231" : "0.0.0-test";
820
820
 
821
821
  // src/util/download/download.ts
822
822
  var download = async ({
@@ -4290,9 +4290,20 @@ function createAsyncIterableStream(source) {
4290
4290
  // src/util/consume-stream.ts
4291
4291
  async function consumeStream({
4292
4292
  stream,
4293
- onError
4293
+ onError,
4294
+ abortSignal
4294
4295
  }) {
4295
4296
  const reader = stream.getReader();
4297
+ let cancelPromise;
4298
+ const cancelOnAbort = () => {
4299
+ cancelPromise != null ? cancelPromise : cancelPromise = reader.cancel().catch(() => {
4300
+ });
4301
+ };
4302
+ if (abortSignal == null ? void 0 : abortSignal.aborted) {
4303
+ cancelOnAbort();
4304
+ } else {
4305
+ abortSignal == null ? void 0 : abortSignal.addEventListener("abort", cancelOnAbort, { once: true });
4306
+ }
4296
4307
  try {
4297
4308
  while (true) {
4298
4309
  const { done } = await reader.read();
@@ -4302,6 +4313,8 @@ async function consumeStream({
4302
4313
  } catch (error) {
4303
4314
  onError == null ? void 0 : onError(error);
4304
4315
  } finally {
4316
+ await cancelPromise;
4317
+ abortSignal == null ? void 0 : abortSignal.removeEventListener("abort", cancelOnAbort);
4305
4318
  reader.releaseLock();
4306
4319
  }
4307
4320
  }
@@ -9331,7 +9344,8 @@ var HttpChatTransport = class {
9331
9344
  const response = await fetch2(api, {
9332
9345
  method: "GET",
9333
9346
  headers,
9334
- credentials
9347
+ credentials,
9348
+ signal: options.abortSignal
9335
9349
  });
9336
9350
  if (response.status === 204) {
9337
9351
  return null;
@@ -9386,6 +9400,7 @@ var AbstractChat = class {
9386
9400
  sendAutomaticallyWhen
9387
9401
  }) {
9388
9402
  this.activeResponse = void 0;
9403
+ this.activeResumeRequest = void 0;
9389
9404
  this.jobExecutor = new SerialJobExecutor();
9390
9405
  /**
9391
9406
  * Appends or replaces a user message to the chat list. This triggers the API call to fetch
@@ -9525,12 +9540,9 @@ var AbstractChat = class {
9525
9540
  * Abort the current request immediately, keep the generated tokens if any.
9526
9541
  */
9527
9542
  this.stop = async () => {
9528
- var _a16;
9529
- if (this.status !== "streaming" && this.status !== "submitted")
9530
- return;
9531
- if ((_a16 = this.activeResponse) == null ? void 0 : _a16.abortController) {
9532
- this.activeResponse.abortController.abort();
9533
- }
9543
+ var _a16, _b;
9544
+ (_a16 = this.activeResumeRequest) == null ? void 0 : _a16.abortController.abort();
9545
+ (_b = this.activeResponse) == null ? void 0 : _b.abortController.abort();
9534
9546
  };
9535
9547
  this.id = id;
9536
9548
  this.transport = transport;
@@ -9583,7 +9595,19 @@ var AbstractChat = class {
9583
9595
  body,
9584
9596
  messageId
9585
9597
  }) {
9586
- var _a16, _b, _c;
9598
+ var _a16, _b, _c, _d;
9599
+ const abortController = new AbortController();
9600
+ const activeResumeRequest = trigger === "resume-stream" ? { abortController } : void 0;
9601
+ if (activeResumeRequest) {
9602
+ (_a16 = this.activeResumeRequest) == null ? void 0 : _a16.abortController.abort();
9603
+ this.activeResumeRequest = activeResumeRequest;
9604
+ }
9605
+ const isCurrentRequest = () => activeResumeRequest == null || this.activeResumeRequest === activeResumeRequest;
9606
+ const clearActiveResumeRequest = () => {
9607
+ if (this.activeResumeRequest === activeResumeRequest) {
9608
+ this.activeResumeRequest = void 0;
9609
+ }
9610
+ };
9587
9611
  this.setStatus({ status: "submitted", error: void 0 });
9588
9612
  const lastMessage = this.lastMessage;
9589
9613
  let isAbort = false;
@@ -9596,7 +9620,7 @@ var AbstractChat = class {
9596
9620
  lastMessage: this.state.snapshot(lastMessage),
9597
9621
  messageId: this.generateId()
9598
9622
  }),
9599
- abortController: new AbortController()
9623
+ abortController
9600
9624
  };
9601
9625
  activeResponse = response;
9602
9626
  response.abortController.signal.addEventListener("abort", () => {
@@ -9607,12 +9631,23 @@ var AbstractChat = class {
9607
9631
  if (trigger === "resume-stream") {
9608
9632
  const reconnect = await this.transport.reconnectToStream({
9609
9633
  chatId: this.id,
9634
+ abortSignal: abortController.signal,
9610
9635
  metadata,
9611
9636
  headers,
9612
9637
  body
9613
9638
  });
9639
+ if (abortController.signal.aborted || !isCurrentRequest()) {
9640
+ await (reconnect == null ? void 0 : reconnect.cancel().catch(() => {
9641
+ }));
9642
+ if (isCurrentRequest()) {
9643
+ this.setStatus({ status: "ready" });
9644
+ }
9645
+ return;
9646
+ }
9614
9647
  if (reconnect == null) {
9615
- this.setStatus({ status: "ready" });
9648
+ if (isCurrentRequest()) {
9649
+ this.setStatus({ status: "ready" });
9650
+ }
9616
9651
  return;
9617
9652
  }
9618
9653
  stream = reconnect;
@@ -9630,11 +9665,17 @@ var AbstractChat = class {
9630
9665
  }
9631
9666
  const runUpdateMessageJob = (job) => (
9632
9667
  // serialize the job execution to avoid race conditions:
9633
- this.jobExecutor.run(
9634
- () => job({
9668
+ this.jobExecutor.run(() => {
9669
+ if (response.abortController.signal.aborted) {
9670
+ return Promise.resolve();
9671
+ }
9672
+ return job({
9635
9673
  state: response.state,
9636
9674
  write: () => {
9637
9675
  var _a17;
9676
+ if (response.abortController.signal.aborted) {
9677
+ return;
9678
+ }
9638
9679
  this.setStatus({ status: "streaming" });
9639
9680
  const replaceLastMessage = response.state.message.id === ((_a17 = this.lastMessage) == null ? void 0 : _a17.id);
9640
9681
  if (replaceLastMessage) {
@@ -9646,8 +9687,8 @@ var AbstractChat = class {
9646
9687
  this.state.pushMessage(response.state.message);
9647
9688
  }
9648
9689
  }
9649
- })
9650
- )
9690
+ });
9691
+ })
9651
9692
  );
9652
9693
  await consumeStream({
9653
9694
  stream: processUIMessageStream({
@@ -9661,15 +9702,29 @@ var AbstractChat = class {
9661
9702
  throw error;
9662
9703
  }
9663
9704
  }),
9705
+ abortSignal: response.abortController.signal,
9664
9706
  onError: (error) => {
9665
9707
  throw error;
9666
9708
  }
9667
9709
  });
9668
- this.setStatus({ status: "ready" });
9710
+ if (isAbort) {
9711
+ if (isCurrentRequest()) {
9712
+ this.setStatus({ status: "ready" });
9713
+ }
9714
+ return null;
9715
+ }
9716
+ if (isCurrentRequest()) {
9717
+ this.setStatus({ status: "ready" });
9718
+ }
9669
9719
  } catch (err) {
9670
9720
  if (isAbort || err.name === "AbortError") {
9671
9721
  isAbort = true;
9672
- this.setStatus({ status: "ready" });
9722
+ if (isCurrentRequest()) {
9723
+ this.setStatus({ status: "ready" });
9724
+ }
9725
+ return null;
9726
+ }
9727
+ if (!isCurrentRequest()) {
9673
9728
  return null;
9674
9729
  }
9675
9730
  isError = true;
@@ -9683,7 +9738,7 @@ var AbstractChat = class {
9683
9738
  } finally {
9684
9739
  try {
9685
9740
  if (activeResponse) {
9686
- (_a16 = this.onFinish) == null ? void 0 : _a16.call(this, {
9741
+ (_b = this.onFinish) == null ? void 0 : _b.call(this, {
9687
9742
  message: activeResponse.state.message,
9688
9743
  messages: this.state.messages,
9689
9744
  isAbort,
@@ -9698,11 +9753,12 @@ var AbstractChat = class {
9698
9753
  if (this.activeResponse === activeResponse) {
9699
9754
  this.activeResponse = void 0;
9700
9755
  }
9756
+ clearActiveResumeRequest();
9701
9757
  }
9702
- if (((_b = this.sendAutomaticallyWhen) == null ? void 0 : _b.call(this, { messages: this.state.messages })) && !isError) {
9758
+ if (((_c = this.sendAutomaticallyWhen) == null ? void 0 : _c.call(this, { messages: this.state.messages })) && !isError) {
9703
9759
  await this.makeRequest({
9704
9760
  trigger: "submit-message",
9705
- messageId: (_c = this.lastMessage) == null ? void 0 : _c.id,
9761
+ messageId: (_d = this.lastMessage) == null ? void 0 : _d.id,
9706
9762
  metadata,
9707
9763
  headers,
9708
9764
  body