@ai-sdk/openai 3.0.96 → 3.0.98

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,32 @@
1
1
  # @ai-sdk/openai
2
2
 
3
+ ## 3.0.98
4
+
5
+ ### Patch Changes
6
+
7
+ - 91880b9: fix(openai): support built-in and provider-defined tools in the Responses `allowedTools` option
8
+
9
+ `allowedTools` emitted every allow-list entry as `{ type: 'function', name }`, but OpenAI identifies
10
+ built-in tools by type. Allow-listing a declared provider-defined tool (web search, image generation,
11
+ MCP, custom, ...) therefore failed with `Tool choice '<name>' not found in 'tools' parameter`. Entries
12
+ are now derived from the declared tool, including the MCP server label and custom tool name.
13
+
14
+ Tools that OpenAI cannot allow-list (the tool search tool, deferred tools, and namespaced tools) are
15
+ dropped from the allow-list with a warning, and an error is thrown if that would leave the allow-list
16
+ empty rather than silently sending an unrestricted request.
17
+
18
+ Ambiguous names are now reported instead of resolved silently. A name that matches both a declared tool
19
+ and another tool's provider tool name resolves to the declared tool and warns; a provider tool name
20
+ shared by several tools in the same request (two MCP servers, for example) is dropped with a warning.
21
+ A name that matches no declared tool keeps its existing behavior and is now warned about.
22
+
23
+ ## 3.0.97
24
+
25
+ ### Patch Changes
26
+
27
+ - Updated dependencies [31205a4]
28
+ - @ai-sdk/provider-utils@4.0.46
29
+
3
30
  ## 3.0.96
4
31
 
5
32
  ### Patch Changes
package/dist/index.js CHANGED
@@ -4888,7 +4888,7 @@ async function prepareResponsesTools({
4888
4888
  toolNameMapping,
4889
4889
  customProviderToolNames
4890
4890
  }) {
4891
- var _a, _b, _c;
4891
+ var _a, _b, _c, _d;
4892
4892
  tools = (tools == null ? void 0 : tools.length) ? tools : void 0;
4893
4893
  const toolWarnings = [];
4894
4894
  if (tools == null) {
@@ -4897,6 +4897,20 @@ async function prepareResponsesTools({
4897
4897
  const openaiTools2 = [];
4898
4898
  const namespaceTools = /* @__PURE__ */ new Map();
4899
4899
  const resolvedCustomProviderToolNames = customProviderToolNames != null ? customProviderToolNames : /* @__PURE__ */ new Set();
4900
+ const allowedToolResolutions = /* @__PURE__ */ new Map();
4901
+ const allowedToolAliases = /* @__PURE__ */ new Map();
4902
+ const recordAllowedTool = (toolName, resolution, canonicalName) => {
4903
+ allowedToolResolutions.set(toolName, resolution);
4904
+ if (canonicalName == null || canonicalName === toolName) {
4905
+ return;
4906
+ }
4907
+ const existingAlias = allowedToolAliases.get(canonicalName);
4908
+ if (existingAlias == null) {
4909
+ allowedToolAliases.set(canonicalName, resolution);
4910
+ } else if (existingAlias !== "ambiguous" && !isSameAllowedTool(existingAlias, resolution)) {
4911
+ allowedToolAliases.set(canonicalName, "ambiguous");
4912
+ }
4913
+ };
4900
4914
  for (const tool of tools) {
4901
4915
  switch (tool.type) {
4902
4916
  case "function": {
@@ -4926,9 +4940,24 @@ async function prepareResponsesTools({
4926
4940
  }
4927
4941
  namespaceTool.tools.push(openaiFunctionTool);
4928
4942
  }
4943
+ recordAllowedTool(
4944
+ tool.name,
4945
+ namespace != null ? {
4946
+ supported: false,
4947
+ reason: "tools inside an OpenAI tool namespace are not visible to tool_choice.allowed_tools"
4948
+ } : (openaiOptions == null ? void 0 : openaiOptions.deferLoading) === true ? {
4949
+ supported: false,
4950
+ reason: "deferred tools are not visible to tool_choice.allowed_tools"
4951
+ } : {
4952
+ supported: true,
4953
+ entry: { type: "function", name: tool.name }
4954
+ },
4955
+ void 0
4956
+ );
4929
4957
  break;
4930
4958
  }
4931
4959
  case "provider": {
4960
+ const openaiToolCountBefore = openaiTools2.length;
4932
4961
  switch (tool.id) {
4933
4962
  case "openai.file_search": {
4934
4963
  const args = await (0, import_provider_utils29.validateTypes)({
@@ -5089,6 +5118,14 @@ async function prepareResponsesTools({
5089
5118
  break;
5090
5119
  }
5091
5120
  }
5121
+ if (openaiTools2.length > openaiToolCountBefore) {
5122
+ const openaiTool = openaiTools2[openaiToolCountBefore];
5123
+ recordAllowedTool(
5124
+ tool.name,
5125
+ toAllowedToolResolution(openaiTool),
5126
+ toolNameMapping == null ? void 0 : toolNameMapping.toProviderToolName(tool.name)
5127
+ );
5128
+ }
5092
5129
  break;
5093
5130
  }
5094
5131
  default:
@@ -5100,18 +5137,63 @@ async function prepareResponsesTools({
5100
5137
  }
5101
5138
  }
5102
5139
  if (allowedTools != null) {
5140
+ const allowedToolEntries = [];
5141
+ const droppedToolNames = [];
5142
+ for (const name of allowedTools.toolNames) {
5143
+ const directResolution = allowedToolResolutions.get(name);
5144
+ const resolution = directResolution != null ? directResolution : allowedToolAliases.get(name);
5145
+ if (directResolution != null && allowedToolAliases.has(name)) {
5146
+ toolWarnings.push({
5147
+ type: "unsupported",
5148
+ feature: `allowedTools entry "${name}"`,
5149
+ details: "this name is both a tool name and the provider tool name of another tool in this request; the tool with this name is allowed"
5150
+ });
5151
+ }
5152
+ if (resolution === "ambiguous") {
5153
+ toolWarnings.push({
5154
+ type: "unsupported",
5155
+ feature: `allowedTools entry "${name}"`,
5156
+ details: "several tools in this request share this provider tool name; use the tool name from the tools for this request instead"
5157
+ });
5158
+ droppedToolNames.push(name);
5159
+ continue;
5160
+ }
5161
+ if (resolution == null) {
5162
+ toolWarnings.push({
5163
+ type: "unsupported",
5164
+ feature: `allowedTools entry "${name}"`,
5165
+ details: "the tool is not part of the tools for this request and is sent as a function tool"
5166
+ });
5167
+ allowedToolEntries.push({
5168
+ type: "function",
5169
+ name: (_b = toolNameMapping == null ? void 0 : toolNameMapping.toProviderToolName(name)) != null ? _b : name
5170
+ });
5171
+ continue;
5172
+ }
5173
+ if (!resolution.supported) {
5174
+ toolWarnings.push({
5175
+ type: "unsupported",
5176
+ feature: `allowedTools entry "${name}"`,
5177
+ details: `${resolution.reason}; the tool is removed from the allowed tools`
5178
+ });
5179
+ droppedToolNames.push(name);
5180
+ continue;
5181
+ }
5182
+ allowedToolEntries.push(resolution.entry);
5183
+ }
5184
+ if (allowedToolEntries.length === 0) {
5185
+ throw new import_provider8.UnsupportedFunctionalityError({
5186
+ functionality: `allowedTools with only tools that cannot be allow-listed (${droppedToolNames.join(
5187
+ ", "
5188
+ )})`
5189
+ });
5190
+ }
5103
5191
  return {
5104
5192
  tools: openaiTools2,
5105
5193
  toolChoice: {
5106
5194
  type: "allowed_tools",
5107
- mode: (_b = allowedTools.mode) != null ? _b : "auto",
5108
- tools: allowedTools.toolNames.map((name) => {
5109
- var _a2;
5110
- return {
5111
- type: "function",
5112
- name: (_a2 = toolNameMapping == null ? void 0 : toolNameMapping.toProviderToolName(name)) != null ? _a2 : name
5113
- };
5114
- })
5195
+ mode: (_c = allowedTools.mode) != null ? _c : "auto",
5196
+ tools: allowedToolEntries
5115
5197
  },
5116
5198
  toolWarnings
5117
5199
  };
@@ -5126,7 +5208,7 @@ async function prepareResponsesTools({
5126
5208
  case "required":
5127
5209
  return { tools: openaiTools2, toolChoice: type, toolWarnings };
5128
5210
  case "tool": {
5129
- const resolvedToolName = (_c = toolNameMapping == null ? void 0 : toolNameMapping.toProviderToolName(toolChoice.toolName)) != null ? _c : toolChoice.toolName;
5211
+ const resolvedToolName = (_d = toolNameMapping == null ? void 0 : toolNameMapping.toProviderToolName(toolChoice.toolName)) != null ? _d : toolChoice.toolName;
5130
5212
  return {
5131
5213
  tools: openaiTools2,
5132
5214
  toolChoice: resolvedToolName === "code_interpreter" || resolvedToolName === "file_search" || resolvedToolName === "image_generation" || resolvedToolName === "web_search_preview" || resolvedToolName === "web_search" || resolvedToolName === "mcp" || resolvedToolName === "apply_patch" ? { type: resolvedToolName } : resolvedCustomProviderToolNames.has(resolvedToolName) ? { type: "custom", name: resolvedToolName } : { type: "function", name: resolvedToolName },
@@ -5141,6 +5223,51 @@ async function prepareResponsesTools({
5141
5223
  }
5142
5224
  }
5143
5225
  }
5226
+ function allowedToolKey(entry) {
5227
+ switch (entry.type) {
5228
+ case "mcp":
5229
+ return `mcp:${entry.server_label}`;
5230
+ case "function":
5231
+ case "custom":
5232
+ return `${entry.type}:${entry.name}`;
5233
+ default:
5234
+ return entry.type;
5235
+ }
5236
+ }
5237
+ function isSameAllowedTool(a, b) {
5238
+ if (a.supported && b.supported) {
5239
+ return allowedToolKey(a.entry) === allowedToolKey(b.entry);
5240
+ }
5241
+ if (!a.supported && !b.supported) {
5242
+ return a.reason === b.reason;
5243
+ }
5244
+ return false;
5245
+ }
5246
+ function toAllowedToolResolution(tool) {
5247
+ switch (tool.type) {
5248
+ case "custom":
5249
+ return { supported: true, entry: { type: "custom", name: tool.name } };
5250
+ case "mcp":
5251
+ return {
5252
+ supported: true,
5253
+ entry: { type: "mcp", server_label: tool.server_label }
5254
+ };
5255
+ case "file_search":
5256
+ case "web_search":
5257
+ case "web_search_preview":
5258
+ case "image_generation":
5259
+ case "code_interpreter":
5260
+ case "apply_patch":
5261
+ case "shell":
5262
+ case "local_shell":
5263
+ return { supported: true, entry: { type: tool.type } };
5264
+ default:
5265
+ return {
5266
+ supported: false,
5267
+ reason: `OpenAI does not support ${tool.type} tools in tool_choice.allowed_tools`
5268
+ };
5269
+ }
5270
+ }
5144
5271
  function prepareFunctionTool({
5145
5272
  tool,
5146
5273
  options
@@ -7357,7 +7484,7 @@ var OpenAITranscriptionModel = class {
7357
7484
  };
7358
7485
 
7359
7486
  // src/version.ts
7360
- var VERSION = true ? "3.0.96" : "0.0.0-test";
7487
+ var VERSION = true ? "3.0.98" : "0.0.0-test";
7361
7488
 
7362
7489
  // src/openai-provider.ts
7363
7490
  function createOpenAI(options = {}) {