ai 6.0.248 → 6.0.250

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,25 @@
1
1
  # ai
2
2
 
3
+ ## 6.0.250
4
+
5
+ ### Patch Changes
6
+
7
+ - a077695: Prevent streaming telemetry spans from ending twice when model calls fail.
8
+ - 7ce3b8c: Prevent `resumeStream` from copying the previous assistant message into the resumed response.
9
+ - Updated dependencies [b2a4d5a]
10
+ - @ai-sdk/provider-utils@4.0.45
11
+ - @ai-sdk/gateway@3.0.170
12
+
13
+ ## 6.0.249
14
+
15
+ ### Patch Changes
16
+
17
+ - a774b7b: Stop pending and active resumed chat streams after cancellation, and prevent
18
+ overlapping resumptions from applying stale updates.
19
+ - Updated dependencies [b39f987]
20
+ - Updated dependencies [d79117b]
21
+ - @ai-sdk/gateway@3.0.169
22
+
3
23
  ## 6.0.248
4
24
 
5
25
  ### 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.250" : "0.0.0-test";
1308
1308
 
1309
1309
  // src/util/download/download.ts
1310
1310
  var download = async ({
@@ -2532,7 +2532,8 @@ async function recordSpan({
2532
2532
  tracer,
2533
2533
  attributes,
2534
2534
  fn,
2535
- endWhenDone = true
2535
+ endWhenDone = true,
2536
+ endOnError = endWhenDone
2536
2537
  }) {
2537
2538
  return tracer.startActiveSpan(
2538
2539
  name22,
@@ -2549,7 +2550,9 @@ async function recordSpan({
2549
2550
  try {
2550
2551
  recordErrorOnSpan(span, error);
2551
2552
  } finally {
2552
- span.end();
2553
+ if (endOnError) {
2554
+ span.end();
2555
+ }
2553
2556
  }
2554
2557
  throw error;
2555
2558
  }
@@ -6591,9 +6594,19 @@ function createAsyncIterableStream(source) {
6591
6594
  // src/util/consume-stream.ts
6592
6595
  async function consumeStream({
6593
6596
  stream,
6594
- onError
6597
+ onError,
6598
+ abortSignal
6595
6599
  }) {
6596
6600
  const reader = stream.getReader();
6601
+ const cancelOnAbort = () => {
6602
+ reader.cancel().catch(() => {
6603
+ });
6604
+ };
6605
+ if (abortSignal == null ? void 0 : abortSignal.aborted) {
6606
+ cancelOnAbort();
6607
+ } else {
6608
+ abortSignal == null ? void 0 : abortSignal.addEventListener("abort", cancelOnAbort, { once: true });
6609
+ }
6597
6610
  try {
6598
6611
  while (true) {
6599
6612
  const { done } = await reader.read();
@@ -6603,6 +6616,7 @@ async function consumeStream({
6603
6616
  } catch (error) {
6604
6617
  onError == null ? void 0 : onError(error);
6605
6618
  } finally {
6619
+ abortSignal == null ? void 0 : abortSignal.removeEventListener("abort", cancelOnAbort);
6606
6620
  reader.releaseLock();
6607
6621
  }
6608
6622
  }
@@ -7890,6 +7904,7 @@ var DefaultStreamTextResult = class {
7890
7904
  }),
7891
7905
  tracer,
7892
7906
  endWhenDone: false,
7907
+ endOnError: true,
7893
7908
  fn: async (doStreamSpan2) => ({
7894
7909
  startTimestampMs: now2(),
7895
7910
  // get before the call
@@ -11388,6 +11403,7 @@ var DefaultStreamObjectResult = class {
11388
11403
  }),
11389
11404
  tracer,
11390
11405
  endWhenDone: false,
11406
+ endOnError: true,
11391
11407
  fn: async (rootSpan) => {
11392
11408
  const standardizedPrompt = await standardizePrompt({
11393
11409
  system,
@@ -11459,6 +11475,7 @@ var DefaultStreamObjectResult = class {
11459
11475
  }),
11460
11476
  tracer,
11461
11477
  endWhenDone: false,
11478
+ endOnError: true,
11462
11479
  fn: async (doStreamSpan2) => ({
11463
11480
  startTimestampMs: now2(),
11464
11481
  doStreamSpan: doStreamSpan2,
@@ -13672,7 +13689,8 @@ var HttpChatTransport = class {
13672
13689
  const response = await fetch2(api, {
13673
13690
  method: "GET",
13674
13691
  headers,
13675
- credentials
13692
+ credentials,
13693
+ signal: options.abortSignal
13676
13694
  });
13677
13695
  if (response.status === 204) {
13678
13696
  return null;
@@ -13727,6 +13745,7 @@ var AbstractChat = class {
13727
13745
  sendAutomaticallyWhen
13728
13746
  }) {
13729
13747
  this.activeResponse = void 0;
13748
+ this.activeResumeRequest = void 0;
13730
13749
  this.jobExecutor = new SerialJobExecutor();
13731
13750
  /**
13732
13751
  * Appends or replaces a user message to the chat list. This triggers the API call to fetch
@@ -13896,12 +13915,9 @@ var AbstractChat = class {
13896
13915
  * Abort the current request immediately, keep the generated tokens if any.
13897
13916
  */
13898
13917
  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
- }
13918
+ var _a22, _b;
13919
+ (_a22 = this.activeResumeRequest) == null ? void 0 : _a22.abortController.abort();
13920
+ (_b = this.activeResponse) == null ? void 0 : _b.abortController.abort();
13905
13921
  };
13906
13922
  this.id = id;
13907
13923
  this.transport = transport;
@@ -13965,25 +13981,60 @@ var AbstractChat = class {
13965
13981
  body,
13966
13982
  messageId
13967
13983
  }) {
13968
- var _a22, _b;
13984
+ var _a22, _b, _c;
13985
+ const abortController = new AbortController();
13986
+ const activeResumeRequest = trigger === "resume-stream" ? { abortController } : void 0;
13987
+ if (activeResumeRequest) {
13988
+ (_a22 = this.activeResumeRequest) == null ? void 0 : _a22.abortController.abort();
13989
+ this.activeResumeRequest = activeResumeRequest;
13990
+ }
13991
+ const isCurrentRequest = () => activeResumeRequest == null || this.activeResumeRequest === activeResumeRequest;
13992
+ const clearActiveResumeRequest = () => {
13993
+ if (this.activeResumeRequest === activeResumeRequest) {
13994
+ this.activeResumeRequest = void 0;
13995
+ }
13996
+ };
13969
13997
  let resumeStream;
13970
13998
  if (trigger === "resume-stream") {
13971
13999
  try {
13972
14000
  const reconnect = await this.transport.reconnectToStream({
13973
14001
  chatId: this.id,
14002
+ abortSignal: abortController.signal,
13974
14003
  metadata,
13975
14004
  headers,
13976
14005
  body
13977
14006
  });
14007
+ if (abortController.signal.aborted || !isCurrentRequest()) {
14008
+ await (reconnect == null ? void 0 : reconnect.cancel().catch(() => {
14009
+ }));
14010
+ if (isCurrentRequest()) {
14011
+ this.setStatus({ status: "ready" });
14012
+ }
14013
+ clearActiveResumeRequest();
14014
+ return;
14015
+ }
13978
14016
  if (reconnect == null) {
14017
+ this.setStatus({ status: "ready" });
14018
+ clearActiveResumeRequest();
13979
14019
  return;
13980
14020
  }
13981
14021
  resumeStream = reconnect;
13982
14022
  } catch (err) {
14023
+ if (abortController.signal.aborted || err.name === "AbortError") {
14024
+ if (isCurrentRequest()) {
14025
+ this.setStatus({ status: "ready" });
14026
+ }
14027
+ clearActiveResumeRequest();
14028
+ return;
14029
+ }
14030
+ if (!isCurrentRequest()) {
14031
+ return;
14032
+ }
13983
14033
  if (this.onError && err instanceof Error) {
13984
14034
  this.onError(err);
13985
14035
  }
13986
14036
  this.setStatus({ status: "error", error: err });
14037
+ clearActiveResumeRequest();
13987
14038
  return;
13988
14039
  }
13989
14040
  }
@@ -13996,10 +14047,10 @@ var AbstractChat = class {
13996
14047
  try {
13997
14048
  const response = {
13998
14049
  state: createStreamingUIMessageState({
13999
- lastMessage: trigger === "regenerate-message" ? void 0 : this.state.snapshot(lastMessage),
14050
+ lastMessage: trigger === "resume-stream" || trigger === "regenerate-message" ? void 0 : this.state.snapshot(lastMessage),
14000
14051
  messageId: this.generateId()
14001
14052
  }),
14002
- abortController: new AbortController()
14053
+ abortController
14003
14054
  };
14004
14055
  activeResponse = response;
14005
14056
  response.abortController.signal.addEventListener("abort", () => {
@@ -14023,11 +14074,17 @@ var AbstractChat = class {
14023
14074
  }
14024
14075
  const runUpdateMessageJob = (job) => (
14025
14076
  // serialize the job execution to avoid race conditions:
14026
- this.jobExecutor.run(
14027
- () => job({
14077
+ this.jobExecutor.run(() => {
14078
+ if (response.abortController.signal.aborted) {
14079
+ return Promise.resolve();
14080
+ }
14081
+ return job({
14028
14082
  state: response.state,
14029
14083
  write: () => {
14030
14084
  var _a23;
14085
+ if (response.abortController.signal.aborted) {
14086
+ return;
14087
+ }
14031
14088
  this.setStatus({ status: "streaming" });
14032
14089
  const replaceLastMessage = response.state.message.id === ((_a23 = this.lastMessage) == null ? void 0 : _a23.id);
14033
14090
  if (replaceLastMessage) {
@@ -14039,8 +14096,8 @@ var AbstractChat = class {
14039
14096
  this.state.pushMessage(response.state.message);
14040
14097
  }
14041
14098
  }
14042
- })
14043
- )
14099
+ });
14100
+ })
14044
14101
  );
14045
14102
  await consumeStream({
14046
14103
  stream: processUIMessageStream({
@@ -14054,15 +14111,29 @@ var AbstractChat = class {
14054
14111
  throw error;
14055
14112
  }
14056
14113
  }),
14114
+ abortSignal: response.abortController.signal,
14057
14115
  onError: (error) => {
14058
14116
  throw error;
14059
14117
  }
14060
14118
  });
14061
- this.setStatus({ status: "ready" });
14119
+ if (isAbort) {
14120
+ if (isCurrentRequest()) {
14121
+ this.setStatus({ status: "ready" });
14122
+ }
14123
+ return null;
14124
+ }
14125
+ if (isCurrentRequest()) {
14126
+ this.setStatus({ status: "ready" });
14127
+ }
14062
14128
  } catch (err) {
14063
14129
  if (isAbort || err.name === "AbortError") {
14064
14130
  isAbort = true;
14065
- this.setStatus({ status: "ready" });
14131
+ if (isCurrentRequest()) {
14132
+ this.setStatus({ status: "ready" });
14133
+ }
14134
+ return null;
14135
+ }
14136
+ if (!isCurrentRequest()) {
14066
14137
  return null;
14067
14138
  }
14068
14139
  isError = true;
@@ -14076,7 +14147,7 @@ var AbstractChat = class {
14076
14147
  } finally {
14077
14148
  try {
14078
14149
  if (activeResponse) {
14079
- (_a22 = this.onFinish) == null ? void 0 : _a22.call(this, {
14150
+ (_b = this.onFinish) == null ? void 0 : _b.call(this, {
14080
14151
  message: activeResponse.state.message,
14081
14152
  messages: this.state.messages,
14082
14153
  isAbort,
@@ -14091,11 +14162,12 @@ var AbstractChat = class {
14091
14162
  if (this.activeResponse === activeResponse) {
14092
14163
  this.activeResponse = void 0;
14093
14164
  }
14165
+ clearActiveResumeRequest();
14094
14166
  }
14095
14167
  if (!isError && await this.shouldSendAutomatically()) {
14096
14168
  await this.makeRequest({
14097
14169
  trigger: "submit-message",
14098
- messageId: (_b = this.lastMessage) == null ? void 0 : _b.id,
14170
+ messageId: (_c = this.lastMessage) == null ? void 0 : _c.id,
14099
14171
  metadata,
14100
14172
  headers,
14101
14173
  body