@ai-sdk/xai 4.0.38 → 4.0.40

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,26 @@
1
1
  # @ai-sdk/xai
2
2
 
3
+ ## 4.0.40
4
+
5
+ ### Patch Changes
6
+
7
+ - 1ffa1d2: feat(xai): speech timestamps, pronunciation replacements, provider metadata, and error parsing
8
+
9
+ - Add `withTimestamps` and `replace` provider options for text to speech. With
10
+ `withTimestamps`, the JSON envelope is decoded and the audio returned as
11
+ usual, while duration, content type, and character-level alignment are
12
+ exposed via `providerMetadata.xai`.
13
+ - Return `providerMetadata.xai.traceId` (from the `x-trace-id` response
14
+ header) on every speech response.
15
+ - Parse the text to speech error shape (`{"error":"..."}`) so `APICallError`
16
+ messages carry xAI's real error detail instead of the HTTP reason phrase.
17
+
18
+ ## 4.0.39
19
+
20
+ ### Patch Changes
21
+
22
+ - 646c86e: fix(provider/xai): report video moderation blocks and missing URLs as an error status instead of throwing
23
+
3
24
  ## 4.0.38
4
25
 
5
26
  ### Patch Changes
package/README.md CHANGED
@@ -36,7 +36,7 @@ import { xai } from '@ai-sdk/xai';
36
36
  import { generateText } from 'ai';
37
37
 
38
38
  const { text } = await generateText({
39
- model: xai('grok-3'),
39
+ model: xai('grok-4.6'),
40
40
  prompt: 'Write a vegetarian lasagna recipe for 4 people.',
41
41
  });
42
42
  ```
package/dist/index.d.ts CHANGED
@@ -65,6 +65,8 @@ declare const xaiErrorDataSchema: z.ZodUnion<readonly [z.ZodObject<{
65
65
  }, z.core.$strip>, z.ZodObject<{
66
66
  code: z.ZodString;
67
67
  error: z.ZodString;
68
+ }, z.core.$strip>, z.ZodObject<{
69
+ error: z.ZodString;
68
70
  }, z.core.$strip>]>;
69
71
  type XaiErrorData = z.infer<typeof xaiErrorDataSchema>;
70
72
 
@@ -218,6 +220,8 @@ declare const xaiSpeechModelOptionsSchema: _ai_sdk_provider_utils.LazySchema<{
218
220
  bitRate?: 32000 | 64000 | 96000 | 128000 | 192000 | null | undefined;
219
221
  optimizeStreamingLatency?: 0 | 1 | 2 | null | undefined;
220
222
  textNormalization?: boolean | null | undefined;
223
+ withTimestamps?: boolean | null | undefined;
224
+ replace?: Record<string, string> | null | undefined;
221
225
  }>;
222
226
  type XaiSpeechModelOptions = InferSchema<typeof xaiSpeechModelOptionsSchema>;
223
227
 
package/dist/index.js CHANGED
@@ -384,13 +384,22 @@ var responsesErrorSchema = z3.object({
384
384
  code: z3.string(),
385
385
  error: z3.string()
386
386
  });
387
+ var speechErrorSchema = z3.object({
388
+ error: z3.string()
389
+ });
387
390
  var xaiErrorDataSchema = z3.union([
388
391
  chatCompletionsErrorSchema,
389
- responsesErrorSchema
392
+ responsesErrorSchema,
393
+ speechErrorSchema
390
394
  ]);
391
395
  var xaiFailedResponseHandler = createJsonErrorResponseHandler({
392
396
  errorSchema: xaiErrorDataSchema,
393
- errorToMessage: (data) => "code" in data ? `${data.code}: ${data.error}` : data.error.message
397
+ errorToMessage: (data) => {
398
+ if (typeof data.error === "string") {
399
+ return "code" in data ? `${data.code}: ${data.error}` : data.error;
400
+ }
401
+ return data.error.message;
402
+ }
394
403
  });
395
404
 
396
405
  // src/xai-prepare-tools.ts
@@ -3720,7 +3729,7 @@ var xaiTools = {
3720
3729
  };
3721
3730
 
3722
3731
  // src/version.ts
3723
- var VERSION = true ? "4.0.38" : "0.0.0-test";
3732
+ var VERSION = true ? "4.0.40" : "0.0.0-test";
3724
3733
 
3725
3734
  // src/files/xai-files.ts
3726
3735
  import {
@@ -4218,16 +4227,26 @@ var XaiVideoModel = class {
4218
4227
  }
4219
4228
  if (statusResponse.status === "done" || statusResponse.status == null && ((_h = statusResponse.video) == null ? void 0 : _h.url)) {
4220
4229
  if (((_i = statusResponse.video) == null ? void 0 : _i.respect_moderation) === false) {
4221
- throw new AISDKError({
4222
- name: "XAI_VIDEO_MODERATION_ERROR",
4223
- message: "Video generation was blocked due to a content policy violation."
4224
- });
4230
+ return {
4231
+ status: "error",
4232
+ error: "Video generation was blocked due to a content policy violation.",
4233
+ response: {
4234
+ timestamp: currentDate,
4235
+ modelId: this.modelId,
4236
+ headers: responseHeaders
4237
+ }
4238
+ };
4225
4239
  }
4226
4240
  if (!((_j = statusResponse.video) == null ? void 0 : _j.url)) {
4227
- throw new AISDKError({
4228
- name: "XAI_VIDEO_GENERATION_ERROR",
4229
- message: "Video generation completed but no video URL was returned."
4230
- });
4241
+ return {
4242
+ status: "error",
4243
+ error: "Video generation completed but no video URL was returned.",
4244
+ response: {
4245
+ timestamp: currentDate,
4246
+ modelId: this.modelId,
4247
+ headers: responseHeaders
4248
+ }
4249
+ };
4231
4250
  }
4232
4251
  return {
4233
4252
  status: "completed",
@@ -4350,7 +4369,9 @@ var xaiVideoStatusResponseHandler = async (options) => {
4350
4369
  // src/xai-speech-model.ts
4351
4370
  import {
4352
4371
  combineHeaders as combineHeaders6,
4372
+ convertBase64ToUint8Array,
4353
4373
  createBinaryResponseHandler as createBinaryResponseHandler2,
4374
+ createJsonResponseHandler as createJsonResponseHandler6,
4354
4375
  parseProviderOptions as parseProviderOptions8,
4355
4376
  postJsonToApi as postJsonToApi5,
4356
4377
  resolve,
@@ -4358,6 +4379,7 @@ import {
4358
4379
  WORKFLOW_DESERIALIZE as WORKFLOW_DESERIALIZE4,
4359
4380
  WORKFLOW_SERIALIZE as WORKFLOW_SERIALIZE4
4360
4381
  } from "@ai-sdk/provider-utils";
4382
+ import { z as z22 } from "zod/v4";
4361
4383
 
4362
4384
  // src/xai-speech-model-options.ts
4363
4385
  import {
@@ -4396,7 +4418,19 @@ var xaiSpeechModelOptionsSchema = lazySchema9(
4396
4418
  /**
4397
4419
  * Normalize written-form text into spoken-form text before synthesis.
4398
4420
  */
4399
- textNormalization: z21.boolean().nullish()
4421
+ textNormalization: z21.boolean().nullish(),
4422
+ /**
4423
+ * Return character-level timing metadata alongside the audio. When
4424
+ * enabled, the response carries per-character start/end times and the
4425
+ * total duration, exposed via `providerMetadata.xai`.
4426
+ */
4427
+ withTimestamps: z21.boolean().nullish(),
4428
+ /**
4429
+ * Map of phrases to spoken substitutions applied before synthesis.
4430
+ * Values may be respellings (`{ 'Acme Mobile': 'Acme Mobull' }`) or IPA
4431
+ * phonetics (`{ nginx: '/ˈɛndʒɪn ˈɛks/' }`).
4432
+ */
4433
+ replace: z21.record(z21.string(), z21.string()).nullish()
4400
4434
  })
4401
4435
  )
4402
4436
  );
@@ -4476,19 +4510,21 @@ var XaiSpeechModel = class _XaiSpeechModel {
4476
4510
  output_format,
4477
4511
  speed,
4478
4512
  optimize_streaming_latency: xaiOptions == null ? void 0 : xaiOptions.optimizeStreamingLatency,
4479
- text_normalization: xaiOptions == null ? void 0 : xaiOptions.textNormalization
4513
+ text_normalization: xaiOptions == null ? void 0 : xaiOptions.textNormalization,
4514
+ with_timestamps: xaiOptions == null ? void 0 : xaiOptions.withTimestamps,
4515
+ replace: xaiOptions == null ? void 0 : xaiOptions.replace
4516
+ };
4517
+ return {
4518
+ requestBody,
4519
+ warnings,
4520
+ withTimestamps: (xaiOptions == null ? void 0 : xaiOptions.withTimestamps) === true
4480
4521
  };
4481
- return { requestBody, warnings };
4482
4522
  }
4483
4523
  async doGenerate(options) {
4484
4524
  var _a, _b, _c;
4485
4525
  const currentDate = (_c = (_b = (_a = this.config._internal) == null ? void 0 : _a.currentDate) == null ? void 0 : _b.call(_a)) != null ? _c : /* @__PURE__ */ new Date();
4486
- const { requestBody, warnings } = await this.getArgs(options);
4487
- const {
4488
- value: audio,
4489
- responseHeaders,
4490
- rawValue: rawResponse
4491
- } = await postJsonToApi5({
4526
+ const { requestBody, warnings, withTimestamps } = await this.getArgs(options);
4527
+ const { value, responseHeaders, rawValue } = await postJsonToApi5({
4492
4528
  url: `${this.config.baseURL}/tts`,
4493
4529
  headers: combineHeaders6(
4494
4530
  this.config.headers ? await resolve(this.config.headers) : void 0,
@@ -4496,10 +4532,19 @@ var XaiSpeechModel = class _XaiSpeechModel {
4496
4532
  ),
4497
4533
  body: requestBody,
4498
4534
  failedResponseHandler: xaiFailedResponseHandler,
4499
- successfulResponseHandler: createBinaryResponseHandler2(),
4535
+ successfulResponseHandler: withTimestamps ? createJsonResponseHandler6(xaiSpeechTimestampsResponseSchema) : createBinaryResponseHandler2(),
4500
4536
  abortSignal: options.abortSignal,
4501
4537
  fetch: this.config.fetch
4502
4538
  });
4539
+ let audio;
4540
+ let envelope;
4541
+ if (value instanceof Uint8Array) {
4542
+ audio = value;
4543
+ } else {
4544
+ envelope = value;
4545
+ audio = envelope.audio != null ? convertBase64ToUint8Array(envelope.audio) : new Uint8Array(0);
4546
+ }
4547
+ const traceId = responseHeaders == null ? void 0 : responseHeaders["x-trace-id"];
4503
4548
  return {
4504
4549
  audio,
4505
4550
  warnings,
@@ -4510,11 +4555,33 @@ var XaiSpeechModel = class _XaiSpeechModel {
4510
4555
  timestamp: currentDate,
4511
4556
  modelId: this.modelId,
4512
4557
  headers: responseHeaders,
4513
- body: rawResponse
4558
+ body: rawValue
4559
+ },
4560
+ providerMetadata: {
4561
+ xai: {
4562
+ ...traceId != null ? { traceId } : {},
4563
+ ...(envelope == null ? void 0 : envelope.duration) != null ? { duration: envelope.duration } : {},
4564
+ ...(envelope == null ? void 0 : envelope.content_type) != null ? { contentType: envelope.content_type } : {},
4565
+ ...(envelope == null ? void 0 : envelope.audio_timestamps) != null ? {
4566
+ audioTimestamps: {
4567
+ graphChars: envelope.audio_timestamps.graph_chars,
4568
+ graphTimes: envelope.audio_timestamps.graph_times
4569
+ }
4570
+ } : {}
4571
+ }
4514
4572
  }
4515
4573
  };
4516
4574
  }
4517
4575
  };
4576
+ var xaiSpeechTimestampsResponseSchema = z22.object({
4577
+ audio: z22.string().nullish(),
4578
+ content_type: z22.string().nullish(),
4579
+ duration: z22.number().nullish(),
4580
+ audio_timestamps: z22.object({
4581
+ graph_chars: z22.array(z22.string()),
4582
+ graph_times: z22.array(z22.tuple([z22.number(), z22.number()]))
4583
+ }).nullish()
4584
+ });
4518
4585
 
4519
4586
  // src/xai-transcription-model.ts
4520
4587
  import {
@@ -4522,8 +4589,8 @@ import {
4522
4589
  } from "@ai-sdk/provider";
4523
4590
  import {
4524
4591
  combineHeaders as combineHeaders7,
4525
- convertBase64ToUint8Array,
4526
- createJsonResponseHandler as createJsonResponseHandler6,
4592
+ convertBase64ToUint8Array as convertBase64ToUint8Array2,
4593
+ createJsonResponseHandler as createJsonResponseHandler7,
4527
4594
  connectToWebSocket,
4528
4595
  mediaTypeToExtension,
4529
4596
  parseProviderOptions as parseProviderOptions9,
@@ -4535,80 +4602,80 @@ import {
4535
4602
  WORKFLOW_DESERIALIZE as WORKFLOW_DESERIALIZE5,
4536
4603
  WORKFLOW_SERIALIZE as WORKFLOW_SERIALIZE5
4537
4604
  } from "@ai-sdk/provider-utils";
4538
- import { z as z23 } from "zod/v4";
4605
+ import { z as z24 } from "zod/v4";
4539
4606
 
4540
4607
  // src/xai-transcription-model-options.ts
4541
4608
  import {
4542
4609
  lazySchema as lazySchema10,
4543
4610
  zodSchema as zodSchema10
4544
4611
  } from "@ai-sdk/provider-utils";
4545
- import { z as z22 } from "zod/v4";
4612
+ import { z as z23 } from "zod/v4";
4546
4613
  var xaiTranscriptionModelOptionsSchema = lazySchema10(
4547
4614
  () => zodSchema10(
4548
- z22.object({
4615
+ z23.object({
4549
4616
  /**
4550
4617
  * Audio encoding for raw, headerless input audio.
4551
4618
  */
4552
- audioFormat: z22.enum(["pcm", "mulaw", "alaw"]).nullish(),
4619
+ audioFormat: z23.enum(["pcm", "mulaw", "alaw"]).nullish(),
4553
4620
  /**
4554
4621
  * Sample rate of the input audio in Hz.
4555
4622
  */
4556
- sampleRate: z22.union([
4557
- z22.literal(8e3),
4558
- z22.literal(16e3),
4559
- z22.literal(22050),
4560
- z22.literal(24e3),
4561
- z22.literal(44100),
4562
- z22.literal(48e3)
4623
+ sampleRate: z23.union([
4624
+ z23.literal(8e3),
4625
+ z23.literal(16e3),
4626
+ z23.literal(22050),
4627
+ z23.literal(24e3),
4628
+ z23.literal(44100),
4629
+ z23.literal(48e3)
4563
4630
  ]).nullish(),
4564
4631
  /**
4565
4632
  * Language code used for inverse text normalization.
4566
4633
  */
4567
- language: z22.string().nullish(),
4634
+ language: z23.string().nullish(),
4568
4635
  /**
4569
4636
  * Enable inverse text normalization. Requires `language`.
4570
4637
  */
4571
- format: z22.boolean().nullish(),
4638
+ format: z23.boolean().nullish(),
4572
4639
  /**
4573
4640
  * Enable per-channel transcription for multichannel audio.
4574
4641
  */
4575
- multichannel: z22.boolean().nullish(),
4642
+ multichannel: z23.boolean().nullish(),
4576
4643
  /**
4577
4644
  * Number of interleaved audio channels.
4578
4645
  */
4579
- channels: z22.number().int().min(2).max(8).nullish(),
4646
+ channels: z23.number().int().min(2).max(8).nullish(),
4580
4647
  /**
4581
4648
  * Enable speaker diarization.
4582
4649
  */
4583
- diarize: z22.boolean().nullish(),
4650
+ diarize: z23.boolean().nullish(),
4584
4651
  /**
4585
4652
  * Terms to bias transcription toward.
4586
4653
  */
4587
- keyterm: z22.union([z22.string(), z22.array(z22.string())]).nullish(),
4654
+ keyterm: z23.union([z23.string(), z23.array(z23.string())]).nullish(),
4588
4655
  /**
4589
4656
  * Include filler words such as "uh" and "um" in the transcript.
4590
4657
  */
4591
- fillerWords: z22.boolean().nullish(),
4658
+ fillerWords: z23.boolean().nullish(),
4592
4659
  /**
4593
4660
  * Options for streaming speech-to-text over WebSocket.
4594
4661
  */
4595
- streaming: z22.object({
4662
+ streaming: z23.object({
4596
4663
  /**
4597
4664
  * Emit interim transcript results while speech is being processed.
4598
4665
  */
4599
- interimResults: z22.boolean().optional(),
4666
+ interimResults: z23.boolean().optional(),
4600
4667
  /**
4601
4668
  * Silence duration in milliseconds before an utterance-final event.
4602
4669
  */
4603
- endpointing: z22.number().int().min(0).max(5e3).optional(),
4670
+ endpointing: z23.number().int().min(0).max(5e3).optional(),
4604
4671
  /**
4605
4672
  * End-of-turn detection threshold. When set, enables Smart Turn.
4606
4673
  */
4607
- smartTurn: z22.number().min(0).max(1).optional(),
4674
+ smartTurn: z23.number().min(0).max(1).optional(),
4608
4675
  /**
4609
4676
  * Maximum silence duration in milliseconds before forcing speech_final.
4610
4677
  */
4611
- smartTurnTimeout: z22.number().int().min(1).max(5e3).optional()
4678
+ smartTurnTimeout: z23.number().int().min(1).max(5e3).optional()
4612
4679
  }).optional()
4613
4680
  })
4614
4681
  )
@@ -4666,7 +4733,7 @@ var XaiTranscriptionModel = class _XaiTranscriptionModel {
4666
4733
  formData.append("keyterm", keyterm);
4667
4734
  }
4668
4735
  }
4669
- const blob = audio instanceof Uint8Array ? new Blob([audio]) : new Blob([convertBase64ToUint8Array(audio)]);
4736
+ const blob = audio instanceof Uint8Array ? new Blob([audio]) : new Blob([convertBase64ToUint8Array2(audio)]);
4670
4737
  const fileExtension = mediaTypeToExtension(mediaType);
4671
4738
  formData.append(
4672
4739
  "file",
@@ -4688,7 +4755,7 @@ var XaiTranscriptionModel = class _XaiTranscriptionModel {
4688
4755
  headers: combineHeaders7((_f = (_e = this.config).headers) == null ? void 0 : _f.call(_e), options.headers),
4689
4756
  formData,
4690
4757
  failedResponseHandler: xaiFailedResponseHandler,
4691
- successfulResponseHandler: createJsonResponseHandler6(
4758
+ successfulResponseHandler: createJsonResponseHandler7(
4692
4759
  xaiTranscriptionResponseSchema
4693
4760
  ),
4694
4761
  abortSignal: options.abortSignal,
@@ -4825,7 +4892,7 @@ function createXaiStreamingTranscriptionStream({
4825
4892
  const { done, value } = await audioReader.read();
4826
4893
  if (done || finished) break;
4827
4894
  socket.send(
4828
- value instanceof Uint8Array ? value : convertBase64ToUint8Array(value)
4895
+ value instanceof Uint8Array ? value : convertBase64ToUint8Array2(value)
4829
4896
  );
4830
4897
  await waitForWebSocketBufferDrain(socket);
4831
4898
  }
@@ -5007,15 +5074,15 @@ function timingFromXaiEvent(event) {
5007
5074
  ...event.start != null && event.duration != null ? { endSecond: event.start + event.duration } : {}
5008
5075
  };
5009
5076
  }
5010
- var xaiTranscriptionResponseSchema = z23.object({
5011
- text: z23.string(),
5012
- language: z23.string().nullish(),
5013
- duration: z23.number().nullish(),
5014
- words: z23.array(
5015
- z23.object({
5016
- text: z23.string(),
5017
- start: z23.number(),
5018
- end: z23.number()
5077
+ var xaiTranscriptionResponseSchema = z24.object({
5078
+ text: z24.string(),
5079
+ language: z24.string().nullish(),
5080
+ duration: z24.number().nullish(),
5081
+ words: z24.array(
5082
+ z24.object({
5083
+ text: z24.string(),
5084
+ start: z24.number(),
5085
+ end: z24.number()
5019
5086
  })
5020
5087
  ).nullish()
5021
5088
  });