ai 5.0.267 → 5.0.269

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
+ ## 5.0.269
4
+
5
+ ### Patch Changes
6
+
7
+ - 11f5cda: Preserve provider metadata on corresponding `smoothStream` chunks without carrying it into subsequent metadata-free deltas.
8
+
9
+ ## 5.0.268
10
+
11
+ ### Patch Changes
12
+
13
+ - dfffb7e: fix(ai): cancel response streams when clients disconnect
14
+ - 1d0096a: fix(ai): continue active UI message parts when resuming after a disconnect
15
+ - Updated dependencies [6dc04c5]
16
+ - Updated dependencies [14810cb]
17
+ - @ai-sdk/gateway@2.0.160
18
+ - @ai-sdk/provider-utils@3.0.40
19
+
3
20
  ## 5.0.267
4
21
 
5
22
  ### 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.267" : "0.0.0-test";
819
+ var VERSION = true ? "5.0.269" : "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();
@@ -8787,28 +8810,51 @@ function smoothStream({
8787
8810
  return () => {
8788
8811
  let buffer = "";
8789
8812
  let id = "";
8813
+ let providerMetadata;
8814
+ function flushBuffer(controller) {
8815
+ if (buffer.length > 0 || providerMetadata != null) {
8816
+ controller.enqueue({
8817
+ type: "text-delta",
8818
+ text: buffer,
8819
+ id,
8820
+ ...providerMetadata != null ? { providerMetadata } : {}
8821
+ });
8822
+ buffer = "";
8823
+ providerMetadata = void 0;
8824
+ }
8825
+ }
8790
8826
  return new TransformStream({
8791
8827
  async transform(chunk, controller) {
8792
8828
  if (chunk.type !== "text-delta") {
8793
- if (buffer.length > 0) {
8794
- controller.enqueue({ type: "text-delta", text: buffer, id });
8795
- buffer = "";
8796
- }
8829
+ flushBuffer(controller);
8797
8830
  controller.enqueue(chunk);
8798
8831
  return;
8799
8832
  }
8800
- if (chunk.id !== id && buffer.length > 0) {
8801
- controller.enqueue({ type: "text-delta", text: buffer, id });
8802
- buffer = "";
8833
+ if (chunk.text.length === 0 && chunk.providerMetadata != null) {
8834
+ flushBuffer(controller);
8835
+ controller.enqueue(chunk);
8836
+ return;
8837
+ }
8838
+ if (buffer.length > 0 && (chunk.id !== id || providerMetadata != null || chunk.providerMetadata != null)) {
8839
+ flushBuffer(controller);
8803
8840
  }
8804
8841
  buffer += chunk.text;
8805
8842
  id = chunk.id;
8843
+ providerMetadata = chunk.providerMetadata;
8806
8844
  let match;
8807
8845
  while ((match = detectChunk(buffer)) != null) {
8808
- controller.enqueue({ type: "text-delta", text: match, id });
8846
+ controller.enqueue({
8847
+ type: "text-delta",
8848
+ text: match,
8849
+ id,
8850
+ ...providerMetadata != null ? { providerMetadata } : {}
8851
+ });
8809
8852
  buffer = buffer.slice(match.length);
8810
8853
  await delay2(isDocumentHidden() ? null : delayInMs);
8811
8854
  }
8855
+ if (buffer.length === 0) {
8856
+ providerMetadata = void 0;
8857
+ }
8812
8858
  }
8813
8859
  });
8814
8860
  };
@@ -9761,6 +9807,7 @@ var AbstractChat = class {
9761
9807
  }) {
9762
9808
  this.activeResponse = void 0;
9763
9809
  this.activeResumeRequest = void 0;
9810
+ this.resumableStreamState = void 0;
9764
9811
  this.jobExecutor = new SerialJobExecutor();
9765
9812
  /**
9766
9813
  * Appends or replaces a user message to the chat list. This triggers the API call to fetch
@@ -9956,6 +10003,9 @@ var AbstractChat = class {
9956
10003
  messageId
9957
10004
  }) {
9958
10005
  var _a16, _b, _c, _d;
10006
+ if (trigger !== "resume-stream") {
10007
+ this.resumableStreamState = void 0;
10008
+ }
9959
10009
  const abortController = new AbortController();
9960
10010
  const activeResumeRequest = trigger === "resume-stream" ? { abortController } : void 0;
9961
10011
  if (activeResumeRequest) {
@@ -9976,7 +10026,7 @@ var AbstractChat = class {
9976
10026
  let activeResponse;
9977
10027
  try {
9978
10028
  const response = {
9979
- state: createStreamingUIMessageState({
10029
+ state: trigger === "resume-stream" && this.resumableStreamState != null ? this.resumableStreamState : createStreamingUIMessageState({
9980
10030
  lastMessage: trigger === "resume-stream" ? void 0 : this.state.snapshot(lastMessage),
9981
10031
  messageId: this.generateId()
9982
10032
  }),
@@ -10001,12 +10051,14 @@ var AbstractChat = class {
10001
10051
  }));
10002
10052
  if (isCurrentRequest()) {
10003
10053
  this.setStatus({ status: "ready" });
10054
+ this.resumableStreamState = void 0;
10004
10055
  }
10005
10056
  return;
10006
10057
  }
10007
10058
  if (reconnect == null) {
10008
10059
  if (isCurrentRequest()) {
10009
10060
  this.setStatus({ status: "ready" });
10061
+ this.resumableStreamState = void 0;
10010
10062
  }
10011
10063
  return;
10012
10064
  }
@@ -10072,17 +10124,26 @@ var AbstractChat = class {
10072
10124
  if (isAbort) {
10073
10125
  if (isCurrentRequest()) {
10074
10126
  this.setStatus({ status: "ready" });
10127
+ if (this.resumableStreamState === response.state) {
10128
+ this.resumableStreamState = void 0;
10129
+ }
10075
10130
  }
10076
10131
  return null;
10077
10132
  }
10078
10133
  if (isCurrentRequest()) {
10079
10134
  this.setStatus({ status: "ready" });
10135
+ if (this.resumableStreamState === response.state) {
10136
+ this.resumableStreamState = void 0;
10137
+ }
10080
10138
  }
10081
10139
  } catch (err) {
10082
10140
  if (isAbort || err.name === "AbortError") {
10083
10141
  isAbort = true;
10084
10142
  if (isCurrentRequest()) {
10085
10143
  this.setStatus({ status: "ready" });
10144
+ if (this.resumableStreamState === (activeResponse == null ? void 0 : activeResponse.state)) {
10145
+ this.resumableStreamState = void 0;
10146
+ }
10086
10147
  }
10087
10148
  return null;
10088
10149
  }
@@ -10093,6 +10154,11 @@ var AbstractChat = class {
10093
10154
  if (err instanceof TypeError && (err.message.toLowerCase().includes("fetch") || err.message.toLowerCase().includes("network"))) {
10094
10155
  isDisconnect = true;
10095
10156
  }
10157
+ if (isDisconnect) {
10158
+ this.resumableStreamState = activeResponse == null ? void 0 : activeResponse.state;
10159
+ } else if (this.resumableStreamState === (activeResponse == null ? void 0 : activeResponse.state)) {
10160
+ this.resumableStreamState = void 0;
10161
+ }
10096
10162
  if (this.onError && err instanceof Error) {
10097
10163
  this.onError(err);
10098
10164
  }