ai 6.0.248 → 6.0.249

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,15 @@
1
1
  # ai
2
2
 
3
+ ## 6.0.249
4
+
5
+ ### Patch Changes
6
+
7
+ - a774b7b: Stop pending and active resumed chat streams after cancellation, and prevent
8
+ overlapping resumptions from applying stale updates.
9
+ - Updated dependencies [b39f987]
10
+ - Updated dependencies [d79117b]
11
+ - @ai-sdk/gateway@3.0.169
12
+
3
13
  ## 6.0.248
4
14
 
5
15
  ### Patch Changes
package/dist/index.d.mts CHANGED
@@ -3620,6 +3620,7 @@ interface ChatTransport<UI_MESSAGE extends UIMessage> {
3620
3620
  *
3621
3621
  * @param options - Configuration object containing:
3622
3622
  * @param options.chatId - Unique identifier for the chat session to reconnect to
3623
+ * @param options.abortSignal - Signal to abort the reconnection request if needed
3623
3624
  * @param options.headers - Additional HTTP headers to include in the reconnection request
3624
3625
  * @param options.body - Additional JSON properties to include in the request body
3625
3626
  * @param options.metadata - Custom metadata to attach to the request
@@ -3633,6 +3634,8 @@ interface ChatTransport<UI_MESSAGE extends UIMessage> {
3633
3634
  reconnectToStream: (options: {
3634
3635
  /** Unique identifier for the chat session to reconnect to */
3635
3636
  chatId: string;
3637
+ /** Signal to abort the reconnection request if needed */
3638
+ abortSignal?: AbortSignal;
3636
3639
  } & ChatRequestOptions) => Promise<ReadableStream<UIMessageChunk> | null>;
3637
3640
  }
3638
3641
 
@@ -3793,6 +3796,7 @@ declare abstract class AbstractChat<UI_MESSAGE extends UIMessage> {
3793
3796
  private onData?;
3794
3797
  private sendAutomaticallyWhen?;
3795
3798
  private activeResponse;
3799
+ private activeResumeRequest;
3796
3800
  private jobExecutor;
3797
3801
  constructor({ generateId, id, transport, messageMetadataSchema, dataPartSchemas, state, onError, onToolCall, onFinish, onData, sendAutomaticallyWhen, }: Omit<ChatInit<UI_MESSAGE>, 'messages'> & {
3798
3802
  state: ChatState<UI_MESSAGE>;
@@ -5264,9 +5268,10 @@ declare function generateObject<SCHEMA extends FlexibleSchema<unknown> = Flexibl
5264
5268
  * @param options.onError - Optional callback to handle errors that occur during consumption.
5265
5269
  * @returns A promise that resolves when the stream is fully consumed.
5266
5270
  */
5267
- declare function consumeStream({ stream, onError, }: {
5271
+ declare function consumeStream({ stream, onError, abortSignal, }: {
5268
5272
  stream: ReadableStream;
5269
5273
  onError?: (error: unknown) => void;
5274
+ abortSignal?: AbortSignal;
5270
5275
  }): Promise<void>;
5271
5276
 
5272
5277
  /**
package/dist/index.d.ts CHANGED
@@ -3620,6 +3620,7 @@ interface ChatTransport<UI_MESSAGE extends UIMessage> {
3620
3620
  *
3621
3621
  * @param options - Configuration object containing:
3622
3622
  * @param options.chatId - Unique identifier for the chat session to reconnect to
3623
+ * @param options.abortSignal - Signal to abort the reconnection request if needed
3623
3624
  * @param options.headers - Additional HTTP headers to include in the reconnection request
3624
3625
  * @param options.body - Additional JSON properties to include in the request body
3625
3626
  * @param options.metadata - Custom metadata to attach to the request
@@ -3633,6 +3634,8 @@ interface ChatTransport<UI_MESSAGE extends UIMessage> {
3633
3634
  reconnectToStream: (options: {
3634
3635
  /** Unique identifier for the chat session to reconnect to */
3635
3636
  chatId: string;
3637
+ /** Signal to abort the reconnection request if needed */
3638
+ abortSignal?: AbortSignal;
3636
3639
  } & ChatRequestOptions) => Promise<ReadableStream<UIMessageChunk> | null>;
3637
3640
  }
3638
3641
 
@@ -3793,6 +3796,7 @@ declare abstract class AbstractChat<UI_MESSAGE extends UIMessage> {
3793
3796
  private onData?;
3794
3797
  private sendAutomaticallyWhen?;
3795
3798
  private activeResponse;
3799
+ private activeResumeRequest;
3796
3800
  private jobExecutor;
3797
3801
  constructor({ generateId, id, transport, messageMetadataSchema, dataPartSchemas, state, onError, onToolCall, onFinish, onData, sendAutomaticallyWhen, }: Omit<ChatInit<UI_MESSAGE>, 'messages'> & {
3798
3802
  state: ChatState<UI_MESSAGE>;
@@ -5264,9 +5268,10 @@ declare function generateObject<SCHEMA extends FlexibleSchema<unknown> = Flexibl
5264
5268
  * @param options.onError - Optional callback to handle errors that occur during consumption.
5265
5269
  * @returns A promise that resolves when the stream is fully consumed.
5266
5270
  */
5267
- declare function consumeStream({ stream, onError, }: {
5271
+ declare function consumeStream({ stream, onError, abortSignal, }: {
5268
5272
  stream: ReadableStream;
5269
5273
  onError?: (error: unknown) => void;
5274
+ abortSignal?: AbortSignal;
5270
5275
  }): Promise<void>;
5271
5276
 
5272
5277
  /**
package/dist/index.js CHANGED
@@ -1304,7 +1304,7 @@ function detectMediaType({
1304
1304
  var import_provider_utils3 = require("@ai-sdk/provider-utils");
1305
1305
 
1306
1306
  // src/version.ts
1307
- var VERSION = true ? "6.0.248" : "0.0.0-test";
1307
+ var VERSION = true ? "6.0.249" : "0.0.0-test";
1308
1308
 
1309
1309
  // src/util/download/download.ts
1310
1310
  var download = async ({
@@ -6591,9 +6591,19 @@ function createAsyncIterableStream(source) {
6591
6591
  // src/util/consume-stream.ts
6592
6592
  async function consumeStream({
6593
6593
  stream,
6594
- onError
6594
+ onError,
6595
+ abortSignal
6595
6596
  }) {
6596
6597
  const reader = stream.getReader();
6598
+ const cancelOnAbort = () => {
6599
+ reader.cancel().catch(() => {
6600
+ });
6601
+ };
6602
+ if (abortSignal == null ? void 0 : abortSignal.aborted) {
6603
+ cancelOnAbort();
6604
+ } else {
6605
+ abortSignal == null ? void 0 : abortSignal.addEventListener("abort", cancelOnAbort, { once: true });
6606
+ }
6597
6607
  try {
6598
6608
  while (true) {
6599
6609
  const { done } = await reader.read();
@@ -6603,6 +6613,7 @@ async function consumeStream({
6603
6613
  } catch (error) {
6604
6614
  onError == null ? void 0 : onError(error);
6605
6615
  } finally {
6616
+ abortSignal == null ? void 0 : abortSignal.removeEventListener("abort", cancelOnAbort);
6606
6617
  reader.releaseLock();
6607
6618
  }
6608
6619
  }
@@ -13672,7 +13683,8 @@ var HttpChatTransport = class {
13672
13683
  const response = await fetch2(api, {
13673
13684
  method: "GET",
13674
13685
  headers,
13675
- credentials
13686
+ credentials,
13687
+ signal: options.abortSignal
13676
13688
  });
13677
13689
  if (response.status === 204) {
13678
13690
  return null;
@@ -13727,6 +13739,7 @@ var AbstractChat = class {
13727
13739
  sendAutomaticallyWhen
13728
13740
  }) {
13729
13741
  this.activeResponse = void 0;
13742
+ this.activeResumeRequest = void 0;
13730
13743
  this.jobExecutor = new SerialJobExecutor();
13731
13744
  /**
13732
13745
  * Appends or replaces a user message to the chat list. This triggers the API call to fetch
@@ -13896,12 +13909,9 @@ var AbstractChat = class {
13896
13909
  * Abort the current request immediately, keep the generated tokens if any.
13897
13910
  */
13898
13911
  this.stop = async () => {
13899
- var _a22;
13900
- if (this.status !== "streaming" && this.status !== "submitted")
13901
- return;
13902
- if ((_a22 = this.activeResponse) == null ? void 0 : _a22.abortController) {
13903
- this.activeResponse.abortController.abort();
13904
- }
13912
+ var _a22, _b;
13913
+ (_a22 = this.activeResumeRequest) == null ? void 0 : _a22.abortController.abort();
13914
+ (_b = this.activeResponse) == null ? void 0 : _b.abortController.abort();
13905
13915
  };
13906
13916
  this.id = id;
13907
13917
  this.transport = transport;
@@ -13965,25 +13975,60 @@ var AbstractChat = class {
13965
13975
  body,
13966
13976
  messageId
13967
13977
  }) {
13968
- var _a22, _b;
13978
+ var _a22, _b, _c;
13979
+ const abortController = new AbortController();
13980
+ const activeResumeRequest = trigger === "resume-stream" ? { abortController } : void 0;
13981
+ if (activeResumeRequest) {
13982
+ (_a22 = this.activeResumeRequest) == null ? void 0 : _a22.abortController.abort();
13983
+ this.activeResumeRequest = activeResumeRequest;
13984
+ }
13985
+ const isCurrentRequest = () => activeResumeRequest == null || this.activeResumeRequest === activeResumeRequest;
13986
+ const clearActiveResumeRequest = () => {
13987
+ if (this.activeResumeRequest === activeResumeRequest) {
13988
+ this.activeResumeRequest = void 0;
13989
+ }
13990
+ };
13969
13991
  let resumeStream;
13970
13992
  if (trigger === "resume-stream") {
13971
13993
  try {
13972
13994
  const reconnect = await this.transport.reconnectToStream({
13973
13995
  chatId: this.id,
13996
+ abortSignal: abortController.signal,
13974
13997
  metadata,
13975
13998
  headers,
13976
13999
  body
13977
14000
  });
14001
+ if (abortController.signal.aborted || !isCurrentRequest()) {
14002
+ await (reconnect == null ? void 0 : reconnect.cancel().catch(() => {
14003
+ }));
14004
+ if (isCurrentRequest()) {
14005
+ this.setStatus({ status: "ready" });
14006
+ }
14007
+ clearActiveResumeRequest();
14008
+ return;
14009
+ }
13978
14010
  if (reconnect == null) {
14011
+ this.setStatus({ status: "ready" });
14012
+ clearActiveResumeRequest();
13979
14013
  return;
13980
14014
  }
13981
14015
  resumeStream = reconnect;
13982
14016
  } catch (err) {
14017
+ if (abortController.signal.aborted || err.name === "AbortError") {
14018
+ if (isCurrentRequest()) {
14019
+ this.setStatus({ status: "ready" });
14020
+ }
14021
+ clearActiveResumeRequest();
14022
+ return;
14023
+ }
14024
+ if (!isCurrentRequest()) {
14025
+ return;
14026
+ }
13983
14027
  if (this.onError && err instanceof Error) {
13984
14028
  this.onError(err);
13985
14029
  }
13986
14030
  this.setStatus({ status: "error", error: err });
14031
+ clearActiveResumeRequest();
13987
14032
  return;
13988
14033
  }
13989
14034
  }
@@ -13999,7 +14044,7 @@ var AbstractChat = class {
13999
14044
  lastMessage: trigger === "regenerate-message" ? void 0 : this.state.snapshot(lastMessage),
14000
14045
  messageId: this.generateId()
14001
14046
  }),
14002
- abortController: new AbortController()
14047
+ abortController
14003
14048
  };
14004
14049
  activeResponse = response;
14005
14050
  response.abortController.signal.addEventListener("abort", () => {
@@ -14023,11 +14068,17 @@ var AbstractChat = class {
14023
14068
  }
14024
14069
  const runUpdateMessageJob = (job) => (
14025
14070
  // serialize the job execution to avoid race conditions:
14026
- this.jobExecutor.run(
14027
- () => job({
14071
+ this.jobExecutor.run(() => {
14072
+ if (response.abortController.signal.aborted) {
14073
+ return Promise.resolve();
14074
+ }
14075
+ return job({
14028
14076
  state: response.state,
14029
14077
  write: () => {
14030
14078
  var _a23;
14079
+ if (response.abortController.signal.aborted) {
14080
+ return;
14081
+ }
14031
14082
  this.setStatus({ status: "streaming" });
14032
14083
  const replaceLastMessage = response.state.message.id === ((_a23 = this.lastMessage) == null ? void 0 : _a23.id);
14033
14084
  if (replaceLastMessage) {
@@ -14039,8 +14090,8 @@ var AbstractChat = class {
14039
14090
  this.state.pushMessage(response.state.message);
14040
14091
  }
14041
14092
  }
14042
- })
14043
- )
14093
+ });
14094
+ })
14044
14095
  );
14045
14096
  await consumeStream({
14046
14097
  stream: processUIMessageStream({
@@ -14054,15 +14105,29 @@ var AbstractChat = class {
14054
14105
  throw error;
14055
14106
  }
14056
14107
  }),
14108
+ abortSignal: response.abortController.signal,
14057
14109
  onError: (error) => {
14058
14110
  throw error;
14059
14111
  }
14060
14112
  });
14061
- this.setStatus({ status: "ready" });
14113
+ if (isAbort) {
14114
+ if (isCurrentRequest()) {
14115
+ this.setStatus({ status: "ready" });
14116
+ }
14117
+ return null;
14118
+ }
14119
+ if (isCurrentRequest()) {
14120
+ this.setStatus({ status: "ready" });
14121
+ }
14062
14122
  } catch (err) {
14063
14123
  if (isAbort || err.name === "AbortError") {
14064
14124
  isAbort = true;
14065
- this.setStatus({ status: "ready" });
14125
+ if (isCurrentRequest()) {
14126
+ this.setStatus({ status: "ready" });
14127
+ }
14128
+ return null;
14129
+ }
14130
+ if (!isCurrentRequest()) {
14066
14131
  return null;
14067
14132
  }
14068
14133
  isError = true;
@@ -14076,7 +14141,7 @@ var AbstractChat = class {
14076
14141
  } finally {
14077
14142
  try {
14078
14143
  if (activeResponse) {
14079
- (_a22 = this.onFinish) == null ? void 0 : _a22.call(this, {
14144
+ (_b = this.onFinish) == null ? void 0 : _b.call(this, {
14080
14145
  message: activeResponse.state.message,
14081
14146
  messages: this.state.messages,
14082
14147
  isAbort,
@@ -14091,11 +14156,12 @@ var AbstractChat = class {
14091
14156
  if (this.activeResponse === activeResponse) {
14092
14157
  this.activeResponse = void 0;
14093
14158
  }
14159
+ clearActiveResumeRequest();
14094
14160
  }
14095
14161
  if (!isError && await this.shouldSendAutomatically()) {
14096
14162
  await this.makeRequest({
14097
14163
  trigger: "submit-message",
14098
- messageId: (_b = this.lastMessage) == null ? void 0 : _b.id,
14164
+ messageId: (_c = this.lastMessage) == null ? void 0 : _c.id,
14099
14165
  metadata,
14100
14166
  headers,
14101
14167
  body