@ai-sdk/xai 4.0.53 → 4.0.54

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/xai",
3
- "version": "4.0.53",
3
+ "version": "4.0.54",
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
  postFormDataToApi,
24
25
  postJsonToApi,
25
26
  safeValidateTypes,
@@ -48,6 +49,24 @@ const xaiBatchEndpoint = '/v1/responses';
48
49
  const xaiBatchName = 'ai-sdk-text-batch';
49
50
  const xaiBatchResultsPageSize = 1000;
50
51
 
52
+ const xaiBatchProviderOptionsSchema = lazySchema(() =>
53
+ zodSchema(
54
+ z.object({
55
+ /**
56
+ * TTL in seconds for the uploaded batch input file, measured from
57
+ * upload time. xAI accepts integers between 3600 (1 hour) and
58
+ * 2592000 (30 days) inclusive. Without it the file has no expiry.
59
+ */
60
+ inputFileExpiresAfter: z
61
+ .number()
62
+ .int()
63
+ .min(3600)
64
+ .max(2_592_000)
65
+ .optional(),
66
+ }),
67
+ ),
68
+ );
69
+
51
70
  type XaiBatchRequest = Parameters<
52
71
  BatchLanguageModelV4['experimental_doStartBatch']
53
72
  >[0]['requests'][number];
@@ -144,6 +163,12 @@ class XaiResponsesBatch {
144
163
  },
145
164
  ];
146
165
 
166
+ const batchOptions = await parseProviderOptions({
167
+ provider: 'xai',
168
+ providerOptions: options.providerOptions,
169
+ schema: xaiBatchProviderOptionsSchema,
170
+ });
171
+
147
172
  for (const request of options.requests) {
148
173
  const preparedRequest = await this.options.prepareRequest(request);
149
174
 
@@ -166,6 +191,14 @@ class XaiResponsesBatch {
166
191
  const file = new Blob(fileParts, { type: 'application/jsonl' });
167
192
  fileParts.length = 0;
168
193
  const formData = new FormData();
194
+ // xAI rejects uploads where expires_after arrives after the file part,
195
+ // so all fields precede the file.
196
+ if (batchOptions?.inputFileExpiresAfter != null) {
197
+ formData.append(
198
+ 'expires_after',
199
+ String(batchOptions.inputFileExpiresAfter),
200
+ );
201
+ }
169
202
  formData.append('file', file, filename);
170
203
 
171
204
  const headers = combineHeaders(
@@ -203,6 +236,18 @@ class XaiResponsesBatch {
203
236
  return {
204
237
  batchId: batch.batch_id,
205
238
  ...convertXaiBatchStatus(batch),
239
+ providerMetadata: {
240
+ xai: {
241
+ inputFileId: uploadedFile.id,
242
+ ...(uploadedFile.expires_at != null
243
+ ? {
244
+ inputFileExpiresAt: new Date(
245
+ uploadedFile.expires_at * 1000,
246
+ ).toISOString(),
247
+ }
248
+ : {}),
249
+ },
250
+ },
206
251
  warnings,
207
252
  };
208
253
  }