@ai-sdk/xai 4.0.57 → 4.0.58

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,19 @@
1
1
  # @ai-sdk/xai
2
2
 
3
+ ## 4.0.58
4
+
5
+ ### Patch Changes
6
+
7
+ - 5ec21a6: fix: reject unsupported batch request types
8
+ - 7469a3b: feat: support image generation requests in batches
9
+ - 0096850: fix(deepseek): preserve reasoning streams across empty tool-call deltas
10
+ - Updated dependencies [5ec21a6]
11
+ - Updated dependencies [7469a3b]
12
+ - Updated dependencies [813bb36]
13
+ - Updated dependencies [c43e4b7]
14
+ - @ai-sdk/provider@4.0.14
15
+ - @ai-sdk/provider-utils@5.0.40
16
+
3
17
  ## 4.0.57
4
18
 
5
19
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -553,6 +553,7 @@ interface XaiProvider extends ProviderV4 {
553
553
  */
554
554
  experimental_batch(): Experimental_BatchV4<{
555
555
  text: XaiResponsesModelId;
556
+ image: XaiImageModelId;
556
557
  }>;
557
558
  /**
558
559
  * Creates an Xai image model for image generation.
package/dist/index.js CHANGED
@@ -898,7 +898,7 @@ var XaiChatLanguageModel = class _XaiChatLanguageModel {
898
898
  delta: delta.reasoning_content
899
899
  });
900
900
  }
901
- if (delta.tool_calls != null) {
901
+ if (delta.tool_calls != null && delta.tool_calls.length > 0) {
902
902
  if (activeReasoningBlockId != null && !contentBlocks[activeReasoningBlockId].ended) {
903
903
  controller.enqueue({
904
904
  type: "reasoning-end",
@@ -1241,12 +1241,16 @@ var xaiImageResponseSchema = z6.object({
1241
1241
 
1242
1242
  // src/xai-batch.ts
1243
1243
  import {
1244
- InvalidArgumentError
1244
+ InvalidArgumentError,
1245
+ UnsupportedFunctionalityError as UnsupportedFunctionalityError5
1245
1246
  } from "@ai-sdk/provider";
1246
1247
  import {
1247
1248
  combineHeaders as combineHeaders4,
1249
+ convertImageModelFileToDataUri as convertImageModelFileToDataUri2,
1250
+ convertBase64ToUint8Array,
1248
1251
  convertAsyncIteratorToReadableStream,
1249
1252
  createJsonResponseHandler as createJsonResponseHandler4,
1253
+ createBinaryResponseHandler as createBinaryResponseHandler2,
1250
1254
  createNullLanguageModelUsage,
1251
1255
  getFromApi as getFromApi2,
1252
1256
  lazySchema as lazySchema7,
@@ -3531,6 +3535,28 @@ var xaiBatchProviderOptionsSchema = lazySchema7(
3531
3535
  })
3532
3536
  )
3533
3537
  );
3538
+ function assertSupportedBatchRequests(requests) {
3539
+ for (const request of requests) {
3540
+ const requestType = request.type;
3541
+ if (requestType !== "text" && requestType !== "image") {
3542
+ throw new UnsupportedFunctionalityError5({
3543
+ functionality: `batch request type: ${requestType}`,
3544
+ message: `The xAI Batch API does not support batch requests with type "${requestType}".`
3545
+ });
3546
+ }
3547
+ }
3548
+ }
3549
+ var xaiBatchImageResponseSchema = z15.object({
3550
+ data: z15.array(
3551
+ z15.object({
3552
+ url: z15.string().nullish(),
3553
+ b64_json: z15.string().nullish(),
3554
+ revised_prompt: z15.string().nullish(),
3555
+ respect_moderation: z15.boolean().nullish()
3556
+ })
3557
+ ),
3558
+ usage: z15.object({ cost_in_usd_ticks: z15.number().nullish() }).nullish()
3559
+ });
3534
3560
  var xaiBatchResponseZodSchema = () => z15.object({
3535
3561
  batch_id: z15.string(),
3536
3562
  name: z15.string().nullish(),
@@ -3557,7 +3583,8 @@ var xaiBatchResultSchema = z15.object({
3557
3583
  batch_request_id: z15.string(),
3558
3584
  batch_result: z15.object({
3559
3585
  response: z15.object({
3560
- chat_get_completion: z15.unknown().nullish()
3586
+ chat_get_completion: z15.unknown().nullish(),
3587
+ image_generation: z15.unknown().nullish()
3561
3588
  }).nullish(),
3562
3589
  error: xaiBatchErrorSchema.nullish()
3563
3590
  }).nullish(),
@@ -3588,6 +3615,7 @@ var XaiBatch = class {
3588
3615
  }
3589
3616
  async doStartBatch(options) {
3590
3617
  var _a, _b;
3618
+ assertSupportedBatchRequests(options.requests);
3591
3619
  const fileParts = [];
3592
3620
  const warnings = options.webhookUrl == null ? [] : [
3593
3621
  {
@@ -3609,7 +3637,7 @@ var XaiBatch = class {
3609
3637
  JSON.stringify({
3610
3638
  custom_id: request.id,
3611
3639
  method: "POST",
3612
- url: xaiBatchEndpoint,
3640
+ url: preparedRequest.endpoint,
3613
3641
  body: preparedRequest.body
3614
3642
  }),
3615
3643
  "\n"
@@ -3776,12 +3804,12 @@ var XaiBatch = class {
3776
3804
  validateUrl: false
3777
3805
  });
3778
3806
  for (const result of page.results) {
3779
- yield await this.convertBatchResult(result);
3807
+ yield await this.convertBatchResult(result, options.abortSignal);
3780
3808
  }
3781
3809
  paginationToken = (_c = page.pagination_token) != null ? _c : void 0;
3782
3810
  } while (paginationToken != null);
3783
3811
  }
3784
- async convertBatchResult(result) {
3812
+ async convertBatchResult(result, abortSignal) {
3785
3813
  var _a, _b, _c, _d, _e, _f;
3786
3814
  const error = (_a = result.batch_result) == null ? void 0 : _a.error;
3787
3815
  if (((_c = (_b = result.error_message) == null ? void 0 : _b.length) != null ? _c : 0) > 0 || (error == null ? void 0 : error.code) != null && error.code !== 0 && error.code !== "0" || (error == null ? void 0 : error.code) == null && ((_e = (_d = error == null ? void 0 : error.message) == null ? void 0 : _d.length) != null ? _e : 0) > 0) {
@@ -3815,14 +3843,127 @@ var XaiBatch = class {
3815
3843
  error: conversion.error
3816
3844
  };
3817
3845
  }
3846
+ if ((response == null ? void 0 : response.image_generation) != null) {
3847
+ const validation = await safeValidateTypes({
3848
+ value: response.image_generation,
3849
+ schema: zodSchema7(xaiBatchImageResponseSchema)
3850
+ });
3851
+ if (!validation.success) {
3852
+ return invalidXaiImageBatchResult(result.batch_request_id);
3853
+ }
3854
+ if (validation.value.data.some((image) => image.respect_moderation === false)) {
3855
+ return {
3856
+ type: "image",
3857
+ id: result.batch_request_id,
3858
+ status: "failed",
3859
+ error: {
3860
+ message: "Image generation was blocked due to a content policy violation."
3861
+ }
3862
+ };
3863
+ }
3864
+ const imageResult = await this.convertImageBatchResponse(
3865
+ validation.value,
3866
+ abortSignal
3867
+ );
3868
+ return {
3869
+ type: "image",
3870
+ id: result.batch_request_id,
3871
+ status: "succeeded",
3872
+ result: imageResult
3873
+ };
3874
+ }
3818
3875
  return invalidXaiBatchResult(result.batch_request_id);
3819
3876
  }
3820
3877
  async prepareRequest(request) {
3821
- const { args: body, warnings } = await XaiResponsesLanguageModel.prepareRequest({
3822
- modelId: request.modelId,
3823
- options: request.options
3878
+ if (request.type === "text") {
3879
+ const { args: body2, warnings: warnings2 } = await XaiResponsesLanguageModel.prepareRequest({
3880
+ modelId: request.modelId,
3881
+ options: request.options
3882
+ });
3883
+ return { endpoint: xaiBatchEndpoint, body: body2, warnings: warnings2 };
3884
+ }
3885
+ const { prompt, n, size, aspectRatio, seed, files, mask, providerOptions } = request.options;
3886
+ const warnings = [];
3887
+ if (size != null) {
3888
+ warnings.push({
3889
+ type: "unsupported",
3890
+ feature: "size",
3891
+ details: "This model does not support the `size` option. Use `aspectRatio` instead."
3892
+ });
3893
+ }
3894
+ if (seed != null) warnings.push({ type: "unsupported", feature: "seed" });
3895
+ if (mask != null) warnings.push({ type: "unsupported", feature: "mask" });
3896
+ const xaiOptions = await parseProviderOptions6({
3897
+ provider: "xai",
3898
+ providerOptions,
3899
+ schema: xaiImageModelOptions
3824
3900
  });
3825
- return { body, warnings };
3901
+ const imageUrls = (files != null ? files : []).map(convertImageModelFileToDataUri2);
3902
+ const body = {
3903
+ model: request.modelId,
3904
+ prompt,
3905
+ n,
3906
+ response_format: "b64_json"
3907
+ };
3908
+ if (aspectRatio != null) body.aspect_ratio = aspectRatio;
3909
+ if ((xaiOptions == null ? void 0 : xaiOptions.output_format) != null)
3910
+ body.output_format = xaiOptions.output_format;
3911
+ if ((xaiOptions == null ? void 0 : xaiOptions.sync_mode) != null) body.sync_mode = xaiOptions.sync_mode;
3912
+ if ((xaiOptions == null ? void 0 : xaiOptions.aspect_ratio) != null && aspectRatio == null)
3913
+ body.aspect_ratio = xaiOptions.aspect_ratio;
3914
+ if ((xaiOptions == null ? void 0 : xaiOptions.resolution) != null) body.resolution = xaiOptions.resolution;
3915
+ if ((xaiOptions == null ? void 0 : xaiOptions.quality) != null) body.quality = xaiOptions.quality;
3916
+ if ((xaiOptions == null ? void 0 : xaiOptions.user) != null) body.user = xaiOptions.user;
3917
+ if (imageUrls.length === 1) {
3918
+ body.image = { url: imageUrls[0], type: "image_url" };
3919
+ } else if (imageUrls.length > 1) {
3920
+ body.images = imageUrls.map((url) => ({ url, type: "image_url" }));
3921
+ }
3922
+ return {
3923
+ endpoint: (files == null ? void 0 : files.length) ? "/v1/images/edits" : "/v1/images/generations",
3924
+ body,
3925
+ warnings
3926
+ };
3927
+ }
3928
+ async convertImageBatchResponse(response, abortSignal) {
3929
+ var _a;
3930
+ const hasAllBase64 = response.data.every((image) => image.b64_json != null);
3931
+ const images = hasAllBase64 ? response.data.map((image) => image.b64_json) : await Promise.all(
3932
+ response.data.map(async (image) => {
3933
+ if (image.b64_json != null) {
3934
+ return convertBase64ToUint8Array(image.b64_json);
3935
+ }
3936
+ if (image.url == null) {
3937
+ throw new InvalidArgumentError({
3938
+ argument: "batchResult",
3939
+ message: "xAI returned an image without data or a URL."
3940
+ });
3941
+ }
3942
+ const { value } = await getFromApi2({
3943
+ url: image.url,
3944
+ validateUrl: true,
3945
+ trustedOrigin: this.options.config.baseURL,
3946
+ abortSignal,
3947
+ failedResponseHandler: xaiFailedResponseHandler,
3948
+ successfulResponseHandler: createBinaryResponseHandler2(),
3949
+ fetch: this.options.config.fetch
3950
+ });
3951
+ return value;
3952
+ })
3953
+ );
3954
+ return {
3955
+ images,
3956
+ warnings: [],
3957
+ response: { timestamp: /* @__PURE__ */ new Date(), modelId: "", headers: void 0 },
3958
+ providerMetadata: {
3959
+ xai: {
3960
+ images: response.data.map(
3961
+ (item) => item.revised_prompt != null ? { revisedPrompt: item.revised_prompt } : {}
3962
+ ),
3963
+ ...((_a = response.usage) == null ? void 0 : _a.cost_in_usd_ticks) != null ? { costInUsdTicks: response.usage.cost_in_usd_ticks } : {}
3964
+ }
3965
+ }
3966
+ };
3826
3967
  }
3827
3968
  getUrl(path) {
3828
3969
  var _a;
@@ -3888,6 +4029,17 @@ function invalidXaiBatchResult(id) {
3888
4029
  }
3889
4030
  };
3890
4031
  }
4032
+ function invalidXaiImageBatchResult(id) {
4033
+ return {
4034
+ type: "image",
4035
+ id,
4036
+ status: "failed",
4037
+ error: {
4038
+ message: "xAI returned an invalid image batch result.",
4039
+ code: "invalid_response"
4040
+ }
4041
+ };
4042
+ }
3891
4043
  function convertXaiChatBatchResponse(response) {
3892
4044
  var _a, _b, _c, _d, _e, _f;
3893
4045
  if (response.error != null) {
@@ -4410,7 +4562,7 @@ var xaiTools = {
4410
4562
  };
4411
4563
 
4412
4564
  // src/version.ts
4413
- var VERSION = true ? "4.0.57" : "0.0.0-test";
4565
+ var VERSION = true ? "4.0.58" : "0.0.0-test";
4414
4566
 
4415
4567
  // src/files/xai-files.ts
4416
4568
  import {
@@ -5204,8 +5356,8 @@ var xaiVideoStatusResponseHandler = async (options) => {
5204
5356
  // src/xai-speech-model.ts
5205
5357
  import {
5206
5358
  combineHeaders as combineHeaders7,
5207
- convertBase64ToUint8Array,
5208
- createBinaryResponseHandler as createBinaryResponseHandler2,
5359
+ convertBase64ToUint8Array as convertBase64ToUint8Array2,
5360
+ createBinaryResponseHandler as createBinaryResponseHandler3,
5209
5361
  createJsonResponseHandler as createJsonResponseHandler7,
5210
5362
  parseProviderOptions as parseProviderOptions9,
5211
5363
  postJsonToApi as postJsonToApi6,
@@ -5367,7 +5519,7 @@ var XaiSpeechModel = class _XaiSpeechModel {
5367
5519
  ),
5368
5520
  body: requestBody,
5369
5521
  failedResponseHandler: xaiFailedResponseHandler,
5370
- successfulResponseHandler: withTimestamps ? createJsonResponseHandler7(xaiSpeechTimestampsResponseSchema) : createBinaryResponseHandler2(),
5522
+ successfulResponseHandler: withTimestamps ? createJsonResponseHandler7(xaiSpeechTimestampsResponseSchema) : createBinaryResponseHandler3(),
5371
5523
  abortSignal: options.abortSignal,
5372
5524
  fetch: this.config.fetch
5373
5525
  });
@@ -5377,7 +5529,7 @@ var XaiSpeechModel = class _XaiSpeechModel {
5377
5529
  audio = value;
5378
5530
  } else {
5379
5531
  envelope = value;
5380
- audio = envelope.audio != null ? convertBase64ToUint8Array(envelope.audio) : new Uint8Array(0);
5532
+ audio = envelope.audio != null ? convertBase64ToUint8Array2(envelope.audio) : new Uint8Array(0);
5381
5533
  }
5382
5534
  const traceId = responseHeaders == null ? void 0 : responseHeaders["x-trace-id"];
5383
5535
  return {
@@ -5424,7 +5576,7 @@ import {
5424
5576
  } from "@ai-sdk/provider";
5425
5577
  import {
5426
5578
  combineHeaders as combineHeaders8,
5427
- convertBase64ToUint8Array as convertBase64ToUint8Array2,
5579
+ convertBase64ToUint8Array as convertBase64ToUint8Array3,
5428
5580
  createJsonResponseHandler as createJsonResponseHandler8,
5429
5581
  connectToWebSocket,
5430
5582
  mediaTypeToExtension,
@@ -5568,7 +5720,7 @@ var XaiTranscriptionModel = class _XaiTranscriptionModel {
5568
5720
  formData.append("keyterm", keyterm);
5569
5721
  }
5570
5722
  }
5571
- const blob = audio instanceof Uint8Array ? new Blob([audio]) : new Blob([convertBase64ToUint8Array2(audio)]);
5723
+ const blob = audio instanceof Uint8Array ? new Blob([audio]) : new Blob([convertBase64ToUint8Array3(audio)]);
5572
5724
  const fileExtension = mediaTypeToExtension(mediaType);
5573
5725
  formData.append(
5574
5726
  "file",
@@ -5727,7 +5879,7 @@ function createXaiStreamingTranscriptionStream({
5727
5879
  const { done, value } = await audioReader.read();
5728
5880
  if (done || finished) break;
5729
5881
  socket.send(
5730
- value instanceof Uint8Array ? value : convertBase64ToUint8Array2(value)
5882
+ value instanceof Uint8Array ? value : convertBase64ToUint8Array3(value)
5731
5883
  );
5732
5884
  await waitForWebSocketBufferDrain(socket);
5733
5885
  }