ai 7.0.69 → 7.0.70

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,18 @@
1
1
  # ai
2
2
 
3
+ ## 7.0.70
4
+
5
+ ### Patch Changes
6
+
7
+ - 9566914: Stop multi-step text generation for client tool approval even when a provider-executed tool has a deferred result.
8
+ - b181020: fix: reject `streamObject` result promises and report failed completion when the provider stream errors
9
+ - 7054073: Filter preliminary tool outputs when `ignoreIncompleteToolCalls` is enabled.
10
+ - a828527: Prevent automatic tool execution when a model call ends with an unsafe finish reason.
11
+ - d3cc3fe: Clear partial UI message parts when a WorkflowAgent model-call step is retried.
12
+ - Updated dependencies [e6087c9]
13
+ - @ai-sdk/provider-utils@5.0.28
14
+ - @ai-sdk/gateway@4.0.56
15
+
3
16
  ## 7.0.69
4
17
 
5
18
  ### 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.70" : "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 {
@@ -10043,10 +10069,9 @@ var DefaultStreamTextResult = class {
10043
10069
  }
10044
10070
  cleanupStepTimeouts();
10045
10071
  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:
10072
+ // Continue only after all client tool calls have been executed or denied,
10073
+ // and if there are client results or pending deferred provider results.
10074
+ clientToolCalls.length === clientToolOutputs.length + deniedToolApprovalResponses.length && (clientToolCalls.length > 0 || pendingDeferredToolCalls.size > 0) && // continue until a stop condition is met:
10050
10075
  !await isStopConditionMet({
10051
10076
  stopConditions,
10052
10077
  steps: recordedSteps
@@ -10789,7 +10814,7 @@ async function convertToModelMessages(messages, options) {
10789
10814
  messages = messages.map((message) => ({
10790
10815
  ...message,
10791
10816
  parts: message.parts.filter(
10792
- (part) => !isToolUIPart(part) || part.state === "approval-responded" || part.state === "output-available" || part.state === "output-error" || part.state === "output-denied"
10817
+ (part) => !isToolUIPart(part) || part.state === "approval-responded" || part.state === "output-available" && part.preliminary !== true || part.state === "output-error" || part.state === "output-denied"
10793
10818
  )
10794
10819
  }));
10795
10820
  }
@@ -13366,6 +13391,12 @@ function simulateReadableStream({
13366
13391
 
13367
13392
  // src/generate-object/stream-object.ts
13368
13393
  var originalGenerateId5 = createIdGenerator7({ prefix: "aiobj", size: 24 });
13394
+ async function markPromiseAsHandled2(promise) {
13395
+ try {
13396
+ await promise;
13397
+ } catch (e) {
13398
+ }
13399
+ }
13369
13400
  function streamObject(options) {
13370
13401
  const {
13371
13402
  model,
@@ -13595,6 +13626,7 @@ var DefaultStreamObjectResult = class {
13595
13626
  let providerMetadata;
13596
13627
  let object3;
13597
13628
  let error;
13629
+ let terminalError;
13598
13630
  let msToFirstChunk = void 0;
13599
13631
  let accumulatedText = "";
13600
13632
  let textDelta = "";
@@ -13660,16 +13692,27 @@ var DefaultStreamObjectResult = class {
13660
13692
  };
13661
13693
  break;
13662
13694
  }
13695
+ case "error": {
13696
+ if (terminalError === void 0) {
13697
+ const wrappedError = wrapGatewayError(chunk.error);
13698
+ terminalError = { error: wrappedError };
13699
+ error = wrappedError;
13700
+ finishReason = "error";
13701
+ self.rejectResultPromises(wrappedError);
13702
+ }
13703
+ controller.enqueue(chunk);
13704
+ break;
13705
+ }
13663
13706
  case "finish": {
13664
13707
  if (textDelta !== "") {
13665
13708
  controller.enqueue({ type: "text-delta", textDelta });
13666
13709
  }
13667
- finishReason = chunk.finishReason.unified;
13710
+ finishReason = terminalError === void 0 ? chunk.finishReason.unified : "error";
13668
13711
  usage = asLanguageModelUsage(chunk.usage);
13669
13712
  providerMetadata = chunk.providerMetadata;
13670
13713
  controller.enqueue({
13671
13714
  ...chunk,
13672
- finishReason: chunk.finishReason.unified,
13715
+ finishReason,
13673
13716
  usage,
13674
13717
  response: fullResponse
13675
13718
  });
@@ -13678,6 +13721,9 @@ var DefaultStreamObjectResult = class {
13678
13721
  provider: model.provider,
13679
13722
  model: model.modelId
13680
13723
  });
13724
+ if (terminalError !== void 0) {
13725
+ break;
13726
+ }
13681
13727
  self._usage.resolve(usage);
13682
13728
  self._providerMetadata.resolve(providerMetadata);
13683
13729
  self._warnings.resolve(warnings);
@@ -13765,9 +13811,19 @@ var DefaultStreamObjectResult = class {
13765
13811
  }
13766
13812
  })
13767
13813
  );
13768
- stitchableStream.addStream(transformedStream);
13814
+ stitchableStream.addStream(transformedStream, {
13815
+ onError(error2) {
13816
+ const wrappedError = wrapGatewayError(error2);
13817
+ self.rejectResultPromises(wrappedError);
13818
+ void notify({
13819
+ event: { error: wrappedError },
13820
+ callbacks: onError
13821
+ });
13822
+ }
13823
+ });
13769
13824
  })().catch(async (error) => {
13770
13825
  var _a23;
13826
+ self.rejectResultPromises(error);
13771
13827
  await ((_a23 = telemetryDispatcher.onError) == null ? void 0 : _a23.call(telemetryDispatcher, { callId, error }));
13772
13828
  stitchableStream.addStream(
13773
13829
  new ReadableStream({
@@ -13782,6 +13838,24 @@ var DefaultStreamObjectResult = class {
13782
13838
  });
13783
13839
  this.outputStrategy = outputStrategy;
13784
13840
  }
13841
+ rejectResultPromises(error) {
13842
+ this.rejectResultPromise({ delayedPromise: this._object, error });
13843
+ this.rejectResultPromise({ delayedPromise: this._usage, error });
13844
+ this.rejectResultPromise({ delayedPromise: this._providerMetadata, error });
13845
+ this.rejectResultPromise({ delayedPromise: this._warnings, error });
13846
+ this.rejectResultPromise({ delayedPromise: this._request, error });
13847
+ this.rejectResultPromise({ delayedPromise: this._response, error });
13848
+ this.rejectResultPromise({ delayedPromise: this._finishReason, error });
13849
+ }
13850
+ rejectResultPromise({
13851
+ delayedPromise,
13852
+ error
13853
+ }) {
13854
+ if (delayedPromise.isPending()) {
13855
+ delayedPromise.reject(error);
13856
+ markPromiseAsHandled2(delayedPromise.promise);
13857
+ }
13858
+ }
13785
13859
  get object() {
13786
13860
  return this._object.promise;
13787
13861
  }