import type { AssetByteSource, AssetStore } from '../images/asset-support.js'; import type { AssetDescriptor, AssetInput } from '../types/images.js'; import type { OperationLifecycleLike, ProviderCallContext } from '../types/lifecycle.js'; import type { DurableOperationHandle, OperationRunnerConfig } from '../types/operations.js'; import type { ResponseCost } from '../types/response.js'; /** * What a video can be made from beside its prompt: a first frame, a last frame, reference images, * reference videos, or a video to continue (`extend`) or to change as the prompt says (`edit`). */ export type VideoInputKind = 'image' | 'last-frame' | 'references' | 'reference-videos' | 'extend' | 'edit'; /** * A video to work from: one to continue from its end, or one to change as the prompt says. Give the * video itself as `input`, or name a finished job of the same provider as `from`, which the provider * continues from what it already holds, with nothing uploaded. */ export interface VideoSource { /** `extend` continues the video; `edit` changes it as the prompt says. */ mode: 'extend' | 'edit'; /** The video: bytes, a URL the provider can read, or an asset in the manager's store. */ input?: AssetInput; /** Or a video this provider made: its job, and which of the job's videos, from 0. */ from?: { ref: VideoJobRef; index?: number; }; } /** Whether a model makes sound: always, when asked, or never. */ export type VideoAudioSupport = 'always' | 'optional' | 'none'; /** A video to make. */ export interface VideoGenerateRequest { /** What the video shows. May be empty only when `image` is given and the model animates it alone. */ prompt: string; /** The model. Defaults to the provider's. */ model?: string; /** The provider to use. Defaults to the manager's default. */ provider?: string; /** The first frame: the video starts from this image. */ image?: AssetInput; /** The last frame, on a model that moves toward one. */ lastFrame?: AssetInput; /** Images whose subject, character, or style the video keeps. */ references?: readonly AssetInput[]; /** Videos whose motion, subject, or look the video takes after; their sound is ignored. */ referenceVideos?: readonly AssetInput[]; /** A video to extend or edit. */ video?: VideoSource; /** Length in seconds; for `extend`, how much is added. Defaults to the model's. */ durationSeconds?: number; /** Frame shape, such as `16:9` or `9:16`. */ aspectRatio?: string; /** Frame size, such as `720p`, `1080p`, or `4k`. */ resolution?: string; /** Whether the video has sound, on a model where that is a choice. */ audio?: boolean; /** What the video must not show. */ negativePrompt?: string; /** Makes a generation repeatable, on a model that takes one. */ seed?: number; /** Videos to make from this request. Defaults to 1. */ count?: number; /** Fields only this provider knows, sent as they are. */ providerOptions?: Record; /** * Where the video goes: streamed into the manager's store, or returned as bytes. Defaults to * `store` when there is one. `generate()` always stores, since an operation keeps no bytes; `bytes` * is for `start()` and `resume()`. */ delivery?: 'store' | 'bytes'; /** The tenant a stored video belongs to. Defaults to the manager's. */ tenantId?: string; /** How long a stored video is kept, in seconds. Defaults to the manager's. */ ttlSeconds?: number; /** Replays the operation accepted under this key instead of making a second video. */ idempotencyKey?: string; /** Labels kept on the job and its stored videos. */ metadata?: Record; /** Overrides the manager's poll interval. */ pollIntervalMs?: number; /** Gives up waiting after this long. The provider's job is left running. */ timeoutMs?: number; /** Stops waiting. The provider's job keeps running unless it is cancelled. */ signal?: AbortSignal; } /** A request as a provider receives it: its model chosen and its inputs resolved to bytes or URLs. */ export interface VideoProviderRequest { /** What the video shows. */ prompt: string; /** The provider's model name. */ model: string; /** The first frame. */ image?: AssetInput; /** The last frame. */ lastFrame?: AssetInput; /** Reference images. */ references?: readonly AssetInput[]; /** Reference videos, resolved to bytes or URLs. */ referenceVideos?: readonly AssetInput[]; /** A video to extend or edit, its input resolved to bytes or a URL. */ video?: VideoSource; /** Length in seconds; for `extend`, how much is added. */ durationSeconds?: number; /** Frame shape. */ aspectRatio?: string; /** Frame size. */ resolution?: string; /** Whether the video has sound. */ audio?: boolean; /** What the video must not show. */ negativePrompt?: string; /** Makes a generation repeatable. */ seed?: number; /** Videos to make. */ count?: number; /** Fields only this provider knows. */ providerOptions?: Record; /** Labels for the provider's side. */ metadata?: Record; } /** * A provider's video job, as JSON: everything after `submit` takes only this, so a worker can collect * a job it did not submit. */ export interface VideoJobRef { /** The adapter's name. */ provider: string; /** The provider's id for the job. */ id: string; /** The model making it. */ model: string; /** ISO-8601 time it was submitted. */ createdAt: string; /** What the adapter, and the manager, need to finish it. JSON only. */ metadata?: Record; } /** Where a job is. `completed`, `failed`, `cancelled`, and `expired` are final. */ export type VideoJobStatus = 'queued' | 'running' | 'completed' | 'failed' | 'cancelled' | 'expired'; /** Why a job failed. */ export interface VideoJobError { /** What went wrong, in the provider's words. */ message: string; /** The provider's code for it. */ code?: string; /** Whether submitting again may succeed: an internal fault may, a refused prompt will not. */ retryable?: boolean; /** Whether a safety filter refused the prompt, an input, or the video. */ safety?: boolean; } /** A job's state, as a poll reads it. */ export interface VideoJobState { /** Where it is. */ status: VideoJobStatus; /** How far along, from 0 to 1, where the provider says. */ progress?: number; /** Videos ready to download, once it has completed. */ outputs?: number; /** Videos the provider's safety filter withheld. */ filtered?: number; /** Each video's length in seconds, where the provider says. */ durationSeconds?: number; /** Why it failed. */ error?: VideoJobError; /** What it cost, where the provider reports it. */ cost?: ResponseCost; /** ISO-8601 time it finished. */ completedAt?: string; /** The provider's payload. */ raw?: unknown; } /** A finished video's bytes, as they arrive. */ export interface VideoContent { /** The bytes. Read once. */ stream: AssetByteSource; /** Its type, such as `video/mp4`. */ mimeType: string; /** Its size, when the provider says. */ byteLength?: number; } /** What one model makes: the inputs, lengths, shapes, and sizes it takes. */ export interface VideoModelCapabilities { /** What it takes beside a prompt. */ inputs: readonly VideoInputKind[]; /** The lengths it makes, in seconds. Any when absent. */ durations?: readonly number[]; /** Its length when a request names none. */ defaultDurationSeconds?: number; /** The frame shapes it makes. Any when absent. */ aspectRatios?: readonly string[]; /** The frame sizes it makes. Any when absent. */ resolutions?: readonly string[]; /** Whether it makes sound. Defaults to `none`. */ audio?: VideoAudioSupport; /** Most reference images it takes. */ maxReferences?: number; /** Most videos one request makes. Defaults to 1. */ maxCount?: number; /** Whether it takes a seed. */ supportsSeed?: boolean; /** Whether it takes a negative prompt. */ supportsNegativePrompt?: boolean; /** The lengths `extend` adds, in seconds. Any when absent. */ extendDurations?: readonly number[]; /** What every request to it must give, such as `edit` for a model that only changes videos. */ requires?: readonly VideoInputKind[]; /** Whether `video.from` may name a job of its own, which it continues from what it holds. */ continuesJobs?: boolean; /** The longest video it extends or edits, in seconds, read from the video's headers when it is bytes. */ maxInputVideoSeconds?: number; /** Most reference videos it takes. */ maxReferenceVideos?: number; /** How long reference videos may be, in seconds: each, and all together. Read from the bytes' headers. */ referenceVideoSeconds?: { each?: number; total?: number; }; } /** What a video provider supports: its models, and what each makes. */ export interface VideoProviderCapabilities extends VideoModelCapabilities { /** The models it serves. A request naming another is refused. */ models: readonly string[]; /** The model a request naming none uses. Defaults to the first. */ defaultModel?: string; /** Where one model differs from the rest. */ byModel?: Readonly>>; /** How it takes an input image: as bytes, by URL, or both. */ inputLocationKinds: readonly ('bytes' | 'url')[]; /** The image types it takes. Any image when absent. */ inputMimeTypes?: readonly string[]; /** The video types it takes to extend or edit. Any video when absent. */ inputVideoMimeTypes?: readonly string[]; /** Whether a running job can be cancelled. */ supportsCancel?: boolean; /** Whether a finished job's video can be deleted from the provider. */ supportsRemove?: boolean; /** How long it keeps a finished video, in hours. Collect before then. */ retentionHours?: number; } /** Identifies a video provider and what it supports. */ export interface VideoProviderInfo { /** Its name, which its refs carry. */ name: string; /** What it supports. */ capabilities: VideoProviderCapabilities; } /** What every provider call receives. */ export interface VideoCallContext extends ProviderCallContext { /** The attempt, from 1. */ attempt: number; } /** * A video backend: a hosted model's job API, or a stand-in. Every call after `submit` takes only the * `VideoJobRef`, which survives a restart. */ export interface VideoProvider { /** What it is and supports. */ readonly info: VideoProviderInfo; /** Starts a job and returns its ref. */ submit(request: VideoProviderRequest, context: VideoCallContext): Promise; /** Reads the job's state. */ poll(ref: VideoJobRef, context: VideoCallContext): Promise; /** Reads one finished video, by its position from 0, as a stream. */ download(ref: VideoJobRef, index: number, context: VideoCallContext): Promise; /** Cancels a running job. */ cancel?(ref: VideoJobRef, context: VideoCallContext): Promise; /** Deletes a finished job's videos from the provider. */ remove?(ref: VideoJobRef, context: VideoCallContext): Promise; } /** A made video: stored, or as bytes, with its length and where it came from. */ export interface VideoAsset extends AssetDescriptor { /** Its length in seconds, when known. */ durationSeconds?: number; } /** Something about a video job the caller should know, which did not fail it. */ export interface VideoWarning { /** A stable code, such as `provider.remove_failed`. */ code: string; /** What happened. */ message: string; } /** A finished video job. */ export interface VideoResult { /** The job. */ ref: VideoJobRef; /** The videos, in the provider's order. */ videos: VideoAsset[]; /** Each video's length in seconds, when known. */ durationSeconds?: number; /** Videos the provider's safety filter withheld. */ filtered?: number; /** What it cost: reported by the provider, or priced per second from the registry. */ cost?: ResponseCost; /** The request's id, on its lifecycle operation and its stored videos. */ requestId: string; /** ISO-8601 time it finished. */ completedAt: string; /** What the caller should know. */ warnings?: VideoWarning[]; /** The provider's final state payload. */ raw?: unknown; } export { VideoError, type VideoErrorCode, VideoJobFailedError } from './errors.js'; /** A model's price per second of video: one rate, or one per frame size. */ export interface VideoPrice { /** Per second, in `currency`: one rate, or by resolution such as `{ '720p': 0.4, '4k': 0.6 }`. */ perSecond: number | Readonly>; /** Per second without sound, on a model where that is cheaper. */ perSecondSilent?: number | Readonly>; /** The frame size priced when a request names none. Defaults to `720p`, or the first listed. */ defaultResolution?: string; /** Defaults to `USD`. */ currency?: string; } /** * List prices on the Gemini API's paid tier, in dollars per second with sound, as published on * 2026-10-20. Gemini Omni Flash is billed by output token, 5,792 a second of 720p video at $17.50 a * million, which is the rate here; Google publishes no rate for its other sizes, which stay unpriced. * The Veo 3.1 previews shut down on 2026-10-22. An account priced otherwise passes its own as `prices`. */ export declare const VIDEO_PRICES: Readonly>; /** * Prices `seconds` of video from `model`, or `undefined` when no price is known for it, so an unpriced * model is never recorded as free. */ export declare function priceVideo(model: string, seconds: number, options?: { resolution?: string; audio?: boolean; prices?: Readonly>; }): ResponseCost | undefined; /** Configuration for `VideoManager`. */ export interface VideoConfig { /** Providers, by name. */ providers?: Record; /** The provider a request naming none uses. Defaults to the first registered. */ defaultProvider?: string; /** Where finished videos are streamed. Without one, a video comes back as bytes. */ store?: AssetStore; /** The tenant stored videos belong to, when a request names none. Defaults to `default`. */ tenantId?: string; /** How long a stored video is kept, in seconds, when a request names none. Kept until deleted otherwise. */ ttlSeconds?: number; /** Deletes the provider's copy of a video once it is collected, on a provider that can. */ removeFromProvider?: boolean; /** Most bytes a video returned as bytes may hold. Defaults to 512 MiB. */ maxBytes?: number; /** How often to poll a running job. Defaults to 10 seconds. */ pollIntervalMs?: number; /** The longest poll interval, once backoff has grown it. Defaults to 1 minute. */ maxPollIntervalMs?: number; /** How long a generation waits before giving up. Defaults to 1 hour. */ timeoutMs?: number; /** Prices by model, over the bundled ones. */ prices?: Record; } /** What the manager runs on. */ export interface VideoRuntime { /** Persists each generation, so a submitted job survives a restart. Share its store between workers. */ operations?: OperationRunnerConfig; /** * Runs every generation as one operation of a client's lifecycle, family `video`: pass * `ai.lifecycle`. It is authorized and budgeted before the provider sees it, and its cost is * reconciled when the video is collected. */ lifecycle?: OperationLifecycleLike; } /** How `resume()` waits and where it puts the video. */ export interface VideoCollectOptions { /** Stops waiting. */ signal?: AbortSignal; /** Overrides the manager's poll interval. */ pollIntervalMs?: number; /** Streamed into the store, or returned as bytes. Defaults to the manager's. */ delivery?: 'store' | 'bytes'; /** The tenant a stored video belongs to. */ tenantId?: string; /** How long a stored video is kept, in seconds. */ ttlSeconds?: number; } /** * Video providers behind one handle. `generate()` submits a job as a durable operation that records * the job the moment it exists and each video as it is stored, so a worker that dies is replaced by * one that collects that job and stores nothing twice. * * ```ts * const video = new VideoManager( * { providers: { google: new GoogleVideoProvider({ apiKey }) }, store: new S3AssetStore({ ... }) }, * { operations: { store: new RedisOperationStore({ client }) }, lifecycle: ai.lifecycle }, * ); * const handle = await video.generate({ prompt: 'a lighthouse at dusk', durationSeconds: 8 }); * const { videos, cost } = await handle.result(); * ``` */ export declare class VideoManager { private readonly config; private readonly runtime; private readonly providers; /** Loaded on the first `generate()`: `start()` and `resume()` need neither the runner nor the lifecycle. */ private durable?; constructor(config?: VideoConfig, runtime?: VideoRuntime); /** Registers a provider under a name. Returns the manager, for chaining. */ registerVideoProvider(name: string, provider: VideoProvider): this; /** Whether a provider is registered. */ hasVideoProvider(name: string): boolean; /** Every registered provider's name. */ listVideoProviders(): string[]; /** * Makes a video as a durable operation: submits the job, waits, and streams the video into the store. * Returns at once with a handle that settles when the video is collected, minutes away: persist * `handle.id` rather than block a request on `handle.result()`. */ generate(request: VideoGenerateRequest): Promise>; /** * Takes over generations whose worker stopped heartbeating, typically because its process died, and * finishes them here: each job is collected, never submitted again. Run it on a schedule in every * worker that shares the operation store. */ recover(limit?: number): Promise>>; /** * Submits a job and returns its ref at once, without waiting or recording an operation: for a caller * that keeps the ref itself and collects it later with `resume()`. */ start(request: VideoGenerateRequest): Promise; /** Waits for a job, submitted here or by another process, and collects its videos. */ resume(ref: VideoJobRef, options?: VideoCollectOptions): Promise; /** The job's state now, without waiting. */ status(ref: VideoJobRef): Promise; /** One finished video as a stream, to send on without storing it. */ download(ref: VideoJobRef, index?: number): Promise; /** Cancels a running job. Throws when the provider cannot. */ cancel(ref: VideoJobRef): Promise; private loadDurable; /** One attempt of a generation: the first, or a worker's that took over after another died. */ private execute; private collect; private deliver; private deliveryFor; /** Checks a request against the provider's model and resolves stored inputs to bytes. */ private prepare; /** Checks a video to work from: a mode the model takes, and one source, an input or a job of this provider's. */ private checkVideo; /** An input as the provider takes it: a stored asset read from the manager's store into bytes. */ private resolveInput; private resolveProvider; /** The provider a ref belongs to: by its registered name, or the adapter's own name the ref carries. */ /** * Runs a call that continues a job outside its operation, `start()` and the calls on a ref, with its * tenant's credentials and inside its regions, when the lifecycle gives them, its errors cleaned of * every credential. */ private continuing; /** The name a ref's provider is registered under: a ref records the adapter's own name. */ private nameOf; /** The tenant a job runs for: the one its ref records, or the manager's. */ private tenantOf; private providerFor; } /** A model's capabilities: the provider's, with that model's differences laid over them. */ export declare function capabilitiesOf(capabilities: VideoProviderCapabilities, model: string): VideoModelCapabilities; /** What `runVideoConformance()` asks a provider for. */ export interface VideoConformanceOptions { /** Overrides the request it submits. Defaults to a short prompt at the model's shortest length. */ request?: Partial; /** An image, to check image-to-video on a provider that takes one. */ image?: AssetInput; /** * A video of the provider's limits, to check extending or editing it on a model that takes that. A * model that continues its own jobs is also asked to extend the first job it made. */ video?: { mode: 'extend' | 'edit'; input: AssetInput; }; /** A short video of the provider's limits, to check making a video from reference videos where a model takes them. */ referenceVideo?: AssetInput; /** Submits and cancels a second job, on a provider that can cancel. Off by default: it costs a job. */ checkCancel?: boolean; /** How often to poll. Defaults to 5 seconds. */ pollIntervalMs?: number; /** Gives up after this long. Defaults to 10 minutes. */ timeoutMs?: number; } /** How a provider did against the video contract. */ export interface VideoConformanceReport { /** The provider. */ provider: string; /** Checks that passed. */ passed: string[]; /** Checks that failed, each with why. */ failures: string[]; } /** * Checks a provider against the video contract: its capabilities are coherent, its ref survives JSON * as it would a restart, a job settles and is read back through a ref parsed afresh, and the video * streams as non-empty bytes of a video type. Never throws; failures are listed. */ export declare function runVideoConformance(provider: VideoProvider, options?: VideoConformanceOptions): Promise;