@ai-sdk/xai
Advanced tools
+4
-4
| { | ||
| "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": { |
+113
-25
| 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
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
723834
1.64%10363
1.16%+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
Updated
Updated