ai 5.0.266 → 5.0.268

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,23 @@
1
1
  # ai
2
2
 
3
+ ## 5.0.268
4
+
5
+ ### Patch Changes
6
+
7
+ - dfffb7e: fix(ai): cancel response streams when clients disconnect
8
+ - 1d0096a: fix(ai): continue active UI message parts when resuming after a disconnect
9
+ - Updated dependencies [6dc04c5]
10
+ - Updated dependencies [14810cb]
11
+ - @ai-sdk/gateway@2.0.160
12
+ - @ai-sdk/provider-utils@3.0.40
13
+
14
+ ## 5.0.267
15
+
16
+ ### Patch Changes
17
+
18
+ - Updated dependencies [3569298]
19
+ - @ai-sdk/gateway@2.0.159
20
+
3
21
  ## 5.0.266
4
22
 
5
23
  ### Patch Changes
package/dist/index.d.mts CHANGED
@@ -4158,6 +4158,7 @@ declare abstract class AbstractChat<UI_MESSAGE extends UIMessage> {
4158
4158
  private sendAutomaticallyWhen?;
4159
4159
  private activeResponse;
4160
4160
  private activeResumeRequest;
4161
+ private resumableStreamState;
4161
4162
  private jobExecutor;
4162
4163
  constructor({ generateId, id, transport, messageMetadataSchema, dataPartSchemas, state, onError, onToolCall, onFinish, onData, sendAutomaticallyWhen, }: Omit<ChatInit<UI_MESSAGE>, 'messages'> & {
4163
4164
  state: ChatState<UI_MESSAGE>;
package/dist/index.d.ts CHANGED
@@ -4158,6 +4158,7 @@ declare abstract class AbstractChat<UI_MESSAGE extends UIMessage> {
4158
4158
  private sendAutomaticallyWhen?;
4159
4159
  private activeResponse;
4160
4160
  private activeResumeRequest;
4161
+ private resumableStreamState;
4161
4162
  private jobExecutor;
4162
4163
  constructor({ generateId, id, transport, messageMetadataSchema, dataPartSchemas, state, onError, onToolCall, onFinish, onData, sendAutomaticallyWhen, }: Omit<ChatInit<UI_MESSAGE>, 'messages'> & {
4163
4164
  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.266" : "0.0.0-test";
819
+ var VERSION = true ? "5.0.268" : "0.0.0-test";
820
820
 
821
821
  // src/util/download/download.ts
822
822
  var download = async ({
@@ -3006,21 +3006,44 @@ function writeToServerResponse({
3006
3006
  response.writeHead(statusCode, headers);
3007
3007
  }
3008
3008
  const reader = stream.getReader();
3009
+ let clientDisconnected = false;
3010
+ let onDisconnect;
3011
+ const handleClose = () => {
3012
+ if (response.writableFinished) {
3013
+ return;
3014
+ }
3015
+ clientDisconnected = true;
3016
+ onDisconnect == null ? void 0 : onDisconnect();
3017
+ reader.cancel(new Error("Client disconnected.")).catch(() => {
3018
+ });
3019
+ };
3020
+ response.once("close", handleClose);
3021
+ if (response.destroyed) {
3022
+ handleClose();
3023
+ }
3009
3024
  const read = async () => {
3010
3025
  try {
3011
3026
  while (true) {
3012
3027
  const { done, value } = await reader.read();
3013
- if (done)
3028
+ if (done || clientDisconnected || response.destroyed)
3014
3029
  break;
3015
3030
  const canContinue = response.write(value);
3016
3031
  if (!canContinue) {
3017
3032
  await new Promise((resolve2) => {
3033
+ onDisconnect = resolve2;
3018
3034
  response.once("drain", resolve2);
3019
3035
  });
3036
+ onDisconnect = void 0;
3020
3037
  }
3021
3038
  }
3022
3039
  } finally {
3023
- response.end();
3040
+ response.off("close", handleClose);
3041
+ if (clientDisconnected || response.destroyed) {
3042
+ reader.cancel().catch(() => {
3043
+ });
3044
+ } else {
3045
+ response.end();
3046
+ }
3024
3047
  }
3025
3048
  };
3026
3049
  return read();
@@ -9761,6 +9784,7 @@ var AbstractChat = class {
9761
9784
  }) {
9762
9785
  this.activeResponse = void 0;
9763
9786
  this.activeResumeRequest = void 0;
9787
+ this.resumableStreamState = void 0;
9764
9788
  this.jobExecutor = new SerialJobExecutor();
9765
9789
  /**
9766
9790
  * Appends or replaces a user message to the chat list. This triggers the API call to fetch
@@ -9956,6 +9980,9 @@ var AbstractChat = class {
9956
9980
  messageId
9957
9981
  }) {
9958
9982
  var _a16, _b, _c, _d;
9983
+ if (trigger !== "resume-stream") {
9984
+ this.resumableStreamState = void 0;
9985
+ }
9959
9986
  const abortController = new AbortController();
9960
9987
  const activeResumeRequest = trigger === "resume-stream" ? { abortController } : void 0;
9961
9988
  if (activeResumeRequest) {
@@ -9976,7 +10003,7 @@ var AbstractChat = class {
9976
10003
  let activeResponse;
9977
10004
  try {
9978
10005
  const response = {
9979
- state: createStreamingUIMessageState({
10006
+ state: trigger === "resume-stream" && this.resumableStreamState != null ? this.resumableStreamState : createStreamingUIMessageState({
9980
10007
  lastMessage: trigger === "resume-stream" ? void 0 : this.state.snapshot(lastMessage),
9981
10008
  messageId: this.generateId()
9982
10009
  }),
@@ -10001,12 +10028,14 @@ var AbstractChat = class {
10001
10028
  }));
10002
10029
  if (isCurrentRequest()) {
10003
10030
  this.setStatus({ status: "ready" });
10031
+ this.resumableStreamState = void 0;
10004
10032
  }
10005
10033
  return;
10006
10034
  }
10007
10035
  if (reconnect == null) {
10008
10036
  if (isCurrentRequest()) {
10009
10037
  this.setStatus({ status: "ready" });
10038
+ this.resumableStreamState = void 0;
10010
10039
  }
10011
10040
  return;
10012
10041
  }
@@ -10072,17 +10101,26 @@ var AbstractChat = class {
10072
10101
  if (isAbort) {
10073
10102
  if (isCurrentRequest()) {
10074
10103
  this.setStatus({ status: "ready" });
10104
+ if (this.resumableStreamState === response.state) {
10105
+ this.resumableStreamState = void 0;
10106
+ }
10075
10107
  }
10076
10108
  return null;
10077
10109
  }
10078
10110
  if (isCurrentRequest()) {
10079
10111
  this.setStatus({ status: "ready" });
10112
+ if (this.resumableStreamState === response.state) {
10113
+ this.resumableStreamState = void 0;
10114
+ }
10080
10115
  }
10081
10116
  } catch (err) {
10082
10117
  if (isAbort || err.name === "AbortError") {
10083
10118
  isAbort = true;
10084
10119
  if (isCurrentRequest()) {
10085
10120
  this.setStatus({ status: "ready" });
10121
+ if (this.resumableStreamState === (activeResponse == null ? void 0 : activeResponse.state)) {
10122
+ this.resumableStreamState = void 0;
10123
+ }
10086
10124
  }
10087
10125
  return null;
10088
10126
  }
@@ -10093,6 +10131,11 @@ var AbstractChat = class {
10093
10131
  if (err instanceof TypeError && (err.message.toLowerCase().includes("fetch") || err.message.toLowerCase().includes("network"))) {
10094
10132
  isDisconnect = true;
10095
10133
  }
10134
+ if (isDisconnect) {
10135
+ this.resumableStreamState = activeResponse == null ? void 0 : activeResponse.state;
10136
+ } else if (this.resumableStreamState === (activeResponse == null ? void 0 : activeResponse.state)) {
10137
+ this.resumableStreamState = void 0;
10138
+ }
10096
10139
  if (this.onError && err instanceof Error) {
10097
10140
  this.onError(err);
10098
10141
  }