ai 5.0.230 → 5.0.232

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.232
4
+
5
+ ### Patch Changes
6
+
7
+ - 66dd974: Prevent streaming telemetry spans from ending twice or remaining unfinished when model calls fail.
8
+ - Updated dependencies [0e51b7b]
9
+ - @ai-sdk/provider-utils@3.0.32
10
+ - @ai-sdk/gateway@2.0.131
11
+
12
+ ## 5.0.231
13
+
14
+ ### Patch Changes
15
+
16
+ - 2709314: Stop pending and active resumed chat streams after cancellation, and prevent overlapping resumptions from applying stale updates.
17
+ - Updated dependencies [b474448]
18
+ - @ai-sdk/gateway@2.0.130
19
+
3
20
  ## 5.0.230
4
21
 
5
22
  ### 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.230" : "0.0.0-test";
819
+ var VERSION = true ? "5.0.232" : "0.0.0-test";
820
820
 
821
821
  // src/util/download/download.ts
822
822
  var download = async ({
@@ -1715,7 +1715,8 @@ function recordSpan({
1715
1715
  tracer,
1716
1716
  attributes,
1717
1717
  fn,
1718
- endWhenDone = true
1718
+ endWhenDone = true,
1719
+ endOnError = endWhenDone
1719
1720
  }) {
1720
1721
  return tracer.startActiveSpan(name16, { attributes }, async (span) => {
1721
1722
  try {
@@ -1728,7 +1729,9 @@ function recordSpan({
1728
1729
  try {
1729
1730
  recordErrorOnSpan(span, error);
1730
1731
  } finally {
1731
- span.end();
1732
+ if (endOnError) {
1733
+ span.end();
1734
+ }
1732
1735
  }
1733
1736
  throw error;
1734
1737
  }
@@ -4290,9 +4293,20 @@ function createAsyncIterableStream(source) {
4290
4293
  // src/util/consume-stream.ts
4291
4294
  async function consumeStream({
4292
4295
  stream,
4293
- onError
4296
+ onError,
4297
+ abortSignal
4294
4298
  }) {
4295
4299
  const reader = stream.getReader();
4300
+ let cancelPromise;
4301
+ const cancelOnAbort = () => {
4302
+ cancelPromise != null ? cancelPromise : cancelPromise = reader.cancel().catch(() => {
4303
+ });
4304
+ };
4305
+ if (abortSignal == null ? void 0 : abortSignal.aborted) {
4306
+ cancelOnAbort();
4307
+ } else {
4308
+ abortSignal == null ? void 0 : abortSignal.addEventListener("abort", cancelOnAbort, { once: true });
4309
+ }
4296
4310
  try {
4297
4311
  while (true) {
4298
4312
  const { done } = await reader.read();
@@ -4302,6 +4316,8 @@ async function consumeStream({
4302
4316
  } catch (error) {
4303
4317
  onError == null ? void 0 : onError(error);
4304
4318
  } finally {
4319
+ await cancelPromise;
4320
+ abortSignal == null ? void 0 : abortSignal.removeEventListener("abort", cancelOnAbort);
4305
4321
  reader.releaseLock();
4306
4322
  }
4307
4323
  }
@@ -5251,6 +5267,7 @@ var DefaultStreamTextResult = class {
5251
5267
  }),
5252
5268
  tracer,
5253
5269
  endWhenDone: false,
5270
+ endOnError: true,
5254
5271
  fn: async (doStreamSpan2) => {
5255
5272
  return {
5256
5273
  startTimestampMs: now2(),
@@ -7746,6 +7763,7 @@ var DefaultStreamObjectResult = class {
7746
7763
  }),
7747
7764
  tracer,
7748
7765
  endWhenDone: false,
7766
+ endOnError: true,
7749
7767
  fn: async (rootSpan) => {
7750
7768
  const standardizedPrompt = await standardizePrompt({
7751
7769
  system,
@@ -7817,6 +7835,7 @@ var DefaultStreamObjectResult = class {
7817
7835
  }),
7818
7836
  tracer,
7819
7837
  endWhenDone: false,
7838
+ endOnError: true,
7820
7839
  fn: async (doStreamSpan2) => ({
7821
7840
  startTimestampMs: now2(),
7822
7841
  doStreamSpan: doStreamSpan2,
@@ -9331,7 +9350,8 @@ var HttpChatTransport = class {
9331
9350
  const response = await fetch2(api, {
9332
9351
  method: "GET",
9333
9352
  headers,
9334
- credentials
9353
+ credentials,
9354
+ signal: options.abortSignal
9335
9355
  });
9336
9356
  if (response.status === 204) {
9337
9357
  return null;
@@ -9386,6 +9406,7 @@ var AbstractChat = class {
9386
9406
  sendAutomaticallyWhen
9387
9407
  }) {
9388
9408
  this.activeResponse = void 0;
9409
+ this.activeResumeRequest = void 0;
9389
9410
  this.jobExecutor = new SerialJobExecutor();
9390
9411
  /**
9391
9412
  * Appends or replaces a user message to the chat list. This triggers the API call to fetch
@@ -9525,12 +9546,9 @@ var AbstractChat = class {
9525
9546
  * Abort the current request immediately, keep the generated tokens if any.
9526
9547
  */
9527
9548
  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
- }
9549
+ var _a16, _b;
9550
+ (_a16 = this.activeResumeRequest) == null ? void 0 : _a16.abortController.abort();
9551
+ (_b = this.activeResponse) == null ? void 0 : _b.abortController.abort();
9534
9552
  };
9535
9553
  this.id = id;
9536
9554
  this.transport = transport;
@@ -9583,7 +9601,19 @@ var AbstractChat = class {
9583
9601
  body,
9584
9602
  messageId
9585
9603
  }) {
9586
- var _a16, _b, _c;
9604
+ var _a16, _b, _c, _d;
9605
+ const abortController = new AbortController();
9606
+ const activeResumeRequest = trigger === "resume-stream" ? { abortController } : void 0;
9607
+ if (activeResumeRequest) {
9608
+ (_a16 = this.activeResumeRequest) == null ? void 0 : _a16.abortController.abort();
9609
+ this.activeResumeRequest = activeResumeRequest;
9610
+ }
9611
+ const isCurrentRequest = () => activeResumeRequest == null || this.activeResumeRequest === activeResumeRequest;
9612
+ const clearActiveResumeRequest = () => {
9613
+ if (this.activeResumeRequest === activeResumeRequest) {
9614
+ this.activeResumeRequest = void 0;
9615
+ }
9616
+ };
9587
9617
  this.setStatus({ status: "submitted", error: void 0 });
9588
9618
  const lastMessage = this.lastMessage;
9589
9619
  let isAbort = false;
@@ -9596,7 +9626,7 @@ var AbstractChat = class {
9596
9626
  lastMessage: this.state.snapshot(lastMessage),
9597
9627
  messageId: this.generateId()
9598
9628
  }),
9599
- abortController: new AbortController()
9629
+ abortController
9600
9630
  };
9601
9631
  activeResponse = response;
9602
9632
  response.abortController.signal.addEventListener("abort", () => {
@@ -9607,12 +9637,23 @@ var AbstractChat = class {
9607
9637
  if (trigger === "resume-stream") {
9608
9638
  const reconnect = await this.transport.reconnectToStream({
9609
9639
  chatId: this.id,
9640
+ abortSignal: abortController.signal,
9610
9641
  metadata,
9611
9642
  headers,
9612
9643
  body
9613
9644
  });
9645
+ if (abortController.signal.aborted || !isCurrentRequest()) {
9646
+ await (reconnect == null ? void 0 : reconnect.cancel().catch(() => {
9647
+ }));
9648
+ if (isCurrentRequest()) {
9649
+ this.setStatus({ status: "ready" });
9650
+ }
9651
+ return;
9652
+ }
9614
9653
  if (reconnect == null) {
9615
- this.setStatus({ status: "ready" });
9654
+ if (isCurrentRequest()) {
9655
+ this.setStatus({ status: "ready" });
9656
+ }
9616
9657
  return;
9617
9658
  }
9618
9659
  stream = reconnect;
@@ -9630,11 +9671,17 @@ var AbstractChat = class {
9630
9671
  }
9631
9672
  const runUpdateMessageJob = (job) => (
9632
9673
  // serialize the job execution to avoid race conditions:
9633
- this.jobExecutor.run(
9634
- () => job({
9674
+ this.jobExecutor.run(() => {
9675
+ if (response.abortController.signal.aborted) {
9676
+ return Promise.resolve();
9677
+ }
9678
+ return job({
9635
9679
  state: response.state,
9636
9680
  write: () => {
9637
9681
  var _a17;
9682
+ if (response.abortController.signal.aborted) {
9683
+ return;
9684
+ }
9638
9685
  this.setStatus({ status: "streaming" });
9639
9686
  const replaceLastMessage = response.state.message.id === ((_a17 = this.lastMessage) == null ? void 0 : _a17.id);
9640
9687
  if (replaceLastMessage) {
@@ -9646,8 +9693,8 @@ var AbstractChat = class {
9646
9693
  this.state.pushMessage(response.state.message);
9647
9694
  }
9648
9695
  }
9649
- })
9650
- )
9696
+ });
9697
+ })
9651
9698
  );
9652
9699
  await consumeStream({
9653
9700
  stream: processUIMessageStream({
@@ -9661,15 +9708,29 @@ var AbstractChat = class {
9661
9708
  throw error;
9662
9709
  }
9663
9710
  }),
9711
+ abortSignal: response.abortController.signal,
9664
9712
  onError: (error) => {
9665
9713
  throw error;
9666
9714
  }
9667
9715
  });
9668
- this.setStatus({ status: "ready" });
9716
+ if (isAbort) {
9717
+ if (isCurrentRequest()) {
9718
+ this.setStatus({ status: "ready" });
9719
+ }
9720
+ return null;
9721
+ }
9722
+ if (isCurrentRequest()) {
9723
+ this.setStatus({ status: "ready" });
9724
+ }
9669
9725
  } catch (err) {
9670
9726
  if (isAbort || err.name === "AbortError") {
9671
9727
  isAbort = true;
9672
- this.setStatus({ status: "ready" });
9728
+ if (isCurrentRequest()) {
9729
+ this.setStatus({ status: "ready" });
9730
+ }
9731
+ return null;
9732
+ }
9733
+ if (!isCurrentRequest()) {
9673
9734
  return null;
9674
9735
  }
9675
9736
  isError = true;
@@ -9683,7 +9744,7 @@ var AbstractChat = class {
9683
9744
  } finally {
9684
9745
  try {
9685
9746
  if (activeResponse) {
9686
- (_a16 = this.onFinish) == null ? void 0 : _a16.call(this, {
9747
+ (_b = this.onFinish) == null ? void 0 : _b.call(this, {
9687
9748
  message: activeResponse.state.message,
9688
9749
  messages: this.state.messages,
9689
9750
  isAbort,
@@ -9698,11 +9759,12 @@ var AbstractChat = class {
9698
9759
  if (this.activeResponse === activeResponse) {
9699
9760
  this.activeResponse = void 0;
9700
9761
  }
9762
+ clearActiveResumeRequest();
9701
9763
  }
9702
- if (((_b = this.sendAutomaticallyWhen) == null ? void 0 : _b.call(this, { messages: this.state.messages })) && !isError) {
9764
+ if (((_c = this.sendAutomaticallyWhen) == null ? void 0 : _c.call(this, { messages: this.state.messages })) && !isError) {
9703
9765
  await this.makeRequest({
9704
9766
  trigger: "submit-message",
9705
- messageId: (_c = this.lastMessage) == null ? void 0 : _c.id,
9767
+ messageId: (_d = this.lastMessage) == null ? void 0 : _d.id,
9706
9768
  metadata,
9707
9769
  headers,
9708
9770
  body