Sign In

ai

Package Overview
Dependencies
Maintainers
5
Versions
1469
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ai - npm Package Compare versions

Comparing version
7.0.74
to
7.0.76
+66
src/generate-video/get-video-status.ts
import type {
Experimental_VideoModelV4OperationStatusResult,
JSONValue,
} from '@ai-sdk/provider';
import { withUserAgentSuffix } from '@ai-sdk/provider-utils';
import { resolveVideoModel } from '../model/resolve-model';
import type { VideoModel } from '../types/video-model';
import { prepareRetries } from '../util/prepare-retries';
import { VERSION } from '../version';
/**
* The result of an `experimental_getVideoStatus` call: the spec-level status
* payload, discriminated by `status` (`pending` | `completed` | `error`).
*/
export type GetVideoStatusResult =
Experimental_VideoModelV4OperationStatusResult;
/**
* Checks the status of an asynchronous video generation started with
* `experimental_startVideo`.
*
* A single check — no polling loop. Poll by calling this on your own
* schedule, or skip polling entirely when the start used `webhookUrl` and
* your receiver fetches the result after the terminal notification arrives.
*
* @param model - The video model the operation was started on.
* @param operation - The opaque reference returned by `experimental_startVideo`.
* @param headers - Additional HTTP headers to be sent with the request. Only applicable for HTTP-based providers.
* @param abortSignal - An optional abort signal that can be used to cancel the call.
* @param maxRetries - Maximum number of retries for the status call. Set to 0 to disable retries. Default: 2.
*/
export async function experimental_getVideoStatus(
modelArg: VideoModel,
{
operation,
headers,
abortSignal,
maxRetries: maxRetriesArg,
}: {
operation: JSONValue;
headers?: Record<string, string>;
abortSignal?: AbortSignal;
maxRetries?: number;
},
): Promise<GetVideoStatusResult> {
const model = resolveVideoModel(modelArg);
if (model.doStatus == null) {
throw new Error(
`Video model ${model.modelId} does not implement doStatus.`,
);
}
const { retry } = prepareRetries({
maxRetries: maxRetriesArg,
abortSignal,
});
return retry(() =>
model.doStatus!({
operation,
headers: withUserAgentSuffix(headers ?? {}, `ai/${VERSION}`),
abortSignal,
}),
);
}
import type {
Experimental_VideoModelV4CallOptions,
Experimental_VideoModelV4FrameType,
JSONValue,
} from '@ai-sdk/provider';
import {
generateId,
withUserAgentSuffix,
type DataContent,
type ProviderOptions,
} from '@ai-sdk/provider-utils';
import { resolveVideoModel } from '../model/resolve-model';
import type {
VideoModel,
VideoModelProviderMetadata,
} from '../types/video-model';
import type { VideoModelResponseMetadata } from '../types/video-model-response-metadata';
import type { Warning } from '../types/warning';
import { prepareRetries } from '../util/prepare-retries';
import { VERSION } from '../version';
import {
normalizeVideoCallInputs,
type GenerateVideoPrompt,
} from './generate-video';
/**
* The result of an `experimental_startVideo` call.
*/
export interface StartVideoResult {
/**
* JSON-serializable opaque reference to the started generation.
* Persist it and pass it to `experimental_getVideoStatus` to retrieve the
* status and result later — from any process.
*/
readonly operation: JSONValue;
/**
* Warnings for the call, e.g. unsupported settings.
*/
readonly warnings: Array<Warning>;
/**
* Provider-specific metadata passed through from the provider.
* Carries the provider's own job identifiers (e.g. the AI Gateway's
* `providerMetadata.gateway.asyncJob.jobId` and, when `webhookUrl` was
* given, its `webhookSigningSecret`).
*/
readonly providerMetadata?: VideoModelProviderMetadata;
/**
* Response metadata from the provider.
*/
readonly response: VideoModelResponseMetadata;
}
/**
* Starts an asynchronous video generation and returns immediately with an
* opaque `operation` reference — without waiting for the video to finish.
*
* This is the fire-and-forget counterpart to `experimental_generateVideo`:
* use it to fan out many jobs, to submit from a process that will not stay
* alive, or together with `webhookUrl` so the provider notifies your endpoint
* at the terminal state. Check the outcome with `experimental_getVideoStatus`,
* or let your webhook receiver fetch the result.
*
* @param model - The video model to use. Must implement `doStart`.
* @param prompt - The prompt that should be used to generate the video.
* @param n - Number of videos to generate. Default: 1. Must not exceed the
* model's `maxVideosPerCall` — fan out with multiple `startVideo` calls.
* @param aspectRatio - Aspect ratio of the videos to generate. Must have the format `{width}:{height}`, or `'adaptive'`.
* @param resolution - Resolution of the videos to generate. Must have the format `{width}x${height}`.
* @param duration - Duration of the video in seconds.
* @param fps - Frames per second for the video.
* @param seed - Seed for the video generation.
* @param frameImages - Role-tagged image inputs for image-to-video and first-last-frame generation.
* @param inputReferences - Reference image or video inputs for reference-to-video generation.
* @param generateAudio - Whether the model should generate audio alongside the video.
* @param providerOptions - Additional provider-specific options that are passed through to the provider
* as body parameters.
* @param maxRetries - Maximum number of retries for the start call. Set to 0 to disable retries. Default: 2.
* @param abortSignal - An optional abort signal that can be used to cancel the call.
* @param headers - Additional HTTP headers to be sent with the request. Only applicable for HTTP-based providers.
* @param webhookUrl - A URL the provider should notify when the generation
* reaches a terminal state.
*
* @returns A result object that contains the opaque `operation` reference,
* warnings, provider metadata (including the provider's job id), and response
* metadata.
*/
export async function experimental_startVideo({
model: modelArg,
prompt: promptArg,
n = 1,
maxVideosPerCall,
aspectRatio,
resolution,
duration,
fps,
seed,
frameImages,
inputReferences,
generateAudio,
providerOptions,
maxRetries: maxRetriesArg,
abortSignal,
headers,
webhookUrl,
}: {
model: VideoModel;
prompt: GenerateVideoPrompt;
n?: number;
maxVideosPerCall?: number;
aspectRatio?: `${number}:${number}` | 'adaptive';
resolution?: `${number}x${number}`;
duration?: number;
fps?: number;
seed?: number;
frameImages?: Array<{
image: DataContent;
frameType: Experimental_VideoModelV4FrameType;
}>;
inputReferences?: Array<
DataContent | { data: DataContent; mediaType?: string }
>;
generateAudio?: boolean;
providerOptions?: ProviderOptions;
maxRetries?: number;
abortSignal?: AbortSignal;
headers?: Record<string, string>;
webhookUrl?: string;
}): Promise<StartVideoResult> {
const model = resolveVideoModel(modelArg);
if (model.doStart == null) {
throw new Error(
`Video model ${model.modelId} does not implement doStart. ` +
'Use generateVideo for models without an asynchronous start/status flow.',
);
}
if (!Number.isInteger(n) || n < 1) {
throw new Error(
`Invalid n: expected a positive integer, received ${JSON.stringify(n)}.`,
);
}
// A start yields one operation covering all n videos: refuse to silently
// exceed a known per-call limit instead of splitting into several starts.
const knownMaxVideosPerCall =
maxVideosPerCall ??
(typeof model.maxVideosPerCall === 'function'
? await model.maxVideosPerCall({ modelId: model.modelId })
: model.maxVideosPerCall);
if (knownMaxVideosPerCall != null && n > knownMaxVideosPerCall) {
throw new Error(
`Video model ${model.modelId} supports at most ${knownMaxVideosPerCall} video(s) per call, ` +
`but ${n} were requested. Split the batch across multiple startVideo calls.`,
);
}
const {
prompt,
resolvedImage,
normalizedFrameImages,
effectiveInputReferences,
warnings,
} = normalizeVideoCallInputs({ promptArg, frameImages, inputReferences });
const { retry } = prepareRetries({
maxRetries: maxRetriesArg,
abortSignal,
});
// `doStart` is billable: mint one idempotency token per logical start,
// outside the retry closure; a caller-supplied key wins.
const callerIdempotencyKey = Object.entries(headers ?? {}).find(
([key, value]) =>
key.toLowerCase() === 'idempotency-key' && value !== undefined,
);
const callOptions: Experimental_VideoModelV4CallOptions & {
webhookUrl?: string;
} = {
prompt,
n,
aspectRatio,
resolution,
duration,
fps,
seed,
image: resolvedImage,
frameImages: normalizedFrameImages,
inputReferences: effectiveInputReferences,
generateAudio,
providerOptions: providerOptions ?? {},
headers: {
...withUserAgentSuffix(headers ?? {}, `ai/${VERSION}`),
...(callerIdempotencyKey
? {}
: { 'idempotency-key': `aisdk_vid_${generateId()}` }),
},
abortSignal,
webhookUrl,
};
const startResult = await retry(() => model.doStart!(callOptions));
return {
operation: startResult.operation,
warnings: [...warnings, ...startResult.warnings],
providerMetadata: startResult.providerMetadata,
response: startResult.response,
};
}
+2
-2
{
"name": "ai",
"version": "7.0.74",
"version": "7.0.76",
"type": "module",

@@ -45,3 +45,3 @@ "description": "AI SDK by Vercel - build apps like ChatGPT, Claude, Gemini, and more with a single interface for any model using the Vercel AI Gateway or go direct to OpenAI, Anthropic, Google, or any other model provider.",

"dependencies": {
"@ai-sdk/gateway": "4.0.60",
"@ai-sdk/gateway": "4.0.61",
"@ai-sdk/provider": "4.0.7",

@@ -48,0 +48,0 @@ "@ai-sdk/provider-utils": "5.0.28"

@@ -295,56 +295,10 @@ import type {

const { prompt, image } = normalizePrompt(promptArg);
const {
prompt,
resolvedImage,
normalizedFrameImages,
effectiveInputReferences,
warnings,
} = normalizeVideoCallInputs({ promptArg, frameImages, inputReferences });
const normalizedFrameImages:
| Array<Experimental_VideoModelV4FrameImage>
| undefined = frameImages?.flatMap(frame => {
const normalizedImage = normalizeImageData(frame.image);
return normalizedImage != null
? [{ image: normalizedImage, frameType: frame.frameType }]
: [];
});
const normalizedInputReferences:
| Array<Experimental_VideoModelV4File>
| undefined = inputReferences?.flatMap(reference => {
const normalized = normalizeReferenceData(reference);
return normalized != null ? [normalized] : [];
});
const effectiveInputReferences =
normalizedFrameImages != null && normalizedFrameImages.length > 0
? undefined
: normalizedInputReferences;
const warnings: Array<Warning> = [];
if (
normalizedFrameImages != null &&
normalizedFrameImages.length > 0 &&
normalizedInputReferences != null &&
normalizedInputReferences.length > 0
) {
warnings.push({
type: 'other',
message:
'inputReferences were ignored because frameImages were provided; ' +
'frameImages and inputReferences cannot be combined.',
});
}
const firstFrameImage = normalizedFrameImages?.find(
frame => frame.frameType === 'first_frame',
)?.image;
if (image != null && firstFrameImage != null) {
warnings.push({
type: 'other',
message:
'prompt.image was ignored because a first_frame frameImage was provided; ' +
'the first_frame frameImage takes precedence as the start image.',
});
}
const resolvedImage = firstFrameImage ?? image;
const maxVideosPerCallWithDefault =

@@ -741,2 +695,90 @@ maxVideosPerCall ?? (await invokeModelMaxVideosPerCall(model)) ?? 1;

/**
* Shared input normalization for `experimental_generateVideo` and
* `experimental_startVideo`: prompt/image plus the frameImages /
* inputReferences precedence rules and their warnings.
*/
export function normalizeVideoCallInputs({
promptArg,
frameImages,
inputReferences,
}: {
promptArg: GenerateVideoPrompt;
frameImages?: Array<{
image: DataContent;
frameType: Experimental_VideoModelV4FrameType;
}>;
inputReferences?: Array<
DataContent | { data: DataContent; mediaType?: string }
>;
}): {
prompt: string | undefined;
resolvedImage: Experimental_VideoModelV4File | undefined;
normalizedFrameImages: Array<Experimental_VideoModelV4FrameImage> | undefined;
effectiveInputReferences: Array<Experimental_VideoModelV4File> | undefined;
warnings: Array<Warning>;
} {
const { prompt, image } = normalizePrompt(promptArg);
const normalizedFrameImages:
| Array<Experimental_VideoModelV4FrameImage>
| undefined = frameImages?.flatMap(frame => {
const normalizedImage = normalizeImageData(frame.image);
return normalizedImage != null
? [{ image: normalizedImage, frameType: frame.frameType }]
: [];
});
const normalizedInputReferences:
| Array<Experimental_VideoModelV4File>
| undefined = inputReferences?.flatMap(reference => {
const normalized = normalizeReferenceData(reference);
return normalized != null ? [normalized] : [];
});
const effectiveInputReferences =
normalizedFrameImages != null && normalizedFrameImages.length > 0
? undefined
: normalizedInputReferences;
const warnings: Array<Warning> = [];
if (
normalizedFrameImages != null &&
normalizedFrameImages.length > 0 &&
normalizedInputReferences != null &&
normalizedInputReferences.length > 0
) {
warnings.push({
type: 'other',
message:
'inputReferences were ignored because frameImages were provided; ' +
'frameImages and inputReferences cannot be combined.',
});
}
const firstFrameImage = normalizedFrameImages?.find(
frame => frame.frameType === 'first_frame',
)?.image;
if (image != null && firstFrameImage != null) {
warnings.push({
type: 'other',
message:
'prompt.image was ignored because a first_frame frameImage was provided; ' +
'the first_frame frameImage takes precedence as the start image.',
});
}
const resolvedImage = firstFrameImage ?? image;
return {
prompt,
resolvedImage,
normalizedFrameImages,
effectiveInputReferences,
warnings,
};
}
function detectFileMediaType(

@@ -743,0 +785,0 @@ data: Uint8Array,

export type { GenerateVideoPrompt } from './generate-video';
export { experimental_generateVideo } from './generate-video';
export type { GenerateVideoResult } from './generate-video-result';
export { experimental_startVideo } from './start-video';
export type { StartVideoResult } from './start-video';
export { experimental_getVideoStatus } from './get-video-status';
export type { GetVideoStatusResult } from './get-video-status';

@@ -194,3 +194,3 @@ import {

messageMetadataSchema?: FlexibleSchema<InferUIMessageMetadata<UI_MESSAGE>>;
messageMetadataSchema?: FlexibleSchema<UI_MESSAGE['metadata']>;
dataPartSchemas?: UIDataTypesToSchemas<InferUIMessageData<UI_MESSAGE>>;

@@ -250,3 +250,3 @@

private messageMetadataSchema:
| FlexibleSchema<InferUIMessageMetadata<UI_MESSAGE>>
| FlexibleSchema<UI_MESSAGE['metadata']>
| undefined;

@@ -253,0 +253,0 @@ private dataPartSchemas:

@@ -93,3 +93,3 @@ import type { JSONObject } from '@ai-sdk/provider';

stream: ReadableStream<UIMessageChunk>;
messageMetadataSchema?: FlexibleSchema<InferUIMessageMetadata<UI_MESSAGE>>;
messageMetadataSchema?: FlexibleSchema<UI_MESSAGE['metadata']>;
dataPartSchemas?: UIDataTypesToSchemas<InferUIMessageData<UI_MESSAGE>>;

@@ -96,0 +96,0 @@ onToolCall?: (options: {

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 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

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