ai 7.0.148 → 7.0.149

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.
Files changed (30) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/index.d.ts +5 -1
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +47 -32
  5. package/dist/index.js.map +1 -1
  6. package/dist/internal/index.d.ts +2 -1
  7. package/dist/internal/index.d.ts.map +1 -1
  8. package/dist/internal/index.js +4 -1
  9. package/dist/internal/index.js.map +1 -1
  10. package/docs/03-ai-sdk-core/15-tools-and-tool-calling.mdx +7 -0
  11. package/docs/03-ai-sdk-core/18-code-mode.mdx +3 -1
  12. package/docs/03-ai-sdk-core/36-transcription.mdx +40 -39
  13. package/docs/03-ai-sdk-core/37-speech.mdx +1 -0
  14. package/docs/03-ai-sdk-core/60-telemetry.mdx +25 -2
  15. package/docs/03-ai-sdk-harnesses/05-harness-adapters.mdx +1 -1
  16. package/docs/07-reference/01-ai-sdk-core/01-generate-text.mdx +4 -4
  17. package/docs/07-reference/01-ai-sdk-core/02-stream-text.mdx +7 -7
  18. package/docs/07-reference/02-ai-sdk-ui/01-use-chat.mdx +1 -1
  19. package/docs/07-reference/02-ai-sdk-ui/40-create-ui-message-stream.mdx +1 -1
  20. package/docs/07-reference/03-ai-sdk-rsc/01-stream-ui.mdx +1 -1
  21. package/docs/07-reference/05-ai-sdk-errors/ai-tool-choice-violation-error.mdx +12 -7
  22. package/package.json +12 -12
  23. package/src/error/tool-choice-violation-error.ts +6 -4
  24. package/src/generate-text/collect-tool-approvals.ts +10 -0
  25. package/src/generate-text/generate-text.ts +24 -12
  26. package/src/generate-text/stream-language-model-call.ts +37 -12
  27. package/src/generate-text/stream-text.ts +4 -1
  28. package/src/types/language-model.ts +2 -0
  29. package/src/ui/chat.ts +40 -12
  30. package/src/ui-message-stream/ui-message-chunks.ts +1 -0
package/dist/index.js CHANGED
@@ -389,7 +389,7 @@ const symbol$6 = Symbol.for(marker$6);
389
389
  * Thrown when a model response does not satisfy an enforced tool choice.
390
390
  */
391
391
  var ToolChoiceViolationError = class extends AISDKError$1 {
392
- constructor({ toolChoice, finishReason, provider, modelId, content, message = toolChoice.type === "required" ? "Model response did not contain a tool call even though tool choice was required." : `Model response did not contain a call to the required tool '${toolChoice.toolName}'.` }) {
392
+ constructor({ toolChoice, finishReason, provider, modelId, content, message = toolChoice.type === "none" ? "Model response contained a tool call even though tool choice was none." : toolChoice.type === "required" ? "Model response did not contain a tool call even though tool choice was required." : `Model response did not contain a call to the required tool '${toolChoice.toolName}'.` }) {
393
393
  super({
394
394
  name: name$6,
395
395
  message
@@ -1174,7 +1174,7 @@ function cloneValue(value) {
1174
1174
  }
1175
1175
  //#endregion
1176
1176
  //#region src/version.ts
1177
- const VERSION = "7.0.148";
1177
+ const VERSION = "7.0.149";
1178
1178
  //#endregion
1179
1179
  //#region src/util/download/download.ts
1180
1180
  /**
@@ -2740,6 +2740,7 @@ function collectToolApprovals({ messages }) {
2740
2740
  for (const part of lastMessage.content) if (part.type === "tool-result") toolResults[part.toolCallId] = part;
2741
2741
  const approvedToolApprovals = [];
2742
2742
  const deniedToolApprovals = [];
2743
+ const collectedToolCallIds = /* @__PURE__ */ new Set();
2743
2744
  const approvalResponses = lastMessage.content.filter((part) => part.type === "tool-approval-response");
2744
2745
  for (const approvalResponse of approvalResponses) {
2745
2746
  const approvalRequest = toolApprovalRequestsByApprovalId[approvalResponse.approvalId];
@@ -2751,6 +2752,8 @@ function collectToolApprovals({ messages }) {
2751
2752
  toolCallId: approvalRequest.toolCallId,
2752
2753
  approvalId: approvalRequest.approvalId
2753
2754
  });
2755
+ if (collectedToolCallIds.has(toolCall.toolCallId)) continue;
2756
+ collectedToolCallIds.add(toolCall.toolCallId);
2754
2757
  const approval = {
2755
2758
  approvalRequest,
2756
2759
  approvalResponse,
@@ -5569,7 +5572,7 @@ async function generateText({ model: modelArg, tools, toolChoice, instructions,
5569
5572
  tools,
5570
5573
  activeTools: prepareStepResult?.activeTools ?? activeTools
5571
5574
  });
5572
- const { executionTools: stepExecutionTools, modelTools: stepModelTools, toolCallerMessages } = prepareToolsForToolCallers({
5575
+ const { executionTools, modelTools: stepModelTools, toolCallerMessages } = prepareToolsForToolCallers({
5573
5576
  tools: prepareToolSearch(stepActiveTools, {
5574
5577
  toolsContext,
5575
5578
  experimental_sandbox: stepSandbox
@@ -5584,6 +5587,7 @@ async function generateText({ model: modelArg, tools, toolChoice, instructions,
5584
5587
  experimental_sandbox: stepSandbox
5585
5588
  });
5586
5589
  const stepToolChoice = prepareToolChoice({ toolChoice: prepareStepResult?.toolChoice ?? toolChoice });
5590
+ const stepExecutionTools = stepToolChoice.type === "none" ? void 0 : executionTools;
5587
5591
  const stepMessages = appendToolCallerMessages({
5588
5592
  messages: prepareStepResult?.messages ?? stepInputMessages,
5589
5593
  toolCallerMessages
@@ -5675,8 +5679,8 @@ async function generateText({ model: modelArg, tools, toolChoice, instructions,
5675
5679
  const stepToolCalls = await Promise.all(currentModelResponse.content.filter((part) => part.type === "tool-call").map((toolCall) => parseToolCall({
5676
5680
  toolCall,
5677
5681
  tools: stepModelTools,
5678
- repairToolCall,
5679
- refineToolInput,
5682
+ repairToolCall: stepToolChoice.type === "none" ? void 0 : repairToolCall,
5683
+ refineToolInput: stepToolChoice.type === "none" ? void 0 : refineToolInput,
5680
5684
  instructions: stepInstructions,
5681
5685
  messages: stepMessages,
5682
5686
  abortSignal: mergedAbortSignal
@@ -5722,8 +5726,8 @@ async function generateText({ model: modelArg, tools, toolChoice, instructions,
5722
5726
  },
5723
5727
  callbacks: [resolvedOnLanguageModelCallEnd, telemetryDispatcher.onLanguageModelCallEnd]
5724
5728
  });
5725
- const enforcedToolChoice = stepToolChoice.type === "required" || stepToolChoice.type === "tool" ? stepToolChoice : void 0;
5726
- if (enforcedToolChoice != null && !stepToolCalls.some((toolCall) => enforcedToolChoice.type === "required" || toolCall.toolName === enforcedToolChoice.toolName)) throw new ToolChoiceViolationError({
5729
+ const enforcedToolChoice = stepToolChoice.type === "auto" ? void 0 : stepToolChoice;
5730
+ if (enforcedToolChoice != null && (enforcedToolChoice.type === "none" ? stepToolCalls.length > 0 : currentModelResponse.finishReason.unified !== "interrupted" && !stepToolCalls.some((toolCall) => enforcedToolChoice.type === "required" || toolCall.toolName === enforcedToolChoice.toolName))) throw new ToolChoiceViolationError({
5727
5731
  toolChoice: enforcedToolChoice,
5728
5732
  finishReason: currentModelResponse.finishReason.unified,
5729
5733
  provider: stepModel.provider,
@@ -5943,7 +5947,7 @@ async function generateText({ model: modelArg, tools, toolChoice, instructions,
5943
5947
  } finally {
5944
5948
  if (stepTimeoutId != null) clearTimeout(stepTimeoutId);
5945
5949
  }
5946
- } while (clientToolOutputs.length + deniedToolApprovalResponses.length === clientToolCalls.length && (clientToolCalls.length > 0 || pendingDeferredToolCalls.size > 0) && !await isStopConditionMet({
5950
+ } while (steps[steps.length - 1].finishReason !== "interrupted" && clientToolOutputs.length + deniedToolApprovalResponses.length === clientToolCalls.length && (clientToolCalls.length > 0 || pendingDeferredToolCalls.size > 0) && !await isStopConditionMet({
5947
5951
  stopConditions,
5948
5952
  steps
5949
5953
  }));
@@ -6520,6 +6524,7 @@ const uiMessageChunkSchema = lazySchema(() => zodSchema$1(z.union([
6520
6524
  "content-filter",
6521
6525
  "tool-calls",
6522
6526
  "error",
6527
+ "interrupted",
6523
6528
  "other"
6524
6529
  ]).optional(),
6525
6530
  messageMetadata: z.unknown().optional()
@@ -8394,6 +8399,7 @@ function createLanguageModelV4StreamPartToLanguageModelStreamPartTransform({ too
8394
8399
  let timeToFirstOutputMs;
8395
8400
  let previousOutputChunkTimestampMs;
8396
8401
  const timeBetweenOutputChunksMs = [];
8402
+ const withholdToolParts = toolChoice.type === "none";
8397
8403
  return new TransformStream({ async transform(chunk, controller) {
8398
8404
  if (isOutputChunk(chunk)) {
8399
8405
  const outputChunkTimestampMs = now();
@@ -8401,6 +8407,7 @@ function createLanguageModelV4StreamPartToLanguageModelStreamPartTransform({ too
8401
8407
  else if (previousOutputChunkTimestampMs != null) timeBetweenOutputChunksMs.push(outputChunkTimestampMs - previousOutputChunkTimestampMs);
8402
8408
  previousOutputChunkTimestampMs = outputChunkTimestampMs;
8403
8409
  }
8410
+ if (withholdToolParts && (chunk.type === "tool-input-start" || chunk.type === "tool-input-delta" || chunk.type === "tool-input-end")) return;
8404
8411
  switch (chunk.type) {
8405
8412
  case "error":
8406
8413
  controller.enqueue({
@@ -8562,8 +8569,8 @@ function createLanguageModelV4StreamPartToLanguageModelStreamPartTransform({ too
8562
8569
  },
8563
8570
  callbacks: onLanguageModelCallEnd
8564
8571
  });
8565
- const enforcedToolChoice = toolChoice.type === "required" || toolChoice.type === "tool" ? toolChoice : void 0;
8566
- const toolChoiceViolationError = enforcedToolChoice != null && ![...toolCallsByToolCallId.values()].some((toolCall) => enforcedToolChoice.type === "required" || toolCall.toolName === enforcedToolChoice.toolName) ? new ToolChoiceViolationError({
8572
+ const enforcedToolChoice = toolChoice.type === "auto" ? void 0 : toolChoice;
8573
+ const toolChoiceViolationError = enforcedToolChoice != null && (enforcedToolChoice.type === "none" ? toolCallsByToolCallId.size > 0 : chunk.finishReason.unified !== "interrupted" && ![...toolCallsByToolCallId.values()].some((toolCall) => enforcedToolChoice.type === "required" || toolCall.toolName === enforcedToolChoice.toolName)) ? new ToolChoiceViolationError({
8567
8574
  toolChoice: enforcedToolChoice,
8568
8575
  finishReason: chunk.finishReason.unified,
8569
8576
  provider,
@@ -8593,15 +8600,16 @@ function createLanguageModelV4StreamPartToLanguageModelStreamPartTransform({ too
8593
8600
  const toolCall = await parseToolCall({
8594
8601
  toolCall: chunk,
8595
8602
  tools,
8596
- repairToolCall,
8597
- refineToolInput,
8603
+ repairToolCall: withholdToolParts ? void 0 : repairToolCall,
8604
+ refineToolInput: withholdToolParts ? void 0 : refineToolInput,
8598
8605
  instructions,
8599
8606
  messages,
8600
8607
  abortSignal
8601
8608
  });
8602
8609
  toolCallsByToolCallId.set(toolCall.toolCallId, toolCall);
8603
- controller.enqueue(toolCall);
8604
8610
  if (collectContent) modelCallContent.push(toolCall);
8611
+ if (withholdToolParts) break;
8612
+ controller.enqueue(toolCall);
8605
8613
  if (toolCall.invalid) {
8606
8614
  if (!toolCall.providerExecuted) controller.enqueue({
8607
8615
  type: "tool-error",
@@ -8624,6 +8632,7 @@ function createLanguageModelV4StreamPartToLanguageModelStreamPartTransform({ too
8624
8632
  break;
8625
8633
  case "tool-approval-request": {
8626
8634
  if (collectContent) rawModelCallContent.push(chunk);
8635
+ if (withholdToolParts) break;
8627
8636
  const toolCall = toolCallsByToolCallId.get(chunk.toolCallId);
8628
8637
  if (toolCall == null) {
8629
8638
  controller.enqueue({
@@ -8669,7 +8678,7 @@ function createLanguageModelV4StreamPartToLanguageModelStreamPartTransform({ too
8669
8678
  ...chunk.providerMetadata != null ? { providerMetadata: chunk.providerMetadata } : {},
8670
8679
  ...toolCall?.toolMetadata != null ? { toolMetadata: toolCall.toolMetadata } : {}
8671
8680
  };
8672
- controller.enqueue(toolResultPart);
8681
+ if (!withholdToolParts) controller.enqueue(toolResultPart);
8673
8682
  if (collectContent) modelCallContent.push(toolResultPart);
8674
8683
  break;
8675
8684
  }
@@ -9783,7 +9792,7 @@ var DefaultStreamTextResult = class {
9783
9792
  tools,
9784
9793
  activeTools: prepareStepResult?.activeTools ?? activeTools
9785
9794
  });
9786
- const { executionTools: stepExecutionTools, modelTools: stepModelTools, toolCallerMessages } = prepareToolsForToolCallers({
9795
+ const { executionTools, modelTools: stepModelTools, toolCallerMessages } = prepareToolsForToolCallers({
9787
9796
  tools: prepareToolSearch(stepActiveTools, {
9788
9797
  toolsContext,
9789
9798
  experimental_sandbox: stepSandbox
@@ -9798,6 +9807,7 @@ var DefaultStreamTextResult = class {
9798
9807
  experimental_sandbox: stepSandbox
9799
9808
  });
9800
9809
  const stepToolChoice = prepareToolChoice({ toolChoice: prepareStepResult?.toolChoice ?? toolChoice });
9810
+ const stepExecutionTools = stepToolChoice.type === "none" ? void 0 : executionTools;
9801
9811
  const stepMessages = appendToolCallerMessages({
9802
9812
  messages: prepareStepResult?.messages ?? stepInputMessages,
9803
9813
  toolCallerMessages
@@ -10244,7 +10254,7 @@ var DefaultStreamTextResult = class {
10244
10254
  }
10245
10255
  for (const output of stepToolOutputs) if (output.type === "tool-result" || output.type === "tool-error") pendingDeferredToolCalls.delete(output.toolCallId);
10246
10256
  cleanupStepTimeouts();
10247
- if (clientToolCalls.length === clientToolOutputs.length + deniedToolApprovalResponses.length && (clientToolCalls.length > 0 || pendingDeferredToolCalls.size > 0) && !await isStopConditionMet({
10257
+ if (stepFinishReason !== "interrupted" && clientToolCalls.length === clientToolOutputs.length + deniedToolApprovalResponses.length && (clientToolCalls.length > 0 || pendingDeferredToolCalls.size > 0) && !await isStopConditionMet({
10248
10258
  stopConditions,
10249
10259
  steps: recordedSteps
10250
10260
  })) try {
@@ -20035,6 +20045,7 @@ var AbstractChat = class {
20035
20045
  }
20036
20046
  constructor({ generateId = generateId$1, id, transport = new DefaultChatTransport(), messageMetadataSchema, dataPartSchemas, state, onError, onToolCall, onFinish, onData, sendAutomaticallyWhen }) {
20037
20047
  this.pendingMessagePreparations = /* @__PURE__ */ new Set();
20048
+ this.interruptedMessageIds = /* @__PURE__ */ new Set();
20038
20049
  this.activeResponse = void 0;
20039
20050
  this.activeResumeRequest = void 0;
20040
20051
  this.resumableStreamState = void 0;
@@ -20166,7 +20177,7 @@ var AbstractChat = class {
20166
20177
  }
20167
20178
  if (this.activeResponse) this.activeResponse.state.message.parts = this.activeResponse.state.message.parts.map(updatePart);
20168
20179
  if (messageIndex !== -1 && this.status !== "streaming" && this.status !== "submitted" && this.sendAutomaticallyWhen) {
20169
- const shouldSend = await this.shouldSendAutomatically();
20180
+ const shouldSend = await this.shouldSendAutomatically(messages[messageIndex].id);
20170
20181
  if (shouldSend) this.runAutomaticRequest(() => {
20171
20182
  const messageId = messageIndex === -1 ? this.lastMessage?.id : messages[messageIndex].id;
20172
20183
  return this.makeRequestForToolApproval({
@@ -20212,7 +20223,7 @@ var AbstractChat = class {
20212
20223
  }
20213
20224
  if (this.activeResponse) this.activeResponse.state.message.parts = this.activeResponse.state.message.parts.map(updatePart);
20214
20225
  if (messageIndex !== -1 && this.status !== "streaming" && this.status !== "submitted" && this.sendAutomaticallyWhen) {
20215
- const shouldSend = await this.shouldSendAutomatically();
20226
+ const shouldSend = await this.shouldSendAutomatically(messages[messageIndex].id);
20216
20227
  if (shouldSend) this.runAutomaticRequest(() => this.makeRequest({
20217
20228
  trigger: "submit-message",
20218
20229
  messageId: messages[messageIndex].id,
@@ -20283,11 +20294,10 @@ var AbstractChat = class {
20283
20294
  set messages(messages) {
20284
20295
  this.state.messages = messages;
20285
20296
  }
20286
- async shouldSendAutomatically() {
20287
- if (!this.sendAutomaticallyWhen) return false;
20288
- const result = this.sendAutomaticallyWhen({ messages: this.state.messages });
20289
- if (result && typeof result === "object" && "then" in result) return await result;
20290
- return result;
20297
+ async shouldSendAutomatically(messageId = this.lastMessage?.id) {
20298
+ const isInterrupted = (id) => id != null && this.interruptedMessageIds.has(id);
20299
+ if (!this.sendAutomaticallyWhen || isInterrupted(messageId) || isInterrupted(this.lastMessage?.id)) return false;
20300
+ return await this.sendAutomaticallyWhen({ messages: this.state.messages }) && !isInterrupted(messageId) && !isInterrupted(this.lastMessage?.id);
20291
20301
  }
20292
20302
  async runAutomaticRequest(request, shouldSend) {
20293
20303
  const stopGeneration = this.stopGeneration;
@@ -20486,20 +20496,25 @@ var AbstractChat = class {
20486
20496
  });
20487
20497
  } finally {
20488
20498
  try {
20489
- if (activeResponse) this.onFinish?.({
20490
- message: activeResponse.state.message,
20491
- messages: this.state.messages,
20492
- isAbort,
20493
- isDisconnect,
20494
- isError,
20495
- finishReason: activeResponse.state.finishReason
20496
- });
20499
+ if (activeResponse) {
20500
+ const { message, finishReason } = activeResponse.state;
20501
+ if (finishReason === "interrupted") this.interruptedMessageIds.add(message.id);
20502
+ else if (!isAbort && !isError) this.interruptedMessageIds.delete(message.id);
20503
+ this.onFinish?.({
20504
+ message: activeResponse.state.message,
20505
+ messages: this.state.messages,
20506
+ isAbort,
20507
+ isDisconnect,
20508
+ isError,
20509
+ finishReason: activeResponse.state.finishReason
20510
+ });
20511
+ }
20497
20512
  } finally {
20498
20513
  if (this.activeResponse === activeResponse) this.activeResponse = void 0;
20499
20514
  clearActiveResumeRequest();
20500
20515
  }
20501
20516
  }
20502
- if (!isAbort && !isError) await this.runAutomaticRequest(() => this.makeRequest({
20517
+ if (!isAbort && !isError && activeResponse?.state.finishReason !== "interrupted") await this.runAutomaticRequest(() => this.makeRequest({
20503
20518
  trigger: "submit-message",
20504
20519
  messageId: this.lastMessage?.id,
20505
20520
  metadata,