@ai-sdk/openai 4.0.42 → 4.0.43

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,25 @@
1
1
  # @ai-sdk/openai
2
2
 
3
+ ## 4.0.43
4
+
5
+ ### Patch Changes
6
+
7
+ - a062795: 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
+
3
23
  ## 4.0.42
4
24
 
5
25
  ### Patch Changes
package/dist/index.js CHANGED
@@ -5648,7 +5648,7 @@ async function prepareResponsesTools({
5648
5648
  customProviderToolNames,
5649
5649
  outputSchemaToolNames
5650
5650
  }) {
5651
- var _a, _b, _c;
5651
+ var _a, _b, _c, _d;
5652
5652
  tools = (tools == null ? void 0 : tools.length) ? tools : void 0;
5653
5653
  const toolWarnings = [];
5654
5654
  if (tools == null) {
@@ -5657,6 +5657,20 @@ async function prepareResponsesTools({
5657
5657
  const openaiTools2 = [];
5658
5658
  const namespaceTools = /* @__PURE__ */ new Map();
5659
5659
  const resolvedCustomProviderToolNames = customProviderToolNames != null ? customProviderToolNames : /* @__PURE__ */ new Set();
5660
+ const allowedToolResolutions = /* @__PURE__ */ new Map();
5661
+ const allowedToolAliases = /* @__PURE__ */ new Map();
5662
+ const recordAllowedTool = (toolName, resolution, canonicalName) => {
5663
+ allowedToolResolutions.set(toolName, resolution);
5664
+ if (canonicalName == null || canonicalName === toolName) {
5665
+ return;
5666
+ }
5667
+ const existingAlias = allowedToolAliases.get(canonicalName);
5668
+ if (existingAlias == null) {
5669
+ allowedToolAliases.set(canonicalName, resolution);
5670
+ } else if (existingAlias !== "ambiguous" && !isSameAllowedTool(existingAlias, resolution)) {
5671
+ allowedToolAliases.set(canonicalName, "ambiguous");
5672
+ }
5673
+ };
5660
5674
  for (const tool of tools) {
5661
5675
  switch (tool.type) {
5662
5676
  case "function": {
@@ -5689,9 +5703,24 @@ async function prepareResponsesTools({
5689
5703
  }
5690
5704
  namespaceTool.tools.push(openaiFunctionTool);
5691
5705
  }
5706
+ recordAllowedTool(
5707
+ tool.name,
5708
+ namespace != null ? {
5709
+ supported: false,
5710
+ reason: "tools inside an OpenAI tool namespace are not visible to tool_choice.allowed_tools"
5711
+ } : (openaiOptions == null ? void 0 : openaiOptions.deferLoading) === true ? {
5712
+ supported: false,
5713
+ reason: "deferred tools are not visible to tool_choice.allowed_tools"
5714
+ } : {
5715
+ supported: true,
5716
+ entry: { type: "function", name: tool.name }
5717
+ },
5718
+ void 0
5719
+ );
5692
5720
  break;
5693
5721
  }
5694
5722
  case "provider": {
5723
+ const openaiToolCountBefore = openaiTools2.length;
5695
5724
  switch (tool.id) {
5696
5725
  case "openai.file_search": {
5697
5726
  const args = await validateTypes2({
@@ -5864,6 +5893,14 @@ async function prepareResponsesTools({
5864
5893
  break;
5865
5894
  }
5866
5895
  }
5896
+ if (openaiTools2.length > openaiToolCountBefore) {
5897
+ const openaiTool = openaiTools2[openaiToolCountBefore];
5898
+ recordAllowedTool(
5899
+ tool.name,
5900
+ toAllowedToolResolution(openaiTool),
5901
+ toolNameMapping == null ? void 0 : toolNameMapping.toProviderToolName(tool.name)
5902
+ );
5903
+ }
5867
5904
  break;
5868
5905
  }
5869
5906
  default:
@@ -5875,18 +5912,63 @@ async function prepareResponsesTools({
5875
5912
  }
5876
5913
  }
5877
5914
  if (allowedTools != null) {
5915
+ const allowedToolEntries = [];
5916
+ const droppedToolNames = [];
5917
+ for (const name of allowedTools.toolNames) {
5918
+ const directResolution = allowedToolResolutions.get(name);
5919
+ const resolution = directResolution != null ? directResolution : allowedToolAliases.get(name);
5920
+ if (directResolution != null && allowedToolAliases.has(name)) {
5921
+ toolWarnings.push({
5922
+ type: "unsupported",
5923
+ feature: `allowedTools entry "${name}"`,
5924
+ 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"
5925
+ });
5926
+ }
5927
+ if (resolution === "ambiguous") {
5928
+ toolWarnings.push({
5929
+ type: "unsupported",
5930
+ feature: `allowedTools entry "${name}"`,
5931
+ details: "several tools in this request share this provider tool name; use the tool name from the tools for this request instead"
5932
+ });
5933
+ droppedToolNames.push(name);
5934
+ continue;
5935
+ }
5936
+ if (resolution == null) {
5937
+ toolWarnings.push({
5938
+ type: "unsupported",
5939
+ feature: `allowedTools entry "${name}"`,
5940
+ details: "the tool is not part of the tools for this request and is sent as a function tool"
5941
+ });
5942
+ allowedToolEntries.push({
5943
+ type: "function",
5944
+ name: (_b = toolNameMapping == null ? void 0 : toolNameMapping.toProviderToolName(name)) != null ? _b : name
5945
+ });
5946
+ continue;
5947
+ }
5948
+ if (!resolution.supported) {
5949
+ toolWarnings.push({
5950
+ type: "unsupported",
5951
+ feature: `allowedTools entry "${name}"`,
5952
+ details: `${resolution.reason}; the tool is removed from the allowed tools`
5953
+ });
5954
+ droppedToolNames.push(name);
5955
+ continue;
5956
+ }
5957
+ allowedToolEntries.push(resolution.entry);
5958
+ }
5959
+ if (allowedToolEntries.length === 0) {
5960
+ throw new UnsupportedFunctionalityError5({
5961
+ functionality: `allowedTools with only tools that cannot be allow-listed (${droppedToolNames.join(
5962
+ ", "
5963
+ )})`
5964
+ });
5965
+ }
5878
5966
  return {
5879
5967
  tools: openaiTools2,
5880
5968
  toolChoice: {
5881
5969
  type: "allowed_tools",
5882
- mode: (_b = allowedTools.mode) != null ? _b : "auto",
5883
- tools: allowedTools.toolNames.map((name) => {
5884
- var _a2;
5885
- return {
5886
- type: "function",
5887
- name: (_a2 = toolNameMapping == null ? void 0 : toolNameMapping.toProviderToolName(name)) != null ? _a2 : name
5888
- };
5889
- })
5970
+ mode: (_c = allowedTools.mode) != null ? _c : "auto",
5971
+ tools: allowedToolEntries
5890
5972
  },
5891
5973
  toolWarnings
5892
5974
  };
@@ -5901,7 +5983,7 @@ async function prepareResponsesTools({
5901
5983
  case "required":
5902
5984
  return { tools: openaiTools2, toolChoice: type, toolWarnings };
5903
5985
  case "tool": {
5904
- const resolvedToolName = (_c = toolNameMapping == null ? void 0 : toolNameMapping.toProviderToolName(toolChoice.toolName)) != null ? _c : toolChoice.toolName;
5986
+ const resolvedToolName = (_d = toolNameMapping == null ? void 0 : toolNameMapping.toProviderToolName(toolChoice.toolName)) != null ? _d : toolChoice.toolName;
5905
5987
  return {
5906
5988
  tools: openaiTools2,
5907
5989
  toolChoice: resolvedToolName === "code_interpreter" || resolvedToolName === "file_search" || resolvedToolName === "image_generation" || resolvedToolName === "web_search_preview" || resolvedToolName === "web_search" || resolvedToolName === "mcp" || resolvedToolName === "apply_patch" || resolvedToolName === "computer" || resolvedToolName === "programmatic_tool_calling" ? { type: resolvedToolName } : resolvedCustomProviderToolNames.has(resolvedToolName) ? { type: "custom", name: resolvedToolName } : { type: "function", name: resolvedToolName },
@@ -5916,6 +5998,53 @@ async function prepareResponsesTools({
5916
5998
  }
5917
5999
  }
5918
6000
  }
6001
+ function allowedToolKey(entry) {
6002
+ switch (entry.type) {
6003
+ case "mcp":
6004
+ return `mcp:${entry.server_label}`;
6005
+ case "function":
6006
+ case "custom":
6007
+ return `${entry.type}:${entry.name}`;
6008
+ default:
6009
+ return entry.type;
6010
+ }
6011
+ }
6012
+ function isSameAllowedTool(a, b) {
6013
+ if (a.supported && b.supported) {
6014
+ return allowedToolKey(a.entry) === allowedToolKey(b.entry);
6015
+ }
6016
+ if (!a.supported && !b.supported) {
6017
+ return a.reason === b.reason;
6018
+ }
6019
+ return false;
6020
+ }
6021
+ function toAllowedToolResolution(tool) {
6022
+ switch (tool.type) {
6023
+ case "custom":
6024
+ return { supported: true, entry: { type: "custom", name: tool.name } };
6025
+ case "mcp":
6026
+ return {
6027
+ supported: true,
6028
+ entry: { type: "mcp", server_label: tool.server_label }
6029
+ };
6030
+ case "file_search":
6031
+ case "web_search":
6032
+ case "web_search_preview":
6033
+ case "image_generation":
6034
+ case "code_interpreter":
6035
+ case "computer":
6036
+ case "apply_patch":
6037
+ case "shell":
6038
+ case "local_shell":
6039
+ case "programmatic_tool_calling":
6040
+ return { supported: true, entry: { type: tool.type } };
6041
+ default:
6042
+ return {
6043
+ supported: false,
6044
+ reason: `OpenAI does not support ${tool.type} tools in tool_choice.allowed_tools`
6045
+ };
6046
+ }
6047
+ }
5919
6048
  function prepareFunctionTool({
5920
6049
  tool,
5921
6050
  options
@@ -10031,7 +10160,7 @@ var OpenAISkills = class {
10031
10160
  };
10032
10161
 
10033
10162
  // src/version.ts
10034
- var VERSION = true ? "4.0.42" : "0.0.0-test";
10163
+ var VERSION = true ? "4.0.43" : "0.0.0-test";
10035
10164
 
10036
10165
  // src/openai-provider.ts
10037
10166
  function createOpenAI(options = {}) {