@ai-sdk/xai 4.0.39 → 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,20 @@
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
+
3
18
  ## 4.0.39
4
19
 
5
20
  ### Patch Changes
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.39" : "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 {
@@ -4360,7 +4369,9 @@ var xaiVideoStatusResponseHandler = async (options) => {
4360
4369
  // src/xai-speech-model.ts
4361
4370
  import {
4362
4371
  combineHeaders as combineHeaders6,
4372
+ convertBase64ToUint8Array,
4363
4373
  createBinaryResponseHandler as createBinaryResponseHandler2,
4374
+ createJsonResponseHandler as createJsonResponseHandler6,
4364
4375
  parseProviderOptions as parseProviderOptions8,
4365
4376
  postJsonToApi as postJsonToApi5,
4366
4377
  resolve,
@@ -4368,6 +4379,7 @@ import {
4368
4379
  WORKFLOW_DESERIALIZE as WORKFLOW_DESERIALIZE4,
4369
4380
  WORKFLOW_SERIALIZE as WORKFLOW_SERIALIZE4
4370
4381
  } from "@ai-sdk/provider-utils";
4382
+ import { z as z22 } from "zod/v4";
4371
4383
 
4372
4384
  // src/xai-speech-model-options.ts
4373
4385
  import {
@@ -4406,7 +4418,19 @@ var xaiSpeechModelOptionsSchema = lazySchema9(
4406
4418
  /**
4407
4419
  * Normalize written-form text into spoken-form text before synthesis.
4408
4420
  */
4409
- 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()
4410
4434
  })
4411
4435
  )
4412
4436
  );
@@ -4486,19 +4510,21 @@ var XaiSpeechModel = class _XaiSpeechModel {
4486
4510
  output_format,
4487
4511
  speed,
4488
4512
  optimize_streaming_latency: xaiOptions == null ? void 0 : xaiOptions.optimizeStreamingLatency,
4489
- 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
4490
4521
  };
4491
- return { requestBody, warnings };
4492
4522
  }
4493
4523
  async doGenerate(options) {
4494
4524
  var _a, _b, _c;
4495
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();
4496
- const { requestBody, warnings } = await this.getArgs(options);
4497
- const {
4498
- value: audio,
4499
- responseHeaders,
4500
- rawValue: rawResponse
4501
- } = await postJsonToApi5({
4526
+ const { requestBody, warnings, withTimestamps } = await this.getArgs(options);
4527
+ const { value, responseHeaders, rawValue } = await postJsonToApi5({
4502
4528
  url: `${this.config.baseURL}/tts`,
4503
4529
  headers: combineHeaders6(
4504
4530
  this.config.headers ? await resolve(this.config.headers) : void 0,
@@ -4506,10 +4532,19 @@ var XaiSpeechModel = class _XaiSpeechModel {
4506
4532
  ),
4507
4533
  body: requestBody,
4508
4534
  failedResponseHandler: xaiFailedResponseHandler,
4509
- successfulResponseHandler: createBinaryResponseHandler2(),
4535
+ successfulResponseHandler: withTimestamps ? createJsonResponseHandler6(xaiSpeechTimestampsResponseSchema) : createBinaryResponseHandler2(),
4510
4536
  abortSignal: options.abortSignal,
4511
4537
  fetch: this.config.fetch
4512
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"];
4513
4548
  return {
4514
4549
  audio,
4515
4550
  warnings,
@@ -4520,11 +4555,33 @@ var XaiSpeechModel = class _XaiSpeechModel {
4520
4555
  timestamp: currentDate,
4521
4556
  modelId: this.modelId,
4522
4557
  headers: responseHeaders,
4523
- 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
+ }
4524
4572
  }
4525
4573
  };
4526
4574
  }
4527
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
+ });
4528
4585
 
4529
4586
  // src/xai-transcription-model.ts
4530
4587
  import {
@@ -4532,8 +4589,8 @@ import {
4532
4589
  } from "@ai-sdk/provider";
4533
4590
  import {
4534
4591
  combineHeaders as combineHeaders7,
4535
- convertBase64ToUint8Array,
4536
- createJsonResponseHandler as createJsonResponseHandler6,
4592
+ convertBase64ToUint8Array as convertBase64ToUint8Array2,
4593
+ createJsonResponseHandler as createJsonResponseHandler7,
4537
4594
  connectToWebSocket,
4538
4595
  mediaTypeToExtension,
4539
4596
  parseProviderOptions as parseProviderOptions9,
@@ -4545,80 +4602,80 @@ import {
4545
4602
  WORKFLOW_DESERIALIZE as WORKFLOW_DESERIALIZE5,
4546
4603
  WORKFLOW_SERIALIZE as WORKFLOW_SERIALIZE5
4547
4604
  } from "@ai-sdk/provider-utils";
4548
- import { z as z23 } from "zod/v4";
4605
+ import { z as z24 } from "zod/v4";
4549
4606
 
4550
4607
  // src/xai-transcription-model-options.ts
4551
4608
  import {
4552
4609
  lazySchema as lazySchema10,
4553
4610
  zodSchema as zodSchema10
4554
4611
  } from "@ai-sdk/provider-utils";
4555
- import { z as z22 } from "zod/v4";
4612
+ import { z as z23 } from "zod/v4";
4556
4613
  var xaiTranscriptionModelOptionsSchema = lazySchema10(
4557
4614
  () => zodSchema10(
4558
- z22.object({
4615
+ z23.object({
4559
4616
  /**
4560
4617
  * Audio encoding for raw, headerless input audio.
4561
4618
  */
4562
- audioFormat: z22.enum(["pcm", "mulaw", "alaw"]).nullish(),
4619
+ audioFormat: z23.enum(["pcm", "mulaw", "alaw"]).nullish(),
4563
4620
  /**
4564
4621
  * Sample rate of the input audio in Hz.
4565
4622
  */
4566
- sampleRate: z22.union([
4567
- z22.literal(8e3),
4568
- z22.literal(16e3),
4569
- z22.literal(22050),
4570
- z22.literal(24e3),
4571
- z22.literal(44100),
4572
- 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)
4573
4630
  ]).nullish(),
4574
4631
  /**
4575
4632
  * Language code used for inverse text normalization.
4576
4633
  */
4577
- language: z22.string().nullish(),
4634
+ language: z23.string().nullish(),
4578
4635
  /**
4579
4636
  * Enable inverse text normalization. Requires `language`.
4580
4637
  */
4581
- format: z22.boolean().nullish(),
4638
+ format: z23.boolean().nullish(),
4582
4639
  /**
4583
4640
  * Enable per-channel transcription for multichannel audio.
4584
4641
  */
4585
- multichannel: z22.boolean().nullish(),
4642
+ multichannel: z23.boolean().nullish(),
4586
4643
  /**
4587
4644
  * Number of interleaved audio channels.
4588
4645
  */
4589
- channels: z22.number().int().min(2).max(8).nullish(),
4646
+ channels: z23.number().int().min(2).max(8).nullish(),
4590
4647
  /**
4591
4648
  * Enable speaker diarization.
4592
4649
  */
4593
- diarize: z22.boolean().nullish(),
4650
+ diarize: z23.boolean().nullish(),
4594
4651
  /**
4595
4652
  * Terms to bias transcription toward.
4596
4653
  */
4597
- keyterm: z22.union([z22.string(), z22.array(z22.string())]).nullish(),
4654
+ keyterm: z23.union([z23.string(), z23.array(z23.string())]).nullish(),
4598
4655
  /**
4599
4656
  * Include filler words such as "uh" and "um" in the transcript.
4600
4657
  */
4601
- fillerWords: z22.boolean().nullish(),
4658
+ fillerWords: z23.boolean().nullish(),
4602
4659
  /**
4603
4660
  * Options for streaming speech-to-text over WebSocket.
4604
4661
  */
4605
- streaming: z22.object({
4662
+ streaming: z23.object({
4606
4663
  /**
4607
4664
  * Emit interim transcript results while speech is being processed.
4608
4665
  */
4609
- interimResults: z22.boolean().optional(),
4666
+ interimResults: z23.boolean().optional(),
4610
4667
  /**
4611
4668
  * Silence duration in milliseconds before an utterance-final event.
4612
4669
  */
4613
- endpointing: z22.number().int().min(0).max(5e3).optional(),
4670
+ endpointing: z23.number().int().min(0).max(5e3).optional(),
4614
4671
  /**
4615
4672
  * End-of-turn detection threshold. When set, enables Smart Turn.
4616
4673
  */
4617
- smartTurn: z22.number().min(0).max(1).optional(),
4674
+ smartTurn: z23.number().min(0).max(1).optional(),
4618
4675
  /**
4619
4676
  * Maximum silence duration in milliseconds before forcing speech_final.
4620
4677
  */
4621
- smartTurnTimeout: z22.number().int().min(1).max(5e3).optional()
4678
+ smartTurnTimeout: z23.number().int().min(1).max(5e3).optional()
4622
4679
  }).optional()
4623
4680
  })
4624
4681
  )
@@ -4676,7 +4733,7 @@ var XaiTranscriptionModel = class _XaiTranscriptionModel {
4676
4733
  formData.append("keyterm", keyterm);
4677
4734
  }
4678
4735
  }
4679
- 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)]);
4680
4737
  const fileExtension = mediaTypeToExtension(mediaType);
4681
4738
  formData.append(
4682
4739
  "file",
@@ -4698,7 +4755,7 @@ var XaiTranscriptionModel = class _XaiTranscriptionModel {
4698
4755
  headers: combineHeaders7((_f = (_e = this.config).headers) == null ? void 0 : _f.call(_e), options.headers),
4699
4756
  formData,
4700
4757
  failedResponseHandler: xaiFailedResponseHandler,
4701
- successfulResponseHandler: createJsonResponseHandler6(
4758
+ successfulResponseHandler: createJsonResponseHandler7(
4702
4759
  xaiTranscriptionResponseSchema
4703
4760
  ),
4704
4761
  abortSignal: options.abortSignal,
@@ -4835,7 +4892,7 @@ function createXaiStreamingTranscriptionStream({
4835
4892
  const { done, value } = await audioReader.read();
4836
4893
  if (done || finished) break;
4837
4894
  socket.send(
4838
- value instanceof Uint8Array ? value : convertBase64ToUint8Array(value)
4895
+ value instanceof Uint8Array ? value : convertBase64ToUint8Array2(value)
4839
4896
  );
4840
4897
  await waitForWebSocketBufferDrain(socket);
4841
4898
  }
@@ -5017,15 +5074,15 @@ function timingFromXaiEvent(event) {
5017
5074
  ...event.start != null && event.duration != null ? { endSecond: event.start + event.duration } : {}
5018
5075
  };
5019
5076
  }
5020
- var xaiTranscriptionResponseSchema = z23.object({
5021
- text: z23.string(),
5022
- language: z23.string().nullish(),
5023
- duration: z23.number().nullish(),
5024
- words: z23.array(
5025
- z23.object({
5026
- text: z23.string(),
5027
- start: z23.number(),
5028
- 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()
5029
5086
  })
5030
5087
  ).nullish()
5031
5088
  });