@ai-sdk/openai 4.0.41 → 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,31 @@
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
+
23
+ ## 4.0.42
24
+
25
+ ### Patch Changes
26
+
27
+ - b6fff2e: feat(provider/openai): support explicit Responses compaction triggers
28
+
3
29
  ## 4.0.41
4
30
 
5
31
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -1379,6 +1379,7 @@ declare const openaiLanguageModelResponsesOptionsSchema: _ai_sdk_provider_utils.
1379
1379
  type: "compaction";
1380
1380
  compactThreshold: number;
1381
1381
  }[] | null | undefined;
1382
+ compactionTrigger?: boolean | undefined;
1382
1383
  allowedTools?: {
1383
1384
  toolNames: string[];
1384
1385
  mode?: "auto" | "required" | undefined;
package/dist/index.js CHANGED
@@ -5609,6 +5609,11 @@ var openaiLanguageModelResponsesOptionsSchema = lazySchema25(
5609
5609
  compactThreshold: z27.number()
5610
5610
  })
5611
5611
  ).nullish(),
5612
+ /**
5613
+ * Request explicit server-side compaction by appending a
5614
+ * `compaction_trigger` item to the Responses input.
5615
+ */
5616
+ compactionTrigger: z27.boolean().optional(),
5612
5617
  /**
5613
5618
  * Restrict the callable tools to a subset while keeping the full tools
5614
5619
  * list intact, so prompt caching is preserved across requests with
@@ -5643,7 +5648,7 @@ async function prepareResponsesTools({
5643
5648
  customProviderToolNames,
5644
5649
  outputSchemaToolNames
5645
5650
  }) {
5646
- var _a, _b, _c;
5651
+ var _a, _b, _c, _d;
5647
5652
  tools = (tools == null ? void 0 : tools.length) ? tools : void 0;
5648
5653
  const toolWarnings = [];
5649
5654
  if (tools == null) {
@@ -5652,6 +5657,20 @@ async function prepareResponsesTools({
5652
5657
  const openaiTools2 = [];
5653
5658
  const namespaceTools = /* @__PURE__ */ new Map();
5654
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
+ };
5655
5674
  for (const tool of tools) {
5656
5675
  switch (tool.type) {
5657
5676
  case "function": {
@@ -5684,9 +5703,24 @@ async function prepareResponsesTools({
5684
5703
  }
5685
5704
  namespaceTool.tools.push(openaiFunctionTool);
5686
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
+ );
5687
5720
  break;
5688
5721
  }
5689
5722
  case "provider": {
5723
+ const openaiToolCountBefore = openaiTools2.length;
5690
5724
  switch (tool.id) {
5691
5725
  case "openai.file_search": {
5692
5726
  const args = await validateTypes2({
@@ -5859,6 +5893,14 @@ async function prepareResponsesTools({
5859
5893
  break;
5860
5894
  }
5861
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
+ }
5862
5904
  break;
5863
5905
  }
5864
5906
  default:
@@ -5870,18 +5912,63 @@ async function prepareResponsesTools({
5870
5912
  }
5871
5913
  }
5872
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
+ }
5873
5966
  return {
5874
5967
  tools: openaiTools2,
5875
5968
  toolChoice: {
5876
5969
  type: "allowed_tools",
5877
- mode: (_b = allowedTools.mode) != null ? _b : "auto",
5878
- tools: allowedTools.toolNames.map((name) => {
5879
- var _a2;
5880
- return {
5881
- type: "function",
5882
- name: (_a2 = toolNameMapping == null ? void 0 : toolNameMapping.toProviderToolName(name)) != null ? _a2 : name
5883
- };
5884
- })
5970
+ mode: (_c = allowedTools.mode) != null ? _c : "auto",
5971
+ tools: allowedToolEntries
5885
5972
  },
5886
5973
  toolWarnings
5887
5974
  };
@@ -5896,7 +5983,7 @@ async function prepareResponsesTools({
5896
5983
  case "required":
5897
5984
  return { tools: openaiTools2, toolChoice: type, toolWarnings };
5898
5985
  case "tool": {
5899
- 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;
5900
5987
  return {
5901
5988
  tools: openaiTools2,
5902
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 },
@@ -5911,6 +5998,53 @@ async function prepareResponsesTools({
5911
5998
  }
5912
5999
  }
5913
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
+ }
5914
6048
  function prepareFunctionTool({
5915
6049
  tool,
5916
6050
  options
@@ -6192,6 +6326,9 @@ var OpenAIResponsesLanguageModel = class _OpenAIResponsesLanguageModel {
6192
6326
  outputSchemaToolNames: outputSchemaToolNames.size > 0 ? outputSchemaToolNames : void 0
6193
6327
  });
6194
6328
  warnings.push(...inputWarnings);
6329
+ if (openaiOptions == null ? void 0 : openaiOptions.compactionTrigger) {
6330
+ input.push({ type: "compaction_trigger" });
6331
+ }
6195
6332
  const strictJsonSchema = (_g = openaiOptions == null ? void 0 : openaiOptions.strictJsonSchema) != null ? _g : true;
6196
6333
  let include = openaiOptions == null ? void 0 : openaiOptions.include;
6197
6334
  function addInclude(key) {
@@ -10023,7 +10160,7 @@ var OpenAISkills = class {
10023
10160
  };
10024
10161
 
10025
10162
  // src/version.ts
10026
- var VERSION = true ? "4.0.41" : "0.0.0-test";
10163
+ var VERSION = true ? "4.0.43" : "0.0.0-test";
10027
10164
 
10028
10165
  // src/openai-provider.ts
10029
10166
  function createOpenAI(options = {}) {