ai 6.0.312 → 6.0.314

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,24 @@
1
1
  # ai
2
2
 
3
+ ## 6.0.314
4
+
5
+ ### Patch Changes
6
+
7
+ - 6572f26: Fix `toolChoice: 'none'` by forwarding it to the Hugging Face Responses API and rejecting tool calls before local execution in `generateText` and `streamText`. Streamed tool parts are withheld so client-side tools cannot act on them, and `experimental_repairToolCall` is not invoked for rejected tool calls.
8
+
9
+ ## 6.0.313
10
+
11
+ ### Patch Changes
12
+
13
+ - 52803fb: fix(ai): process only the first approval response per tool call, so repeated or conflicting responses in the final tool message no longer execute a tool twice or both execute and deny it
14
+ - a0f7494: fix(ai): remove orphaned reasoning, including consecutive reasoning parts, when pruning tool calls
15
+ - a48e8a9: fix(ai): preserve repaired tool names in streamed UI message parts
16
+ - Updated dependencies [fa49238]
17
+ - Updated dependencies [d301a16]
18
+ - Updated dependencies [965effe]
19
+ - Updated dependencies [4f82ab0]
20
+ - @ai-sdk/gateway@3.0.220
21
+
3
22
  ## 6.0.312
4
23
 
5
24
  ### Patch Changes
package/dist/index.d.mts CHANGED
@@ -4985,6 +4985,8 @@ declare class NoVideoGeneratedError extends AISDKError {
4985
4985
 
4986
4986
  declare const symbol$7: unique symbol;
4987
4987
  type EnforcedToolChoice = Extract<LanguageModelV3ToolChoice, {
4988
+ type: 'none';
4989
+ } | {
4988
4990
  type: 'required';
4989
4991
  } | {
4990
4992
  type: 'tool';
package/dist/index.d.ts CHANGED
@@ -4985,6 +4985,8 @@ declare class NoVideoGeneratedError extends AISDKError {
4985
4985
 
4986
4986
  declare const symbol$7: unique symbol;
4987
4987
  type EnforcedToolChoice = Extract<LanguageModelV3ToolChoice, {
4988
+ type: 'none';
4989
+ } | {
4988
4990
  type: 'required';
4989
4991
  } | {
4990
4992
  type: 'tool';
package/dist/index.js CHANGED
@@ -521,7 +521,7 @@ var ToolChoiceViolationError = class extends import_provider15.AISDKError {
521
521
  provider,
522
522
  modelId,
523
523
  content,
524
- 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}'.`
524
+ 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}'.`
525
525
  }) {
526
526
  super({ name: name15, message });
527
527
  this[_a15] = true;
@@ -1335,7 +1335,7 @@ function detectMediaType({
1335
1335
  var import_provider_utils3 = require("@ai-sdk/provider-utils");
1336
1336
 
1337
1337
  // src/version.ts
1338
- var VERSION = true ? "6.0.312" : "0.0.0-test";
1338
+ var VERSION = true ? "6.0.314" : "0.0.0-test";
1339
1339
 
1340
1340
  // src/util/download/download.ts
1341
1341
  var download = async ({
@@ -2976,6 +2976,7 @@ function collectToolApprovals({
2976
2976
  }
2977
2977
  const approvedToolApprovals = [];
2978
2978
  const deniedToolApprovals = [];
2979
+ const collectedToolCallIds = /* @__PURE__ */ new Set();
2979
2980
  const approvalResponses = lastMessage.content.filter(
2980
2981
  (part) => part.type === "tool-approval-response"
2981
2982
  );
@@ -2996,6 +2997,10 @@ function collectToolApprovals({
2996
2997
  approvalId: approvalRequest.approvalId
2997
2998
  });
2998
2999
  }
3000
+ if (collectedToolCallIds.has(toolCall.toolCallId)) {
3001
+ continue;
3002
+ }
3003
+ collectedToolCallIds.add(toolCall.toolCallId);
2999
3004
  const approval = {
3000
3005
  approvalRequest,
3001
3006
  approvalResponse,
@@ -5040,16 +5045,18 @@ async function generateText({
5040
5045
  (toolCall) => parseToolCall({
5041
5046
  toolCall,
5042
5047
  tools: stepToolSet,
5043
- repairToolCall,
5048
+ // tool calls are rejected with tool choice none,
5049
+ // so user callbacks must not process them:
5050
+ repairToolCall: (stepToolChoice == null ? void 0 : stepToolChoice.type) === "none" ? void 0 : repairToolCall,
5044
5051
  system,
5045
5052
  messages: stepInputMessages
5046
5053
  })
5047
5054
  )
5048
5055
  );
5049
- const enforcedToolChoice = (stepToolChoice == null ? void 0 : stepToolChoice.type) === "required" || (stepToolChoice == null ? void 0 : stepToolChoice.type) === "tool" ? stepToolChoice : void 0;
5050
- if (enforcedToolChoice != null && !stepToolCalls.some(
5056
+ const enforcedToolChoice = (stepToolChoice == null ? void 0 : stepToolChoice.type) === "auto" ? void 0 : stepToolChoice;
5057
+ if (enforcedToolChoice != null && (enforcedToolChoice.type === "none" ? stepToolCalls.length > 0 : !stepToolCalls.some(
5051
5058
  (toolCall) => enforcedToolChoice.type === "required" || toolCall.toolName === enforcedToolChoice.toolName
5052
- )) {
5059
+ ))) {
5053
5060
  throw new ToolChoiceViolationError({
5054
5061
  toolChoice: enforcedToolChoice,
5055
5062
  finishReason: currentModelResponse.finishReason.unified,
@@ -6148,6 +6155,7 @@ function processUIMessageStream({
6148
6155
  const anyPart = part;
6149
6156
  if (part != null) {
6150
6157
  part.state = options.state;
6158
+ anyPart.type = `tool-${options.toolName}`;
6151
6159
  anyPart.input = anyOptions.input;
6152
6160
  anyPart.output = anyOptions.output;
6153
6161
  anyPart.errorText = anyOptions.errorText;
@@ -7100,6 +7108,7 @@ function createStitchableStream() {
7100
7108
  var import_provider_utils19 = require("@ai-sdk/provider-utils");
7101
7109
  function runToolsTransformation({
7102
7110
  tools,
7111
+ toolChoice,
7103
7112
  generatorStream,
7104
7113
  tracer,
7105
7114
  telemetry,
@@ -7189,10 +7198,19 @@ function runToolsTransformation({
7189
7198
  });
7190
7199
  }
7191
7200
  const activeToolCallToolNames = /* @__PURE__ */ new Map();
7201
+ const withholdToolParts = (toolChoice == null ? void 0 : toolChoice.type) === "none";
7202
+ const withheldToolContent = [];
7192
7203
  const forwardStream = new TransformStream({
7193
7204
  async transform(chunk, controller) {
7194
- var _a23, _b, _c, _d;
7205
+ var _a23, _b, _c, _d, _e, _f;
7195
7206
  const chunkType = chunk.type;
7207
+ if (withholdToolParts && (chunkType === "tool-input-start" || chunkType === "tool-input-delta" || chunkType === "tool-input-end" || chunkType === "tool-approval-request")) {
7208
+ return;
7209
+ }
7210
+ if (withholdToolParts && (chunkType === "tool-call" || chunkType === "tool-result")) {
7211
+ withheldToolContent.push(chunk);
7212
+ return;
7213
+ }
7196
7214
  switch (chunkType) {
7197
7215
  case "stream-start":
7198
7216
  case "text-start":
@@ -7250,13 +7268,26 @@ function runToolsTransformation({
7250
7268
  break;
7251
7269
  }
7252
7270
  case "finish": {
7271
+ const toolChoiceViolationError = withholdToolParts && withheldToolContent.some((part) => part.type === "tool-call") ? new ToolChoiceViolationError({
7272
+ toolChoice: { type: "none" },
7273
+ finishReason: chunk.finishReason.unified,
7274
+ provider: (_e = model == null ? void 0 : model.provider) != null ? _e : "unknown",
7275
+ modelId: (_f = model == null ? void 0 : model.modelId) != null ? _f : "unknown",
7276
+ content: withheldToolContent
7277
+ }) : void 0;
7253
7278
  finishChunk = {
7254
7279
  type: "finish",
7255
- finishReason: chunk.finishReason.unified,
7280
+ finishReason: toolChoiceViolationError == null ? chunk.finishReason.unified : "error",
7256
7281
  rawFinishReason: chunk.finishReason.raw,
7257
7282
  usage: asLanguageModelUsage(chunk.usage),
7258
7283
  providerMetadata: chunk.providerMetadata
7259
7284
  };
7285
+ if (toolChoiceViolationError != null) {
7286
+ controller.enqueue({
7287
+ type: "error",
7288
+ error: toolChoiceViolationError
7289
+ });
7290
+ }
7260
7291
  if (isToolExecutionAllowedFinishReason(chunk.finishReason.unified)) {
7261
7292
  for (const toolCall of toolCallsToExecute.splice(0)) {
7262
7293
  executeToolCallAfterFinish(toolCall);
@@ -8445,6 +8476,7 @@ var DefaultStreamTextResult = class {
8445
8476
  );
8446
8477
  const streamWithToolResults = runToolsTransformation({
8447
8478
  tools: stepToolSet,
8479
+ toolChoice: stepToolChoice,
8448
8480
  generatorStream: stream2,
8449
8481
  tracer,
8450
8482
  telemetry,
@@ -12840,18 +12872,53 @@ function pruneMessages({
12840
12872
  if (message.role !== "assistant" && message.role !== "tool" || typeof message.content === "string" || keepLastMessagesCount && messageIndex >= messages.length - keepLastMessagesCount) {
12841
12873
  return message;
12842
12874
  }
12843
- return {
12844
- ...message,
12845
- content: message.content.filter((part) => {
12846
- if (part.type !== "tool-call" && part.type !== "tool-result" && part.type !== "tool-approval-request" && part.type !== "tool-approval-response") {
12847
- return true;
12875
+ const keepParts = message.content.map((part) => {
12876
+ if (part.type !== "tool-call" && part.type !== "tool-result" && part.type !== "tool-approval-request" && part.type !== "tool-approval-response") {
12877
+ return true;
12878
+ }
12879
+ if ((part.type === "tool-call" || part.type === "tool-result") && keptToolCallIds.has(part.toolCallId) || (part.type === "tool-approval-request" || part.type === "tool-approval-response") && keptApprovalIds.has(part.approvalId)) {
12880
+ return true;
12881
+ }
12882
+ const partToolName = part.type === "tool-call" || part.type === "tool-result" ? part.toolName : approvalIdToToolName.get(part.approvalId);
12883
+ return toolCall.tools != null && partToolName != null && !toolCall.tools.includes(partToolName);
12884
+ });
12885
+ if (message.role === "assistant") {
12886
+ for (let reasoningIndex = 0; reasoningIndex < message.content.length; reasoningIndex++) {
12887
+ const part = message.content[reasoningIndex];
12888
+ if (part.type !== "reasoning") {
12889
+ continue;
12890
+ }
12891
+ let reasoningEndIndex = reasoningIndex + 1;
12892
+ while (reasoningEndIndex < message.content.length) {
12893
+ const nextPart = message.content[reasoningEndIndex];
12894
+ if (nextPart.type !== "reasoning") {
12895
+ break;
12896
+ }
12897
+ reasoningEndIndex++;
12848
12898
  }
12849
- if ((part.type === "tool-call" || part.type === "tool-result") && keptToolCallIds.has(part.toolCallId) || (part.type === "tool-approval-request" || part.type === "tool-approval-response") && keptApprovalIds.has(part.approvalId)) {
12850
- return true;
12899
+ let followingPartIndex = reasoningEndIndex;
12900
+ let hasFollowingPart = false;
12901
+ let hasKeptFollowingPart = false;
12902
+ while (followingPartIndex < message.content.length) {
12903
+ const followingPart = message.content[followingPartIndex];
12904
+ if (followingPart.type === "reasoning") {
12905
+ break;
12906
+ }
12907
+ hasFollowingPart = true;
12908
+ hasKeptFollowingPart || (hasKeptFollowingPart = keepParts[followingPartIndex]);
12909
+ followingPartIndex++;
12851
12910
  }
12852
- const partToolName = part.type === "tool-call" || part.type === "tool-result" ? part.toolName : approvalIdToToolName.get(part.approvalId);
12853
- return toolCall.tools != null && partToolName != null && !toolCall.tools.includes(partToolName);
12854
- })
12911
+ if (hasFollowingPart && !hasKeptFollowingPart) {
12912
+ for (let index = reasoningIndex; index < reasoningEndIndex; index++) {
12913
+ keepParts[index] = false;
12914
+ }
12915
+ }
12916
+ reasoningIndex = followingPartIndex - 1;
12917
+ }
12918
+ }
12919
+ return {
12920
+ ...message,
12921
+ content: message.content.filter((_, index) => keepParts[index])
12855
12922
  };
12856
12923
  });
12857
12924
  }