@ai-sdk/xai 4.0.51 → 4.0.53

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 CHANGED
@@ -1,5 +1,21 @@
1
1
  # @ai-sdk/xai
2
2
 
3
+ ## 4.0.53
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [6bcc0f8]
8
+ - @ai-sdk/provider-utils@5.0.36
9
+
10
+ ## 4.0.52
11
+
12
+ ### Patch Changes
13
+
14
+ - f1513f0: feat(xai): implement `getFileMetadata`, `downloadFile` (streaming), and `deleteFile` on the xAI files interface, support `expiresAfter` upload TTLs (integer 3600–2592000 seconds, emitted before the file part as xAI requires) and streaming uploads via `{ type: 'stream' }` data, expose `byteSize`/`createdAt`/`expiresAt` on upload results, and thread `abortSignal`/`headers` through all file operations; blank and dot-segment file ids are rejected/encoded so they cannot retarget request paths
15
+ - Updated dependencies [5190b67]
16
+ - @ai-sdk/provider@4.0.10
17
+ - @ai-sdk/provider-utils@5.0.35
18
+
3
19
  ## 4.0.51
4
20
 
5
21
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -248,6 +248,7 @@ declare const xaiFilesOptionsSchema: _ai_sdk_provider_utils.LazySchema<{
248
248
  [x: string]: unknown;
249
249
  teamId?: string | undefined;
250
250
  filePath?: string | undefined;
251
+ expiresAfter?: number | undefined;
251
252
  }>;
252
253
  type XaiFilesOptions = InferSchema<typeof xaiFilesOptionsSchema>;
253
254
 
package/dist/index.js CHANGED
@@ -1270,12 +1270,22 @@ var xaiFilesResponseSchema = lazySchema(
1270
1270
  object: z7.string().nullish(),
1271
1271
  bytes: z7.number().nullish(),
1272
1272
  created_at: z7.number().nullish(),
1273
+ expires_at: z7.number().nullish(),
1273
1274
  filename: z7.string().nullish(),
1274
1275
  purpose: z7.string().nullish(),
1275
1276
  status: z7.string().nullish()
1276
1277
  })
1277
1278
  )
1278
1279
  );
1280
+ var xaiFileDeleteResponseSchema = lazySchema(
1281
+ () => zodSchema(
1282
+ z7.object({
1283
+ id: z7.string(),
1284
+ object: z7.string().nullish(),
1285
+ deleted: z7.boolean()
1286
+ })
1287
+ )
1288
+ );
1279
1289
 
1280
1290
  // src/responses/xai-responses-language-model.ts
1281
1291
  import {
@@ -4319,15 +4329,22 @@ var xaiTools = {
4319
4329
  };
4320
4330
 
4321
4331
  // src/version.ts
4322
- var VERSION = true ? "4.0.51" : "0.0.0-test";
4332
+ var VERSION = true ? "4.0.53" : "0.0.0-test";
4323
4333
 
4324
4334
  // src/files/xai-files.ts
4335
+ import {
4336
+ InvalidArgumentError as InvalidArgumentError2
4337
+ } from "@ai-sdk/provider";
4325
4338
  import {
4326
4339
  combineHeaders as combineHeaders5,
4327
4340
  convertInlineFileDataToUint8Array,
4341
+ createBinaryStreamResponseHandler,
4328
4342
  createJsonResponseHandler as createJsonResponseHandler5,
4343
+ deleteFromApi,
4344
+ getFromApi as getFromApi3,
4329
4345
  parseProviderOptions as parseProviderOptions6,
4330
- postFormDataToApi as postFormDataToApi2
4346
+ postFormDataToApi as postFormDataToApi2,
4347
+ postMultipartStreamToApi
4331
4348
  } from "@ai-sdk/provider-utils";
4332
4349
 
4333
4350
  // src/files/xai-files-options.ts
@@ -4340,12 +4357,22 @@ var xaiFilesOptionsSchema = lazySchema8(
4340
4357
  () => zodSchema8(
4341
4358
  z19.looseObject({
4342
4359
  teamId: z19.string().optional(),
4343
- filePath: z19.string().optional()
4360
+ filePath: z19.string().optional(),
4361
+ /**
4362
+ * TTL in seconds measured from upload time; xAI accepts integers
4363
+ * between 3600 (1 hour) and 2592000 (30 days) inclusive.
4364
+ * Omit to keep the file until it is deleted.
4365
+ */
4366
+ expiresAfter: z19.number().int().min(3600).max(2592e3).optional()
4344
4367
  })
4345
4368
  )
4346
4369
  );
4347
4370
 
4348
4371
  // src/files/xai-files.ts
4372
+ function encodePathSegment(value) {
4373
+ const encodedValue = encodeURIComponent(value);
4374
+ return encodedValue === "." ? "%252E" : encodedValue === ".." ? "%252E%252E" : encodedValue;
4375
+ }
4349
4376
  var XaiFiles = class {
4350
4377
  constructor(config) {
4351
4378
  this.config = config;
@@ -4354,55 +4381,205 @@ var XaiFiles = class {
4354
4381
  get provider() {
4355
4382
  return this.config.provider;
4356
4383
  }
4384
+ getFileId(file) {
4385
+ const fileId = file.xai;
4386
+ if (fileId == null || fileId.trim() === "") {
4387
+ throw new InvalidArgumentError2({
4388
+ argument: "file",
4389
+ message: "file reference is missing an 'xai' file id."
4390
+ });
4391
+ }
4392
+ return fileId;
4393
+ }
4394
+ getHeaders(headers) {
4395
+ return combineHeaders5(this.config.headers(), headers);
4396
+ }
4357
4397
  async uploadFile({
4358
4398
  data,
4359
4399
  mediaType,
4360
4400
  filename,
4401
+ abortSignal,
4402
+ headers,
4361
4403
  providerOptions
4362
4404
  }) {
4363
4405
  var _a, _b;
4364
- const xaiOptions = await parseProviderOptions6({
4365
- provider: "xai",
4366
- providerOptions,
4367
- schema: xaiFilesOptionsSchema
4368
- });
4369
- const fileBytes = convertInlineFileDataToUint8Array(data);
4370
- const blob = new Blob([fileBytes], {
4371
- type: mediaType
4372
- });
4373
- const formData = new FormData();
4374
- if (filename != null) {
4375
- formData.append("file", blob, filename);
4376
- } else {
4377
- formData.append("file", blob);
4406
+ let xaiOptions;
4407
+ try {
4408
+ xaiOptions = await parseProviderOptions6({
4409
+ provider: "xai",
4410
+ providerOptions,
4411
+ schema: xaiFilesOptionsSchema
4412
+ });
4413
+ } catch (error) {
4414
+ if (data.type === "stream") {
4415
+ await data.stream.cancel(error).catch(() => {
4416
+ });
4417
+ }
4418
+ throw error;
4378
4419
  }
4379
- if ((xaiOptions == null ? void 0 : xaiOptions.teamId) != null) {
4380
- formData.append("team_id", xaiOptions.teamId);
4420
+ const requestHeaders = this.getHeaders(headers);
4421
+ const url = `${this.config.baseURL}/files`;
4422
+ let response;
4423
+ if (data.type === "stream") {
4424
+ const parts = [];
4425
+ if ((xaiOptions == null ? void 0 : xaiOptions.expiresAfter) != null) {
4426
+ parts.push({
4427
+ type: "field",
4428
+ name: "expires_after",
4429
+ value: String(xaiOptions.expiresAfter)
4430
+ });
4431
+ }
4432
+ if ((xaiOptions == null ? void 0 : xaiOptions.teamId) != null) {
4433
+ parts.push({
4434
+ type: "field",
4435
+ name: "team_id",
4436
+ value: xaiOptions.teamId
4437
+ });
4438
+ }
4439
+ parts.push({
4440
+ type: "file",
4441
+ name: "file",
4442
+ filename,
4443
+ mediaType,
4444
+ content: data.stream
4445
+ });
4446
+ ({ value: response } = await postMultipartStreamToApi({
4447
+ url,
4448
+ headers: requestHeaders,
4449
+ parts,
4450
+ failedResponseHandler: xaiFailedResponseHandler,
4451
+ successfulResponseHandler: createJsonResponseHandler5(
4452
+ xaiFilesResponseSchema
4453
+ ),
4454
+ abortSignal,
4455
+ fetch: this.config.fetch
4456
+ }));
4457
+ } else {
4458
+ const fileBytes = convertInlineFileDataToUint8Array(data);
4459
+ const blob = new Blob([fileBytes], {
4460
+ type: mediaType
4461
+ });
4462
+ const formData = new FormData();
4463
+ if ((xaiOptions == null ? void 0 : xaiOptions.expiresAfter) != null) {
4464
+ formData.append("expires_after", String(xaiOptions.expiresAfter));
4465
+ }
4466
+ if ((xaiOptions == null ? void 0 : xaiOptions.teamId) != null) {
4467
+ formData.append("team_id", xaiOptions.teamId);
4468
+ }
4469
+ if (filename != null) {
4470
+ formData.append("file", blob, filename);
4471
+ } else {
4472
+ formData.append("file", blob);
4473
+ }
4474
+ ({ value: response } = await postFormDataToApi2({
4475
+ url,
4476
+ headers: requestHeaders,
4477
+ formData,
4478
+ failedResponseHandler: xaiFailedResponseHandler,
4479
+ successfulResponseHandler: createJsonResponseHandler5(
4480
+ xaiFilesResponseSchema
4481
+ ),
4482
+ abortSignal,
4483
+ fetch: this.config.fetch
4484
+ }));
4381
4485
  }
4382
- const { value: response } = await postFormDataToApi2({
4383
- url: `${this.config.baseURL}/files`,
4384
- headers: combineHeaders5(this.config.headers()),
4385
- formData,
4486
+ return {
4487
+ warnings: [],
4488
+ providerReference: { xai: response.id },
4489
+ ...((_a = response.filename) != null ? _a : filename) ? { filename: (_b = response.filename) != null ? _b : filename } : {},
4490
+ ...mediaType != null ? { mediaType } : {},
4491
+ ...response.bytes != null ? { byteSize: response.bytes } : {},
4492
+ ...response.created_at != null ? { createdAt: new Date(response.created_at * 1e3) } : {},
4493
+ ...response.expires_at != null ? { expiresAt: new Date(response.expires_at * 1e3) } : {},
4494
+ providerMetadata: {
4495
+ xai: this.toFileMetadata(response)
4496
+ }
4497
+ };
4498
+ }
4499
+ async getFileMetadata({
4500
+ file,
4501
+ abortSignal,
4502
+ headers
4503
+ }) {
4504
+ const fileId = this.getFileId(file);
4505
+ const { value: response } = await getFromApi3({
4506
+ url: `${this.config.baseURL}/files/${encodePathSegment(fileId)}`,
4507
+ headers: this.getHeaders(headers),
4386
4508
  failedResponseHandler: xaiFailedResponseHandler,
4387
4509
  successfulResponseHandler: createJsonResponseHandler5(
4388
4510
  xaiFilesResponseSchema
4389
4511
  ),
4390
- fetch: this.config.fetch
4512
+ abortSignal,
4513
+ fetch: this.config.fetch,
4514
+ validateUrl: false
4391
4515
  });
4392
4516
  return {
4393
4517
  warnings: [],
4394
4518
  providerReference: { xai: response.id },
4395
- ...((_a = response.filename) != null ? _a : filename) ? { filename: (_b = response.filename) != null ? _b : filename } : {},
4396
- ...mediaType != null ? { mediaType } : {},
4519
+ ...response.filename != null ? { filename: response.filename } : {},
4520
+ ...response.bytes != null ? { byteSize: response.bytes } : {},
4521
+ ...response.created_at != null ? { createdAt: new Date(response.created_at * 1e3) } : {},
4522
+ ...response.expires_at != null ? { expiresAt: new Date(response.expires_at * 1e3) } : {},
4397
4523
  providerMetadata: {
4398
- xai: {
4399
- ...response.filename != null ? { filename: response.filename } : {},
4400
- ...response.bytes != null ? { bytes: response.bytes } : {},
4401
- ...response.created_at != null ? { createdAt: response.created_at } : {}
4402
- }
4524
+ xai: this.toFileMetadata(response)
4403
4525
  }
4404
4526
  };
4405
4527
  }
4528
+ async downloadFile({
4529
+ file,
4530
+ abortSignal,
4531
+ headers
4532
+ }) {
4533
+ var _a;
4534
+ const fileId = this.getFileId(file);
4535
+ const { value: content, responseHeaders } = await getFromApi3({
4536
+ url: `${this.config.baseURL}/files/${encodePathSegment(fileId)}/content`,
4537
+ headers: this.getHeaders(headers),
4538
+ failedResponseHandler: xaiFailedResponseHandler,
4539
+ successfulResponseHandler: createBinaryStreamResponseHandler(),
4540
+ abortSignal,
4541
+ fetch: this.config.fetch,
4542
+ validateUrl: false
4543
+ });
4544
+ const mediaType = (_a = responseHeaders == null ? void 0 : responseHeaders["content-type"]) == null ? void 0 : _a.split(";")[0].trim();
4545
+ return {
4546
+ warnings: [],
4547
+ content,
4548
+ ...mediaType ? { mediaType } : {}
4549
+ };
4550
+ }
4551
+ async deleteFile({
4552
+ file,
4553
+ abortSignal,
4554
+ headers
4555
+ }) {
4556
+ const fileId = this.getFileId(file);
4557
+ const { value: response } = await deleteFromApi({
4558
+ url: `${this.config.baseURL}/files/${encodePathSegment(fileId)}`,
4559
+ headers: this.getHeaders(headers),
4560
+ failedResponseHandler: xaiFailedResponseHandler,
4561
+ successfulResponseHandler: createJsonResponseHandler5(
4562
+ xaiFileDeleteResponseSchema
4563
+ ),
4564
+ abortSignal,
4565
+ fetch: this.config.fetch
4566
+ });
4567
+ return {
4568
+ warnings: [],
4569
+ providerReference: { xai: response.id },
4570
+ deleted: response.deleted
4571
+ };
4572
+ }
4573
+ toFileMetadata(response) {
4574
+ return {
4575
+ ...response.filename != null ? { filename: response.filename } : {},
4576
+ ...response.purpose != null ? { purpose: response.purpose } : {},
4577
+ ...response.bytes != null ? { bytes: response.bytes } : {},
4578
+ ...response.created_at != null ? { createdAt: response.created_at } : {},
4579
+ ...response.status != null ? { status: response.status } : {},
4580
+ ...response.expires_at != null ? { expiresAt: response.expires_at } : {}
4581
+ };
4582
+ }
4406
4583
  };
4407
4584
 
4408
4585
  // src/xai-video-model.ts
@@ -4415,7 +4592,7 @@ import {
4415
4592
  convertUint8ArrayToBase64,
4416
4593
  createJsonResponseHandler as createJsonResponseHandler6,
4417
4594
  extractResponseHeaders as extractResponseHeaders2,
4418
- getFromApi as getFromApi3,
4595
+ getFromApi as getFromApi4,
4419
4596
  getTopLevelMediaType as getTopLevelMediaType3,
4420
4597
  parseProviderOptions as parseProviderOptions7,
4421
4598
  postJsonToApi as postJsonToApi5,
@@ -4447,7 +4624,7 @@ var xaiVideoModelOptionsSchema = lazySchema9(
4447
4624
  );
4448
4625
 
4449
4626
  // src/xai-video-model.ts
4450
- function encodePathSegment(value) {
4627
+ function encodePathSegment2(value) {
4451
4628
  const encodedValue = encodeURIComponent(value);
4452
4629
  return encodedValue === "." ? "%252E" : encodedValue === ".." ? "%252E%252E" : encodedValue;
4453
4630
  }
@@ -4770,8 +4947,8 @@ var XaiVideoModel = class {
4770
4947
  const currentDate = (_c = (_b = (_a = this.config._internal) == null ? void 0 : _a.currentDate) == null ? void 0 : _b.call(_a)) != null ? _c : /* @__PURE__ */ new Date();
4771
4948
  const { requestId } = options.operation;
4772
4949
  const baseURL = (_d = this.config.baseURL) != null ? _d : "https://api.x.ai/v1";
4773
- const { value: statusResponse, responseHeaders } = await getFromApi3({
4774
- url: `${baseURL}/videos/${encodePathSegment(requestId)}`,
4950
+ const { value: statusResponse, responseHeaders } = await getFromApi4({
4951
+ url: `${baseURL}/videos/${encodePathSegment2(requestId)}`,
4775
4952
  validateUrl: false,
4776
4953
  headers: combineHeaders6(this.config.headers(), options.headers),
4777
4954
  successfulResponseHandler: xaiVideoStatusResponseHandler,
@@ -5162,7 +5339,7 @@ var xaiSpeechTimestampsResponseSchema = z23.object({
5162
5339
 
5163
5340
  // src/xai-transcription-model.ts
5164
5341
  import {
5165
- InvalidArgumentError as InvalidArgumentError2
5342
+ InvalidArgumentError as InvalidArgumentError3
5166
5343
  } from "@ai-sdk/provider";
5167
5344
  import {
5168
5345
  combineHeaders as combineHeaders8,
@@ -5366,7 +5543,7 @@ var XaiTranscriptionModel = class _XaiTranscriptionModel {
5366
5543
  schema: xaiTranscriptionModelOptionsSchema
5367
5544
  });
5368
5545
  if ((xaiOptions == null ? void 0 : xaiOptions.multichannel) === true && xaiOptions.channels == null) {
5369
- throw new InvalidArgumentError2({
5546
+ throw new InvalidArgumentError3({
5370
5547
  argument: "providerOptions",
5371
5548
  message: "providerOptions.xai.channels is required when providerOptions.xai.multichannel is true"
5372
5549
  });