ai 7.0.69 → 7.0.71

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,26 @@
1
1
  # ai
2
2
 
3
+ ## 7.0.71
4
+
5
+ ### Patch Changes
6
+
7
+ - 9a37469: Prevent exceptions in streaming `onChunk` and `onError` callbacks from terminating the stream or masking provider errors.
8
+ - Updated dependencies [936719b]
9
+ - @ai-sdk/gateway@4.0.57
10
+
11
+ ## 7.0.70
12
+
13
+ ### Patch Changes
14
+
15
+ - 9566914: Stop multi-step text generation for client tool approval even when a provider-executed tool has a deferred result.
16
+ - b181020: fix: reject `streamObject` result promises and report failed completion when the provider stream errors
17
+ - 7054073: Filter preliminary tool outputs when `ignoreIncompleteToolCalls` is enabled.
18
+ - a828527: Prevent automatic tool execution when a model call ends with an unsafe finish reason.
19
+ - d3cc3fe: Clear partial UI message parts when a WorkflowAgent model-call step is retried.
20
+ - Updated dependencies [e6087c9]
21
+ - @ai-sdk/provider-utils@5.0.28
22
+ - @ai-sdk/gateway@4.0.56
23
+
3
24
  ## 7.0.69
4
25
 
5
26
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -2403,6 +2403,11 @@ type UIMessageChunk<METADATA = unknown, DATA_TYPES extends UIDataTypes = UIDataT
2403
2403
  type: 'start-step';
2404
2404
  } | {
2405
2405
  type: 'finish-step';
2406
+ } | {
2407
+ /**
2408
+ * Removes all message parts added during the current step.
2409
+ */
2410
+ type: 'reset-step';
2406
2411
  } | {
2407
2412
  type: 'start';
2408
2413
  messageId?: string;
package/dist/index.js CHANGED
@@ -1143,7 +1143,7 @@ import {
1143
1143
  } from "@ai-sdk/provider-utils";
1144
1144
 
1145
1145
  // src/version.ts
1146
- var VERSION = true ? "7.0.69" : "0.0.0-test";
1146
+ var VERSION = true ? "7.0.71" : "0.0.0-test";
1147
1147
 
1148
1148
  // src/util/download/download.ts
1149
1149
  var download = async ({
@@ -3139,6 +3139,11 @@ var DefaultGeneratedFileWithType = class extends DefaultGeneratedFile {
3139
3139
  }
3140
3140
  };
3141
3141
 
3142
+ // src/generate-text/is-tool-execution-allowed-finish-reason.ts
3143
+ function isToolExecutionAllowedFinishReason(finishReason) {
3144
+ return finishReason === "stop" || finishReason === "tool-calls";
3145
+ }
3146
+
3142
3147
  // src/generate-text/output.ts
3143
3148
  var output_exports = {};
3144
3149
  __export(output_exports, {
@@ -5838,7 +5843,9 @@ async function generateText({
5838
5843
  (toolApprovalResponse) => toolApprovalResponse.approved === false
5839
5844
  );
5840
5845
  const toolExecutionMs = {};
5841
- if (stepExecutionTools != null) {
5846
+ if (stepExecutionTools != null && isToolExecutionAllowedFinishReason(
5847
+ currentModelResponse.finishReason.unified
5848
+ )) {
5842
5849
  const toolExecutionResults = await executeTools({
5843
5850
  toolCalls: clientToolCalls.filter(
5844
5851
  (toolCall) => !toolCall.invalid && !blockedToolCallIds.has(toolCall.toolCallId)
@@ -5974,10 +5981,9 @@ async function generateText({
5974
5981
  }
5975
5982
  }
5976
5983
  } while (
5977
- // Continue if:
5978
- // 1. There are client tool calls that have all been executed or denied, OR
5979
- // 2. There are pending deferred results from provider-executed tools
5980
- (clientToolCalls.length > 0 && clientToolOutputs.length + deniedToolApprovalResponses.length === clientToolCalls.length || pendingDeferredToolCalls.size > 0) && // continue until a stop condition is met:
5984
+ // Continue only after all client tool calls have been executed or denied,
5985
+ // and if there are client results or pending deferred provider results.
5986
+ clientToolOutputs.length + deniedToolApprovalResponses.length === clientToolCalls.length && (clientToolCalls.length > 0 || pendingDeferredToolCalls.size > 0) && // continue until a stop condition is met:
5981
5987
  !await isStopConditionMet({ stopConditions, steps })
5982
5988
  );
5983
5989
  const lastStep = steps[steps.length - 1];
@@ -6711,6 +6717,9 @@ var uiMessageChunkSchema = lazySchema(
6711
6717
  z.looseObject({
6712
6718
  type: z.literal("finish-step")
6713
6719
  }),
6720
+ z.looseObject({
6721
+ type: z.literal("reset-step")
6722
+ }),
6714
6723
  z.looseObject({
6715
6724
  type: z.literal("start"),
6716
6725
  messageId: z.string().optional(),
@@ -7364,6 +7373,20 @@ function processUIMessageStream({
7364
7373
  state.activeReasoningParts = createIdMap();
7365
7374
  break;
7366
7375
  }
7376
+ case "reset-step": {
7377
+ const currentStepParts = getCurrentStepParts();
7378
+ state.activeTextParts = createIdMap();
7379
+ state.activeReasoningParts = createIdMap();
7380
+ state.partialToolCalls = createIdMap();
7381
+ if (currentStepParts.length > 0) {
7382
+ state.message.parts.splice(
7383
+ state.message.parts.length - currentStepParts.length,
7384
+ currentStepParts.length
7385
+ );
7386
+ write();
7387
+ }
7388
+ break;
7389
+ }
7367
7390
  case "start": {
7368
7391
  if (chunk.messageId != null) {
7369
7392
  state.message.id = chunk.messageId;
@@ -8169,6 +8192,9 @@ function executeToolsFromStream({
8169
8192
  return;
8170
8193
  }
8171
8194
  case "model-call-end": {
8195
+ if (!isToolExecutionAllowedFinishReason(chunk.finishReason)) {
8196
+ return;
8197
+ }
8172
8198
  await Promise.all(
8173
8199
  toolCallsToExecute.map(async (toolCall) => {
8174
8200
  try {
@@ -9112,13 +9138,19 @@ var DefaultStreamTextResult = class {
9112
9138
  var _a23, _b, _c, _d;
9113
9139
  controller.enqueue(chunk);
9114
9140
  const { part } = chunk;
9115
- await (onChunk == null ? void 0 : onChunk({ chunk: part }));
9141
+ await notify({
9142
+ event: { chunk: part },
9143
+ callbacks: onChunk
9144
+ });
9116
9145
  if (part.type === "error") {
9117
9146
  const error = wrapGatewayError(part.error);
9118
9147
  if (NoOutputGeneratedError.isInstance(error)) {
9119
9148
  recordedNoOutputError = error;
9120
9149
  }
9121
- await onError({ error });
9150
+ await notify({
9151
+ event: { error },
9152
+ callbacks: onError
9153
+ });
9122
9154
  }
9123
9155
  if (part.type === "custom" || part.type === "source" || part.type === "tool-call" || part.type === "tool-approval-request" || part.type === "tool-approval-response" || part.type === "tool-error") {
9124
9156
  recordedContent.push(part);
@@ -10043,10 +10075,9 @@ var DefaultStreamTextResult = class {
10043
10075
  }
10044
10076
  cleanupStepTimeouts();
10045
10077
  if (
10046
- // Continue if:
10047
- // 1. There are client tool calls that have all been executed or denied, OR
10048
- // 2. There are pending deferred results from provider-executed tools, OR
10049
- (clientToolCalls.length > 0 && clientToolCalls.length === clientToolOutputs.length + deniedToolApprovalResponses.length || pendingDeferredToolCalls.size > 0) && // continue until a stop condition is met:
10078
+ // Continue only after all client tool calls have been executed or denied,
10079
+ // and if there are client results or pending deferred provider results.
10080
+ clientToolCalls.length === clientToolOutputs.length + deniedToolApprovalResponses.length && (clientToolCalls.length > 0 || pendingDeferredToolCalls.size > 0) && // continue until a stop condition is met:
10050
10081
  !await isStopConditionMet({
10051
10082
  stopConditions,
10052
10083
  steps: recordedSteps
@@ -10789,7 +10820,7 @@ async function convertToModelMessages(messages, options) {
10789
10820
  messages = messages.map((message) => ({
10790
10821
  ...message,
10791
10822
  parts: message.parts.filter(
10792
- (part) => !isToolUIPart(part) || part.state === "approval-responded" || part.state === "output-available" || part.state === "output-error" || part.state === "output-denied"
10823
+ (part) => !isToolUIPart(part) || part.state === "approval-responded" || part.state === "output-available" && part.preliminary !== true || part.state === "output-error" || part.state === "output-denied"
10793
10824
  )
10794
10825
  }));
10795
10826
  }
@@ -13366,6 +13397,12 @@ function simulateReadableStream({
13366
13397
 
13367
13398
  // src/generate-object/stream-object.ts
13368
13399
  var originalGenerateId5 = createIdGenerator7({ prefix: "aiobj", size: 24 });
13400
+ async function markPromiseAsHandled2(promise) {
13401
+ try {
13402
+ await promise;
13403
+ } catch (e) {
13404
+ }
13405
+ }
13369
13406
  function streamObject(options) {
13370
13407
  const {
13371
13408
  model,
@@ -13497,7 +13534,10 @@ var DefaultStreamObjectResult = class {
13497
13534
  transform(chunk, controller) {
13498
13535
  controller.enqueue(chunk);
13499
13536
  if (chunk.type === "error") {
13500
- onError({ error: wrapGatewayError(chunk.error) });
13537
+ void notify({
13538
+ event: { error: wrapGatewayError(chunk.error) },
13539
+ callbacks: onError
13540
+ });
13501
13541
  }
13502
13542
  }
13503
13543
  });
@@ -13595,6 +13635,7 @@ var DefaultStreamObjectResult = class {
13595
13635
  let providerMetadata;
13596
13636
  let object3;
13597
13637
  let error;
13638
+ let terminalError;
13598
13639
  let msToFirstChunk = void 0;
13599
13640
  let accumulatedText = "";
13600
13641
  let textDelta = "";
@@ -13660,16 +13701,27 @@ var DefaultStreamObjectResult = class {
13660
13701
  };
13661
13702
  break;
13662
13703
  }
13704
+ case "error": {
13705
+ if (terminalError === void 0) {
13706
+ const wrappedError = wrapGatewayError(chunk.error);
13707
+ terminalError = { error: wrappedError };
13708
+ error = wrappedError;
13709
+ finishReason = "error";
13710
+ self.rejectResultPromises(wrappedError);
13711
+ }
13712
+ controller.enqueue(chunk);
13713
+ break;
13714
+ }
13663
13715
  case "finish": {
13664
13716
  if (textDelta !== "") {
13665
13717
  controller.enqueue({ type: "text-delta", textDelta });
13666
13718
  }
13667
- finishReason = chunk.finishReason.unified;
13719
+ finishReason = terminalError === void 0 ? chunk.finishReason.unified : "error";
13668
13720
  usage = asLanguageModelUsage(chunk.usage);
13669
13721
  providerMetadata = chunk.providerMetadata;
13670
13722
  controller.enqueue({
13671
13723
  ...chunk,
13672
- finishReason: chunk.finishReason.unified,
13724
+ finishReason,
13673
13725
  usage,
13674
13726
  response: fullResponse
13675
13727
  });
@@ -13678,6 +13730,9 @@ var DefaultStreamObjectResult = class {
13678
13730
  provider: model.provider,
13679
13731
  model: model.modelId
13680
13732
  });
13733
+ if (terminalError !== void 0) {
13734
+ break;
13735
+ }
13681
13736
  self._usage.resolve(usage);
13682
13737
  self._providerMetadata.resolve(providerMetadata);
13683
13738
  self._warnings.resolve(warnings);
@@ -13765,9 +13820,19 @@ var DefaultStreamObjectResult = class {
13765
13820
  }
13766
13821
  })
13767
13822
  );
13768
- stitchableStream.addStream(transformedStream);
13823
+ stitchableStream.addStream(transformedStream, {
13824
+ onError(error2) {
13825
+ const wrappedError = wrapGatewayError(error2);
13826
+ self.rejectResultPromises(wrappedError);
13827
+ void notify({
13828
+ event: { error: wrappedError },
13829
+ callbacks: onError
13830
+ });
13831
+ }
13832
+ });
13769
13833
  })().catch(async (error) => {
13770
13834
  var _a23;
13835
+ self.rejectResultPromises(error);
13771
13836
  await ((_a23 = telemetryDispatcher.onError) == null ? void 0 : _a23.call(telemetryDispatcher, { callId, error }));
13772
13837
  stitchableStream.addStream(
13773
13838
  new ReadableStream({
@@ -13782,6 +13847,24 @@ var DefaultStreamObjectResult = class {
13782
13847
  });
13783
13848
  this.outputStrategy = outputStrategy;
13784
13849
  }
13850
+ rejectResultPromises(error) {
13851
+ this.rejectResultPromise({ delayedPromise: this._object, error });
13852
+ this.rejectResultPromise({ delayedPromise: this._usage, error });
13853
+ this.rejectResultPromise({ delayedPromise: this._providerMetadata, error });
13854
+ this.rejectResultPromise({ delayedPromise: this._warnings, error });
13855
+ this.rejectResultPromise({ delayedPromise: this._request, error });
13856
+ this.rejectResultPromise({ delayedPromise: this._response, error });
13857
+ this.rejectResultPromise({ delayedPromise: this._finishReason, error });
13858
+ }
13859
+ rejectResultPromise({
13860
+ delayedPromise,
13861
+ error
13862
+ }) {
13863
+ if (delayedPromise.isPending()) {
13864
+ delayedPromise.reject(error);
13865
+ markPromiseAsHandled2(delayedPromise.promise);
13866
+ }
13867
+ }
13785
13868
  get object() {
13786
13869
  return this._object.promise;
13787
13870
  }