@openai/agents-openai 0.5.3 → 0.6.0

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.
@@ -18,6 +18,78 @@ const responsesTransportUtils_1 = require("./responsesTransportUtils.js");
18
18
  const tools_1 = require("./tools.js");
19
19
  const providerData_1 = require("./utils/providerData.js");
20
20
  const utils_1 = require("@openai/agents-core/utils");
21
+ /**
22
+ * Tool search outputs are replayed through agents-core protocol items, which use camelCase
23
+ * field names, while the Responses API wire shape uses snake_case. Keep this codec even with
24
+ * first-class upstream types because the local protocol still normalizes these payloads.
25
+ */
26
+ function toOpenAIToolSearchOutputToolPayload(tool, _withinNamespace = false) {
27
+ if (!tool || typeof tool !== 'object' || Array.isArray(tool)) {
28
+ return tool;
29
+ }
30
+ if (tool.type === 'tool_reference' && typeof tool.functionName === 'string') {
31
+ return {
32
+ type: 'tool_reference',
33
+ function_name: tool.functionName,
34
+ ...(typeof tool.namespace === 'string'
35
+ ? { namespace: tool.namespace }
36
+ : {}),
37
+ };
38
+ }
39
+ if (tool.type === 'namespace' && Array.isArray(tool.tools)) {
40
+ return {
41
+ ...tool,
42
+ tools: tool.tools.map((entry) => toOpenAIToolSearchOutputToolPayload(entry, true)),
43
+ };
44
+ }
45
+ if (tool.type === 'function') {
46
+ const { deferLoading, ...rest } = tool;
47
+ return {
48
+ ...rest,
49
+ ...(typeof deferLoading === 'boolean'
50
+ ? { defer_loading: deferLoading }
51
+ : {}),
52
+ };
53
+ }
54
+ return tool;
55
+ }
56
+ function fromOpenAIToolSearchOutputToolPayload(tool, _withinNamespace = false) {
57
+ if (!tool || typeof tool !== 'object' || Array.isArray(tool)) {
58
+ return tool;
59
+ }
60
+ if (tool.type === 'tool_reference' &&
61
+ typeof tool.function_name === 'string') {
62
+ return {
63
+ type: 'tool_reference',
64
+ functionName: tool.function_name,
65
+ ...(typeof tool.namespace === 'string'
66
+ ? { namespace: tool.namespace }
67
+ : {}),
68
+ };
69
+ }
70
+ if (tool.type === 'namespace' && Array.isArray(tool.tools)) {
71
+ return {
72
+ ...tool,
73
+ tools: tool.tools.map((entry) => fromOpenAIToolSearchOutputToolPayload(entry, true)),
74
+ };
75
+ }
76
+ if (tool.type === 'function') {
77
+ const { defer_loading, ...rest } = tool;
78
+ return {
79
+ ...rest,
80
+ ...(typeof defer_loading === 'boolean'
81
+ ? { deferLoading: defer_loading }
82
+ : {}),
83
+ };
84
+ }
85
+ return tool;
86
+ }
87
+ function hasSerializedComputerDisplayMetadata(tool) {
88
+ return (typeof tool.environment === 'string' &&
89
+ Array.isArray(tool.dimensions) &&
90
+ tool.dimensions.length === 2 &&
91
+ tool.dimensions.every((value) => typeof value === 'number'));
92
+ }
21
93
  const HostedToolChoice = zod_1.z.enum([
22
94
  'file_search',
23
95
  'web_search',
@@ -26,12 +98,16 @@ const HostedToolChoice = zod_1.z.enum([
26
98
  'image_generation',
27
99
  'mcp',
28
100
  // Specialized local tools
29
- 'computer_use_preview',
30
101
  'shell',
31
102
  'apply_patch',
32
103
  ]);
33
104
  const DefaultToolChoice = zod_1.z.enum(['auto', 'required', 'none']);
34
- function getToolChoice(toolChoice) {
105
+ const BuiltinComputerToolChoice = zod_1.z.enum([
106
+ 'computer',
107
+ 'computer_use',
108
+ 'computer_use_preview',
109
+ ]);
110
+ function getToolChoice(toolChoice, options) {
35
111
  if (typeof toolChoice === 'undefined') {
36
112
  return undefined;
37
113
  }
@@ -39,12 +115,202 @@ function getToolChoice(toolChoice) {
39
115
  if (resultDefaultCheck.success) {
40
116
  return resultDefaultCheck.data;
41
117
  }
118
+ const builtinComputerToolChoice = BuiltinComputerToolChoice.safeParse(toolChoice);
119
+ if (builtinComputerToolChoice.success) {
120
+ if (hasBuiltinComputerTool(options?.tools) ||
121
+ options?.allowPromptSuppliedComputerTool === true) {
122
+ return getBuiltinComputerToolChoice(builtinComputerToolChoice.data, {
123
+ model: options?.model,
124
+ });
125
+ }
126
+ if (builtinComputerToolChoice.data === 'computer_use_preview') {
127
+ return { type: 'computer_use_preview' };
128
+ }
129
+ return { type: 'function', name: builtinComputerToolChoice.data };
130
+ }
42
131
  const result = HostedToolChoice.safeParse(toolChoice);
43
132
  if (result.success) {
44
133
  return { type: result.data };
45
134
  }
46
135
  return { type: 'function', name: toolChoice };
47
136
  }
137
+ function normalizeToolSearchStatus(status) {
138
+ return status === 'in_progress' ||
139
+ status === 'completed' ||
140
+ status === 'incomplete'
141
+ ? status
142
+ : null;
143
+ }
144
+ function hasBuiltinComputerTool(tools) {
145
+ return (tools ?? []).some((tool) => tool.type === 'computer' ||
146
+ tool.type === 'computer_use' ||
147
+ tool.type === 'computer_use_preview');
148
+ }
149
+ function isPreviewComputerModel(model) {
150
+ return typeof model === 'string' && model.startsWith('computer-use-preview');
151
+ }
152
+ function shouldUsePreviewComputerTool(options) {
153
+ if (isPreviewComputerModel(options?.model)) {
154
+ return true;
155
+ }
156
+ if (typeof options?.model === 'string') {
157
+ return false;
158
+ }
159
+ if (options?.toolChoice === 'computer' ||
160
+ options?.toolChoice === 'computer_use') {
161
+ return false;
162
+ }
163
+ return true;
164
+ }
165
+ function getBuiltinComputerToolChoice(toolChoice, options) {
166
+ if (shouldUsePreviewComputerTool({
167
+ model: options?.model,
168
+ toolChoice,
169
+ })) {
170
+ return { type: 'computer_use_preview' };
171
+ }
172
+ if (toolChoice === 'computer_use') {
173
+ return { type: 'computer_use' };
174
+ }
175
+ return { type: 'computer' };
176
+ }
177
+ function isBuiltinComputerToolType(type) {
178
+ return (type === 'computer' ||
179
+ type === 'computer_use' ||
180
+ type === 'computer_use_preview');
181
+ }
182
+ function isCompatibleBuiltinComputerToolChoice(toolChoiceType, toolType) {
183
+ if (!isBuiltinComputerToolType(toolChoiceType)) {
184
+ return false;
185
+ }
186
+ if (toolChoiceType === 'computer_use_preview') {
187
+ return toolType === 'computer_use_preview';
188
+ }
189
+ return toolType === 'computer';
190
+ }
191
+ function isToolChoiceAvailable(toolChoice, tools) {
192
+ if (toolChoice === 'auto' || toolChoice === 'none') {
193
+ return true;
194
+ }
195
+ if (toolChoice === 'required') {
196
+ return tools.length > 0;
197
+ }
198
+ if (toolChoice.type === 'function') {
199
+ return hasFunctionToolChoiceName(toolChoice.name, tools);
200
+ }
201
+ return tools.some((tool) => isCompatibleBuiltinComputerToolChoice(toolChoice.type, tool.type)
202
+ ? true
203
+ : tool.type === toolChoice.type);
204
+ }
205
+ function hasFunctionToolChoiceName(toolChoiceName, tools, namespacePrefix) {
206
+ return (findFunctionToolChoice(toolChoiceName, tools, namespacePrefix) !== undefined);
207
+ }
208
+ function findFunctionToolChoice(toolChoiceName, tools, namespacePrefix) {
209
+ for (const tool of tools) {
210
+ if (isNamedFunctionTool(tool)) {
211
+ const qualifiedName = namespacePrefix
212
+ ? `${namespacePrefix}.${tool.name}`
213
+ : tool.name;
214
+ if (toolChoiceName === qualifiedName) {
215
+ return tool;
216
+ }
217
+ continue;
218
+ }
219
+ if (isNamespaceTool(tool)) {
220
+ const nestedNamespace = namespacePrefix
221
+ ? `${namespacePrefix}.${tool.name}`
222
+ : tool.name;
223
+ const matchedTool = findFunctionToolChoice(toolChoiceName, tool.tools, nestedNamespace);
224
+ if (matchedTool) {
225
+ return matchedTool;
226
+ }
227
+ }
228
+ }
229
+ return undefined;
230
+ }
231
+ function collectAvailableToolChoiceNames(tools, namespacePrefix) {
232
+ const availableToolChoices = [];
233
+ for (const tool of tools) {
234
+ if (isNamedFunctionTool(tool)) {
235
+ availableToolChoices.push(namespacePrefix ? `${namespacePrefix}.${tool.name}` : tool.name);
236
+ continue;
237
+ }
238
+ if (isNamespaceTool(tool)) {
239
+ const nestedNamespace = namespacePrefix
240
+ ? `${namespacePrefix}.${tool.name}`
241
+ : tool.name;
242
+ availableToolChoices.push(...collectAvailableToolChoiceNames(tool.tools, nestedNamespace));
243
+ continue;
244
+ }
245
+ availableToolChoices.push(tool.type);
246
+ }
247
+ return availableToolChoices;
248
+ }
249
+ function isNamedFunctionTool(tool) {
250
+ return (tool.type === 'function' &&
251
+ typeof tool.name === 'string');
252
+ }
253
+ function isNamespaceTool(tool) {
254
+ const candidate = tool;
255
+ return (tool.type === 'namespace' &&
256
+ typeof candidate.name === 'string' &&
257
+ Array.isArray(candidate.tools));
258
+ }
259
+ function getExtraBodyToolsForToolChoiceValidation(extraBody) {
260
+ if (!extraBody || !Array.isArray(extraBody.tools)) {
261
+ return [];
262
+ }
263
+ return extraBody.tools;
264
+ }
265
+ function assertSupportedToolChoice(toolChoice, tools, options) {
266
+ const allowPromptSuppliedTools = options?.allowPromptSuppliedTools === true;
267
+ if (!toolChoice ||
268
+ toolChoice === 'auto' ||
269
+ toolChoice === 'required' ||
270
+ toolChoice === 'none' ||
271
+ toolChoice.type !== 'function') {
272
+ return;
273
+ }
274
+ const matchedFunctionTool = findFunctionToolChoice(toolChoice.name, tools);
275
+ if (!matchedFunctionTool &&
276
+ allowPromptSuppliedTools &&
277
+ toolChoice.name !== 'tool_search') {
278
+ return;
279
+ }
280
+ if (matchedFunctionTool
281
+ ?.defer_loading === true) {
282
+ throw new agents_core_1.UserError(`modelSettings.toolChoice="${toolChoice.name}" cannot force a deferred function tool in Responses. Use "auto" so tool_search can load it.`);
283
+ }
284
+ if (toolChoice.name === 'tool_search' &&
285
+ !hasFunctionToolChoiceName(toolChoice.name, tools)) {
286
+ throw new agents_core_1.UserError('modelSettings.toolChoice="tool_search" is only supported for a custom function named "tool_search". Responses does not support forcing the built-in tool_search tool. Use "auto" instead.');
287
+ }
288
+ }
289
+ function getCompatibleToolChoice(toolChoice, tools, options) {
290
+ const allowPromptSuppliedTools = options?.allowPromptSuppliedTools === true;
291
+ if (typeof toolChoice === 'undefined') {
292
+ return undefined;
293
+ }
294
+ if (isToolChoiceAvailable(toolChoice, tools) || allowPromptSuppliedTools) {
295
+ return toolChoice;
296
+ }
297
+ const availableToolChoices = [
298
+ ...new Set(collectAvailableToolChoiceNames(tools)),
299
+ ];
300
+ const availableToolChoicesMessage = availableToolChoices.length > 0
301
+ ? ` Available tools: ${availableToolChoices.join(', ')}.`
302
+ : ' No tools are available in the outgoing Responses request.';
303
+ if (toolChoice === 'required') {
304
+ throw new agents_core_1.UserError(`modelSettings.toolChoice="required" requires at least one available tool in the outgoing Responses request.${availableToolChoicesMessage}`);
305
+ }
306
+ if (toolChoice === 'auto' || toolChoice === 'none') {
307
+ throw new Error(`Unexpected unavailable tool choice: ${JSON.stringify(toolChoice)}`);
308
+ }
309
+ if (toolChoice.type === 'function') {
310
+ throw new agents_core_1.UserError(`modelSettings.toolChoice="${toolChoice.name}" does not match any available tool in the outgoing Responses request.${availableToolChoicesMessage}`);
311
+ }
312
+ throw new agents_core_1.UserError(`modelSettings.toolChoice="${toolChoice.type}" is unavailable in the outgoing Responses request.${availableToolChoicesMessage}`);
313
+ }
48
314
  function getResponseFormat(outputType, otherProperties) {
49
315
  if (outputType === 'text') {
50
316
  return otherProperties;
@@ -98,12 +364,13 @@ function convertLegacyToolOutputContent(output) {
98
364
  const legacyImageUrl = output.imageUrl;
99
365
  const legacyFileId = output.fileId;
100
366
  const dataValue = output.data;
367
+ const topLevelInlineMediaType = getImageInlineMediaType(output);
101
368
  if (typeof output.image === 'string' && output.image.length > 0) {
102
369
  structured.image = output.image;
103
370
  }
104
371
  else if (isRecord(output.image)) {
105
372
  const imageObj = output.image;
106
- const inlineMediaType = getImageInlineMediaType(imageObj);
373
+ const inlineMediaType = getImageInlineMediaType(imageObj) ?? topLevelInlineMediaType;
107
374
  if (typeof imageObj.url === 'string' && imageObj.url.length > 0) {
108
375
  structured.image = imageObj.url;
109
376
  }
@@ -143,7 +410,7 @@ function convertLegacyToolOutputContent(output) {
143
410
  base64Data = (0, utils_1.encodeUint8ArrayToBase64)(dataValue);
144
411
  }
145
412
  if (base64Data) {
146
- structured.image = base64Data;
413
+ structured.image = formatInlineData(base64Data, topLevelInlineMediaType);
147
414
  }
148
415
  }
149
416
  if (output.providerData) {
@@ -388,9 +655,16 @@ function getImageInlineMediaType(source) {
388
655
  if (typeof source.mediaType === 'string' && source.mediaType.length > 0) {
389
656
  return source.mediaType;
390
657
  }
658
+ if (typeof source.mimeType === 'string' &&
659
+ source.mimeType.length > 0) {
660
+ return source.mimeType;
661
+ }
391
662
  return undefined;
392
663
  }
393
664
  function formatInlineData(data, mediaType) {
665
+ if (typeof data === 'string' && data.startsWith('data:')) {
666
+ return data;
667
+ }
394
668
  const base64 = typeof data === 'string' ? data : (0, utils_1.encodeUint8ArrayToBase64)(data);
395
669
  return mediaType ? `data:${mediaType};base64,${base64}` : base64;
396
670
  }
@@ -507,11 +781,70 @@ function toOpenAIShellEnvironment(environment) {
507
781
  }
508
782
  throw new agents_core_1.UserError(`Unsupported shell environment type: ${String(environment.type)}`);
509
783
  }
510
- function getTools(tools, handoffs) {
784
+ function getTools(tools, handoffs, options) {
511
785
  const openaiTools = [];
512
786
  const include = [];
787
+ const namespaceStateByName = new Map();
788
+ let hasDeferredSearchableTool = false;
789
+ let hasToolSearch = false;
790
+ const usePreviewComputerTool = shouldUsePreviewComputerTool({
791
+ model: options?.model,
792
+ toolChoice: options?.toolChoice,
793
+ });
513
794
  for (const tool of tools) {
514
- const { tool: openaiTool, include: openaiIncludes } = converTool(tool);
795
+ if (tool.type === 'function') {
796
+ const isDeferredFunction = tool.deferLoading === true;
797
+ hasDeferredSearchableTool ||= isDeferredFunction;
798
+ const namespaceName = typeof tool.namespace === 'string' ? tool.namespace.trim() : '';
799
+ if (namespaceName.length > 0) {
800
+ const namespaceDescription = typeof tool.namespaceDescription === 'string'
801
+ ? tool.namespaceDescription.trim()
802
+ : '';
803
+ if (namespaceDescription.length === 0) {
804
+ throw new agents_core_1.UserError(`All tools in namespace "${namespaceName}" must provide a non-empty description.`);
805
+ }
806
+ let namespaceState = namespaceStateByName.get(namespaceName);
807
+ if (!namespaceState) {
808
+ namespaceState = {
809
+ index: openaiTools.length,
810
+ description: namespaceDescription,
811
+ functionNames: new Set(),
812
+ tools: [],
813
+ };
814
+ namespaceStateByName.set(namespaceName, namespaceState);
815
+ openaiTools.push({});
816
+ }
817
+ else if (namespaceState.description !== namespaceDescription) {
818
+ throw new agents_core_1.UserError(`All tools in namespace "${namespaceName}" must share the same description.`);
819
+ }
820
+ const { tool: openaiTool, include: openaiIncludes } = converTool(tool, {
821
+ usePreviewComputerTool,
822
+ });
823
+ if (namespaceState.functionNames.has(tool.name)) {
824
+ throw new agents_core_1.UserError(`Namespace "${namespaceName}" cannot contain duplicate function tool name "${tool.name}".`);
825
+ }
826
+ namespaceState.functionNames.add(tool.name);
827
+ namespaceState.tools.push(openaiTool);
828
+ if (openaiIncludes && openaiIncludes.length > 0) {
829
+ for (const item of openaiIncludes) {
830
+ include.push(item);
831
+ }
832
+ }
833
+ continue;
834
+ }
835
+ }
836
+ if (tool.type === 'hosted_tool' &&
837
+ tool.providerData?.type === 'tool_search') {
838
+ hasToolSearch = true;
839
+ }
840
+ if (tool.type === 'hosted_tool' &&
841
+ tool.providerData?.type === 'mcp' &&
842
+ tool.providerData.defer_loading === true) {
843
+ hasDeferredSearchableTool = true;
844
+ }
845
+ const { tool: openaiTool, include: openaiIncludes } = converTool(tool, {
846
+ usePreviewComputerTool,
847
+ });
515
848
  openaiTools.push(openaiTool);
516
849
  if (openaiIncludes && openaiIncludes.length > 0) {
517
850
  for (const item of openaiIncludes) {
@@ -519,31 +852,57 @@ function getTools(tools, handoffs) {
519
852
  }
520
853
  }
521
854
  }
855
+ if (hasDeferredSearchableTool && !hasToolSearch) {
856
+ throw new agents_core_1.UserError('Deferred function tools and hosted MCP tools with deferLoading: true require toolSearchTool() in the same request.');
857
+ }
858
+ for (const [namespaceName, namespaceState,] of namespaceStateByName.entries()) {
859
+ openaiTools[namespaceState.index] = {
860
+ type: 'namespace',
861
+ name: namespaceName,
862
+ description: namespaceState.description,
863
+ tools: namespaceState.tools,
864
+ };
865
+ }
522
866
  return {
523
867
  tools: [...openaiTools, ...handoffs.map(getHandoffTool)],
524
868
  include,
525
869
  };
526
870
  }
527
- function converTool(tool) {
871
+ function converTool(tool, options) {
528
872
  if (tool.type === 'function') {
873
+ const openaiTool = {
874
+ type: 'function',
875
+ name: tool.name,
876
+ description: tool.description,
877
+ parameters: tool.parameters,
878
+ strict: tool.strict,
879
+ };
880
+ if (tool.deferLoading) {
881
+ openaiTool.defer_loading = true;
882
+ }
529
883
  return {
530
- tool: {
531
- type: 'function',
532
- name: tool.name,
533
- description: tool.description,
534
- parameters: tool.parameters,
535
- strict: tool.strict,
536
- },
884
+ tool: openaiTool,
537
885
  include: undefined,
538
886
  };
539
887
  }
540
888
  else if (tool.type === 'computer') {
889
+ if (options?.usePreviewComputerTool) {
890
+ if (!hasSerializedComputerDisplayMetadata(tool)) {
891
+ throw new agents_core_1.UserError('Preview computer tools require environment and dimensions. Provide them on your Computer implementation or target a GA computer model such as gpt-5.4.');
892
+ }
893
+ return {
894
+ tool: {
895
+ type: 'computer_use_preview',
896
+ environment: tool.environment,
897
+ display_width: tool.dimensions[0],
898
+ display_height: tool.dimensions[1],
899
+ },
900
+ include: undefined,
901
+ };
902
+ }
541
903
  return {
542
904
  tool: {
543
- type: 'computer_use_preview',
544
- environment: tool.environment,
545
- display_width: tool.dimensions[0],
546
- display_height: tool.dimensions[1],
905
+ type: 'computer',
547
906
  },
548
907
  include: undefined,
549
908
  };
@@ -614,6 +973,17 @@ function converTool(tool) {
614
973
  include: undefined,
615
974
  };
616
975
  }
976
+ else if (tool.providerData?.type === 'tool_search') {
977
+ return {
978
+ tool: {
979
+ type: 'tool_search',
980
+ execution: tool.providerData.execution,
981
+ description: tool.providerData.description,
982
+ parameters: tool.providerData.parameters,
983
+ },
984
+ include: undefined,
985
+ };
986
+ }
617
987
  else if (tool.providerData?.type === 'image_generation') {
618
988
  return {
619
989
  tool: {
@@ -633,17 +1003,22 @@ function converTool(tool) {
633
1003
  };
634
1004
  }
635
1005
  else if (tool.providerData?.type === 'mcp') {
1006
+ const openaiTool = {
1007
+ type: 'mcp',
1008
+ server_label: tool.providerData.server_label,
1009
+ server_url: tool.providerData.server_url,
1010
+ connector_id: tool.providerData.connector_id,
1011
+ authorization: tool.providerData.authorization,
1012
+ allowed_tools: tool.providerData.allowed_tools,
1013
+ headers: tool.providerData.headers,
1014
+ require_approval: convertMCPRequireApproval(tool.providerData.require_approval),
1015
+ server_description: tool.providerData.server_description,
1016
+ };
1017
+ if (tool.providerData.defer_loading === true) {
1018
+ openaiTool.defer_loading = true;
1019
+ }
636
1020
  return {
637
- tool: {
638
- type: 'mcp',
639
- server_label: tool.providerData.server_label,
640
- server_url: tool.providerData.server_url,
641
- connector_id: tool.providerData.connector_id,
642
- authorization: tool.providerData.authorization,
643
- allowed_tools: tool.providerData.allowed_tools,
644
- headers: tool.providerData.headers,
645
- require_approval: convertMCPRequireApproval(tool.providerData.require_approval),
646
- },
1021
+ tool: openaiTool,
647
1022
  include: undefined,
648
1023
  };
649
1024
  }
@@ -682,7 +1057,10 @@ function getInputMessageContent(entry) {
682
1057
  return {
683
1058
  type: 'input_text',
684
1059
  text: entry.text,
685
- ...(0, providerData_1.camelOrSnakeToSnakeCase)(entry.providerData),
1060
+ ...(0, providerData_1.getSnakeCasedProviderDataWithoutReservedKeys)(entry.providerData, [
1061
+ 'type',
1062
+ 'text',
1063
+ ]),
686
1064
  };
687
1065
  }
688
1066
  else if (entry.type === 'input_image') {
@@ -704,7 +1082,12 @@ function getInputMessageContent(entry) {
704
1082
  }
705
1083
  return {
706
1084
  ...imageEntry,
707
- ...(0, providerData_1.camelOrSnakeToSnakeCase)(entry.providerData),
1085
+ ...(0, providerData_1.getSnakeCasedProviderDataWithoutReservedKeys)(entry.providerData, [
1086
+ 'type',
1087
+ 'detail',
1088
+ 'image_url',
1089
+ 'file_id',
1090
+ ]),
708
1091
  };
709
1092
  }
710
1093
  else if (entry.type === 'input_file') {
@@ -749,25 +1132,54 @@ function getInputMessageContent(entry) {
749
1132
  }
750
1133
  return {
751
1134
  ...fileEntry,
752
- ...(0, providerData_1.camelOrSnakeToSnakeCase)(entry.providerData),
1135
+ ...(0, providerData_1.getSnakeCasedProviderDataWithoutReservedKeys)(entry.providerData, [
1136
+ 'type',
1137
+ 'file_data',
1138
+ 'file_url',
1139
+ 'file_id',
1140
+ 'filename',
1141
+ ]),
753
1142
  };
754
1143
  }
755
1144
  throw new agents_core_1.UserError(`Unsupported input content type: ${JSON.stringify(entry)}`);
756
1145
  }
1146
+ function getProviderDataField(providerData, keys) {
1147
+ if (!providerData ||
1148
+ typeof providerData !== 'object' ||
1149
+ Array.isArray(providerData)) {
1150
+ return undefined;
1151
+ }
1152
+ const record = providerData;
1153
+ for (const key of keys) {
1154
+ if (typeof record[key] !== 'undefined') {
1155
+ return record[key];
1156
+ }
1157
+ }
1158
+ return undefined;
1159
+ }
757
1160
  function getOutputMessageContent(entry) {
758
1161
  if (entry.type === 'output_text') {
1162
+ const annotations = getProviderDataField(entry.providerData, ['annotations']);
1163
+ const normalizedAnnotations = Array.isArray(annotations) ? annotations : [];
759
1164
  return {
760
1165
  type: 'output_text',
761
1166
  text: entry.text,
762
- annotations: [],
763
- ...(0, providerData_1.camelOrSnakeToSnakeCase)(entry.providerData),
1167
+ annotations: normalizedAnnotations,
1168
+ ...(0, providerData_1.getSnakeCasedProviderDataWithoutReservedKeys)(entry.providerData, [
1169
+ 'type',
1170
+ 'text',
1171
+ 'annotations',
1172
+ ]),
764
1173
  };
765
1174
  }
766
1175
  if (entry.type === 'refusal') {
767
1176
  return {
768
1177
  type: 'refusal',
769
1178
  refusal: entry.refusal,
770
- ...(0, providerData_1.camelOrSnakeToSnakeCase)(entry.providerData),
1179
+ ...(0, providerData_1.getSnakeCasedProviderDataWithoutReservedKeys)(entry.providerData, [
1180
+ 'type',
1181
+ 'refusal',
1182
+ ]),
771
1183
  };
772
1184
  }
773
1185
  throw new agents_core_1.UserError(`Unsupported output content type: ${JSON.stringify(entry)}`);
@@ -778,7 +1190,11 @@ function getMessageItem(item) {
778
1190
  id: item.id,
779
1191
  role: 'system',
780
1192
  content: item.content,
781
- ...(0, providerData_1.camelOrSnakeToSnakeCase)(item.providerData),
1193
+ ...(0, providerData_1.getSnakeCasedProviderDataWithoutReservedKeys)(item.providerData, [
1194
+ 'id',
1195
+ 'role',
1196
+ 'content',
1197
+ ]),
782
1198
  };
783
1199
  }
784
1200
  if (item.role === 'user') {
@@ -787,14 +1203,22 @@ function getMessageItem(item) {
787
1203
  id: item.id,
788
1204
  role: 'user',
789
1205
  content: item.content,
790
- ...(0, providerData_1.camelOrSnakeToSnakeCase)(item.providerData),
1206
+ ...(0, providerData_1.getSnakeCasedProviderDataWithoutReservedKeys)(item.providerData, [
1207
+ 'id',
1208
+ 'role',
1209
+ 'content',
1210
+ ]),
791
1211
  };
792
1212
  }
793
1213
  return {
794
1214
  id: item.id,
795
1215
  role: 'user',
796
1216
  content: item.content.map(getInputMessageContent),
797
- ...(0, providerData_1.camelOrSnakeToSnakeCase)(item.providerData),
1217
+ ...(0, providerData_1.getSnakeCasedProviderDataWithoutReservedKeys)(item.providerData, [
1218
+ 'id',
1219
+ 'role',
1220
+ 'content',
1221
+ ]),
798
1222
  };
799
1223
  }
800
1224
  if (item.role === 'assistant') {
@@ -804,7 +1228,13 @@ function getMessageItem(item) {
804
1228
  role: 'assistant',
805
1229
  content: item.content.map(getOutputMessageContent),
806
1230
  status: item.status,
807
- ...(0, providerData_1.camelOrSnakeToSnakeCase)(item.providerData),
1231
+ ...(0, providerData_1.getSnakeCasedProviderDataWithoutReservedKeys)(item.providerData, [
1232
+ 'type',
1233
+ 'id',
1234
+ 'role',
1235
+ 'content',
1236
+ 'status',
1237
+ ]),
808
1238
  };
809
1239
  return assistantMessage;
810
1240
  }
@@ -851,6 +1281,52 @@ function getInputItems(input) {
851
1281
  if (isMessageItem(item)) {
852
1282
  return getMessageItem(item);
853
1283
  }
1284
+ if (item.type === 'tool_search_call') {
1285
+ const status = normalizeToolSearchStatus(item.status);
1286
+ const callId = (0, utils_1.getToolSearchProviderCallId)(item);
1287
+ const execution = (0, utils_1.getToolSearchExecution)(item);
1288
+ const toolSearchCall = {
1289
+ type: 'tool_search_call',
1290
+ id: item.id,
1291
+ ...(status !== null ? { status } : {}),
1292
+ arguments: item.arguments,
1293
+ ...(callId ? { call_id: callId } : {}),
1294
+ ...(execution ? { execution } : {}),
1295
+ ...(0, providerData_1.getSnakeCasedProviderDataWithoutReservedKeys)(item.providerData, [
1296
+ 'type',
1297
+ 'id',
1298
+ 'status',
1299
+ 'arguments',
1300
+ 'call_id',
1301
+ 'callId',
1302
+ 'execution',
1303
+ ]),
1304
+ };
1305
+ return toolSearchCall;
1306
+ }
1307
+ if (item.type === 'tool_search_output') {
1308
+ const status = normalizeToolSearchStatus(item.status);
1309
+ const callId = (0, utils_1.getToolSearchProviderCallId)(item);
1310
+ const execution = (0, utils_1.getToolSearchExecution)(item);
1311
+ const toolSearchOutput = {
1312
+ type: 'tool_search_output',
1313
+ id: item.id,
1314
+ ...(status !== null ? { status } : {}),
1315
+ tools: item.tools.map((tool) => toOpenAIToolSearchOutputToolPayload(tool)),
1316
+ ...(callId ? { call_id: callId } : {}),
1317
+ ...(execution ? { execution } : {}),
1318
+ ...(0, providerData_1.getSnakeCasedProviderDataWithoutReservedKeys)(item.providerData, [
1319
+ 'type',
1320
+ 'id',
1321
+ 'status',
1322
+ 'tools',
1323
+ 'call_id',
1324
+ 'callId',
1325
+ 'execution',
1326
+ ]),
1327
+ };
1328
+ return toolSearchOutput;
1329
+ }
854
1330
  if (item.type === 'function_call') {
855
1331
  const entry = {
856
1332
  id: item.id,
@@ -859,7 +1335,18 @@ function getInputItems(input) {
859
1335
  call_id: item.callId,
860
1336
  arguments: item.arguments,
861
1337
  status: item.status,
862
- ...(0, providerData_1.camelOrSnakeToSnakeCase)(item.providerData),
1338
+ ...(typeof item.namespace === 'string'
1339
+ ? { namespace: item.namespace }
1340
+ : {}),
1341
+ ...(0, providerData_1.getSnakeCasedProviderDataWithoutReservedKeys)(item.providerData, [
1342
+ 'id',
1343
+ 'type',
1344
+ 'name',
1345
+ 'call_id',
1346
+ 'arguments',
1347
+ 'status',
1348
+ 'namespace',
1349
+ ]),
863
1350
  };
864
1351
  return entry;
865
1352
  }
@@ -871,45 +1358,98 @@ function getInputItems(input) {
871
1358
  call_id: item.callId,
872
1359
  output: normalizedOutput,
873
1360
  status: item.status,
874
- ...(0, providerData_1.camelOrSnakeToSnakeCase)(item.providerData),
1361
+ ...(0, providerData_1.getSnakeCasedProviderDataWithoutReservedKeys)(item.providerData, [
1362
+ 'type',
1363
+ 'id',
1364
+ 'call_id',
1365
+ 'output',
1366
+ 'status',
1367
+ 'namespace',
1368
+ ]),
875
1369
  };
876
1370
  return entry;
877
1371
  }
878
1372
  if (item.type === 'reasoning') {
1373
+ const encryptedContent = getProviderDataField(item.providerData, [
1374
+ 'encryptedContent',
1375
+ 'encrypted_content',
1376
+ ]);
879
1377
  const entry = {
880
1378
  id: item.id,
881
1379
  type: 'reasoning',
882
1380
  summary: item.content.map((content) => ({
883
1381
  type: 'summary_text',
884
1382
  text: content.text,
885
- ...(0, providerData_1.camelOrSnakeToSnakeCase)(content.providerData),
1383
+ ...(0, providerData_1.getSnakeCasedProviderDataWithoutReservedKeys)(content.providerData, ['type', 'text']),
886
1384
  })),
887
- encrypted_content: item.providerData?.encryptedContent,
888
- ...(0, providerData_1.camelOrSnakeToSnakeCase)(item.providerData),
1385
+ ...(typeof encryptedContent === 'string'
1386
+ ? { encrypted_content: encryptedContent }
1387
+ : {}),
1388
+ ...(0, providerData_1.getSnakeCasedProviderDataWithoutReservedKeys)(item.providerData, [
1389
+ 'id',
1390
+ 'type',
1391
+ 'summary',
1392
+ 'encrypted_content',
1393
+ ]),
889
1394
  };
890
1395
  return entry;
891
1396
  }
892
1397
  if (item.type === 'computer_call') {
1398
+ const pendingSafetyChecks = getProviderDataField(item.providerData, ['pendingSafetyChecks', 'pending_safety_checks']);
1399
+ const normalizedPendingSafetyChecks = Array.isArray(pendingSafetyChecks) ? pendingSafetyChecks : [];
1400
+ const batchedActions = Array.isArray(item.actions)
1401
+ ? (item
1402
+ .actions ?? [])
1403
+ : [];
1404
+ const actionPayload = batchedActions.length > 0
1405
+ ? {
1406
+ action: item.action ?? batchedActions[0],
1407
+ actions: batchedActions,
1408
+ }
1409
+ : item.action
1410
+ ? { action: item.action }
1411
+ : {};
893
1412
  const entry = {
894
1413
  type: 'computer_call',
895
1414
  call_id: item.callId,
896
1415
  id: item.id,
897
- action: item.action,
898
1416
  status: item.status,
899
- pending_safety_checks: [],
900
- ...(0, providerData_1.camelOrSnakeToSnakeCase)(item.providerData),
1417
+ pending_safety_checks: normalizedPendingSafetyChecks,
1418
+ ...actionPayload,
1419
+ ...(0, providerData_1.getSnakeCasedProviderDataWithoutReservedKeys)(item.providerData, [
1420
+ 'type',
1421
+ 'call_id',
1422
+ 'id',
1423
+ 'action',
1424
+ 'actions',
1425
+ 'status',
1426
+ 'pending_safety_checks',
1427
+ ]),
901
1428
  };
902
1429
  return entry;
903
1430
  }
904
1431
  if (item.type === 'computer_call_result') {
1432
+ const acknowledgedSafetyChecks = getProviderDataField(item.providerData, [
1433
+ 'acknowledgedSafetyChecks',
1434
+ 'acknowledged_safety_checks',
1435
+ ]);
905
1436
  const entry = {
906
1437
  type: 'computer_call_output',
907
1438
  id: item.id,
908
1439
  call_id: item.callId,
909
1440
  output: buildResponseOutput(item),
910
1441
  status: item.providerData?.status,
911
- acknowledged_safety_checks: item.providerData?.acknowledgedSafetyChecks,
912
- ...(0, providerData_1.camelOrSnakeToSnakeCase)(item.providerData),
1442
+ acknowledged_safety_checks: Array.isArray(acknowledgedSafetyChecks)
1443
+ ? acknowledgedSafetyChecks
1444
+ : [],
1445
+ ...(0, providerData_1.getSnakeCasedProviderDataWithoutReservedKeys)(item.providerData, [
1446
+ 'type',
1447
+ 'id',
1448
+ 'call_id',
1449
+ 'output',
1450
+ 'status',
1451
+ 'acknowledged_safety_checks',
1452
+ ]),
913
1453
  };
914
1454
  return entry;
915
1455
  }
@@ -1162,6 +1702,30 @@ function convertToOutputItem(items) {
1162
1702
  providerData,
1163
1703
  };
1164
1704
  }
1705
+ else if (item.type === 'tool_search_call') {
1706
+ const { id, type: _type, status, arguments: args, ...providerData } = item;
1707
+ const output = {
1708
+ type: 'tool_search_call',
1709
+ id,
1710
+ status,
1711
+ arguments: args,
1712
+ providerData,
1713
+ };
1714
+ return output;
1715
+ }
1716
+ else if (item.type === 'tool_search_output') {
1717
+ const { id, type: _type, status, tools, ...providerData } = item;
1718
+ const output = {
1719
+ type: 'tool_search_output',
1720
+ id,
1721
+ status,
1722
+ tools: Array.isArray(tools)
1723
+ ? tools.map((tool) => fromOpenAIToolSearchOutputToolPayload(tool))
1724
+ : [],
1725
+ providerData,
1726
+ };
1727
+ return output;
1728
+ }
1165
1729
  else if (item.type === 'file_search_call' ||
1166
1730
  item.type === 'web_search_call' ||
1167
1731
  item.type === 'image_generation_call' ||
@@ -1184,12 +1748,14 @@ function convertToOutputItem(items) {
1184
1748
  return output;
1185
1749
  }
1186
1750
  else if (item.type === 'function_call') {
1187
- const { call_id, name, status, arguments: args, ...providerData } = item;
1751
+ const functionCall = item;
1752
+ const { call_id, name, namespace, status, arguments: args, ...providerData } = functionCall;
1188
1753
  const output = {
1189
1754
  type: 'function_call',
1190
- id: item.id,
1755
+ id: functionCall.id,
1191
1756
  callId: call_id,
1192
1757
  name,
1758
+ ...(typeof namespace === 'string' ? { namespace } : {}),
1193
1759
  status,
1194
1760
  arguments: args,
1195
1761
  providerData,
@@ -1197,12 +1763,13 @@ function convertToOutputItem(items) {
1197
1763
  return output;
1198
1764
  }
1199
1765
  else if (item.type === 'function_call_output') {
1200
- const { call_id, status, output: rawOutput, name: toolName, function_name: functionName, ...providerData } = item;
1766
+ const { call_id, status, output: rawOutput, name: toolName, function_name: functionName, namespace, ...providerData } = item;
1201
1767
  const output = {
1202
1768
  type: 'function_call_result',
1203
1769
  id: item.id,
1204
1770
  callId: call_id,
1205
1771
  name: toolName ?? functionName ?? call_id,
1772
+ ...(typeof namespace === 'string' ? { namespace } : {}),
1206
1773
  status: status ?? 'completed',
1207
1774
  output: convertFunctionCallOutputToProtocol(rawOutput),
1208
1775
  providerData,
@@ -1210,13 +1777,18 @@ function convertToOutputItem(items) {
1210
1777
  return output;
1211
1778
  }
1212
1779
  else if (item.type === 'computer_call') {
1213
- const { call_id, status, action, ...providerData } = item;
1780
+ const { call_id, status, action, actions, ...providerData } = item;
1781
+ const normalizedActions = Array.isArray(actions) && actions.length > 0 ? actions : undefined;
1782
+ if (!normalizedActions && !action) {
1783
+ throw new agents_core_1.UserError(`Unsupported computer call item without an action or actions: ${JSON.stringify(item)}`);
1784
+ }
1214
1785
  const output = {
1215
1786
  type: 'computer_call',
1216
1787
  id: item.id,
1217
1788
  callId: call_id,
1218
1789
  status,
1219
- action,
1790
+ action: action ?? normalizedActions?.[0],
1791
+ ...(normalizedActions ? { actions: normalizedActions } : {}),
1220
1792
  providerData,
1221
1793
  };
1222
1794
  return output;
@@ -1495,9 +2067,30 @@ class OpenAIResponsesModel {
1495
2067
  }
1496
2068
  _buildResponsesCreateRequest(request, stream) {
1497
2069
  const input = getInputItems(request.input);
1498
- const { tools, include } = getTools(request.tools, request.handoffs);
1499
- const toolChoice = getToolChoice(request.modelSettings.toolChoice);
2070
+ const prompt = getPrompt(request.prompt);
2071
+ // When a prompt template already declares a model, skip sending the agent's default model.
2072
+ // If the caller explicitly requests an override, include the resolved model name in the request.
2073
+ const shouldSendModel = !request.prompt || request.overridePromptModel === true;
2074
+ const effectiveRequestModel = shouldSendModel ? this._model : undefined;
1500
2075
  const { providerData: providerDataWithoutTransport, overrides: transportOverrides, } = (0, responsesTransportUtils_1.splitResponsesTransportOverrides)(request.modelSettings.providerData);
2076
+ const { tools, include } = getTools(request.tools, request.handoffs, {
2077
+ model: effectiveRequestModel,
2078
+ toolChoice: request.modelSettings.toolChoice,
2079
+ });
2080
+ const toolChoiceValidationTools = [
2081
+ ...tools,
2082
+ ...getExtraBodyToolsForToolChoiceValidation(transportOverrides.extraBody),
2083
+ ];
2084
+ const allowPromptSuppliedTools = Boolean(request.prompt) &&
2085
+ !(request.toolsExplicitlyProvided === true && tools.length === 0);
2086
+ const toolChoice = getToolChoice(request.modelSettings.toolChoice, {
2087
+ tools: toolChoiceValidationTools,
2088
+ model: effectiveRequestModel,
2089
+ allowPromptSuppliedComputerTool: allowPromptSuppliedTools,
2090
+ });
2091
+ assertSupportedToolChoice(toolChoice, toolChoiceValidationTools, {
2092
+ allowPromptSuppliedTools,
2093
+ });
1501
2094
  const { text, ...restOfProviderData } = providerDataWithoutTransport;
1502
2095
  if (request.modelSettings.reasoning) {
1503
2096
  // Merge top-level reasoning settings with provider data.
@@ -1512,25 +2105,19 @@ class OpenAIResponsesModel {
1512
2105
  mergedText = { ...request.modelSettings.text, ...text };
1513
2106
  }
1514
2107
  const responseFormat = getResponseFormat(request.outputType, mergedText);
1515
- const prompt = getPrompt(request.prompt);
1516
2108
  let parallelToolCalls = undefined;
1517
2109
  if (typeof request.modelSettings.parallelToolCalls === 'boolean') {
1518
- if (request.modelSettings.parallelToolCalls && tools.length === 0) {
1519
- throw new Error('Parallel tool calls are not supported without tools');
1520
- }
1521
2110
  parallelToolCalls = request.modelSettings.parallelToolCalls;
1522
2111
  }
1523
- // When a prompt template already declares a model, skip sending the agent's default model.
1524
- // If the caller explicitly requests an override, include the resolved model name in the request.
1525
- const shouldSendModel = !request.prompt || request.overridePromptModel === true;
1526
2112
  const shouldSendTools = tools.length > 0 ||
1527
2113
  request.toolsExplicitlyProvided === true ||
1528
2114
  !request.prompt;
1529
- const shouldOmitToolChoice = Boolean(request.prompt) &&
1530
- !shouldSendTools &&
1531
- typeof toolChoice === 'object';
2115
+ const compatibleToolChoice = getCompatibleToolChoice(toolChoice, toolChoiceValidationTools, {
2116
+ allowPromptSuppliedTools,
2117
+ });
2118
+ const shouldOmitToolChoice = typeof compatibleToolChoice === 'undefined';
1532
2119
  let requestData = {
1533
- ...(shouldSendModel ? { model: this._model } : {}),
2120
+ ...(effectiveRequestModel ? { model: effectiveRequestModel } : {}),
1534
2121
  instructions: normalizeInstructions(request.systemInstructions),
1535
2122
  input,
1536
2123
  include,
@@ -1547,7 +2134,7 @@ class OpenAIResponsesModel {
1547
2134
  truncation: request.modelSettings.truncation,
1548
2135
  max_output_tokens: request.modelSettings.maxTokens,
1549
2136
  ...(!shouldOmitToolChoice
1550
- ? { tool_choice: toolChoice }
2137
+ ? { tool_choice: compatibleToolChoice }
1551
2138
  : {}),
1552
2139
  parallel_tool_calls: parallelToolCalls,
1553
2140
  stream,