@depup/ai-sdk__openai 3.0.41-depup.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.
Files changed (74) hide show
  1. package/CHANGELOG.md +3101 -0
  2. package/LICENSE +13 -0
  3. package/README.md +25 -0
  4. package/changes.json +5 -0
  5. package/dist/index.d.mts +1107 -0
  6. package/dist/index.d.ts +1107 -0
  7. package/dist/index.js +6408 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/index.mjs +6493 -0
  10. package/dist/index.mjs.map +1 -0
  11. package/dist/internal/index.d.mts +1137 -0
  12. package/dist/internal/index.d.ts +1137 -0
  13. package/dist/internal/index.js +6256 -0
  14. package/dist/internal/index.js.map +1 -0
  15. package/dist/internal/index.mjs +6306 -0
  16. package/dist/internal/index.mjs.map +1 -0
  17. package/docs/03-openai.mdx +2396 -0
  18. package/internal.d.ts +1 -0
  19. package/package.json +96 -0
  20. package/src/chat/convert-openai-chat-usage.ts +57 -0
  21. package/src/chat/convert-to-openai-chat-messages.ts +225 -0
  22. package/src/chat/get-response-metadata.ts +15 -0
  23. package/src/chat/map-openai-finish-reason.ts +19 -0
  24. package/src/chat/openai-chat-api.ts +198 -0
  25. package/src/chat/openai-chat-language-model.ts +703 -0
  26. package/src/chat/openai-chat-options.ts +192 -0
  27. package/src/chat/openai-chat-prepare-tools.ts +84 -0
  28. package/src/chat/openai-chat-prompt.ts +70 -0
  29. package/src/completion/convert-openai-completion-usage.ts +46 -0
  30. package/src/completion/convert-to-openai-completion-prompt.ts +93 -0
  31. package/src/completion/get-response-metadata.ts +15 -0
  32. package/src/completion/map-openai-finish-reason.ts +19 -0
  33. package/src/completion/openai-completion-api.ts +81 -0
  34. package/src/completion/openai-completion-language-model.ts +336 -0
  35. package/src/completion/openai-completion-options.ts +61 -0
  36. package/src/embedding/openai-embedding-api.ts +13 -0
  37. package/src/embedding/openai-embedding-model.ts +95 -0
  38. package/src/embedding/openai-embedding-options.ts +30 -0
  39. package/src/image/openai-image-api.ts +35 -0
  40. package/src/image/openai-image-model.ts +349 -0
  41. package/src/image/openai-image-options.ts +31 -0
  42. package/src/index.ts +23 -0
  43. package/src/internal/index.ts +19 -0
  44. package/src/openai-config.ts +18 -0
  45. package/src/openai-error.ts +22 -0
  46. package/src/openai-language-model-capabilities.ts +52 -0
  47. package/src/openai-provider.ts +270 -0
  48. package/src/openai-tools.ts +126 -0
  49. package/src/responses/convert-openai-responses-usage.ts +53 -0
  50. package/src/responses/convert-to-openai-responses-input.ts +735 -0
  51. package/src/responses/map-openai-responses-finish-reason.ts +22 -0
  52. package/src/responses/openai-responses-api.ts +1260 -0
  53. package/src/responses/openai-responses-language-model.ts +2098 -0
  54. package/src/responses/openai-responses-options.ts +299 -0
  55. package/src/responses/openai-responses-prepare-tools.ts +408 -0
  56. package/src/responses/openai-responses-provider-metadata.ts +62 -0
  57. package/src/speech/openai-speech-api.ts +38 -0
  58. package/src/speech/openai-speech-model.ts +137 -0
  59. package/src/speech/openai-speech-options.ts +26 -0
  60. package/src/tool/apply-patch.ts +141 -0
  61. package/src/tool/code-interpreter.ts +104 -0
  62. package/src/tool/custom.ts +64 -0
  63. package/src/tool/file-search.ts +145 -0
  64. package/src/tool/image-generation.ts +126 -0
  65. package/src/tool/local-shell.ts +72 -0
  66. package/src/tool/mcp.ts +125 -0
  67. package/src/tool/shell.ts +203 -0
  68. package/src/tool/web-search-preview.ts +141 -0
  69. package/src/tool/web-search.ts +181 -0
  70. package/src/transcription/openai-transcription-api.ts +37 -0
  71. package/src/transcription/openai-transcription-model.ts +232 -0
  72. package/src/transcription/openai-transcription-options.ts +53 -0
  73. package/src/transcription/transcription-test.mp3 +0 -0
  74. package/src/version.ts +6 -0
@@ -0,0 +1,299 @@
1
+ import { InferSchema, lazySchema, zodSchema } from '@ai-sdk/provider-utils';
2
+ import { z } from 'zod/v4';
3
+
4
+ /**
5
+ * `top_logprobs` request body argument can be set to an integer between
6
+ * 0 and 20 specifying the number of most likely tokens to return at each
7
+ * token position, each with an associated log probability.
8
+ *
9
+ * @see https://platform.openai.com/docs/api-reference/responses/create#responses_create-top_logprobs
10
+ */
11
+ export const TOP_LOGPROBS_MAX = 20;
12
+
13
+ export const openaiResponsesReasoningModelIds = [
14
+ 'o1',
15
+ 'o1-2024-12-17',
16
+ 'o3',
17
+ 'o3-2025-04-16',
18
+ 'o3-mini',
19
+ 'o3-mini-2025-01-31',
20
+ 'o4-mini',
21
+ 'o4-mini-2025-04-16',
22
+ 'gpt-5',
23
+ 'gpt-5-2025-08-07',
24
+ 'gpt-5-codex',
25
+ 'gpt-5-mini',
26
+ 'gpt-5-mini-2025-08-07',
27
+ 'gpt-5-nano',
28
+ 'gpt-5-nano-2025-08-07',
29
+ 'gpt-5-pro',
30
+ 'gpt-5-pro-2025-10-06',
31
+ 'gpt-5.1',
32
+ 'gpt-5.1-chat-latest',
33
+ 'gpt-5.1-codex-mini',
34
+ 'gpt-5.1-codex',
35
+ 'gpt-5.1-codex-max',
36
+ 'gpt-5.2',
37
+ 'gpt-5.2-chat-latest',
38
+ 'gpt-5.2-pro',
39
+ 'gpt-5.2-codex',
40
+ 'gpt-5.3-codex',
41
+ ] as const;
42
+
43
+ export const openaiResponsesModelIds = [
44
+ 'gpt-4.1',
45
+ 'gpt-4.1-2025-04-14',
46
+ 'gpt-4.1-mini',
47
+ 'gpt-4.1-mini-2025-04-14',
48
+ 'gpt-4.1-nano',
49
+ 'gpt-4.1-nano-2025-04-14',
50
+ 'gpt-4o',
51
+ 'gpt-4o-2024-05-13',
52
+ 'gpt-4o-2024-08-06',
53
+ 'gpt-4o-2024-11-20',
54
+ 'gpt-4o-audio-preview',
55
+ 'gpt-4o-audio-preview-2024-12-17',
56
+ 'gpt-4o-search-preview',
57
+ 'gpt-4o-search-preview-2025-03-11',
58
+ 'gpt-4o-mini-search-preview',
59
+ 'gpt-4o-mini-search-preview-2025-03-11',
60
+ 'gpt-4o-mini',
61
+ 'gpt-4o-mini-2024-07-18',
62
+ 'gpt-3.5-turbo-0125',
63
+ 'gpt-3.5-turbo',
64
+ 'gpt-3.5-turbo-1106',
65
+ 'gpt-5-chat-latest',
66
+ ...openaiResponsesReasoningModelIds,
67
+ ] as const;
68
+
69
+ export type OpenAIResponsesModelId =
70
+ | 'gpt-3.5-turbo-0125'
71
+ | 'gpt-3.5-turbo-1106'
72
+ | 'gpt-3.5-turbo'
73
+ | 'gpt-4.1-2025-04-14'
74
+ | 'gpt-4.1-mini-2025-04-14'
75
+ | 'gpt-4.1-mini'
76
+ | 'gpt-4.1-nano-2025-04-14'
77
+ | 'gpt-4.1-nano'
78
+ | 'gpt-4.1'
79
+ | 'gpt-4o-2024-05-13'
80
+ | 'gpt-4o-2024-08-06'
81
+ | 'gpt-4o-2024-11-20'
82
+ | 'gpt-4o-mini-2024-07-18'
83
+ | 'gpt-4o-mini'
84
+ | 'gpt-4o'
85
+ | 'gpt-5.1'
86
+ | 'gpt-5.1-2025-11-13'
87
+ | 'gpt-5.1-chat-latest'
88
+ | 'gpt-5.1-codex-mini'
89
+ | 'gpt-5.1-codex'
90
+ | 'gpt-5.1-codex-max'
91
+ | 'gpt-5.2'
92
+ | 'gpt-5.2-2025-12-11'
93
+ | 'gpt-5.2-chat-latest'
94
+ | 'gpt-5.2-pro'
95
+ | 'gpt-5.2-pro-2025-12-11'
96
+ | 'gpt-5.2-codex'
97
+ | 'gpt-5.3-codex'
98
+ | 'gpt-5-2025-08-07'
99
+ | 'gpt-5-chat-latest'
100
+ | 'gpt-5-codex'
101
+ | 'gpt-5-mini-2025-08-07'
102
+ | 'gpt-5-mini'
103
+ | 'gpt-5-nano-2025-08-07'
104
+ | 'gpt-5-nano'
105
+ | 'gpt-5-pro-2025-10-06'
106
+ | 'gpt-5-pro'
107
+ | 'gpt-5'
108
+ | 'o1-2024-12-17'
109
+ | 'o1'
110
+ | 'o3-2025-04-16'
111
+ | 'o3-mini-2025-01-31'
112
+ | 'o3-mini'
113
+ | 'o3'
114
+ | 'o4-mini'
115
+ | 'o4-mini-2025-04-16'
116
+ | (string & {});
117
+
118
+ // TODO AI SDK 6: use optional here instead of nullish
119
+ export const openaiLanguageModelResponsesOptionsSchema = lazySchema(() =>
120
+ zodSchema(
121
+ z.object({
122
+ /**
123
+ * The ID of the OpenAI Conversation to continue.
124
+ * You must create a conversation first via the OpenAI API.
125
+ * Cannot be used in conjunction with `previousResponseId`.
126
+ * Defaults to `undefined`.
127
+ * @see https://platform.openai.com/docs/api-reference/conversations/create
128
+ */
129
+ conversation: z.string().nullish(),
130
+
131
+ /**
132
+ * The set of extra fields to include in the response (advanced, usually not needed).
133
+ * Example values: 'reasoning.encrypted_content', 'file_search_call.results', 'message.output_text.logprobs'.
134
+ */
135
+ include: z
136
+ .array(
137
+ z.enum([
138
+ 'reasoning.encrypted_content', // handled internally by default, only needed for unknown reasoning models
139
+ 'file_search_call.results',
140
+ 'message.output_text.logprobs',
141
+ ]),
142
+ )
143
+ .nullish(),
144
+
145
+ /**
146
+ * Instructions for the model.
147
+ * They can be used to change the system or developer message when continuing a conversation using the `previousResponseId` option.
148
+ * Defaults to `undefined`.
149
+ */
150
+ instructions: z.string().nullish(),
151
+
152
+ /**
153
+ * Return the log probabilities of the tokens. Including logprobs will increase
154
+ * the response size and can slow down response times. However, it can
155
+ * be useful to better understand how the model is behaving.
156
+ *
157
+ * Setting to true will return the log probabilities of the tokens that
158
+ * were generated.
159
+ *
160
+ * Setting to a number will return the log probabilities of the top n
161
+ * tokens that were generated.
162
+ *
163
+ * @see https://platform.openai.com/docs/api-reference/responses/create
164
+ * @see https://cookbook.openai.com/examples/using_logprobs
165
+ */
166
+ logprobs: z
167
+ .union([z.boolean(), z.number().min(1).max(TOP_LOGPROBS_MAX)])
168
+ .optional(),
169
+
170
+ /**
171
+ * The maximum number of total calls to built-in tools that can be processed in a response.
172
+ * This maximum number applies across all built-in tool calls, not per individual tool.
173
+ * Any further attempts to call a tool by the model will be ignored.
174
+ */
175
+ maxToolCalls: z.number().nullish(),
176
+
177
+ /**
178
+ * Additional metadata to store with the generation.
179
+ */
180
+ metadata: z.any().nullish(),
181
+
182
+ /**
183
+ * Whether to use parallel tool calls. Defaults to `true`.
184
+ */
185
+ parallelToolCalls: z.boolean().nullish(),
186
+
187
+ /**
188
+ * The ID of the previous response. You can use it to continue a conversation.
189
+ * Defaults to `undefined`.
190
+ */
191
+ previousResponseId: z.string().nullish(),
192
+
193
+ /**
194
+ * Sets a cache key to tie this prompt to cached prefixes for better caching performance.
195
+ */
196
+ promptCacheKey: z.string().nullish(),
197
+
198
+ /**
199
+ * The retention policy for the prompt cache.
200
+ * - 'in_memory': Default. Standard prompt caching behavior.
201
+ * - '24h': Extended prompt caching that keeps cached prefixes active for up to 24 hours.
202
+ * Currently only available for 5.1 series models.
203
+ *
204
+ * @default 'in_memory'
205
+ */
206
+ promptCacheRetention: z.enum(['in_memory', '24h']).nullish(),
207
+
208
+ /**
209
+ * Reasoning effort for reasoning models. Defaults to `medium`. If you use
210
+ * `providerOptions` to set the `reasoningEffort` option, this model setting will be ignored.
211
+ * Valid values: 'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh'
212
+ *
213
+ * The 'none' type for `reasoningEffort` is only available for OpenAI's GPT-5.1
214
+ * models. Also, the 'xhigh' type for `reasoningEffort` is only available for
215
+ * OpenAI's GPT-5.1-Codex-Max model. Setting `reasoningEffort` to 'none' or 'xhigh' with unsupported models will result in
216
+ * an error.
217
+ */
218
+ reasoningEffort: z.string().nullish(),
219
+
220
+ /**
221
+ * Controls reasoning summary output from the model.
222
+ * Set to "auto" to automatically receive the richest level available,
223
+ * or "detailed" for comprehensive summaries.
224
+ */
225
+ reasoningSummary: z.string().nullish(),
226
+
227
+ /**
228
+ * The identifier for safety monitoring and tracking.
229
+ */
230
+ safetyIdentifier: z.string().nullish(),
231
+
232
+ /**
233
+ * Service tier for the request.
234
+ * Set to 'flex' for 50% cheaper processing at the cost of increased latency (available for o3, o4-mini, and gpt-5 models).
235
+ * Set to 'priority' for faster processing with Enterprise access (available for gpt-4, gpt-5, gpt-5-mini, o3, o4-mini; gpt-5-nano is not supported).
236
+ *
237
+ * Defaults to 'auto'.
238
+ */
239
+ serviceTier: z.enum(['auto', 'flex', 'priority', 'default']).nullish(),
240
+
241
+ /**
242
+ * Whether to store the generation. Defaults to `true`.
243
+ */
244
+ store: z.boolean().nullish(),
245
+
246
+ /**
247
+ * Whether to use strict JSON schema validation.
248
+ * Defaults to `true`.
249
+ */
250
+ strictJsonSchema: z.boolean().nullish(),
251
+
252
+ /**
253
+ * Controls the verbosity of the model's responses. Lower values ('low') will result
254
+ * in more concise responses, while higher values ('high') will result in more verbose responses.
255
+ * Valid values: 'low', 'medium', 'high'.
256
+ */
257
+ textVerbosity: z.enum(['low', 'medium', 'high']).nullish(),
258
+
259
+ /**
260
+ * Controls output truncation. 'auto' (default) performs truncation automatically;
261
+ * 'disabled' turns truncation off.
262
+ */
263
+ truncation: z.enum(['auto', 'disabled']).nullish(),
264
+
265
+ /**
266
+ * A unique identifier representing your end-user, which can help OpenAI to
267
+ * monitor and detect abuse.
268
+ * Defaults to `undefined`.
269
+ * @see https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids
270
+ */
271
+ user: z.string().nullish(),
272
+
273
+ /**
274
+ * Override the system message mode for this model.
275
+ * - 'system': Use the 'system' role for system messages (default for most models)
276
+ * - 'developer': Use the 'developer' role for system messages (used by reasoning models)
277
+ * - 'remove': Remove system messages entirely
278
+ *
279
+ * If not specified, the mode is automatically determined based on the model.
280
+ */
281
+ systemMessageMode: z.enum(['system', 'developer', 'remove']).optional(),
282
+
283
+ /**
284
+ * Force treating this model as a reasoning model.
285
+ *
286
+ * This is useful for "stealth" reasoning models (e.g. via a custom baseURL)
287
+ * where the model ID is not recognized by the SDK's allowlist.
288
+ *
289
+ * When enabled, the SDK applies reasoning-model parameter compatibility rules
290
+ * and defaults `systemMessageMode` to `developer` unless overridden.
291
+ */
292
+ forceReasoning: z.boolean().optional(),
293
+ }),
294
+ ),
295
+ );
296
+
297
+ export type OpenAILanguageModelResponsesOptions = InferSchema<
298
+ typeof openaiLanguageModelResponsesOptionsSchema
299
+ >;
@@ -0,0 +1,408 @@
1
+ import {
2
+ LanguageModelV3CallOptions,
3
+ SharedV3Warning,
4
+ UnsupportedFunctionalityError,
5
+ } from '@ai-sdk/provider';
6
+ import { ToolNameMapping, validateTypes } from '@ai-sdk/provider-utils';
7
+ import { codeInterpreterArgsSchema } from '../tool/code-interpreter';
8
+ import { fileSearchArgsSchema } from '../tool/file-search';
9
+ import { imageGenerationArgsSchema } from '../tool/image-generation';
10
+ import { customArgsSchema } from '../tool/custom';
11
+ import { mcpArgsSchema } from '../tool/mcp';
12
+ import { shellArgsSchema } from '../tool/shell';
13
+ import { webSearchArgsSchema } from '../tool/web-search';
14
+ import { webSearchPreviewArgsSchema } from '../tool/web-search-preview';
15
+ import { OpenAIResponsesTool } from './openai-responses-api';
16
+
17
+ export async function prepareResponsesTools({
18
+ tools,
19
+ toolChoice,
20
+ toolNameMapping,
21
+ customProviderToolNames,
22
+ }: {
23
+ tools: LanguageModelV3CallOptions['tools'];
24
+ toolChoice: LanguageModelV3CallOptions['toolChoice'] | undefined;
25
+ toolNameMapping?: ToolNameMapping;
26
+ customProviderToolNames?: Set<string>;
27
+ }): Promise<{
28
+ tools?: Array<OpenAIResponsesTool>;
29
+ toolChoice?:
30
+ | 'auto'
31
+ | 'none'
32
+ | 'required'
33
+ | { type: 'file_search' }
34
+ | { type: 'web_search_preview' }
35
+ | { type: 'web_search' }
36
+ | { type: 'function'; name: string }
37
+ | { type: 'custom'; name: string }
38
+ | { type: 'code_interpreter' }
39
+ | { type: 'mcp' }
40
+ | { type: 'image_generation' }
41
+ | { type: 'apply_patch' };
42
+ toolWarnings: SharedV3Warning[];
43
+ }> {
44
+ // when the tools array is empty, change it to undefined to prevent errors:
45
+ tools = tools?.length ? tools : undefined;
46
+
47
+ const toolWarnings: SharedV3Warning[] = [];
48
+
49
+ if (tools == null) {
50
+ return { tools: undefined, toolChoice: undefined, toolWarnings };
51
+ }
52
+
53
+ const openaiTools: Array<OpenAIResponsesTool> = [];
54
+ const resolvedCustomProviderToolNames =
55
+ customProviderToolNames ?? new Set<string>();
56
+
57
+ for (const tool of tools) {
58
+ switch (tool.type) {
59
+ case 'function':
60
+ openaiTools.push({
61
+ type: 'function',
62
+ name: tool.name,
63
+ description: tool.description,
64
+ parameters: tool.inputSchema,
65
+ ...(tool.strict != null ? { strict: tool.strict } : {}),
66
+ });
67
+ break;
68
+ case 'provider': {
69
+ switch (tool.id) {
70
+ case 'openai.file_search': {
71
+ const args = await validateTypes({
72
+ value: tool.args,
73
+ schema: fileSearchArgsSchema,
74
+ });
75
+
76
+ openaiTools.push({
77
+ type: 'file_search',
78
+ vector_store_ids: args.vectorStoreIds,
79
+ max_num_results: args.maxNumResults,
80
+ ranking_options: args.ranking
81
+ ? {
82
+ ranker: args.ranking.ranker,
83
+ score_threshold: args.ranking.scoreThreshold,
84
+ }
85
+ : undefined,
86
+ filters: args.filters,
87
+ });
88
+
89
+ break;
90
+ }
91
+ case 'openai.local_shell': {
92
+ openaiTools.push({
93
+ type: 'local_shell',
94
+ });
95
+ break;
96
+ }
97
+ case 'openai.shell': {
98
+ const args = await validateTypes({
99
+ value: tool.args,
100
+ schema: shellArgsSchema,
101
+ });
102
+
103
+ openaiTools.push({
104
+ type: 'shell',
105
+ ...(args.environment && {
106
+ environment: mapShellEnvironment(args.environment),
107
+ }),
108
+ });
109
+ break;
110
+ }
111
+ case 'openai.apply_patch': {
112
+ openaiTools.push({
113
+ type: 'apply_patch',
114
+ });
115
+ break;
116
+ }
117
+ case 'openai.web_search_preview': {
118
+ const args = await validateTypes({
119
+ value: tool.args,
120
+ schema: webSearchPreviewArgsSchema,
121
+ });
122
+ openaiTools.push({
123
+ type: 'web_search_preview',
124
+ search_context_size: args.searchContextSize,
125
+ user_location: args.userLocation,
126
+ });
127
+ break;
128
+ }
129
+ case 'openai.web_search': {
130
+ const args = await validateTypes({
131
+ value: tool.args,
132
+ schema: webSearchArgsSchema,
133
+ });
134
+ openaiTools.push({
135
+ type: 'web_search',
136
+ filters:
137
+ args.filters != null
138
+ ? { allowed_domains: args.filters.allowedDomains }
139
+ : undefined,
140
+ external_web_access: args.externalWebAccess,
141
+ search_context_size: args.searchContextSize,
142
+ user_location: args.userLocation,
143
+ });
144
+ break;
145
+ }
146
+ case 'openai.code_interpreter': {
147
+ const args = await validateTypes({
148
+ value: tool.args,
149
+ schema: codeInterpreterArgsSchema,
150
+ });
151
+
152
+ openaiTools.push({
153
+ type: 'code_interpreter',
154
+ container:
155
+ args.container == null
156
+ ? { type: 'auto', file_ids: undefined }
157
+ : typeof args.container === 'string'
158
+ ? args.container
159
+ : { type: 'auto', file_ids: args.container.fileIds },
160
+ });
161
+ break;
162
+ }
163
+ case 'openai.image_generation': {
164
+ const args = await validateTypes({
165
+ value: tool.args,
166
+ schema: imageGenerationArgsSchema,
167
+ });
168
+
169
+ openaiTools.push({
170
+ type: 'image_generation',
171
+ background: args.background,
172
+ input_fidelity: args.inputFidelity,
173
+ input_image_mask: args.inputImageMask
174
+ ? {
175
+ file_id: args.inputImageMask.fileId,
176
+ image_url: args.inputImageMask.imageUrl,
177
+ }
178
+ : undefined,
179
+ model: args.model,
180
+ moderation: args.moderation,
181
+ partial_images: args.partialImages,
182
+ quality: args.quality,
183
+ output_compression: args.outputCompression,
184
+ output_format: args.outputFormat,
185
+ size: args.size,
186
+ });
187
+ break;
188
+ }
189
+ case 'openai.mcp': {
190
+ const args = await validateTypes({
191
+ value: tool.args,
192
+ schema: mcpArgsSchema,
193
+ });
194
+
195
+ const mapApprovalFilter = (filter: { toolNames?: string[] }) => ({
196
+ tool_names: filter.toolNames,
197
+ });
198
+
199
+ const requireApproval = args.requireApproval;
200
+ const requireApprovalParam:
201
+ | 'always'
202
+ | 'never'
203
+ | {
204
+ never?: { tool_names?: string[] };
205
+ }
206
+ | undefined =
207
+ requireApproval == null
208
+ ? undefined
209
+ : typeof requireApproval === 'string'
210
+ ? requireApproval
211
+ : requireApproval.never != null
212
+ ? { never: mapApprovalFilter(requireApproval.never) }
213
+ : undefined;
214
+
215
+ openaiTools.push({
216
+ type: 'mcp',
217
+ server_label: args.serverLabel,
218
+ allowed_tools: Array.isArray(args.allowedTools)
219
+ ? args.allowedTools
220
+ : args.allowedTools
221
+ ? {
222
+ read_only: args.allowedTools.readOnly,
223
+ tool_names: args.allowedTools.toolNames,
224
+ }
225
+ : undefined,
226
+ authorization: args.authorization,
227
+ connector_id: args.connectorId,
228
+ headers: args.headers,
229
+ require_approval: requireApprovalParam ?? 'never',
230
+ server_description: args.serverDescription,
231
+ server_url: args.serverUrl,
232
+ });
233
+
234
+ break;
235
+ }
236
+ case 'openai.custom': {
237
+ const args = await validateTypes({
238
+ value: tool.args,
239
+ schema: customArgsSchema,
240
+ });
241
+
242
+ openaiTools.push({
243
+ type: 'custom',
244
+ name: args.name,
245
+ description: args.description,
246
+ format: args.format,
247
+ });
248
+ resolvedCustomProviderToolNames.add(args.name);
249
+ break;
250
+ }
251
+ }
252
+ break;
253
+ }
254
+ default:
255
+ toolWarnings.push({
256
+ type: 'unsupported',
257
+ feature: `function tool ${tool}`,
258
+ });
259
+ break;
260
+ }
261
+ }
262
+
263
+ if (toolChoice == null) {
264
+ return { tools: openaiTools, toolChoice: undefined, toolWarnings };
265
+ }
266
+
267
+ const type = toolChoice.type;
268
+
269
+ switch (type) {
270
+ case 'auto':
271
+ case 'none':
272
+ case 'required':
273
+ return { tools: openaiTools, toolChoice: type, toolWarnings };
274
+ case 'tool': {
275
+ const resolvedToolName =
276
+ toolNameMapping?.toProviderToolName(toolChoice.toolName) ??
277
+ toolChoice.toolName;
278
+
279
+ return {
280
+ tools: openaiTools,
281
+ toolChoice:
282
+ resolvedToolName === 'code_interpreter' ||
283
+ resolvedToolName === 'file_search' ||
284
+ resolvedToolName === 'image_generation' ||
285
+ resolvedToolName === 'web_search_preview' ||
286
+ resolvedToolName === 'web_search' ||
287
+ resolvedToolName === 'mcp' ||
288
+ resolvedToolName === 'apply_patch'
289
+ ? { type: resolvedToolName }
290
+ : resolvedCustomProviderToolNames.has(resolvedToolName)
291
+ ? { type: 'custom', name: resolvedToolName }
292
+ : { type: 'function', name: resolvedToolName },
293
+ toolWarnings,
294
+ };
295
+ }
296
+ default: {
297
+ const _exhaustiveCheck: never = type;
298
+ throw new UnsupportedFunctionalityError({
299
+ functionality: `tool choice type: ${_exhaustiveCheck}`,
300
+ });
301
+ }
302
+ }
303
+ }
304
+
305
+ function mapShellEnvironment(environment: {
306
+ type?: string;
307
+ [key: string]: unknown;
308
+ }): NonNullable<
309
+ Extract<OpenAIResponsesTool, { type: 'shell' }>['environment']
310
+ > {
311
+ if (environment.type === 'containerReference') {
312
+ const env = environment as {
313
+ type: 'containerReference';
314
+ containerId: string;
315
+ };
316
+ return {
317
+ type: 'container_reference',
318
+ container_id: env.containerId,
319
+ };
320
+ }
321
+
322
+ if (environment.type === 'containerAuto') {
323
+ const env = environment as {
324
+ type: 'containerAuto';
325
+ fileIds?: string[];
326
+ memoryLimit?: '1g' | '4g' | '16g' | '64g';
327
+ networkPolicy?: {
328
+ type: string;
329
+ allowedDomains?: string[];
330
+ domainSecrets?: Array<{
331
+ domain: string;
332
+ name: string;
333
+ value: string;
334
+ }>;
335
+ };
336
+ skills?: Array<{
337
+ type: string;
338
+ skillId?: string;
339
+ version?: string;
340
+ name?: string;
341
+ description?: string;
342
+ source?: { type: string; mediaType: string; data: string };
343
+ }>;
344
+ };
345
+
346
+ return {
347
+ type: 'container_auto',
348
+ file_ids: env.fileIds,
349
+ memory_limit: env.memoryLimit,
350
+ network_policy:
351
+ env.networkPolicy == null
352
+ ? undefined
353
+ : env.networkPolicy.type === 'disabled'
354
+ ? { type: 'disabled' as const }
355
+ : {
356
+ type: 'allowlist' as const,
357
+ allowed_domains: env.networkPolicy.allowedDomains!,
358
+ domain_secrets: env.networkPolicy.domainSecrets,
359
+ },
360
+ skills: mapShellSkills(env.skills),
361
+ };
362
+ }
363
+
364
+ const env = environment as {
365
+ type?: 'local';
366
+ skills?: Array<{
367
+ name: string;
368
+ description: string;
369
+ path: string;
370
+ }>;
371
+ };
372
+ return {
373
+ type: 'local',
374
+ skills: env.skills,
375
+ };
376
+ }
377
+
378
+ function mapShellSkills(
379
+ skills:
380
+ | Array<{
381
+ type: string;
382
+ skillId?: string;
383
+ version?: string;
384
+ name?: string;
385
+ description?: string;
386
+ source?: { type: string; mediaType: string; data: string };
387
+ }>
388
+ | undefined,
389
+ ) {
390
+ return skills?.map(skill =>
391
+ skill.type === 'skillReference'
392
+ ? {
393
+ type: 'skill_reference' as const,
394
+ skill_id: skill.skillId!,
395
+ version: skill.version,
396
+ }
397
+ : {
398
+ type: 'inline' as const,
399
+ name: skill.name!,
400
+ description: skill.description!,
401
+ source: {
402
+ type: 'base64' as const,
403
+ media_type: skill.source!.mediaType as 'application/zip',
404
+ data: skill.source!.data,
405
+ },
406
+ },
407
+ );
408
+ }