@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 +14 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +170 -18
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/xai-batch.ts +196 -10
- package/src/xai-chat-language-model.ts +1 -1
- package/src/xai-provider.ts +4 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-sdk/xai",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.58",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
}
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@ai-sdk/provider": "4.0.
|
|
33
|
-
"@ai-sdk/provider-utils": "5.0.
|
|
32
|
+
"@ai-sdk/provider": "4.0.14",
|
|
33
|
+
"@ai-sdk/provider-utils": "5.0.40"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@ai-sdk/test-server": "2.0.1",
|
package/src/xai-batch.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
InvalidArgumentError,
|
|
3
|
+
UnsupportedFunctionalityError,
|
|
3
4
|
type Experimental_BatchV4 as BatchV4,
|
|
4
5
|
type Experimental_BatchV4CancelResult as BatchV4CancelResult,
|
|
5
6
|
type Experimental_BatchV4Error as BatchV4Error,
|
|
@@ -10,17 +11,23 @@ import {
|
|
|
10
11
|
type Experimental_BatchV4StartResult as BatchV4StartResult,
|
|
11
12
|
type Experimental_BatchV4Status as BatchV4Status,
|
|
12
13
|
type Experimental_TextBatchV4Request as TextBatchV4Request,
|
|
14
|
+
type Experimental_ImageBatchV4Request as ImageBatchV4Request,
|
|
15
|
+
type Experimental_ImageBatchV4ItemResult as ImageBatchV4ItemResult,
|
|
13
16
|
type Experimental_TextBatchV4ItemResult as TextBatchV4ItemResult,
|
|
14
17
|
type Experimental_BatchV4StartOptions as BatchV4StartOptions,
|
|
15
18
|
type LanguageModelV4Content,
|
|
16
19
|
type LanguageModelV4GenerateResult,
|
|
17
20
|
type SharedV4ProviderMetadata,
|
|
18
21
|
type SharedV4Warning,
|
|
22
|
+
type ImageModelV4Result,
|
|
19
23
|
} from '@ai-sdk/provider';
|
|
20
24
|
import {
|
|
21
25
|
combineHeaders,
|
|
26
|
+
convertImageModelFileToDataUri,
|
|
27
|
+
convertBase64ToUint8Array,
|
|
22
28
|
convertAsyncIteratorToReadableStream,
|
|
23
29
|
createJsonResponseHandler,
|
|
30
|
+
createBinaryResponseHandler,
|
|
24
31
|
createNullLanguageModelUsage,
|
|
25
32
|
getFromApi,
|
|
26
33
|
lazySchema,
|
|
@@ -48,6 +55,8 @@ import {
|
|
|
48
55
|
type XaiResponsesConfig,
|
|
49
56
|
} from './responses/xai-responses-language-model';
|
|
50
57
|
import type { XaiResponsesModelId } from './responses/xai-responses-language-model-options';
|
|
58
|
+
import type { XaiImageModelId } from './xai-image-settings';
|
|
59
|
+
import { xaiImageModelOptions } from './xai-image-model-options';
|
|
51
60
|
|
|
52
61
|
const xaiBatchEndpoint = '/v1/responses';
|
|
53
62
|
const xaiBatchName = 'ai-sdk-text-batch';
|
|
@@ -71,14 +80,45 @@ const xaiBatchProviderOptionsSchema = lazySchema(() =>
|
|
|
71
80
|
),
|
|
72
81
|
);
|
|
73
82
|
|
|
74
|
-
type XaiBatchModelIds = {
|
|
83
|
+
type XaiBatchModelIds = {
|
|
84
|
+
readonly text: XaiResponsesModelId;
|
|
85
|
+
readonly image: XaiImageModelId;
|
|
86
|
+
};
|
|
75
87
|
type XaiBatchRequest = TextBatchV4Request<XaiResponsesModelId>;
|
|
88
|
+
type XaiImageBatchRequest = ImageBatchV4Request<XaiImageModelId>;
|
|
89
|
+
|
|
90
|
+
function assertSupportedBatchRequests(
|
|
91
|
+
requests: BatchV4StartOptions<XaiBatchModelIds>['requests'],
|
|
92
|
+
) {
|
|
93
|
+
for (const request of requests) {
|
|
94
|
+
const requestType = request.type;
|
|
95
|
+
if (requestType !== 'text' && requestType !== 'image') {
|
|
96
|
+
throw new UnsupportedFunctionalityError({
|
|
97
|
+
functionality: `batch request type: ${requestType}`,
|
|
98
|
+
message: `The xAI Batch API does not support batch requests with type "${requestType}".`,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
76
103
|
|
|
77
104
|
type XaiBatchPreparedRequest = {
|
|
105
|
+
endpoint: string;
|
|
78
106
|
body: unknown;
|
|
79
107
|
warnings: SharedV4Warning[];
|
|
80
108
|
};
|
|
81
109
|
|
|
110
|
+
const xaiBatchImageResponseSchema = z.object({
|
|
111
|
+
data: z.array(
|
|
112
|
+
z.object({
|
|
113
|
+
url: z.string().nullish(),
|
|
114
|
+
b64_json: z.string().nullish(),
|
|
115
|
+
revised_prompt: z.string().nullish(),
|
|
116
|
+
respect_moderation: z.boolean().nullish(),
|
|
117
|
+
}),
|
|
118
|
+
),
|
|
119
|
+
usage: z.object({ cost_in_usd_ticks: z.number().nullish() }).nullish(),
|
|
120
|
+
});
|
|
121
|
+
|
|
82
122
|
type XaiBatchResponseConversion =
|
|
83
123
|
| { success: true; result: LanguageModelV4GenerateResult }
|
|
84
124
|
| { success: false; error: BatchV4Error };
|
|
@@ -120,6 +160,7 @@ const xaiBatchResultSchema = z.object({
|
|
|
120
160
|
response: z
|
|
121
161
|
.object({
|
|
122
162
|
chat_get_completion: z.unknown().nullish(),
|
|
163
|
+
image_generation: z.unknown().nullish(),
|
|
123
164
|
})
|
|
124
165
|
.nullish(),
|
|
125
166
|
error: xaiBatchErrorSchema.nullish(),
|
|
@@ -165,6 +206,7 @@ export class XaiBatch implements BatchV4<XaiBatchModelIds> {
|
|
|
165
206
|
async doStartBatch(
|
|
166
207
|
options: BatchV4StartOptions<XaiBatchModelIds>,
|
|
167
208
|
): Promise<BatchV4StartResult> {
|
|
209
|
+
assertSupportedBatchRequests(options.requests);
|
|
168
210
|
const fileParts: string[] = [];
|
|
169
211
|
const warnings: BatchV4StartResult['warnings'] =
|
|
170
212
|
options.webhookUrl == null
|
|
@@ -193,7 +235,7 @@ export class XaiBatch implements BatchV4<XaiBatchModelIds> {
|
|
|
193
235
|
JSON.stringify({
|
|
194
236
|
custom_id: request.id,
|
|
195
237
|
method: 'POST',
|
|
196
|
-
url:
|
|
238
|
+
url: preparedRequest.endpoint,
|
|
197
239
|
body: preparedRequest.body,
|
|
198
240
|
}),
|
|
199
241
|
'\n',
|
|
@@ -392,7 +434,7 @@ export class XaiBatch implements BatchV4<XaiBatchModelIds> {
|
|
|
392
434
|
});
|
|
393
435
|
|
|
394
436
|
for (const result of page.results) {
|
|
395
|
-
yield await this.convertBatchResult(result);
|
|
437
|
+
yield await this.convertBatchResult(result, options.abortSignal);
|
|
396
438
|
}
|
|
397
439
|
|
|
398
440
|
paginationToken = page.pagination_token ?? undefined;
|
|
@@ -401,7 +443,8 @@ export class XaiBatch implements BatchV4<XaiBatchModelIds> {
|
|
|
401
443
|
|
|
402
444
|
private async convertBatchResult(
|
|
403
445
|
result: XaiBatchResult,
|
|
404
|
-
|
|
446
|
+
abortSignal: AbortSignal | undefined,
|
|
447
|
+
): Promise<TextBatchV4ItemResult | ImageBatchV4ItemResult> {
|
|
405
448
|
const error = result.batch_result?.error;
|
|
406
449
|
if (
|
|
407
450
|
(result.error_message?.length ?? 0) > 0 ||
|
|
@@ -445,18 +488,149 @@ export class XaiBatch implements BatchV4<XaiBatchModelIds> {
|
|
|
445
488
|
};
|
|
446
489
|
}
|
|
447
490
|
|
|
491
|
+
if (response?.image_generation != null) {
|
|
492
|
+
const validation = await safeValidateTypes({
|
|
493
|
+
value: response.image_generation,
|
|
494
|
+
schema: zodSchema(xaiBatchImageResponseSchema),
|
|
495
|
+
});
|
|
496
|
+
if (!validation.success) {
|
|
497
|
+
return invalidXaiImageBatchResult(result.batch_request_id);
|
|
498
|
+
}
|
|
499
|
+
if (
|
|
500
|
+
validation.value.data.some(image => image.respect_moderation === false)
|
|
501
|
+
) {
|
|
502
|
+
return {
|
|
503
|
+
type: 'image',
|
|
504
|
+
id: result.batch_request_id,
|
|
505
|
+
status: 'failed',
|
|
506
|
+
error: {
|
|
507
|
+
message:
|
|
508
|
+
'Image generation was blocked due to a content policy violation.',
|
|
509
|
+
},
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
const imageResult = await this.convertImageBatchResponse(
|
|
513
|
+
validation.value,
|
|
514
|
+
abortSignal,
|
|
515
|
+
);
|
|
516
|
+
return {
|
|
517
|
+
type: 'image',
|
|
518
|
+
id: result.batch_request_id,
|
|
519
|
+
status: 'succeeded',
|
|
520
|
+
result: imageResult,
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
|
|
448
524
|
return invalidXaiBatchResult(result.batch_request_id);
|
|
449
525
|
}
|
|
450
526
|
|
|
451
527
|
private async prepareRequest(
|
|
452
|
-
request: XaiBatchRequest,
|
|
528
|
+
request: XaiBatchRequest | XaiImageBatchRequest,
|
|
453
529
|
): Promise<XaiBatchPreparedRequest> {
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
530
|
+
if (request.type === 'text') {
|
|
531
|
+
const { args: body, warnings } =
|
|
532
|
+
await XaiResponsesLanguageModel.prepareRequest({
|
|
533
|
+
modelId: request.modelId,
|
|
534
|
+
options: request.options,
|
|
535
|
+
});
|
|
536
|
+
return { endpoint: xaiBatchEndpoint, body, warnings };
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
const { prompt, n, size, aspectRatio, seed, files, mask, providerOptions } =
|
|
540
|
+
request.options;
|
|
541
|
+
const warnings: SharedV4Warning[] = [];
|
|
542
|
+
if (size != null) {
|
|
543
|
+
warnings.push({
|
|
544
|
+
type: 'unsupported',
|
|
545
|
+
feature: 'size',
|
|
546
|
+
details:
|
|
547
|
+
'This model does not support the `size` option. Use `aspectRatio` instead.',
|
|
458
548
|
});
|
|
459
|
-
|
|
549
|
+
}
|
|
550
|
+
if (seed != null) warnings.push({ type: 'unsupported', feature: 'seed' });
|
|
551
|
+
if (mask != null) warnings.push({ type: 'unsupported', feature: 'mask' });
|
|
552
|
+
|
|
553
|
+
const xaiOptions = await parseProviderOptions({
|
|
554
|
+
provider: 'xai',
|
|
555
|
+
providerOptions,
|
|
556
|
+
schema: xaiImageModelOptions,
|
|
557
|
+
});
|
|
558
|
+
const imageUrls = (files ?? []).map(convertImageModelFileToDataUri);
|
|
559
|
+
const body: Record<string, unknown> = {
|
|
560
|
+
model: request.modelId,
|
|
561
|
+
prompt,
|
|
562
|
+
n,
|
|
563
|
+
response_format: 'b64_json',
|
|
564
|
+
};
|
|
565
|
+
if (aspectRatio != null) body.aspect_ratio = aspectRatio;
|
|
566
|
+
if (xaiOptions?.output_format != null)
|
|
567
|
+
body.output_format = xaiOptions.output_format;
|
|
568
|
+
if (xaiOptions?.sync_mode != null) body.sync_mode = xaiOptions.sync_mode;
|
|
569
|
+
if (xaiOptions?.aspect_ratio != null && aspectRatio == null)
|
|
570
|
+
body.aspect_ratio = xaiOptions.aspect_ratio;
|
|
571
|
+
if (xaiOptions?.resolution != null) body.resolution = xaiOptions.resolution;
|
|
572
|
+
if (xaiOptions?.quality != null) body.quality = xaiOptions.quality;
|
|
573
|
+
if (xaiOptions?.user != null) body.user = xaiOptions.user;
|
|
574
|
+
if (imageUrls.length === 1) {
|
|
575
|
+
body.image = { url: imageUrls[0], type: 'image_url' };
|
|
576
|
+
} else if (imageUrls.length > 1) {
|
|
577
|
+
body.images = imageUrls.map(url => ({ url, type: 'image_url' }));
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
return {
|
|
581
|
+
endpoint: files?.length ? '/v1/images/edits' : '/v1/images/generations',
|
|
582
|
+
body,
|
|
583
|
+
warnings,
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
private async convertImageBatchResponse(
|
|
588
|
+
response: z.infer<typeof xaiBatchImageResponseSchema>,
|
|
589
|
+
abortSignal: AbortSignal | undefined,
|
|
590
|
+
): Promise<ImageModelV4Result> {
|
|
591
|
+
const hasAllBase64 = response.data.every(image => image.b64_json != null);
|
|
592
|
+
const images = hasAllBase64
|
|
593
|
+
? response.data.map(image => image.b64_json!)
|
|
594
|
+
: await Promise.all(
|
|
595
|
+
response.data.map(async image => {
|
|
596
|
+
if (image.b64_json != null) {
|
|
597
|
+
return convertBase64ToUint8Array(image.b64_json);
|
|
598
|
+
}
|
|
599
|
+
if (image.url == null) {
|
|
600
|
+
throw new InvalidArgumentError({
|
|
601
|
+
argument: 'batchResult',
|
|
602
|
+
message: 'xAI returned an image without data or a URL.',
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
const { value } = await getFromApi({
|
|
606
|
+
url: image.url,
|
|
607
|
+
validateUrl: true,
|
|
608
|
+
trustedOrigin: this.options.config.baseURL,
|
|
609
|
+
abortSignal,
|
|
610
|
+
failedResponseHandler: xaiFailedResponseHandler,
|
|
611
|
+
successfulResponseHandler: createBinaryResponseHandler(),
|
|
612
|
+
fetch: this.options.config.fetch,
|
|
613
|
+
});
|
|
614
|
+
return value;
|
|
615
|
+
}),
|
|
616
|
+
);
|
|
617
|
+
return {
|
|
618
|
+
images,
|
|
619
|
+
warnings: [],
|
|
620
|
+
response: { timestamp: new Date(), modelId: '', headers: undefined },
|
|
621
|
+
providerMetadata: {
|
|
622
|
+
xai: {
|
|
623
|
+
images: response.data.map(item =>
|
|
624
|
+
item.revised_prompt != null
|
|
625
|
+
? { revisedPrompt: item.revised_prompt }
|
|
626
|
+
: {},
|
|
627
|
+
),
|
|
628
|
+
...(response.usage?.cost_in_usd_ticks != null
|
|
629
|
+
? { costInUsdTicks: response.usage.cost_in_usd_ticks }
|
|
630
|
+
: {}),
|
|
631
|
+
},
|
|
632
|
+
},
|
|
633
|
+
};
|
|
460
634
|
}
|
|
461
635
|
|
|
462
636
|
private getUrl(path: string) {
|
|
@@ -552,6 +726,18 @@ function invalidXaiBatchResult(id: string): TextBatchV4ItemResult {
|
|
|
552
726
|
};
|
|
553
727
|
}
|
|
554
728
|
|
|
729
|
+
function invalidXaiImageBatchResult(id: string): ImageBatchV4ItemResult {
|
|
730
|
+
return {
|
|
731
|
+
type: 'image',
|
|
732
|
+
id,
|
|
733
|
+
status: 'failed',
|
|
734
|
+
error: {
|
|
735
|
+
message: 'xAI returned an invalid image batch result.',
|
|
736
|
+
code: 'invalid_response',
|
|
737
|
+
},
|
|
738
|
+
};
|
|
739
|
+
}
|
|
740
|
+
|
|
555
741
|
function convertXaiChatBatchResponse(
|
|
556
742
|
response: XaiChatResponse,
|
|
557
743
|
): XaiBatchResponseConversion {
|
|
@@ -590,7 +590,7 @@ export class XaiChatLanguageModel implements LanguageModelV4 {
|
|
|
590
590
|
}
|
|
591
591
|
|
|
592
592
|
// process tool calls
|
|
593
|
-
if (delta.tool_calls != null) {
|
|
593
|
+
if (delta.tool_calls != null && delta.tool_calls.length > 0) {
|
|
594
594
|
// end active reasoning block before tool calls start
|
|
595
595
|
if (
|
|
596
596
|
activeReasoningBlockId != null &&
|
package/src/xai-provider.ts
CHANGED
|
@@ -56,7 +56,10 @@ export interface XaiProvider extends ProviderV4 {
|
|
|
56
56
|
/**
|
|
57
57
|
* Returns a BatchV4 interface for processing batches with xAI.
|
|
58
58
|
*/
|
|
59
|
-
experimental_batch(): BatchV4<{
|
|
59
|
+
experimental_batch(): BatchV4<{
|
|
60
|
+
text: XaiResponsesModelId;
|
|
61
|
+
image: XaiImageModelId;
|
|
62
|
+
}>;
|
|
60
63
|
|
|
61
64
|
/**
|
|
62
65
|
* Creates an Xai image model for image generation.
|