@ai-sdk/openai 4.0.53 → 4.0.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.js +340 -75
- package/dist/index.js.map +1 -1
- package/dist/internal/index.d.ts +213 -207
- package/dist/internal/index.js +15 -14
- package/dist/internal/index.js.map +1 -1
- package/package.json +3 -3
- package/src/files/openai-files-api.ts +10 -0
- package/src/files/openai-files.ts +250 -46
- package/src/openai-responses-batch.ts +127 -9
- package/src/responses/openai-responses-api.ts +21 -19
- package/src/responses/openai-responses-language-model.ts +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-sdk/openai",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.55",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
}
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@ai-sdk/provider": "4.0.
|
|
39
|
-
"@ai-sdk/provider-utils": "5.0.
|
|
38
|
+
"@ai-sdk/provider": "4.0.10",
|
|
39
|
+
"@ai-sdk/provider-utils": "5.0.35"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@ai-sdk/test-server": "2.0.1",
|
|
@@ -15,3 +15,13 @@ export const openaiFilesResponseSchema = lazySchema(() =>
|
|
|
15
15
|
}),
|
|
16
16
|
),
|
|
17
17
|
);
|
|
18
|
+
|
|
19
|
+
export const openaiFileDeleteResponseSchema = lazySchema(() =>
|
|
20
|
+
zodSchema(
|
|
21
|
+
z.object({
|
|
22
|
+
id: z.string(),
|
|
23
|
+
object: z.string().nullish(),
|
|
24
|
+
deleted: z.boolean(),
|
|
25
|
+
}),
|
|
26
|
+
),
|
|
27
|
+
);
|
|
@@ -1,22 +1,40 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import {
|
|
2
|
+
InvalidArgumentError,
|
|
3
|
+
type FilesV4,
|
|
4
|
+
type FilesV4DeleteFileCallOptions,
|
|
5
|
+
type FilesV4DeleteFileResult,
|
|
6
|
+
type FilesV4DownloadFileCallOptions,
|
|
7
|
+
type FilesV4DownloadFileResult,
|
|
8
|
+
type FilesV4GetFileMetadataCallOptions,
|
|
9
|
+
type FilesV4GetFileMetadataResult,
|
|
10
|
+
type FilesV4UploadFileCallOptions,
|
|
11
|
+
type FilesV4UploadFileResult,
|
|
12
|
+
type SharedV4ProviderReference,
|
|
5
13
|
} from '@ai-sdk/provider';
|
|
6
14
|
import {
|
|
7
15
|
combineHeaders,
|
|
8
16
|
convertInlineFileDataToUint8Array,
|
|
17
|
+
createBinaryStreamResponseHandler,
|
|
9
18
|
createJsonResponseHandler,
|
|
19
|
+
deleteFromApi,
|
|
20
|
+
getFromApi,
|
|
10
21
|
parseProviderOptions,
|
|
11
22
|
postFormDataToApi,
|
|
23
|
+
postMultipartStreamToApi,
|
|
12
24
|
type FetchFunction,
|
|
25
|
+
type InferSchema,
|
|
26
|
+
type MultipartStreamPart,
|
|
13
27
|
} from '@ai-sdk/provider-utils';
|
|
14
28
|
import { openaiFailedResponseHandler } from '../openai-error';
|
|
15
|
-
import {
|
|
29
|
+
import {
|
|
30
|
+
openaiFileDeleteResponseSchema,
|
|
31
|
+
openaiFilesResponseSchema,
|
|
32
|
+
} from './openai-files-api';
|
|
16
33
|
import {
|
|
17
34
|
openaiFilesOptionsSchema,
|
|
18
35
|
type OpenAIFilesOptions,
|
|
19
36
|
} from './openai-files-options';
|
|
37
|
+
|
|
20
38
|
interface OpenAIFilesConfig {
|
|
21
39
|
provider: string;
|
|
22
40
|
baseURL: string;
|
|
@@ -24,6 +42,19 @@ interface OpenAIFilesConfig {
|
|
|
24
42
|
fetch?: FetchFunction;
|
|
25
43
|
}
|
|
26
44
|
|
|
45
|
+
type OpenAIFilesResponse = InferSchema<typeof openaiFilesResponseSchema>;
|
|
46
|
+
|
|
47
|
+
function encodePathSegment(value: string): string {
|
|
48
|
+
const encodedValue = encodeURIComponent(value);
|
|
49
|
+
|
|
50
|
+
// URL parsing normalizes both literal and percent-encoded dot segments.
|
|
51
|
+
return encodedValue === '.'
|
|
52
|
+
? '%252E'
|
|
53
|
+
: encodedValue === '..'
|
|
54
|
+
? '%252E%252E'
|
|
55
|
+
: encodedValue;
|
|
56
|
+
}
|
|
57
|
+
|
|
27
58
|
export class OpenAIFiles implements FilesV4 {
|
|
28
59
|
readonly specificationVersion = 'v4';
|
|
29
60
|
|
|
@@ -33,72 +64,245 @@ export class OpenAIFiles implements FilesV4 {
|
|
|
33
64
|
|
|
34
65
|
constructor(private readonly config: OpenAIFilesConfig) {}
|
|
35
66
|
|
|
67
|
+
private getFileId(file: SharedV4ProviderReference): string {
|
|
68
|
+
const fileId = file.openai;
|
|
69
|
+
if (fileId == null || fileId.trim() === '') {
|
|
70
|
+
throw new InvalidArgumentError({
|
|
71
|
+
argument: 'file',
|
|
72
|
+
message: "file reference is missing an 'openai' file id.",
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return fileId;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
private getHeaders(
|
|
79
|
+
headers: Record<string, string | undefined> | undefined,
|
|
80
|
+
): Record<string, string | undefined> {
|
|
81
|
+
return combineHeaders(this.config.headers(), headers);
|
|
82
|
+
}
|
|
83
|
+
|
|
36
84
|
async uploadFile({
|
|
37
85
|
data,
|
|
38
86
|
mediaType,
|
|
39
87
|
filename,
|
|
88
|
+
abortSignal,
|
|
89
|
+
headers,
|
|
40
90
|
providerOptions,
|
|
41
91
|
}: FilesV4UploadFileCallOptions): Promise<FilesV4UploadFileResult> {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
92
|
+
let openaiOptions: OpenAIFilesOptions | undefined;
|
|
93
|
+
try {
|
|
94
|
+
openaiOptions = (await parseProviderOptions({
|
|
95
|
+
provider: 'openai',
|
|
96
|
+
providerOptions,
|
|
97
|
+
schema: openaiFilesOptionsSchema,
|
|
98
|
+
})) as OpenAIFilesOptions | undefined;
|
|
99
|
+
} catch (error) {
|
|
100
|
+
// rejected before any request: release the caller's stream
|
|
101
|
+
if (data.type === 'stream') {
|
|
102
|
+
await data.stream.cancel(error).catch(() => {});
|
|
103
|
+
}
|
|
104
|
+
throw error;
|
|
105
|
+
}
|
|
47
106
|
|
|
48
|
-
const
|
|
107
|
+
const purpose = openaiOptions?.purpose ?? 'assistants';
|
|
108
|
+
const requestHeaders = this.getHeaders(headers);
|
|
109
|
+
const url = `${this.config.baseURL}/files`;
|
|
49
110
|
|
|
50
|
-
|
|
51
|
-
type: mediaType,
|
|
52
|
-
});
|
|
111
|
+
let response: OpenAIFilesResponse;
|
|
53
112
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
113
|
+
if (data.type === 'stream') {
|
|
114
|
+
const parts: Array<MultipartStreamPart> = [
|
|
115
|
+
{ type: 'field', name: 'purpose', value: purpose },
|
|
116
|
+
];
|
|
117
|
+
|
|
118
|
+
if (openaiOptions?.expiresAfter != null) {
|
|
119
|
+
parts.push(
|
|
120
|
+
{ type: 'field', name: 'expires_after[anchor]', value: 'created_at' },
|
|
121
|
+
{
|
|
122
|
+
type: 'field',
|
|
123
|
+
name: 'expires_after[seconds]',
|
|
124
|
+
value: String(openaiOptions.expiresAfter),
|
|
125
|
+
},
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
parts.push({
|
|
130
|
+
type: 'file',
|
|
131
|
+
name: 'file',
|
|
132
|
+
filename,
|
|
133
|
+
mediaType,
|
|
134
|
+
content: data.stream,
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
({ value: response } = await postMultipartStreamToApi({
|
|
138
|
+
url,
|
|
139
|
+
headers: requestHeaders,
|
|
140
|
+
parts,
|
|
141
|
+
failedResponseHandler: openaiFailedResponseHandler,
|
|
142
|
+
successfulResponseHandler: createJsonResponseHandler(
|
|
143
|
+
openaiFilesResponseSchema,
|
|
144
|
+
),
|
|
145
|
+
abortSignal,
|
|
146
|
+
fetch: this.config.fetch,
|
|
147
|
+
}));
|
|
57
148
|
} else {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
formData
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
149
|
+
const fileBytes = convertInlineFileDataToUint8Array(data);
|
|
150
|
+
|
|
151
|
+
const blob = new Blob([fileBytes], {
|
|
152
|
+
type: mediaType,
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
const formData = new FormData();
|
|
156
|
+
if (filename != null) {
|
|
157
|
+
formData.append('file', blob, filename);
|
|
158
|
+
} else {
|
|
159
|
+
formData.append('file', blob);
|
|
160
|
+
}
|
|
161
|
+
formData.append('purpose', purpose);
|
|
162
|
+
|
|
163
|
+
if (openaiOptions?.expiresAfter != null) {
|
|
164
|
+
formData.append('expires_after[anchor]', 'created_at');
|
|
165
|
+
formData.append(
|
|
166
|
+
'expires_after[seconds]',
|
|
167
|
+
String(openaiOptions.expiresAfter),
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
({ value: response } = await postFormDataToApi({
|
|
172
|
+
url,
|
|
173
|
+
headers: requestHeaders,
|
|
174
|
+
formData,
|
|
175
|
+
failedResponseHandler: openaiFailedResponseHandler,
|
|
176
|
+
successfulResponseHandler: createJsonResponseHandler(
|
|
177
|
+
openaiFilesResponseSchema,
|
|
178
|
+
),
|
|
179
|
+
abortSignal,
|
|
180
|
+
fetch: this.config.fetch,
|
|
181
|
+
}));
|
|
68
182
|
}
|
|
69
183
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
184
|
+
return {
|
|
185
|
+
warnings: [],
|
|
186
|
+
providerReference: { openai: response.id },
|
|
187
|
+
...((response.filename ?? filename)
|
|
188
|
+
? { filename: response.filename ?? filename }
|
|
189
|
+
: {}),
|
|
190
|
+
...(mediaType != null ? { mediaType } : {}),
|
|
191
|
+
...(response.bytes != null ? { byteSize: response.bytes } : {}),
|
|
192
|
+
...(response.created_at != null
|
|
193
|
+
? { createdAt: new Date(response.created_at * 1000) }
|
|
194
|
+
: {}),
|
|
195
|
+
...(response.expires_at != null
|
|
196
|
+
? { expiresAt: new Date(response.expires_at * 1000) }
|
|
197
|
+
: {}),
|
|
198
|
+
providerMetadata: {
|
|
199
|
+
openai: this.toFileMetadata(response),
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
async getFileMetadata({
|
|
205
|
+
file,
|
|
206
|
+
abortSignal,
|
|
207
|
+
headers,
|
|
208
|
+
}: FilesV4GetFileMetadataCallOptions): Promise<FilesV4GetFileMetadataResult> {
|
|
209
|
+
const fileId = this.getFileId(file);
|
|
210
|
+
|
|
211
|
+
const { value: response } = await getFromApi({
|
|
212
|
+
url: `${this.config.baseURL}/files/${encodePathSegment(fileId)}`,
|
|
213
|
+
headers: this.getHeaders(headers),
|
|
74
214
|
failedResponseHandler: openaiFailedResponseHandler,
|
|
75
215
|
successfulResponseHandler: createJsonResponseHandler(
|
|
76
216
|
openaiFilesResponseSchema,
|
|
77
217
|
),
|
|
218
|
+
abortSignal,
|
|
78
219
|
fetch: this.config.fetch,
|
|
220
|
+
validateUrl: false,
|
|
79
221
|
});
|
|
80
222
|
|
|
81
223
|
return {
|
|
82
224
|
warnings: [],
|
|
83
225
|
providerReference: { openai: response.id },
|
|
84
|
-
...(
|
|
85
|
-
|
|
226
|
+
...(response.filename != null ? { filename: response.filename } : {}),
|
|
227
|
+
...(response.bytes != null ? { byteSize: response.bytes } : {}),
|
|
228
|
+
...(response.created_at != null
|
|
229
|
+
? { createdAt: new Date(response.created_at * 1000) }
|
|
230
|
+
: {}),
|
|
231
|
+
...(response.expires_at != null
|
|
232
|
+
? { expiresAt: new Date(response.expires_at * 1000) }
|
|
86
233
|
: {}),
|
|
87
|
-
...(mediaType != null ? { mediaType } : {}),
|
|
88
234
|
providerMetadata: {
|
|
89
|
-
openai:
|
|
90
|
-
...(response.filename != null ? { filename: response.filename } : {}),
|
|
91
|
-
...(response.purpose != null ? { purpose: response.purpose } : {}),
|
|
92
|
-
...(response.bytes != null ? { bytes: response.bytes } : {}),
|
|
93
|
-
...(response.created_at != null
|
|
94
|
-
? { createdAt: response.created_at }
|
|
95
|
-
: {}),
|
|
96
|
-
...(response.status != null ? { status: response.status } : {}),
|
|
97
|
-
...(response.expires_at != null
|
|
98
|
-
? { expiresAt: response.expires_at }
|
|
99
|
-
: {}),
|
|
100
|
-
},
|
|
235
|
+
openai: this.toFileMetadata(response),
|
|
101
236
|
},
|
|
102
237
|
};
|
|
103
238
|
}
|
|
239
|
+
|
|
240
|
+
async downloadFile({
|
|
241
|
+
file,
|
|
242
|
+
abortSignal,
|
|
243
|
+
headers,
|
|
244
|
+
}: FilesV4DownloadFileCallOptions): Promise<FilesV4DownloadFileResult> {
|
|
245
|
+
const fileId = this.getFileId(file);
|
|
246
|
+
|
|
247
|
+
const { value: content, responseHeaders } = await getFromApi({
|
|
248
|
+
url: `${this.config.baseURL}/files/${encodePathSegment(fileId)}/content`,
|
|
249
|
+
headers: this.getHeaders(headers),
|
|
250
|
+
failedResponseHandler: openaiFailedResponseHandler,
|
|
251
|
+
successfulResponseHandler: createBinaryStreamResponseHandler(),
|
|
252
|
+
abortSignal,
|
|
253
|
+
fetch: this.config.fetch,
|
|
254
|
+
validateUrl: false,
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
// media type from the content endpoint's Content-Type, without parameters
|
|
258
|
+
const mediaType = responseHeaders?.['content-type']?.split(';')[0].trim();
|
|
259
|
+
|
|
260
|
+
return {
|
|
261
|
+
warnings: [],
|
|
262
|
+
content,
|
|
263
|
+
...(mediaType ? { mediaType } : {}),
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
async deleteFile({
|
|
268
|
+
file,
|
|
269
|
+
abortSignal,
|
|
270
|
+
headers,
|
|
271
|
+
}: FilesV4DeleteFileCallOptions): Promise<FilesV4DeleteFileResult> {
|
|
272
|
+
const fileId = this.getFileId(file);
|
|
273
|
+
|
|
274
|
+
const { value: response } = await deleteFromApi({
|
|
275
|
+
url: `${this.config.baseURL}/files/${encodePathSegment(fileId)}`,
|
|
276
|
+
headers: this.getHeaders(headers),
|
|
277
|
+
failedResponseHandler: openaiFailedResponseHandler,
|
|
278
|
+
successfulResponseHandler: createJsonResponseHandler(
|
|
279
|
+
openaiFileDeleteResponseSchema,
|
|
280
|
+
),
|
|
281
|
+
abortSignal,
|
|
282
|
+
fetch: this.config.fetch,
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
return {
|
|
286
|
+
warnings: [],
|
|
287
|
+
providerReference: { openai: response.id },
|
|
288
|
+
deleted: response.deleted,
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
private toFileMetadata(
|
|
293
|
+
response: OpenAIFilesResponse,
|
|
294
|
+
): Record<string, string | number> {
|
|
295
|
+
return {
|
|
296
|
+
...(response.filename != null ? { filename: response.filename } : {}),
|
|
297
|
+
...(response.purpose != null ? { purpose: response.purpose } : {}),
|
|
298
|
+
...(response.bytes != null ? { bytes: response.bytes } : {}),
|
|
299
|
+
...(response.created_at != null
|
|
300
|
+
? { createdAt: response.created_at }
|
|
301
|
+
: {}),
|
|
302
|
+
...(response.status != null ? { status: response.status } : {}),
|
|
303
|
+
...(response.expires_at != null
|
|
304
|
+
? { expiresAt: response.expires_at }
|
|
305
|
+
: {}),
|
|
306
|
+
};
|
|
307
|
+
}
|
|
104
308
|
}
|
|
@@ -44,7 +44,10 @@ import {
|
|
|
44
44
|
openaiResponsesResponseSchema,
|
|
45
45
|
type OpenAIResponsesLogprobs,
|
|
46
46
|
} from './responses/openai-responses-api';
|
|
47
|
-
import {
|
|
47
|
+
import {
|
|
48
|
+
mapWebSearchOutput,
|
|
49
|
+
OpenAIResponsesLanguageModel,
|
|
50
|
+
} from './responses/openai-responses-language-model';
|
|
48
51
|
import type { OpenAIResponsesModelId } from './responses/openai-responses-language-model-options';
|
|
49
52
|
import type { ResponsesReasoningProviderMetadata } from './responses/openai-responses-provider-metadata';
|
|
50
53
|
|
|
@@ -166,6 +169,23 @@ class OpenAIResponsesBatch {
|
|
|
166
169
|
for (const warning of preparedRequest.warnings) {
|
|
167
170
|
warnings.push({ requestId: request.id, warning });
|
|
168
171
|
}
|
|
172
|
+
|
|
173
|
+
for (const tool of request.options.tools ?? []) {
|
|
174
|
+
if (
|
|
175
|
+
tool.type === 'provider' &&
|
|
176
|
+
!openAIBatchConvertibleProviderToolIds.has(tool.id)
|
|
177
|
+
) {
|
|
178
|
+
warnings.push({
|
|
179
|
+
requestId: request.id,
|
|
180
|
+
warning: {
|
|
181
|
+
type: 'unsupported',
|
|
182
|
+
feature: `batch result conversion for tool "${tool.name}"`,
|
|
183
|
+
details:
|
|
184
|
+
'OpenAI may return output for this tool that AI SDK text batches cannot currently convert.',
|
|
185
|
+
},
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
}
|
|
169
189
|
}
|
|
170
190
|
|
|
171
191
|
const filename = 'batch.jsonl';
|
|
@@ -385,6 +405,14 @@ class OpenAIResponsesBatch {
|
|
|
385
405
|
}
|
|
386
406
|
}
|
|
387
407
|
|
|
408
|
+
const openAIBatchConvertibleProviderToolIds = new Set([
|
|
409
|
+
'openai.code_interpreter',
|
|
410
|
+
'openai.custom',
|
|
411
|
+
'openai.file_search',
|
|
412
|
+
'openai.web_search',
|
|
413
|
+
'openai.web_search_preview',
|
|
414
|
+
]);
|
|
415
|
+
|
|
388
416
|
export class OpenAIResponsesBatchLanguageModel
|
|
389
417
|
extends OpenAIResponsesLanguageModel
|
|
390
418
|
implements BatchLanguageModelV4
|
|
@@ -580,6 +608,7 @@ async function convertOpenAIResponsesBatchResponse(
|
|
|
580
608
|
|
|
581
609
|
const content: LanguageModelV4GenerateResult['content'] = [];
|
|
582
610
|
const logprobs: Array<NonNullable<OpenAIResponsesLogprobs>> = [];
|
|
611
|
+
let hasFunctionCall = false;
|
|
583
612
|
|
|
584
613
|
for (const part of response.output) {
|
|
585
614
|
switch (part.type) {
|
|
@@ -615,15 +644,104 @@ async function convertOpenAIResponsesBatchResponse(
|
|
|
615
644
|
}
|
|
616
645
|
|
|
617
646
|
case 'function_call':
|
|
647
|
+
hasFunctionCall = true;
|
|
648
|
+
content.push({
|
|
649
|
+
type: 'tool-call',
|
|
650
|
+
toolCallId: part.call_id,
|
|
651
|
+
toolName: part.name,
|
|
652
|
+
input: part.arguments,
|
|
653
|
+
providerMetadata: {
|
|
654
|
+
openai: {
|
|
655
|
+
itemId: part.id,
|
|
656
|
+
...(part.namespace != null && { namespace: part.namespace }),
|
|
657
|
+
...(part.caller != null && {
|
|
658
|
+
caller:
|
|
659
|
+
part.caller.type === 'program'
|
|
660
|
+
? { type: 'program', callerId: part.caller.caller_id }
|
|
661
|
+
: part.caller,
|
|
662
|
+
}),
|
|
663
|
+
},
|
|
664
|
+
},
|
|
665
|
+
});
|
|
666
|
+
break;
|
|
667
|
+
|
|
618
668
|
case 'custom_tool_call':
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
669
|
+
hasFunctionCall = true;
|
|
670
|
+
content.push({
|
|
671
|
+
type: 'tool-call',
|
|
672
|
+
toolCallId: part.call_id,
|
|
673
|
+
toolName: part.name,
|
|
674
|
+
input: JSON.stringify(part.input),
|
|
675
|
+
providerMetadata: { openai: { itemId: part.id } },
|
|
676
|
+
});
|
|
677
|
+
break;
|
|
678
|
+
|
|
679
|
+
case 'web_search_call':
|
|
680
|
+
content.push({
|
|
681
|
+
type: 'tool-call',
|
|
682
|
+
toolCallId: part.id,
|
|
683
|
+
toolName: 'web_search',
|
|
684
|
+
input: '{}',
|
|
685
|
+
providerExecuted: true,
|
|
686
|
+
dynamic: true,
|
|
687
|
+
});
|
|
688
|
+
content.push({
|
|
689
|
+
type: 'tool-result',
|
|
690
|
+
toolCallId: part.id,
|
|
691
|
+
toolName: 'web_search',
|
|
692
|
+
result: mapWebSearchOutput(part.action),
|
|
693
|
+
dynamic: true,
|
|
694
|
+
});
|
|
695
|
+
break;
|
|
696
|
+
|
|
697
|
+
case 'file_search_call':
|
|
698
|
+
content.push({
|
|
699
|
+
type: 'tool-call',
|
|
700
|
+
toolCallId: part.id,
|
|
701
|
+
toolName: 'file_search',
|
|
702
|
+
input: '{}',
|
|
703
|
+
providerExecuted: true,
|
|
704
|
+
dynamic: true,
|
|
705
|
+
});
|
|
706
|
+
content.push({
|
|
707
|
+
type: 'tool-result',
|
|
708
|
+
toolCallId: part.id,
|
|
709
|
+
toolName: 'file_search',
|
|
710
|
+
result: {
|
|
711
|
+
queries: part.queries,
|
|
712
|
+
results:
|
|
713
|
+
part.results?.map(result => ({
|
|
714
|
+
attributes: result.attributes,
|
|
715
|
+
fileId: result.file_id,
|
|
716
|
+
filename: result.filename,
|
|
717
|
+
score: result.score,
|
|
718
|
+
text: result.text,
|
|
719
|
+
})) ?? null,
|
|
625
720
|
},
|
|
626
|
-
|
|
721
|
+
dynamic: true,
|
|
722
|
+
});
|
|
723
|
+
break;
|
|
724
|
+
|
|
725
|
+
case 'code_interpreter_call':
|
|
726
|
+
content.push({
|
|
727
|
+
type: 'tool-call',
|
|
728
|
+
toolCallId: part.id,
|
|
729
|
+
toolName: 'code_interpreter',
|
|
730
|
+
input: JSON.stringify({
|
|
731
|
+
code: part.code,
|
|
732
|
+
containerId: part.container_id,
|
|
733
|
+
}),
|
|
734
|
+
providerExecuted: true,
|
|
735
|
+
dynamic: true,
|
|
736
|
+
});
|
|
737
|
+
content.push({
|
|
738
|
+
type: 'tool-result',
|
|
739
|
+
toolCallId: part.id,
|
|
740
|
+
toolName: 'code_interpreter',
|
|
741
|
+
result: { outputs: part.outputs },
|
|
742
|
+
dynamic: true,
|
|
743
|
+
});
|
|
744
|
+
break;
|
|
627
745
|
|
|
628
746
|
default:
|
|
629
747
|
return {
|
|
@@ -658,7 +776,7 @@ async function convertOpenAIResponsesBatchResponse(
|
|
|
658
776
|
finishReason: {
|
|
659
777
|
unified: mapOpenAIResponseFinishReason({
|
|
660
778
|
finishReason: response.incomplete_details?.reason,
|
|
661
|
-
hasFunctionCall
|
|
779
|
+
hasFunctionCall,
|
|
662
780
|
}),
|
|
663
781
|
raw: response.incomplete_details?.reason ?? undefined,
|
|
664
782
|
},
|
|
@@ -831,24 +831,26 @@ export const openaiResponsesChunkSchema = lazySchema(() =>
|
|
|
831
831
|
type: z.enum(['response.completed', 'response.incomplete']),
|
|
832
832
|
response: z.object({
|
|
833
833
|
incomplete_details: z.object({ reason: z.string() }).nullish(),
|
|
834
|
-
usage: z
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
834
|
+
usage: z
|
|
835
|
+
.object({
|
|
836
|
+
input_tokens: z.number(),
|
|
837
|
+
input_tokens_details: z
|
|
838
|
+
.object({
|
|
839
|
+
cached_tokens: z.number().nullish(),
|
|
840
|
+
cache_write_tokens: z.number().nullish(),
|
|
841
|
+
orchestration_input_tokens: z.number().nullish(),
|
|
842
|
+
orchestration_input_cached_tokens: z.number().nullish(),
|
|
843
|
+
})
|
|
844
|
+
.nullish(),
|
|
845
|
+
output_tokens: z.number(),
|
|
846
|
+
output_tokens_details: z
|
|
847
|
+
.object({
|
|
848
|
+
reasoning_tokens: z.number().nullish(),
|
|
849
|
+
orchestration_output_tokens: z.number().nullish(),
|
|
850
|
+
})
|
|
851
|
+
.nullish(),
|
|
852
|
+
})
|
|
853
|
+
.nullish(),
|
|
852
854
|
reasoning: z
|
|
853
855
|
.object({
|
|
854
856
|
context: z.string().nullish(),
|
|
@@ -1762,7 +1764,7 @@ export const openaiResponsesResponseSchema = lazySchema(() =>
|
|
|
1762
1764
|
})
|
|
1763
1765
|
.nullish(),
|
|
1764
1766
|
})
|
|
1765
|
-
.
|
|
1767
|
+
.nullish(),
|
|
1766
1768
|
}),
|
|
1767
1769
|
),
|
|
1768
1770
|
);
|
|
@@ -2584,7 +2584,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
|
|
|
2584
2584
|
raw: value.response.incomplete_details?.reason ?? undefined,
|
|
2585
2585
|
};
|
|
2586
2586
|
}
|
|
2587
|
-
usage = value.response.usage;
|
|
2587
|
+
usage = value.response.usage ?? undefined;
|
|
2588
2588
|
if (typeof value.response.service_tier === 'string') {
|
|
2589
2589
|
serviceTier = value.response.service_tier;
|
|
2590
2590
|
}
|
|
@@ -2915,7 +2915,7 @@ function isResponseOutputChunk(chunk: OpenAIResponsesChunk): boolean {
|
|
|
2915
2915
|
);
|
|
2916
2916
|
}
|
|
2917
2917
|
|
|
2918
|
-
function mapWebSearchOutput(
|
|
2918
|
+
export function mapWebSearchOutput(
|
|
2919
2919
|
action: OpenAIResponsesWebSearchAction | null | undefined,
|
|
2920
2920
|
): InferSchema<typeof webSearchOutputSchema> {
|
|
2921
2921
|
if (action == null) {
|