@ai-sdk/openai 4.0.56 → 4.0.57

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/openai",
3
- "version": "4.0.56",
3
+ "version": "4.0.57",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "sideEffects": false,
@@ -20,6 +20,7 @@ import {
20
20
  getFromApi,
21
21
  lazySchema,
22
22
  normalizeBatchRequestCounts,
23
+ parseProviderOptions,
23
24
  postJsonToApi,
24
25
  postToApi,
25
26
  safeValidateTypes,
@@ -52,7 +53,25 @@ import type { OpenAIResponsesModelId } from './responses/openai-responses-langua
52
53
  import type { ResponsesReasoningProviderMetadata } from './responses/openai-responses-provider-metadata';
53
54
 
54
55
  const openaiBatchEndpoint = '/v1/responses';
55
- const openaiBatchInputFileExpiresAfterSeconds = 48 * 60 * 60;
56
+ const openaiBatchInputFileDefaultExpiresAfterSeconds = 48 * 60 * 60;
57
+
58
+ const openaiBatchProviderOptionsSchema = lazySchema(() =>
59
+ zodSchema(
60
+ z.object({
61
+ /**
62
+ * TTL in seconds for the uploaded batch input file, measured from
63
+ * upload time. OpenAI accepts integers between 3600 (1 hour) and
64
+ * 2592000 (30 days) inclusive. Defaults to 48 hours.
65
+ */
66
+ inputFileExpiresAfter: z
67
+ .number()
68
+ .int()
69
+ .min(3600)
70
+ .max(2_592_000)
71
+ .optional(),
72
+ }),
73
+ ),
74
+ );
56
75
 
57
76
  type OpenAIBatchRequest = Parameters<
58
77
  BatchLanguageModelV4['experimental_doStartBatch']
@@ -153,6 +172,13 @@ class OpenAIResponsesBatch {
153
172
  },
154
173
  ];
155
174
 
175
+ const batchOptions = await this.parseBatchProviderOptions(
176
+ options.providerOptions,
177
+ );
178
+ const inputFileExpiresAfterSeconds =
179
+ batchOptions?.inputFileExpiresAfter ??
180
+ openaiBatchInputFileDefaultExpiresAfterSeconds;
181
+
156
182
  for (const request of options.requests) {
157
183
  const preparedRequest = await this.options.prepareRequest(request);
158
184
 
@@ -200,7 +226,7 @@ class OpenAIResponsesBatch {
200
226
  formData.append('expires_after[anchor]', 'created_at');
201
227
  formData.append(
202
228
  'expires_after[seconds]',
203
- String(openaiBatchInputFileExpiresAfterSeconds),
229
+ String(inputFileExpiresAfterSeconds),
204
230
  );
205
231
 
206
232
  const { value: uploadedFile } = await postToApi({
@@ -211,9 +237,7 @@ class OpenAIResponsesBatch {
211
237
  values: {
212
238
  purpose: 'batch',
213
239
  'expires_after[anchor]': 'created_at',
214
- 'expires_after[seconds]': String(
215
- openaiBatchInputFileExpiresAfterSeconds,
216
- ),
240
+ 'expires_after[seconds]': String(inputFileExpiresAfterSeconds),
217
241
  file: {
218
242
  name: filename,
219
243
  type: file.type,
@@ -245,13 +269,44 @@ class OpenAIResponsesBatch {
245
269
  fetch: this.options.config.fetch,
246
270
  });
247
271
 
272
+ const inputFileExpiresAt = convertUnixTimestamp(uploadedFile.expires_at);
273
+
248
274
  return {
249
275
  batchId: batch.id,
250
276
  ...convertOpenAIBatchStatus(batch),
277
+ providerMetadata: {
278
+ openai: {
279
+ inputFileId: uploadedFile.id,
280
+ ...(inputFileExpiresAt != null ? { inputFileExpiresAt } : {}),
281
+ },
282
+ },
251
283
  warnings,
252
284
  };
253
285
  }
254
286
 
287
+ private async parseBatchProviderOptions(
288
+ providerOptions: BatchV4StartOptions<OpenAIBatchRequest>['providerOptions'],
289
+ ) {
290
+ const providerOptionsName = this.options.config.provider.includes('azure')
291
+ ? 'azure'
292
+ : 'openai';
293
+ let batchOptions = await parseProviderOptions({
294
+ provider: providerOptionsName,
295
+ providerOptions,
296
+ schema: openaiBatchProviderOptionsSchema,
297
+ });
298
+
299
+ if (batchOptions == null && providerOptionsName !== 'openai') {
300
+ batchOptions = await parseProviderOptions({
301
+ provider: 'openai',
302
+ providerOptions,
303
+ schema: openaiBatchProviderOptionsSchema,
304
+ });
305
+ }
306
+
307
+ return batchOptions;
308
+ }
309
+
255
310
  async getBatchStatus(
256
311
  options: BatchV4OperationOptions,
257
312
  ): Promise<BatchV4Status> {
@@ -1,19 +1,24 @@
1
- import type { LanguageModelV4Usage } from '@ai-sdk/provider';
1
+ import type { JSONObject, LanguageModelV4Usage } from '@ai-sdk/provider';
2
2
  import { createNullLanguageModelUsage } from '@ai-sdk/provider-utils';
3
3
 
4
- export type OpenAIResponsesUsage = {
4
+ export type OpenAIResponsesUsage = JSONObject & {
5
5
  input_tokens: number;
6
6
  output_tokens: number;
7
- input_tokens_details?: {
8
- cached_tokens?: number | null;
9
- cache_write_tokens?: number | null;
10
- orchestration_input_tokens?: number | null;
11
- orchestration_input_cached_tokens?: number | null;
12
- } | null;
13
- output_tokens_details?: {
14
- reasoning_tokens?: number | null;
15
- orchestration_output_tokens?: number | null;
16
- } | null;
7
+ total_tokens?: number;
8
+ input_tokens_details?:
9
+ | (JSONObject & {
10
+ cached_tokens?: number | null;
11
+ cache_write_tokens?: number | null;
12
+ orchestration_input_tokens?: number | null;
13
+ orchestration_input_cached_tokens?: number | null;
14
+ })
15
+ | null;
16
+ output_tokens_details?:
17
+ | (JSONObject & {
18
+ reasoning_tokens?: number | null;
19
+ orchestration_output_tokens?: number | null;
20
+ })
21
+ | null;
17
22
  };
18
23
 
19
24
  export function convertOpenAIResponsesUsage(
@@ -18,6 +18,37 @@ const jsonValueSchema: z.ZodType<JSONValue> = z.lazy(() =>
18
18
  ]),
19
19
  );
20
20
 
21
+ const jsonObjectSchema = z.record(z.string(), jsonValueSchema.optional());
22
+
23
+ const openaiResponsesUsageSchema = z.intersection(
24
+ jsonObjectSchema,
25
+ z.object({
26
+ input_tokens: z.number(),
27
+ input_tokens_details: z
28
+ .intersection(
29
+ jsonObjectSchema,
30
+ z.object({
31
+ cached_tokens: z.number().nullish(),
32
+ cache_write_tokens: z.number().nullish(),
33
+ orchestration_input_tokens: z.number().nullish(),
34
+ orchestration_input_cached_tokens: z.number().nullish(),
35
+ }),
36
+ )
37
+ .nullish(),
38
+ output_tokens: z.number(),
39
+ output_tokens_details: z
40
+ .intersection(
41
+ jsonObjectSchema,
42
+ z.object({
43
+ reasoning_tokens: z.number().nullish(),
44
+ orchestration_output_tokens: z.number().nullish(),
45
+ }),
46
+ )
47
+ .nullish(),
48
+ total_tokens: z.number().optional(),
49
+ }),
50
+ );
51
+
21
52
  const openaiResponsesComputerSafetyCheckSchema = z.object({
22
53
  id: z.string(),
23
54
  code: z.string().nullish(),
@@ -831,26 +862,7 @@ export const openaiResponsesChunkSchema = lazySchema(() =>
831
862
  type: z.enum(['response.completed', 'response.incomplete']),
832
863
  response: z.object({
833
864
  incomplete_details: z.object({ reason: z.string() }).nullish(),
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(),
865
+ usage: openaiResponsesUsageSchema.nullish(),
854
866
  reasoning: z
855
867
  .object({
856
868
  context: z.string().nullish(),
@@ -870,26 +882,7 @@ export const openaiResponsesChunkSchema = lazySchema(() =>
870
882
  })
871
883
  .nullish(),
872
884
  incomplete_details: z.object({ reason: z.string() }).nullish(),
873
- usage: z
874
- .object({
875
- input_tokens: z.number(),
876
- input_tokens_details: z
877
- .object({
878
- cached_tokens: z.number().nullish(),
879
- cache_write_tokens: z.number().nullish(),
880
- orchestration_input_tokens: z.number().nullish(),
881
- orchestration_input_cached_tokens: z.number().nullish(),
882
- })
883
- .nullish(),
884
- output_tokens: z.number(),
885
- output_tokens_details: z
886
- .object({
887
- reasoning_tokens: z.number().nullish(),
888
- orchestration_output_tokens: z.number().nullish(),
889
- })
890
- .nullish(),
891
- })
892
- .nullish(),
885
+ usage: openaiResponsesUsageSchema.nullish(),
893
886
  reasoning: z
894
887
  .object({
895
888
  context: z.string().nullish(),
@@ -1745,26 +1738,7 @@ export const openaiResponsesResponseSchema = lazySchema(() =>
1745
1738
  })
1746
1739
  .nullish(),
1747
1740
  incomplete_details: z.object({ reason: z.string() }).nullish(),
1748
- usage: z
1749
- .object({
1750
- input_tokens: z.number(),
1751
- input_tokens_details: z
1752
- .object({
1753
- cached_tokens: z.number().nullish(),
1754
- cache_write_tokens: z.number().nullish(),
1755
- orchestration_input_tokens: z.number().nullish(),
1756
- orchestration_input_cached_tokens: z.number().nullish(),
1757
- })
1758
- .nullish(),
1759
- output_tokens: z.number(),
1760
- output_tokens_details: z
1761
- .object({
1762
- reasoning_tokens: z.number().nullish(),
1763
- orchestration_output_tokens: z.number().nullish(),
1764
- })
1765
- .nullish(),
1766
- })
1767
- .nullish(),
1741
+ usage: openaiResponsesUsageSchema.nullish(),
1768
1742
  }),
1769
1743
  ),
1770
1744
  );