🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

@ai-sdk/xai

Package Overview
Dependencies
Maintainers
3
Versions
443
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@ai-sdk/xai - npm Package Compare versions

Comparing version
4.0.2
to
4.0.3
+4
-4
package.json
{
"name": "@ai-sdk/xai",
"version": "4.0.2",
"version": "4.0.3",
"type": "module",

@@ -32,5 +32,5 @@ "license": "Apache-2.0",

"dependencies": {
"@ai-sdk/openai-compatible": "3.0.1",
"@ai-sdk/provider": "4.0.0",
"@ai-sdk/provider-utils": "5.0.1"
"@ai-sdk/openai-compatible": "3.0.2",
"@ai-sdk/provider": "4.0.1",
"@ai-sdk/provider-utils": "5.0.2"
},

@@ -37,0 +37,0 @@ "devDependencies": {

import {
AISDKError,
type Experimental_VideoModelV4,
type Experimental_VideoModelV4File,
type SharedV4Warning,

@@ -40,17 +41,83 @@ } from '@ai-sdk/provider';

type XaiVideoDoGenerateOptions = Parameters<
Experimental_VideoModelV4['doGenerate']
>[0];
function getFirstFrameImage(
options: XaiVideoDoGenerateOptions,
): Experimental_VideoModelV4File | undefined {
return options.frameImages?.find(frame => frame.frameType === 'first_frame')
?.image;
}
function getLastFrameImage(
options: XaiVideoDoGenerateOptions,
): Experimental_VideoModelV4File | undefined {
return options.frameImages?.find(frame => frame.frameType === 'last_frame')
?.image;
}
function resolveStartImage(
options: XaiVideoDoGenerateOptions,
): Experimental_VideoModelV4File | undefined {
return getFirstFrameImage(options) ?? options.image;
}
function fileToXaiImageUrl(file: Experimental_VideoModelV4File): string {
if (file.type === 'url') {
return file.url;
}
const base64Data =
typeof file.data === 'string'
? file.data
: convertUint8ArrayToBase64(file.data);
return `data:${file.mediaType ?? 'image/png'};base64,${base64Data}`;
}
// Resolves the reference images for R2V generation. First-class
// `inputReferences` win over the legacy `referenceImageUrls` provider option.
function resolveReferenceImages(
options: XaiVideoDoGenerateOptions,
xaiOptions: XaiParsedVideoModelOptions | undefined,
): Array<{ url: string }> | undefined {
if (options.inputReferences != null && options.inputReferences.length > 0) {
return options.inputReferences.map(reference => ({
url: fileToXaiImageUrl(reference),
}));
}
if (
xaiOptions?.referenceImageUrls != null &&
xaiOptions.referenceImageUrls.length > 0
) {
return xaiOptions.referenceImageUrls.map(url => ({ url }));
}
return undefined;
}
function resolveVideoMode(
options: XaiParsedVideoModelOptions | undefined,
options: XaiVideoDoGenerateOptions,
xaiOptions: XaiParsedVideoModelOptions | undefined,
): XaiParsedVideoModelOptions['mode'] | undefined {
if (options?.mode != null) {
return options.mode;
if (xaiOptions?.mode != null) {
return xaiOptions.mode;
}
if (options?.videoUrl != null) {
if (xaiOptions?.videoUrl != null) {
return 'edit-video';
}
if (
options?.referenceImageUrls != null &&
options.referenceImageUrls.length > 0
) {
// frameImages (first/last frame) take precedence over reference images, so
// only auto-select reference-to-video when no frame images are provided.
const hasFrameImages =
options.frameImages != null && options.frameImages.length > 0;
const hasInputReferences =
options.inputReferences != null && options.inputReferences.length > 0;
const hasLegacyReferenceUrls =
xaiOptions?.referenceImageUrls != null &&
xaiOptions.referenceImageUrls.length > 0;
if (!hasFrameImages && (hasInputReferences || hasLegacyReferenceUrls)) {
return 'reference-to-video';

@@ -87,3 +154,3 @@ }

const effectiveMode = resolveVideoMode(xaiOptions);
const effectiveMode = resolveVideoMode(options, xaiOptions);

@@ -212,24 +279,45 @@ const isEdit = effectiveMode === 'edit-video';

// Convert SDK image input to the nested xAI request image object
if (options.image != null) {
if (options.image.type === 'url') {
body.image = { url: options.image.url };
} else {
const base64Data =
typeof options.image.data === 'string'
? options.image.data
: convertUint8ArrayToBase64(options.image.data);
body.image = {
url: `data:${options.image.mediaType};base64,${base64Data}`,
};
}
// Convert the start image (first_frame or image-to-video input) to the
// nested xAI request image object.
const startImage = resolveStartImage(options);
if (startImage != null) {
body.image = { url: fileToXaiImageUrl(startImage) };
}
// xAI has no first-last-frame interpolation; warn and ignore last_frame.
if (getLastFrameImage(options) != null) {
warnings.push({
type: 'unsupported',
feature: 'frameImages',
details:
'xAI video models do not support last_frame. Use ' +
'providerOptions.xai.mode "extend-video" to continue from a ' +
"video's last frame. The last frame image was ignored.",
});
}
// Reference images for R2V (reference-to-video) generation
if (hasReferenceImages) {
body.reference_images = xaiOptions!.referenceImageUrls!.map(url => ({
url,
}));
const referenceImages = resolveReferenceImages(options, xaiOptions);
if (referenceImages != null) {
body.reference_images = referenceImages;
}
}
// Warn when reference images were provided but cannot be used in the
// resolved mode (e.g. alongside frameImages, or in edit/extend modes).
if (
options.inputReferences != null &&
options.inputReferences.length > 0 &&
!hasReferenceImages
) {
warnings.push({
type: 'unsupported',
feature: 'inputReferences',
details:
'xAI only supports inputReferences for reference-to-video ' +
'generation. The reference images were ignored.',
});
}
if (xaiOptions != null) {

@@ -236,0 +324,0 @@ for (const [key, value] of Object.entries(xaiOptions)) {

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet