@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.
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/metadata.js +3 -3
- package/dist/metadata.mjs +3 -3
- package/dist/openaiChatCompletionsConverter.d.ts +1 -0
- package/dist/openaiChatCompletionsConverter.js +122 -16
- package/dist/openaiChatCompletionsConverter.js.map +1 -1
- package/dist/openaiChatCompletionsConverter.mjs +121 -16
- package/dist/openaiChatCompletionsConverter.mjs.map +1 -1
- package/dist/openaiChatCompletionsModel.js +10 -1
- package/dist/openaiChatCompletionsModel.js.map +1 -1
- package/dist/openaiChatCompletionsModel.mjs +12 -3
- package/dist/openaiChatCompletionsModel.mjs.map +1 -1
- package/dist/openaiResponsesModel.d.ts +16 -4
- package/dist/openaiResponsesModel.js +654 -67
- package/dist/openaiResponsesModel.js.map +1 -1
- package/dist/openaiResponsesModel.mjs +656 -69
- package/dist/openaiResponsesModel.mjs.map +1 -1
- package/dist/tools.d.ts +22 -1
- package/dist/tools.js +38 -0
- package/dist/tools.js.map +1 -1
- package/dist/tools.mjs +37 -0
- package/dist/tools.mjs.map +1 -1
- package/dist/types/providerData.d.ts +4 -0
- package/dist/utils/providerData.d.ts +26 -2
- package/dist/utils/providerData.js +60 -8
- package/dist/utils/providerData.js.map +1 -1
- package/dist/utils/providerData.mjs +57 -8
- package/dist/utils/providerData.mjs.map +1 -1
- package/package.json +3 -3
|
@@ -6,8 +6,80 @@ import { HEADERS } from "./defaults.mjs";
|
|
|
6
6
|
import { ResponsesWebSocketConnection, ResponsesWebSocketInternalError, isWebSocketNotOpenError, shouldWrapNoEventWebSocketError, throwIfAborted, webSocketFrameToText, withAbortSignal, withTimeout, } from "./responsesWebSocketConnection.mjs";
|
|
7
7
|
import { applyHeadersToAccumulator, createHeaderAccumulator, ensureResponsesWebSocketPath, headerAccumulatorToRecord, headerAccumulatorToSDKHeaders, mergeQueryParamsIntoURL, splitResponsesTransportOverrides, } from "./responsesTransportUtils.mjs";
|
|
8
8
|
import { CodeInterpreterStatus, FileSearchStatus, ImageGenerationStatus, WebSearchStatus, } from "./tools.mjs";
|
|
9
|
-
import { camelOrSnakeToSnakeCase } from "./utils/providerData.mjs";
|
|
10
|
-
import { encodeUint8ArrayToBase64 } from '@openai/agents-core/utils';
|
|
9
|
+
import { camelOrSnakeToSnakeCase, getSnakeCasedProviderDataWithoutReservedKeys, } from "./utils/providerData.mjs";
|
|
10
|
+
import { encodeUint8ArrayToBase64, getToolSearchExecution, getToolSearchProviderCallId, } from '@openai/agents-core/utils';
|
|
11
|
+
/**
|
|
12
|
+
* Tool search outputs are replayed through agents-core protocol items, which use camelCase
|
|
13
|
+
* field names, while the Responses API wire shape uses snake_case. Keep this codec even with
|
|
14
|
+
* first-class upstream types because the local protocol still normalizes these payloads.
|
|
15
|
+
*/
|
|
16
|
+
function toOpenAIToolSearchOutputToolPayload(tool, _withinNamespace = false) {
|
|
17
|
+
if (!tool || typeof tool !== 'object' || Array.isArray(tool)) {
|
|
18
|
+
return tool;
|
|
19
|
+
}
|
|
20
|
+
if (tool.type === 'tool_reference' && typeof tool.functionName === 'string') {
|
|
21
|
+
return {
|
|
22
|
+
type: 'tool_reference',
|
|
23
|
+
function_name: tool.functionName,
|
|
24
|
+
...(typeof tool.namespace === 'string'
|
|
25
|
+
? { namespace: tool.namespace }
|
|
26
|
+
: {}),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
if (tool.type === 'namespace' && Array.isArray(tool.tools)) {
|
|
30
|
+
return {
|
|
31
|
+
...tool,
|
|
32
|
+
tools: tool.tools.map((entry) => toOpenAIToolSearchOutputToolPayload(entry, true)),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
if (tool.type === 'function') {
|
|
36
|
+
const { deferLoading, ...rest } = tool;
|
|
37
|
+
return {
|
|
38
|
+
...rest,
|
|
39
|
+
...(typeof deferLoading === 'boolean'
|
|
40
|
+
? { defer_loading: deferLoading }
|
|
41
|
+
: {}),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
return tool;
|
|
45
|
+
}
|
|
46
|
+
function fromOpenAIToolSearchOutputToolPayload(tool, _withinNamespace = false) {
|
|
47
|
+
if (!tool || typeof tool !== 'object' || Array.isArray(tool)) {
|
|
48
|
+
return tool;
|
|
49
|
+
}
|
|
50
|
+
if (tool.type === 'tool_reference' &&
|
|
51
|
+
typeof tool.function_name === 'string') {
|
|
52
|
+
return {
|
|
53
|
+
type: 'tool_reference',
|
|
54
|
+
functionName: tool.function_name,
|
|
55
|
+
...(typeof tool.namespace === 'string'
|
|
56
|
+
? { namespace: tool.namespace }
|
|
57
|
+
: {}),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
if (tool.type === 'namespace' && Array.isArray(tool.tools)) {
|
|
61
|
+
return {
|
|
62
|
+
...tool,
|
|
63
|
+
tools: tool.tools.map((entry) => fromOpenAIToolSearchOutputToolPayload(entry, true)),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
if (tool.type === 'function') {
|
|
67
|
+
const { defer_loading, ...rest } = tool;
|
|
68
|
+
return {
|
|
69
|
+
...rest,
|
|
70
|
+
...(typeof defer_loading === 'boolean'
|
|
71
|
+
? { deferLoading: defer_loading }
|
|
72
|
+
: {}),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
return tool;
|
|
76
|
+
}
|
|
77
|
+
function hasSerializedComputerDisplayMetadata(tool) {
|
|
78
|
+
return (typeof tool.environment === 'string' &&
|
|
79
|
+
Array.isArray(tool.dimensions) &&
|
|
80
|
+
tool.dimensions.length === 2 &&
|
|
81
|
+
tool.dimensions.every((value) => typeof value === 'number'));
|
|
82
|
+
}
|
|
11
83
|
const HostedToolChoice = z.enum([
|
|
12
84
|
'file_search',
|
|
13
85
|
'web_search',
|
|
@@ -16,12 +88,16 @@ const HostedToolChoice = z.enum([
|
|
|
16
88
|
'image_generation',
|
|
17
89
|
'mcp',
|
|
18
90
|
// Specialized local tools
|
|
19
|
-
'computer_use_preview',
|
|
20
91
|
'shell',
|
|
21
92
|
'apply_patch',
|
|
22
93
|
]);
|
|
23
94
|
const DefaultToolChoice = z.enum(['auto', 'required', 'none']);
|
|
24
|
-
|
|
95
|
+
const BuiltinComputerToolChoice = z.enum([
|
|
96
|
+
'computer',
|
|
97
|
+
'computer_use',
|
|
98
|
+
'computer_use_preview',
|
|
99
|
+
]);
|
|
100
|
+
function getToolChoice(toolChoice, options) {
|
|
25
101
|
if (typeof toolChoice === 'undefined') {
|
|
26
102
|
return undefined;
|
|
27
103
|
}
|
|
@@ -29,12 +105,202 @@ function getToolChoice(toolChoice) {
|
|
|
29
105
|
if (resultDefaultCheck.success) {
|
|
30
106
|
return resultDefaultCheck.data;
|
|
31
107
|
}
|
|
108
|
+
const builtinComputerToolChoice = BuiltinComputerToolChoice.safeParse(toolChoice);
|
|
109
|
+
if (builtinComputerToolChoice.success) {
|
|
110
|
+
if (hasBuiltinComputerTool(options?.tools) ||
|
|
111
|
+
options?.allowPromptSuppliedComputerTool === true) {
|
|
112
|
+
return getBuiltinComputerToolChoice(builtinComputerToolChoice.data, {
|
|
113
|
+
model: options?.model,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
if (builtinComputerToolChoice.data === 'computer_use_preview') {
|
|
117
|
+
return { type: 'computer_use_preview' };
|
|
118
|
+
}
|
|
119
|
+
return { type: 'function', name: builtinComputerToolChoice.data };
|
|
120
|
+
}
|
|
32
121
|
const result = HostedToolChoice.safeParse(toolChoice);
|
|
33
122
|
if (result.success) {
|
|
34
123
|
return { type: result.data };
|
|
35
124
|
}
|
|
36
125
|
return { type: 'function', name: toolChoice };
|
|
37
126
|
}
|
|
127
|
+
function normalizeToolSearchStatus(status) {
|
|
128
|
+
return status === 'in_progress' ||
|
|
129
|
+
status === 'completed' ||
|
|
130
|
+
status === 'incomplete'
|
|
131
|
+
? status
|
|
132
|
+
: null;
|
|
133
|
+
}
|
|
134
|
+
function hasBuiltinComputerTool(tools) {
|
|
135
|
+
return (tools ?? []).some((tool) => tool.type === 'computer' ||
|
|
136
|
+
tool.type === 'computer_use' ||
|
|
137
|
+
tool.type === 'computer_use_preview');
|
|
138
|
+
}
|
|
139
|
+
function isPreviewComputerModel(model) {
|
|
140
|
+
return typeof model === 'string' && model.startsWith('computer-use-preview');
|
|
141
|
+
}
|
|
142
|
+
function shouldUsePreviewComputerTool(options) {
|
|
143
|
+
if (isPreviewComputerModel(options?.model)) {
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
if (typeof options?.model === 'string') {
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
if (options?.toolChoice === 'computer' ||
|
|
150
|
+
options?.toolChoice === 'computer_use') {
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
return true;
|
|
154
|
+
}
|
|
155
|
+
function getBuiltinComputerToolChoice(toolChoice, options) {
|
|
156
|
+
if (shouldUsePreviewComputerTool({
|
|
157
|
+
model: options?.model,
|
|
158
|
+
toolChoice,
|
|
159
|
+
})) {
|
|
160
|
+
return { type: 'computer_use_preview' };
|
|
161
|
+
}
|
|
162
|
+
if (toolChoice === 'computer_use') {
|
|
163
|
+
return { type: 'computer_use' };
|
|
164
|
+
}
|
|
165
|
+
return { type: 'computer' };
|
|
166
|
+
}
|
|
167
|
+
function isBuiltinComputerToolType(type) {
|
|
168
|
+
return (type === 'computer' ||
|
|
169
|
+
type === 'computer_use' ||
|
|
170
|
+
type === 'computer_use_preview');
|
|
171
|
+
}
|
|
172
|
+
function isCompatibleBuiltinComputerToolChoice(toolChoiceType, toolType) {
|
|
173
|
+
if (!isBuiltinComputerToolType(toolChoiceType)) {
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
if (toolChoiceType === 'computer_use_preview') {
|
|
177
|
+
return toolType === 'computer_use_preview';
|
|
178
|
+
}
|
|
179
|
+
return toolType === 'computer';
|
|
180
|
+
}
|
|
181
|
+
function isToolChoiceAvailable(toolChoice, tools) {
|
|
182
|
+
if (toolChoice === 'auto' || toolChoice === 'none') {
|
|
183
|
+
return true;
|
|
184
|
+
}
|
|
185
|
+
if (toolChoice === 'required') {
|
|
186
|
+
return tools.length > 0;
|
|
187
|
+
}
|
|
188
|
+
if (toolChoice.type === 'function') {
|
|
189
|
+
return hasFunctionToolChoiceName(toolChoice.name, tools);
|
|
190
|
+
}
|
|
191
|
+
return tools.some((tool) => isCompatibleBuiltinComputerToolChoice(toolChoice.type, tool.type)
|
|
192
|
+
? true
|
|
193
|
+
: tool.type === toolChoice.type);
|
|
194
|
+
}
|
|
195
|
+
function hasFunctionToolChoiceName(toolChoiceName, tools, namespacePrefix) {
|
|
196
|
+
return (findFunctionToolChoice(toolChoiceName, tools, namespacePrefix) !== undefined);
|
|
197
|
+
}
|
|
198
|
+
function findFunctionToolChoice(toolChoiceName, tools, namespacePrefix) {
|
|
199
|
+
for (const tool of tools) {
|
|
200
|
+
if (isNamedFunctionTool(tool)) {
|
|
201
|
+
const qualifiedName = namespacePrefix
|
|
202
|
+
? `${namespacePrefix}.${tool.name}`
|
|
203
|
+
: tool.name;
|
|
204
|
+
if (toolChoiceName === qualifiedName) {
|
|
205
|
+
return tool;
|
|
206
|
+
}
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
if (isNamespaceTool(tool)) {
|
|
210
|
+
const nestedNamespace = namespacePrefix
|
|
211
|
+
? `${namespacePrefix}.${tool.name}`
|
|
212
|
+
: tool.name;
|
|
213
|
+
const matchedTool = findFunctionToolChoice(toolChoiceName, tool.tools, nestedNamespace);
|
|
214
|
+
if (matchedTool) {
|
|
215
|
+
return matchedTool;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return undefined;
|
|
220
|
+
}
|
|
221
|
+
function collectAvailableToolChoiceNames(tools, namespacePrefix) {
|
|
222
|
+
const availableToolChoices = [];
|
|
223
|
+
for (const tool of tools) {
|
|
224
|
+
if (isNamedFunctionTool(tool)) {
|
|
225
|
+
availableToolChoices.push(namespacePrefix ? `${namespacePrefix}.${tool.name}` : tool.name);
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
if (isNamespaceTool(tool)) {
|
|
229
|
+
const nestedNamespace = namespacePrefix
|
|
230
|
+
? `${namespacePrefix}.${tool.name}`
|
|
231
|
+
: tool.name;
|
|
232
|
+
availableToolChoices.push(...collectAvailableToolChoiceNames(tool.tools, nestedNamespace));
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
availableToolChoices.push(tool.type);
|
|
236
|
+
}
|
|
237
|
+
return availableToolChoices;
|
|
238
|
+
}
|
|
239
|
+
function isNamedFunctionTool(tool) {
|
|
240
|
+
return (tool.type === 'function' &&
|
|
241
|
+
typeof tool.name === 'string');
|
|
242
|
+
}
|
|
243
|
+
function isNamespaceTool(tool) {
|
|
244
|
+
const candidate = tool;
|
|
245
|
+
return (tool.type === 'namespace' &&
|
|
246
|
+
typeof candidate.name === 'string' &&
|
|
247
|
+
Array.isArray(candidate.tools));
|
|
248
|
+
}
|
|
249
|
+
function getExtraBodyToolsForToolChoiceValidation(extraBody) {
|
|
250
|
+
if (!extraBody || !Array.isArray(extraBody.tools)) {
|
|
251
|
+
return [];
|
|
252
|
+
}
|
|
253
|
+
return extraBody.tools;
|
|
254
|
+
}
|
|
255
|
+
function assertSupportedToolChoice(toolChoice, tools, options) {
|
|
256
|
+
const allowPromptSuppliedTools = options?.allowPromptSuppliedTools === true;
|
|
257
|
+
if (!toolChoice ||
|
|
258
|
+
toolChoice === 'auto' ||
|
|
259
|
+
toolChoice === 'required' ||
|
|
260
|
+
toolChoice === 'none' ||
|
|
261
|
+
toolChoice.type !== 'function') {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
const matchedFunctionTool = findFunctionToolChoice(toolChoice.name, tools);
|
|
265
|
+
if (!matchedFunctionTool &&
|
|
266
|
+
allowPromptSuppliedTools &&
|
|
267
|
+
toolChoice.name !== 'tool_search') {
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
if (matchedFunctionTool
|
|
271
|
+
?.defer_loading === true) {
|
|
272
|
+
throw new UserError(`modelSettings.toolChoice="${toolChoice.name}" cannot force a deferred function tool in Responses. Use "auto" so tool_search can load it.`);
|
|
273
|
+
}
|
|
274
|
+
if (toolChoice.name === 'tool_search' &&
|
|
275
|
+
!hasFunctionToolChoiceName(toolChoice.name, tools)) {
|
|
276
|
+
throw new 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.');
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
function getCompatibleToolChoice(toolChoice, tools, options) {
|
|
280
|
+
const allowPromptSuppliedTools = options?.allowPromptSuppliedTools === true;
|
|
281
|
+
if (typeof toolChoice === 'undefined') {
|
|
282
|
+
return undefined;
|
|
283
|
+
}
|
|
284
|
+
if (isToolChoiceAvailable(toolChoice, tools) || allowPromptSuppliedTools) {
|
|
285
|
+
return toolChoice;
|
|
286
|
+
}
|
|
287
|
+
const availableToolChoices = [
|
|
288
|
+
...new Set(collectAvailableToolChoiceNames(tools)),
|
|
289
|
+
];
|
|
290
|
+
const availableToolChoicesMessage = availableToolChoices.length > 0
|
|
291
|
+
? ` Available tools: ${availableToolChoices.join(', ')}.`
|
|
292
|
+
: ' No tools are available in the outgoing Responses request.';
|
|
293
|
+
if (toolChoice === 'required') {
|
|
294
|
+
throw new UserError(`modelSettings.toolChoice="required" requires at least one available tool in the outgoing Responses request.${availableToolChoicesMessage}`);
|
|
295
|
+
}
|
|
296
|
+
if (toolChoice === 'auto' || toolChoice === 'none') {
|
|
297
|
+
throw new Error(`Unexpected unavailable tool choice: ${JSON.stringify(toolChoice)}`);
|
|
298
|
+
}
|
|
299
|
+
if (toolChoice.type === 'function') {
|
|
300
|
+
throw new UserError(`modelSettings.toolChoice="${toolChoice.name}" does not match any available tool in the outgoing Responses request.${availableToolChoicesMessage}`);
|
|
301
|
+
}
|
|
302
|
+
throw new UserError(`modelSettings.toolChoice="${toolChoice.type}" is unavailable in the outgoing Responses request.${availableToolChoicesMessage}`);
|
|
303
|
+
}
|
|
38
304
|
function getResponseFormat(outputType, otherProperties) {
|
|
39
305
|
if (outputType === 'text') {
|
|
40
306
|
return otherProperties;
|
|
@@ -88,12 +354,13 @@ function convertLegacyToolOutputContent(output) {
|
|
|
88
354
|
const legacyImageUrl = output.imageUrl;
|
|
89
355
|
const legacyFileId = output.fileId;
|
|
90
356
|
const dataValue = output.data;
|
|
357
|
+
const topLevelInlineMediaType = getImageInlineMediaType(output);
|
|
91
358
|
if (typeof output.image === 'string' && output.image.length > 0) {
|
|
92
359
|
structured.image = output.image;
|
|
93
360
|
}
|
|
94
361
|
else if (isRecord(output.image)) {
|
|
95
362
|
const imageObj = output.image;
|
|
96
|
-
const inlineMediaType = getImageInlineMediaType(imageObj);
|
|
363
|
+
const inlineMediaType = getImageInlineMediaType(imageObj) ?? topLevelInlineMediaType;
|
|
97
364
|
if (typeof imageObj.url === 'string' && imageObj.url.length > 0) {
|
|
98
365
|
structured.image = imageObj.url;
|
|
99
366
|
}
|
|
@@ -133,7 +400,7 @@ function convertLegacyToolOutputContent(output) {
|
|
|
133
400
|
base64Data = encodeUint8ArrayToBase64(dataValue);
|
|
134
401
|
}
|
|
135
402
|
if (base64Data) {
|
|
136
|
-
structured.image = base64Data;
|
|
403
|
+
structured.image = formatInlineData(base64Data, topLevelInlineMediaType);
|
|
137
404
|
}
|
|
138
405
|
}
|
|
139
406
|
if (output.providerData) {
|
|
@@ -378,9 +645,16 @@ function getImageInlineMediaType(source) {
|
|
|
378
645
|
if (typeof source.mediaType === 'string' && source.mediaType.length > 0) {
|
|
379
646
|
return source.mediaType;
|
|
380
647
|
}
|
|
648
|
+
if (typeof source.mimeType === 'string' &&
|
|
649
|
+
source.mimeType.length > 0) {
|
|
650
|
+
return source.mimeType;
|
|
651
|
+
}
|
|
381
652
|
return undefined;
|
|
382
653
|
}
|
|
383
654
|
function formatInlineData(data, mediaType) {
|
|
655
|
+
if (typeof data === 'string' && data.startsWith('data:')) {
|
|
656
|
+
return data;
|
|
657
|
+
}
|
|
384
658
|
const base64 = typeof data === 'string' ? data : encodeUint8ArrayToBase64(data);
|
|
385
659
|
return mediaType ? `data:${mediaType};base64,${base64}` : base64;
|
|
386
660
|
}
|
|
@@ -497,11 +771,70 @@ function toOpenAIShellEnvironment(environment) {
|
|
|
497
771
|
}
|
|
498
772
|
throw new UserError(`Unsupported shell environment type: ${String(environment.type)}`);
|
|
499
773
|
}
|
|
500
|
-
function getTools(tools, handoffs) {
|
|
774
|
+
function getTools(tools, handoffs, options) {
|
|
501
775
|
const openaiTools = [];
|
|
502
776
|
const include = [];
|
|
777
|
+
const namespaceStateByName = new Map();
|
|
778
|
+
let hasDeferredSearchableTool = false;
|
|
779
|
+
let hasToolSearch = false;
|
|
780
|
+
const usePreviewComputerTool = shouldUsePreviewComputerTool({
|
|
781
|
+
model: options?.model,
|
|
782
|
+
toolChoice: options?.toolChoice,
|
|
783
|
+
});
|
|
503
784
|
for (const tool of tools) {
|
|
504
|
-
|
|
785
|
+
if (tool.type === 'function') {
|
|
786
|
+
const isDeferredFunction = tool.deferLoading === true;
|
|
787
|
+
hasDeferredSearchableTool ||= isDeferredFunction;
|
|
788
|
+
const namespaceName = typeof tool.namespace === 'string' ? tool.namespace.trim() : '';
|
|
789
|
+
if (namespaceName.length > 0) {
|
|
790
|
+
const namespaceDescription = typeof tool.namespaceDescription === 'string'
|
|
791
|
+
? tool.namespaceDescription.trim()
|
|
792
|
+
: '';
|
|
793
|
+
if (namespaceDescription.length === 0) {
|
|
794
|
+
throw new UserError(`All tools in namespace "${namespaceName}" must provide a non-empty description.`);
|
|
795
|
+
}
|
|
796
|
+
let namespaceState = namespaceStateByName.get(namespaceName);
|
|
797
|
+
if (!namespaceState) {
|
|
798
|
+
namespaceState = {
|
|
799
|
+
index: openaiTools.length,
|
|
800
|
+
description: namespaceDescription,
|
|
801
|
+
functionNames: new Set(),
|
|
802
|
+
tools: [],
|
|
803
|
+
};
|
|
804
|
+
namespaceStateByName.set(namespaceName, namespaceState);
|
|
805
|
+
openaiTools.push({});
|
|
806
|
+
}
|
|
807
|
+
else if (namespaceState.description !== namespaceDescription) {
|
|
808
|
+
throw new UserError(`All tools in namespace "${namespaceName}" must share the same description.`);
|
|
809
|
+
}
|
|
810
|
+
const { tool: openaiTool, include: openaiIncludes } = converTool(tool, {
|
|
811
|
+
usePreviewComputerTool,
|
|
812
|
+
});
|
|
813
|
+
if (namespaceState.functionNames.has(tool.name)) {
|
|
814
|
+
throw new UserError(`Namespace "${namespaceName}" cannot contain duplicate function tool name "${tool.name}".`);
|
|
815
|
+
}
|
|
816
|
+
namespaceState.functionNames.add(tool.name);
|
|
817
|
+
namespaceState.tools.push(openaiTool);
|
|
818
|
+
if (openaiIncludes && openaiIncludes.length > 0) {
|
|
819
|
+
for (const item of openaiIncludes) {
|
|
820
|
+
include.push(item);
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
continue;
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
if (tool.type === 'hosted_tool' &&
|
|
827
|
+
tool.providerData?.type === 'tool_search') {
|
|
828
|
+
hasToolSearch = true;
|
|
829
|
+
}
|
|
830
|
+
if (tool.type === 'hosted_tool' &&
|
|
831
|
+
tool.providerData?.type === 'mcp' &&
|
|
832
|
+
tool.providerData.defer_loading === true) {
|
|
833
|
+
hasDeferredSearchableTool = true;
|
|
834
|
+
}
|
|
835
|
+
const { tool: openaiTool, include: openaiIncludes } = converTool(tool, {
|
|
836
|
+
usePreviewComputerTool,
|
|
837
|
+
});
|
|
505
838
|
openaiTools.push(openaiTool);
|
|
506
839
|
if (openaiIncludes && openaiIncludes.length > 0) {
|
|
507
840
|
for (const item of openaiIncludes) {
|
|
@@ -509,31 +842,57 @@ function getTools(tools, handoffs) {
|
|
|
509
842
|
}
|
|
510
843
|
}
|
|
511
844
|
}
|
|
845
|
+
if (hasDeferredSearchableTool && !hasToolSearch) {
|
|
846
|
+
throw new UserError('Deferred function tools and hosted MCP tools with deferLoading: true require toolSearchTool() in the same request.');
|
|
847
|
+
}
|
|
848
|
+
for (const [namespaceName, namespaceState,] of namespaceStateByName.entries()) {
|
|
849
|
+
openaiTools[namespaceState.index] = {
|
|
850
|
+
type: 'namespace',
|
|
851
|
+
name: namespaceName,
|
|
852
|
+
description: namespaceState.description,
|
|
853
|
+
tools: namespaceState.tools,
|
|
854
|
+
};
|
|
855
|
+
}
|
|
512
856
|
return {
|
|
513
857
|
tools: [...openaiTools, ...handoffs.map(getHandoffTool)],
|
|
514
858
|
include,
|
|
515
859
|
};
|
|
516
860
|
}
|
|
517
|
-
function converTool(tool) {
|
|
861
|
+
function converTool(tool, options) {
|
|
518
862
|
if (tool.type === 'function') {
|
|
863
|
+
const openaiTool = {
|
|
864
|
+
type: 'function',
|
|
865
|
+
name: tool.name,
|
|
866
|
+
description: tool.description,
|
|
867
|
+
parameters: tool.parameters,
|
|
868
|
+
strict: tool.strict,
|
|
869
|
+
};
|
|
870
|
+
if (tool.deferLoading) {
|
|
871
|
+
openaiTool.defer_loading = true;
|
|
872
|
+
}
|
|
519
873
|
return {
|
|
520
|
-
tool:
|
|
521
|
-
type: 'function',
|
|
522
|
-
name: tool.name,
|
|
523
|
-
description: tool.description,
|
|
524
|
-
parameters: tool.parameters,
|
|
525
|
-
strict: tool.strict,
|
|
526
|
-
},
|
|
874
|
+
tool: openaiTool,
|
|
527
875
|
include: undefined,
|
|
528
876
|
};
|
|
529
877
|
}
|
|
530
878
|
else if (tool.type === 'computer') {
|
|
879
|
+
if (options?.usePreviewComputerTool) {
|
|
880
|
+
if (!hasSerializedComputerDisplayMetadata(tool)) {
|
|
881
|
+
throw new 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.');
|
|
882
|
+
}
|
|
883
|
+
return {
|
|
884
|
+
tool: {
|
|
885
|
+
type: 'computer_use_preview',
|
|
886
|
+
environment: tool.environment,
|
|
887
|
+
display_width: tool.dimensions[0],
|
|
888
|
+
display_height: tool.dimensions[1],
|
|
889
|
+
},
|
|
890
|
+
include: undefined,
|
|
891
|
+
};
|
|
892
|
+
}
|
|
531
893
|
return {
|
|
532
894
|
tool: {
|
|
533
|
-
type: '
|
|
534
|
-
environment: tool.environment,
|
|
535
|
-
display_width: tool.dimensions[0],
|
|
536
|
-
display_height: tool.dimensions[1],
|
|
895
|
+
type: 'computer',
|
|
537
896
|
},
|
|
538
897
|
include: undefined,
|
|
539
898
|
};
|
|
@@ -604,6 +963,17 @@ function converTool(tool) {
|
|
|
604
963
|
include: undefined,
|
|
605
964
|
};
|
|
606
965
|
}
|
|
966
|
+
else if (tool.providerData?.type === 'tool_search') {
|
|
967
|
+
return {
|
|
968
|
+
tool: {
|
|
969
|
+
type: 'tool_search',
|
|
970
|
+
execution: tool.providerData.execution,
|
|
971
|
+
description: tool.providerData.description,
|
|
972
|
+
parameters: tool.providerData.parameters,
|
|
973
|
+
},
|
|
974
|
+
include: undefined,
|
|
975
|
+
};
|
|
976
|
+
}
|
|
607
977
|
else if (tool.providerData?.type === 'image_generation') {
|
|
608
978
|
return {
|
|
609
979
|
tool: {
|
|
@@ -623,17 +993,22 @@ function converTool(tool) {
|
|
|
623
993
|
};
|
|
624
994
|
}
|
|
625
995
|
else if (tool.providerData?.type === 'mcp') {
|
|
996
|
+
const openaiTool = {
|
|
997
|
+
type: 'mcp',
|
|
998
|
+
server_label: tool.providerData.server_label,
|
|
999
|
+
server_url: tool.providerData.server_url,
|
|
1000
|
+
connector_id: tool.providerData.connector_id,
|
|
1001
|
+
authorization: tool.providerData.authorization,
|
|
1002
|
+
allowed_tools: tool.providerData.allowed_tools,
|
|
1003
|
+
headers: tool.providerData.headers,
|
|
1004
|
+
require_approval: convertMCPRequireApproval(tool.providerData.require_approval),
|
|
1005
|
+
server_description: tool.providerData.server_description,
|
|
1006
|
+
};
|
|
1007
|
+
if (tool.providerData.defer_loading === true) {
|
|
1008
|
+
openaiTool.defer_loading = true;
|
|
1009
|
+
}
|
|
626
1010
|
return {
|
|
627
|
-
tool:
|
|
628
|
-
type: 'mcp',
|
|
629
|
-
server_label: tool.providerData.server_label,
|
|
630
|
-
server_url: tool.providerData.server_url,
|
|
631
|
-
connector_id: tool.providerData.connector_id,
|
|
632
|
-
authorization: tool.providerData.authorization,
|
|
633
|
-
allowed_tools: tool.providerData.allowed_tools,
|
|
634
|
-
headers: tool.providerData.headers,
|
|
635
|
-
require_approval: convertMCPRequireApproval(tool.providerData.require_approval),
|
|
636
|
-
},
|
|
1011
|
+
tool: openaiTool,
|
|
637
1012
|
include: undefined,
|
|
638
1013
|
};
|
|
639
1014
|
}
|
|
@@ -672,7 +1047,10 @@ function getInputMessageContent(entry) {
|
|
|
672
1047
|
return {
|
|
673
1048
|
type: 'input_text',
|
|
674
1049
|
text: entry.text,
|
|
675
|
-
...
|
|
1050
|
+
...getSnakeCasedProviderDataWithoutReservedKeys(entry.providerData, [
|
|
1051
|
+
'type',
|
|
1052
|
+
'text',
|
|
1053
|
+
]),
|
|
676
1054
|
};
|
|
677
1055
|
}
|
|
678
1056
|
else if (entry.type === 'input_image') {
|
|
@@ -694,7 +1072,12 @@ function getInputMessageContent(entry) {
|
|
|
694
1072
|
}
|
|
695
1073
|
return {
|
|
696
1074
|
...imageEntry,
|
|
697
|
-
...
|
|
1075
|
+
...getSnakeCasedProviderDataWithoutReservedKeys(entry.providerData, [
|
|
1076
|
+
'type',
|
|
1077
|
+
'detail',
|
|
1078
|
+
'image_url',
|
|
1079
|
+
'file_id',
|
|
1080
|
+
]),
|
|
698
1081
|
};
|
|
699
1082
|
}
|
|
700
1083
|
else if (entry.type === 'input_file') {
|
|
@@ -739,25 +1122,54 @@ function getInputMessageContent(entry) {
|
|
|
739
1122
|
}
|
|
740
1123
|
return {
|
|
741
1124
|
...fileEntry,
|
|
742
|
-
...
|
|
1125
|
+
...getSnakeCasedProviderDataWithoutReservedKeys(entry.providerData, [
|
|
1126
|
+
'type',
|
|
1127
|
+
'file_data',
|
|
1128
|
+
'file_url',
|
|
1129
|
+
'file_id',
|
|
1130
|
+
'filename',
|
|
1131
|
+
]),
|
|
743
1132
|
};
|
|
744
1133
|
}
|
|
745
1134
|
throw new UserError(`Unsupported input content type: ${JSON.stringify(entry)}`);
|
|
746
1135
|
}
|
|
1136
|
+
function getProviderDataField(providerData, keys) {
|
|
1137
|
+
if (!providerData ||
|
|
1138
|
+
typeof providerData !== 'object' ||
|
|
1139
|
+
Array.isArray(providerData)) {
|
|
1140
|
+
return undefined;
|
|
1141
|
+
}
|
|
1142
|
+
const record = providerData;
|
|
1143
|
+
for (const key of keys) {
|
|
1144
|
+
if (typeof record[key] !== 'undefined') {
|
|
1145
|
+
return record[key];
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
return undefined;
|
|
1149
|
+
}
|
|
747
1150
|
function getOutputMessageContent(entry) {
|
|
748
1151
|
if (entry.type === 'output_text') {
|
|
1152
|
+
const annotations = getProviderDataField(entry.providerData, ['annotations']);
|
|
1153
|
+
const normalizedAnnotations = Array.isArray(annotations) ? annotations : [];
|
|
749
1154
|
return {
|
|
750
1155
|
type: 'output_text',
|
|
751
1156
|
text: entry.text,
|
|
752
|
-
annotations:
|
|
753
|
-
...
|
|
1157
|
+
annotations: normalizedAnnotations,
|
|
1158
|
+
...getSnakeCasedProviderDataWithoutReservedKeys(entry.providerData, [
|
|
1159
|
+
'type',
|
|
1160
|
+
'text',
|
|
1161
|
+
'annotations',
|
|
1162
|
+
]),
|
|
754
1163
|
};
|
|
755
1164
|
}
|
|
756
1165
|
if (entry.type === 'refusal') {
|
|
757
1166
|
return {
|
|
758
1167
|
type: 'refusal',
|
|
759
1168
|
refusal: entry.refusal,
|
|
760
|
-
...
|
|
1169
|
+
...getSnakeCasedProviderDataWithoutReservedKeys(entry.providerData, [
|
|
1170
|
+
'type',
|
|
1171
|
+
'refusal',
|
|
1172
|
+
]),
|
|
761
1173
|
};
|
|
762
1174
|
}
|
|
763
1175
|
throw new UserError(`Unsupported output content type: ${JSON.stringify(entry)}`);
|
|
@@ -768,7 +1180,11 @@ function getMessageItem(item) {
|
|
|
768
1180
|
id: item.id,
|
|
769
1181
|
role: 'system',
|
|
770
1182
|
content: item.content,
|
|
771
|
-
...
|
|
1183
|
+
...getSnakeCasedProviderDataWithoutReservedKeys(item.providerData, [
|
|
1184
|
+
'id',
|
|
1185
|
+
'role',
|
|
1186
|
+
'content',
|
|
1187
|
+
]),
|
|
772
1188
|
};
|
|
773
1189
|
}
|
|
774
1190
|
if (item.role === 'user') {
|
|
@@ -777,14 +1193,22 @@ function getMessageItem(item) {
|
|
|
777
1193
|
id: item.id,
|
|
778
1194
|
role: 'user',
|
|
779
1195
|
content: item.content,
|
|
780
|
-
...
|
|
1196
|
+
...getSnakeCasedProviderDataWithoutReservedKeys(item.providerData, [
|
|
1197
|
+
'id',
|
|
1198
|
+
'role',
|
|
1199
|
+
'content',
|
|
1200
|
+
]),
|
|
781
1201
|
};
|
|
782
1202
|
}
|
|
783
1203
|
return {
|
|
784
1204
|
id: item.id,
|
|
785
1205
|
role: 'user',
|
|
786
1206
|
content: item.content.map(getInputMessageContent),
|
|
787
|
-
...
|
|
1207
|
+
...getSnakeCasedProviderDataWithoutReservedKeys(item.providerData, [
|
|
1208
|
+
'id',
|
|
1209
|
+
'role',
|
|
1210
|
+
'content',
|
|
1211
|
+
]),
|
|
788
1212
|
};
|
|
789
1213
|
}
|
|
790
1214
|
if (item.role === 'assistant') {
|
|
@@ -794,7 +1218,13 @@ function getMessageItem(item) {
|
|
|
794
1218
|
role: 'assistant',
|
|
795
1219
|
content: item.content.map(getOutputMessageContent),
|
|
796
1220
|
status: item.status,
|
|
797
|
-
...
|
|
1221
|
+
...getSnakeCasedProviderDataWithoutReservedKeys(item.providerData, [
|
|
1222
|
+
'type',
|
|
1223
|
+
'id',
|
|
1224
|
+
'role',
|
|
1225
|
+
'content',
|
|
1226
|
+
'status',
|
|
1227
|
+
]),
|
|
798
1228
|
};
|
|
799
1229
|
return assistantMessage;
|
|
800
1230
|
}
|
|
@@ -841,6 +1271,52 @@ function getInputItems(input) {
|
|
|
841
1271
|
if (isMessageItem(item)) {
|
|
842
1272
|
return getMessageItem(item);
|
|
843
1273
|
}
|
|
1274
|
+
if (item.type === 'tool_search_call') {
|
|
1275
|
+
const status = normalizeToolSearchStatus(item.status);
|
|
1276
|
+
const callId = getToolSearchProviderCallId(item);
|
|
1277
|
+
const execution = getToolSearchExecution(item);
|
|
1278
|
+
const toolSearchCall = {
|
|
1279
|
+
type: 'tool_search_call',
|
|
1280
|
+
id: item.id,
|
|
1281
|
+
...(status !== null ? { status } : {}),
|
|
1282
|
+
arguments: item.arguments,
|
|
1283
|
+
...(callId ? { call_id: callId } : {}),
|
|
1284
|
+
...(execution ? { execution } : {}),
|
|
1285
|
+
...getSnakeCasedProviderDataWithoutReservedKeys(item.providerData, [
|
|
1286
|
+
'type',
|
|
1287
|
+
'id',
|
|
1288
|
+
'status',
|
|
1289
|
+
'arguments',
|
|
1290
|
+
'call_id',
|
|
1291
|
+
'callId',
|
|
1292
|
+
'execution',
|
|
1293
|
+
]),
|
|
1294
|
+
};
|
|
1295
|
+
return toolSearchCall;
|
|
1296
|
+
}
|
|
1297
|
+
if (item.type === 'tool_search_output') {
|
|
1298
|
+
const status = normalizeToolSearchStatus(item.status);
|
|
1299
|
+
const callId = getToolSearchProviderCallId(item);
|
|
1300
|
+
const execution = getToolSearchExecution(item);
|
|
1301
|
+
const toolSearchOutput = {
|
|
1302
|
+
type: 'tool_search_output',
|
|
1303
|
+
id: item.id,
|
|
1304
|
+
...(status !== null ? { status } : {}),
|
|
1305
|
+
tools: item.tools.map((tool) => toOpenAIToolSearchOutputToolPayload(tool)),
|
|
1306
|
+
...(callId ? { call_id: callId } : {}),
|
|
1307
|
+
...(execution ? { execution } : {}),
|
|
1308
|
+
...getSnakeCasedProviderDataWithoutReservedKeys(item.providerData, [
|
|
1309
|
+
'type',
|
|
1310
|
+
'id',
|
|
1311
|
+
'status',
|
|
1312
|
+
'tools',
|
|
1313
|
+
'call_id',
|
|
1314
|
+
'callId',
|
|
1315
|
+
'execution',
|
|
1316
|
+
]),
|
|
1317
|
+
};
|
|
1318
|
+
return toolSearchOutput;
|
|
1319
|
+
}
|
|
844
1320
|
if (item.type === 'function_call') {
|
|
845
1321
|
const entry = {
|
|
846
1322
|
id: item.id,
|
|
@@ -849,7 +1325,18 @@ function getInputItems(input) {
|
|
|
849
1325
|
call_id: item.callId,
|
|
850
1326
|
arguments: item.arguments,
|
|
851
1327
|
status: item.status,
|
|
852
|
-
...
|
|
1328
|
+
...(typeof item.namespace === 'string'
|
|
1329
|
+
? { namespace: item.namespace }
|
|
1330
|
+
: {}),
|
|
1331
|
+
...getSnakeCasedProviderDataWithoutReservedKeys(item.providerData, [
|
|
1332
|
+
'id',
|
|
1333
|
+
'type',
|
|
1334
|
+
'name',
|
|
1335
|
+
'call_id',
|
|
1336
|
+
'arguments',
|
|
1337
|
+
'status',
|
|
1338
|
+
'namespace',
|
|
1339
|
+
]),
|
|
853
1340
|
};
|
|
854
1341
|
return entry;
|
|
855
1342
|
}
|
|
@@ -861,45 +1348,98 @@ function getInputItems(input) {
|
|
|
861
1348
|
call_id: item.callId,
|
|
862
1349
|
output: normalizedOutput,
|
|
863
1350
|
status: item.status,
|
|
864
|
-
...
|
|
1351
|
+
...getSnakeCasedProviderDataWithoutReservedKeys(item.providerData, [
|
|
1352
|
+
'type',
|
|
1353
|
+
'id',
|
|
1354
|
+
'call_id',
|
|
1355
|
+
'output',
|
|
1356
|
+
'status',
|
|
1357
|
+
'namespace',
|
|
1358
|
+
]),
|
|
865
1359
|
};
|
|
866
1360
|
return entry;
|
|
867
1361
|
}
|
|
868
1362
|
if (item.type === 'reasoning') {
|
|
1363
|
+
const encryptedContent = getProviderDataField(item.providerData, [
|
|
1364
|
+
'encryptedContent',
|
|
1365
|
+
'encrypted_content',
|
|
1366
|
+
]);
|
|
869
1367
|
const entry = {
|
|
870
1368
|
id: item.id,
|
|
871
1369
|
type: 'reasoning',
|
|
872
1370
|
summary: item.content.map((content) => ({
|
|
873
1371
|
type: 'summary_text',
|
|
874
1372
|
text: content.text,
|
|
875
|
-
...
|
|
1373
|
+
...getSnakeCasedProviderDataWithoutReservedKeys(content.providerData, ['type', 'text']),
|
|
876
1374
|
})),
|
|
877
|
-
|
|
878
|
-
|
|
1375
|
+
...(typeof encryptedContent === 'string'
|
|
1376
|
+
? { encrypted_content: encryptedContent }
|
|
1377
|
+
: {}),
|
|
1378
|
+
...getSnakeCasedProviderDataWithoutReservedKeys(item.providerData, [
|
|
1379
|
+
'id',
|
|
1380
|
+
'type',
|
|
1381
|
+
'summary',
|
|
1382
|
+
'encrypted_content',
|
|
1383
|
+
]),
|
|
879
1384
|
};
|
|
880
1385
|
return entry;
|
|
881
1386
|
}
|
|
882
1387
|
if (item.type === 'computer_call') {
|
|
1388
|
+
const pendingSafetyChecks = getProviderDataField(item.providerData, ['pendingSafetyChecks', 'pending_safety_checks']);
|
|
1389
|
+
const normalizedPendingSafetyChecks = Array.isArray(pendingSafetyChecks) ? pendingSafetyChecks : [];
|
|
1390
|
+
const batchedActions = Array.isArray(item.actions)
|
|
1391
|
+
? (item
|
|
1392
|
+
.actions ?? [])
|
|
1393
|
+
: [];
|
|
1394
|
+
const actionPayload = batchedActions.length > 0
|
|
1395
|
+
? {
|
|
1396
|
+
action: item.action ?? batchedActions[0],
|
|
1397
|
+
actions: batchedActions,
|
|
1398
|
+
}
|
|
1399
|
+
: item.action
|
|
1400
|
+
? { action: item.action }
|
|
1401
|
+
: {};
|
|
883
1402
|
const entry = {
|
|
884
1403
|
type: 'computer_call',
|
|
885
1404
|
call_id: item.callId,
|
|
886
1405
|
id: item.id,
|
|
887
|
-
action: item.action,
|
|
888
1406
|
status: item.status,
|
|
889
|
-
pending_safety_checks:
|
|
890
|
-
...
|
|
1407
|
+
pending_safety_checks: normalizedPendingSafetyChecks,
|
|
1408
|
+
...actionPayload,
|
|
1409
|
+
...getSnakeCasedProviderDataWithoutReservedKeys(item.providerData, [
|
|
1410
|
+
'type',
|
|
1411
|
+
'call_id',
|
|
1412
|
+
'id',
|
|
1413
|
+
'action',
|
|
1414
|
+
'actions',
|
|
1415
|
+
'status',
|
|
1416
|
+
'pending_safety_checks',
|
|
1417
|
+
]),
|
|
891
1418
|
};
|
|
892
1419
|
return entry;
|
|
893
1420
|
}
|
|
894
1421
|
if (item.type === 'computer_call_result') {
|
|
1422
|
+
const acknowledgedSafetyChecks = getProviderDataField(item.providerData, [
|
|
1423
|
+
'acknowledgedSafetyChecks',
|
|
1424
|
+
'acknowledged_safety_checks',
|
|
1425
|
+
]);
|
|
895
1426
|
const entry = {
|
|
896
1427
|
type: 'computer_call_output',
|
|
897
1428
|
id: item.id,
|
|
898
1429
|
call_id: item.callId,
|
|
899
1430
|
output: buildResponseOutput(item),
|
|
900
1431
|
status: item.providerData?.status,
|
|
901
|
-
acknowledged_safety_checks:
|
|
902
|
-
|
|
1432
|
+
acknowledged_safety_checks: Array.isArray(acknowledgedSafetyChecks)
|
|
1433
|
+
? acknowledgedSafetyChecks
|
|
1434
|
+
: [],
|
|
1435
|
+
...getSnakeCasedProviderDataWithoutReservedKeys(item.providerData, [
|
|
1436
|
+
'type',
|
|
1437
|
+
'id',
|
|
1438
|
+
'call_id',
|
|
1439
|
+
'output',
|
|
1440
|
+
'status',
|
|
1441
|
+
'acknowledged_safety_checks',
|
|
1442
|
+
]),
|
|
903
1443
|
};
|
|
904
1444
|
return entry;
|
|
905
1445
|
}
|
|
@@ -1152,6 +1692,30 @@ function convertToOutputItem(items) {
|
|
|
1152
1692
|
providerData,
|
|
1153
1693
|
};
|
|
1154
1694
|
}
|
|
1695
|
+
else if (item.type === 'tool_search_call') {
|
|
1696
|
+
const { id, type: _type, status, arguments: args, ...providerData } = item;
|
|
1697
|
+
const output = {
|
|
1698
|
+
type: 'tool_search_call',
|
|
1699
|
+
id,
|
|
1700
|
+
status,
|
|
1701
|
+
arguments: args,
|
|
1702
|
+
providerData,
|
|
1703
|
+
};
|
|
1704
|
+
return output;
|
|
1705
|
+
}
|
|
1706
|
+
else if (item.type === 'tool_search_output') {
|
|
1707
|
+
const { id, type: _type, status, tools, ...providerData } = item;
|
|
1708
|
+
const output = {
|
|
1709
|
+
type: 'tool_search_output',
|
|
1710
|
+
id,
|
|
1711
|
+
status,
|
|
1712
|
+
tools: Array.isArray(tools)
|
|
1713
|
+
? tools.map((tool) => fromOpenAIToolSearchOutputToolPayload(tool))
|
|
1714
|
+
: [],
|
|
1715
|
+
providerData,
|
|
1716
|
+
};
|
|
1717
|
+
return output;
|
|
1718
|
+
}
|
|
1155
1719
|
else if (item.type === 'file_search_call' ||
|
|
1156
1720
|
item.type === 'web_search_call' ||
|
|
1157
1721
|
item.type === 'image_generation_call' ||
|
|
@@ -1174,12 +1738,14 @@ function convertToOutputItem(items) {
|
|
|
1174
1738
|
return output;
|
|
1175
1739
|
}
|
|
1176
1740
|
else if (item.type === 'function_call') {
|
|
1177
|
-
const
|
|
1741
|
+
const functionCall = item;
|
|
1742
|
+
const { call_id, name, namespace, status, arguments: args, ...providerData } = functionCall;
|
|
1178
1743
|
const output = {
|
|
1179
1744
|
type: 'function_call',
|
|
1180
|
-
id:
|
|
1745
|
+
id: functionCall.id,
|
|
1181
1746
|
callId: call_id,
|
|
1182
1747
|
name,
|
|
1748
|
+
...(typeof namespace === 'string' ? { namespace } : {}),
|
|
1183
1749
|
status,
|
|
1184
1750
|
arguments: args,
|
|
1185
1751
|
providerData,
|
|
@@ -1187,12 +1753,13 @@ function convertToOutputItem(items) {
|
|
|
1187
1753
|
return output;
|
|
1188
1754
|
}
|
|
1189
1755
|
else if (item.type === 'function_call_output') {
|
|
1190
|
-
const { call_id, status, output: rawOutput, name: toolName, function_name: functionName, ...providerData } = item;
|
|
1756
|
+
const { call_id, status, output: rawOutput, name: toolName, function_name: functionName, namespace, ...providerData } = item;
|
|
1191
1757
|
const output = {
|
|
1192
1758
|
type: 'function_call_result',
|
|
1193
1759
|
id: item.id,
|
|
1194
1760
|
callId: call_id,
|
|
1195
1761
|
name: toolName ?? functionName ?? call_id,
|
|
1762
|
+
...(typeof namespace === 'string' ? { namespace } : {}),
|
|
1196
1763
|
status: status ?? 'completed',
|
|
1197
1764
|
output: convertFunctionCallOutputToProtocol(rawOutput),
|
|
1198
1765
|
providerData,
|
|
@@ -1200,13 +1767,18 @@ function convertToOutputItem(items) {
|
|
|
1200
1767
|
return output;
|
|
1201
1768
|
}
|
|
1202
1769
|
else if (item.type === 'computer_call') {
|
|
1203
|
-
const { call_id, status, action, ...providerData } = item;
|
|
1770
|
+
const { call_id, status, action, actions, ...providerData } = item;
|
|
1771
|
+
const normalizedActions = Array.isArray(actions) && actions.length > 0 ? actions : undefined;
|
|
1772
|
+
if (!normalizedActions && !action) {
|
|
1773
|
+
throw new UserError(`Unsupported computer call item without an action or actions: ${JSON.stringify(item)}`);
|
|
1774
|
+
}
|
|
1204
1775
|
const output = {
|
|
1205
1776
|
type: 'computer_call',
|
|
1206
1777
|
id: item.id,
|
|
1207
1778
|
callId: call_id,
|
|
1208
1779
|
status,
|
|
1209
|
-
action,
|
|
1780
|
+
action: action ?? normalizedActions?.[0],
|
|
1781
|
+
...(normalizedActions ? { actions: normalizedActions } : {}),
|
|
1210
1782
|
providerData,
|
|
1211
1783
|
};
|
|
1212
1784
|
return output;
|
|
@@ -1486,9 +2058,30 @@ export class OpenAIResponsesModel {
|
|
|
1486
2058
|
}
|
|
1487
2059
|
_buildResponsesCreateRequest(request, stream) {
|
|
1488
2060
|
const input = getInputItems(request.input);
|
|
1489
|
-
const
|
|
1490
|
-
|
|
2061
|
+
const prompt = getPrompt(request.prompt);
|
|
2062
|
+
// When a prompt template already declares a model, skip sending the agent's default model.
|
|
2063
|
+
// If the caller explicitly requests an override, include the resolved model name in the request.
|
|
2064
|
+
const shouldSendModel = !request.prompt || request.overridePromptModel === true;
|
|
2065
|
+
const effectiveRequestModel = shouldSendModel ? this._model : undefined;
|
|
1491
2066
|
const { providerData: providerDataWithoutTransport, overrides: transportOverrides, } = splitResponsesTransportOverrides(request.modelSettings.providerData);
|
|
2067
|
+
const { tools, include } = getTools(request.tools, request.handoffs, {
|
|
2068
|
+
model: effectiveRequestModel,
|
|
2069
|
+
toolChoice: request.modelSettings.toolChoice,
|
|
2070
|
+
});
|
|
2071
|
+
const toolChoiceValidationTools = [
|
|
2072
|
+
...tools,
|
|
2073
|
+
...getExtraBodyToolsForToolChoiceValidation(transportOverrides.extraBody),
|
|
2074
|
+
];
|
|
2075
|
+
const allowPromptSuppliedTools = Boolean(request.prompt) &&
|
|
2076
|
+
!(request.toolsExplicitlyProvided === true && tools.length === 0);
|
|
2077
|
+
const toolChoice = getToolChoice(request.modelSettings.toolChoice, {
|
|
2078
|
+
tools: toolChoiceValidationTools,
|
|
2079
|
+
model: effectiveRequestModel,
|
|
2080
|
+
allowPromptSuppliedComputerTool: allowPromptSuppliedTools,
|
|
2081
|
+
});
|
|
2082
|
+
assertSupportedToolChoice(toolChoice, toolChoiceValidationTools, {
|
|
2083
|
+
allowPromptSuppliedTools,
|
|
2084
|
+
});
|
|
1492
2085
|
const { text, ...restOfProviderData } = providerDataWithoutTransport;
|
|
1493
2086
|
if (request.modelSettings.reasoning) {
|
|
1494
2087
|
// Merge top-level reasoning settings with provider data.
|
|
@@ -1503,25 +2096,19 @@ export class OpenAIResponsesModel {
|
|
|
1503
2096
|
mergedText = { ...request.modelSettings.text, ...text };
|
|
1504
2097
|
}
|
|
1505
2098
|
const responseFormat = getResponseFormat(request.outputType, mergedText);
|
|
1506
|
-
const prompt = getPrompt(request.prompt);
|
|
1507
2099
|
let parallelToolCalls = undefined;
|
|
1508
2100
|
if (typeof request.modelSettings.parallelToolCalls === 'boolean') {
|
|
1509
|
-
if (request.modelSettings.parallelToolCalls && tools.length === 0) {
|
|
1510
|
-
throw new Error('Parallel tool calls are not supported without tools');
|
|
1511
|
-
}
|
|
1512
2101
|
parallelToolCalls = request.modelSettings.parallelToolCalls;
|
|
1513
2102
|
}
|
|
1514
|
-
// When a prompt template already declares a model, skip sending the agent's default model.
|
|
1515
|
-
// If the caller explicitly requests an override, include the resolved model name in the request.
|
|
1516
|
-
const shouldSendModel = !request.prompt || request.overridePromptModel === true;
|
|
1517
2103
|
const shouldSendTools = tools.length > 0 ||
|
|
1518
2104
|
request.toolsExplicitlyProvided === true ||
|
|
1519
2105
|
!request.prompt;
|
|
1520
|
-
const
|
|
1521
|
-
|
|
1522
|
-
|
|
2106
|
+
const compatibleToolChoice = getCompatibleToolChoice(toolChoice, toolChoiceValidationTools, {
|
|
2107
|
+
allowPromptSuppliedTools,
|
|
2108
|
+
});
|
|
2109
|
+
const shouldOmitToolChoice = typeof compatibleToolChoice === 'undefined';
|
|
1523
2110
|
let requestData = {
|
|
1524
|
-
...(
|
|
2111
|
+
...(effectiveRequestModel ? { model: effectiveRequestModel } : {}),
|
|
1525
2112
|
instructions: normalizeInstructions(request.systemInstructions),
|
|
1526
2113
|
input,
|
|
1527
2114
|
include,
|
|
@@ -1538,7 +2125,7 @@ export class OpenAIResponsesModel {
|
|
|
1538
2125
|
truncation: request.modelSettings.truncation,
|
|
1539
2126
|
max_output_tokens: request.modelSettings.maxTokens,
|
|
1540
2127
|
...(!shouldOmitToolChoice
|
|
1541
|
-
? { tool_choice:
|
|
2128
|
+
? { tool_choice: compatibleToolChoice }
|
|
1542
2129
|
: {}),
|
|
1543
2130
|
parallel_tool_calls: parallelToolCalls,
|
|
1544
2131
|
stream,
|