@ai-sdk/black-forest-labs 1.0.49 → 1.0.51

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/black-forest-labs-provider.ts","../src/black-forest-labs-image-model.ts","../src/version.ts"],"sourcesContent":["import {\n NoSuchModelError,\n type ImageModelV3,\n type ProviderV3,\n} from '@ai-sdk/provider';\nimport {\n loadApiKey,\n withoutTrailingSlash,\n withUserAgentSuffix,\n type FetchFunction,\n} from '@ai-sdk/provider-utils';\nimport { BlackForestLabsImageModel } from './black-forest-labs-image-model';\nimport type { BlackForestLabsImageModelId } from './black-forest-labs-image-settings';\nimport { VERSION } from './version';\n\nexport interface BlackForestLabsProviderSettings {\n /**\n * Black Forest Labs API key. Default value is taken from the `BFL_API_KEY` environment variable.\n */\n apiKey?: string;\n\n /**\n * Base URL for the API calls. Defaults to `https://api.bfl.ai/v1`.\n */\n baseURL?: string;\n\n /**\n * Custom headers to include in the requests.\n */\n headers?: Record<string, string>;\n\n /**\n * Custom fetch implementation. You can use it as a middleware to intercept\n * requests, or to provide a custom fetch implementation for e.g. testing.\n */\n fetch?: FetchFunction;\n\n /**\n * Poll interval in milliseconds between status checks. Defaults to 500ms.\n */\n pollIntervalMillis?: number;\n\n /**\n * Overall timeout in milliseconds for polling before giving up. Defaults to 60s.\n */\n pollTimeoutMillis?: number;\n}\n\nexport interface BlackForestLabsProvider extends ProviderV3 {\n /**\n * Creates a model for image generation.\n */\n image(modelId: BlackForestLabsImageModelId): ImageModelV3;\n\n /**\n * Creates a model for image generation.\n */\n imageModel(modelId: BlackForestLabsImageModelId): ImageModelV3;\n\n /**\n * @deprecated Use `embeddingModel` instead.\n */\n textEmbeddingModel(modelId: string): never;\n}\n\nconst defaultBaseURL = 'https://api.bfl.ai/v1';\n\nexport function createBlackForestLabs(\n options: BlackForestLabsProviderSettings = {},\n): BlackForestLabsProvider {\n const baseURL = withoutTrailingSlash(options.baseURL ?? defaultBaseURL);\n const getHeaders = () =>\n withUserAgentSuffix(\n {\n 'x-key': loadApiKey({\n apiKey: options.apiKey,\n environmentVariableName: 'BFL_API_KEY',\n description: 'Black Forest Labs',\n }),\n ...options.headers,\n },\n `ai-sdk/black-forest-labs/${VERSION}`,\n );\n\n const createImageModel = (modelId: BlackForestLabsImageModelId) =>\n new BlackForestLabsImageModel(modelId, {\n provider: 'black-forest-labs.image',\n baseURL: baseURL ?? defaultBaseURL,\n headers: getHeaders,\n fetch: options.fetch,\n pollIntervalMillis: options.pollIntervalMillis,\n pollTimeoutMillis: options.pollTimeoutMillis,\n });\n\n const embeddingModel = (modelId: string) => {\n throw new NoSuchModelError({\n modelId,\n modelType: 'embeddingModel',\n });\n };\n\n return {\n specificationVersion: 'v3',\n imageModel: createImageModel,\n image: createImageModel,\n languageModel: (modelId: string) => {\n throw new NoSuchModelError({\n modelId,\n modelType: 'languageModel',\n });\n },\n embeddingModel,\n textEmbeddingModel: embeddingModel,\n };\n}\n\nexport const blackForestLabs = createBlackForestLabs();\n","import type { ImageModelV3, SharedV3Warning } from '@ai-sdk/provider';\nimport {\n combineHeaders,\n createBinaryResponseHandler,\n createJsonErrorResponseHandler,\n createJsonResponseHandler,\n createStatusCodeErrorResponseHandler,\n delay,\n getFromApi,\n isSameOrigin,\n lazySchema,\n parseProviderOptions,\n postJsonToApi,\n resolve,\n zodSchema,\n type InferSchema,\n type Resolvable,\n type FetchFunction,\n} from '@ai-sdk/provider-utils';\nimport { z } from 'zod/v4';\nimport {\n type BlackForestLabsAspectRatio,\n type BlackForestLabsImageModelId,\n} from './black-forest-labs-image-settings';\n\nconst DEFAULT_POLL_INTERVAL_MILLIS = 500;\nconst DEFAULT_POLL_TIMEOUT_MILLIS = 60000;\n\ninterface BlackForestLabsImageModelConfig {\n provider: string;\n baseURL: string;\n headers?: Resolvable<Record<string, string | undefined>>;\n fetch?: FetchFunction;\n /**\n * Poll interval in milliseconds between status checks. Defaults to 500ms.\n */\n pollIntervalMillis?: number;\n /**\n * Overall timeout in milliseconds for polling before giving up. Defaults to 60s.\n */\n pollTimeoutMillis?: number;\n _internal?: {\n currentDate?: () => Date;\n };\n}\n\nexport class BlackForestLabsImageModel implements ImageModelV3 {\n readonly specificationVersion = 'v3';\n readonly maxImagesPerCall = 1;\n\n get provider(): string {\n return this.config.provider;\n }\n\n constructor(\n readonly modelId: BlackForestLabsImageModelId,\n private readonly config: BlackForestLabsImageModelConfig,\n ) {}\n\n private async getArgs({\n prompt,\n files,\n mask,\n size,\n aspectRatio,\n seed,\n providerOptions,\n }: Parameters<ImageModelV3['doGenerate']>[0]) {\n const warnings: Array<SharedV3Warning> = [];\n\n const finalAspectRatio =\n aspectRatio ?? (size ? convertSizeToAspectRatio(size) : undefined);\n\n if (size && !aspectRatio) {\n warnings.push({\n type: 'unsupported',\n feature: 'size',\n details:\n 'Deriving aspect_ratio from size. Use the width and height provider options to specify dimensions for models that support them.',\n });\n } else if (size && aspectRatio) {\n warnings.push({\n type: 'unsupported',\n feature: 'size',\n details:\n 'Black Forest Labs ignores size when aspectRatio is provided. Use the width and height provider options to specify dimensions for models that support them',\n });\n }\n\n const bflOptions = await parseProviderOptions({\n provider: 'blackForestLabs',\n providerOptions,\n schema: blackForestLabsImageModelOptionsSchema,\n });\n\n const [widthStr, heightStr] = size?.split('x') ?? [];\n\n const inputImages: string[] =\n files?.map(file => {\n if (file.type === 'url') {\n return file.url;\n }\n\n if (typeof file.data === 'string') {\n return file.data;\n }\n\n return Buffer.from(file.data).toString('base64');\n }) || [];\n\n if (inputImages.length > 10) {\n throw new Error('Black Forest Labs supports up to 10 input images.');\n }\n\n const inputImageField =\n this.modelId === 'flux-pro-1.0-fill' ? 'image' : 'input_image';\n const inputImagesObj: Record<string, string> = inputImages.reduce<\n Record<string, string>\n >((acc, img, index) => {\n acc[`${inputImageField}${index === 0 ? '' : `_${index + 1}`}`] = img;\n return acc;\n }, {});\n\n let maskValue: string | undefined;\n if (mask) {\n if (mask.type === 'url') {\n maskValue = mask.url;\n } else {\n if (typeof mask.data === 'string') {\n maskValue = mask.data;\n } else {\n maskValue = Buffer.from(mask.data).toString('base64');\n }\n }\n }\n\n const body: Record<string, unknown> = {\n prompt,\n seed,\n aspect_ratio: finalAspectRatio,\n width: bflOptions?.width ?? (size ? Number(widthStr) : undefined),\n height: bflOptions?.height ?? (size ? Number(heightStr) : undefined),\n steps: bflOptions?.steps,\n guidance: bflOptions?.guidance,\n image_prompt_strength: bflOptions?.imagePromptStrength,\n image_prompt: bflOptions?.imagePrompt,\n ...inputImagesObj,\n mask: maskValue,\n output_format: bflOptions?.outputFormat,\n prompt_upsampling: bflOptions?.promptUpsampling,\n raw: bflOptions?.raw,\n safety_tolerance: bflOptions?.safetyTolerance,\n webhook_secret: bflOptions?.webhookSecret,\n webhook_url: bflOptions?.webhookUrl,\n };\n\n return { body, warnings, bflOptions };\n }\n\n async doGenerate({\n prompt,\n files,\n mask,\n size,\n aspectRatio,\n seed,\n providerOptions,\n headers,\n abortSignal,\n }: Parameters<ImageModelV3['doGenerate']>[0]): Promise<\n Awaited<ReturnType<ImageModelV3['doGenerate']>>\n > {\n const { body, warnings, bflOptions } = await this.getArgs({\n prompt,\n files,\n mask,\n size,\n aspectRatio,\n seed,\n providerOptions,\n n: 1,\n headers,\n abortSignal,\n } as Parameters<ImageModelV3['doGenerate']>[0]);\n\n const currentDate = this.config._internal?.currentDate?.() ?? new Date();\n const combinedHeaders = combineHeaders(\n await resolve(this.config.headers),\n headers,\n );\n\n const submit = await postJsonToApi({\n url: `${this.config.baseURL}/${this.modelId}`,\n headers: combinedHeaders,\n body,\n failedResponseHandler: bflFailedResponseHandler,\n successfulResponseHandler: createJsonResponseHandler(bflSubmitSchema),\n abortSignal,\n fetch: this.config.fetch,\n });\n\n const pollUrl = submit.value.polling_url;\n const requestId = submit.value.id;\n\n const {\n imageUrl,\n seed: resultSeed,\n start_time: resultStartTime,\n end_time: resultEndTime,\n duration: resultDuration,\n } = await this.pollForImageUrl({\n pollUrl,\n requestId,\n headers: combinedHeaders,\n abortSignal,\n pollOverrides: {\n pollIntervalMillis: bflOptions?.pollIntervalMillis,\n pollTimeoutMillis: bflOptions?.pollTimeoutMillis,\n },\n });\n\n const { value: imageBytes, responseHeaders } = await getFromApi({\n url: imageUrl,\n // Only send credentials if the response-supplied URL points back at the\n // provider; the image is typically delivered from a CDN, so the API key\n // must not travel to a foreign host.\n headers: isTrustedUrl(imageUrl, this.config.baseURL)\n ? combinedHeaders\n : undefined,\n abortSignal,\n failedResponseHandler: createStatusCodeErrorResponseHandler(),\n successfulResponseHandler: createBinaryResponseHandler(),\n fetch: this.config.fetch,\n });\n\n return {\n images: [imageBytes],\n warnings,\n providerMetadata: {\n blackForestLabs: {\n images: [\n {\n ...(resultSeed != null && { seed: resultSeed }),\n ...(resultStartTime != null && { start_time: resultStartTime }),\n ...(resultEndTime != null && { end_time: resultEndTime }),\n ...(resultDuration != null && { duration: resultDuration }),\n ...(submit.value.cost != null && { cost: submit.value.cost }),\n ...(submit.value.input_mp != null && {\n inputMegapixels: submit.value.input_mp,\n }),\n ...(submit.value.output_mp != null && {\n outputMegapixels: submit.value.output_mp,\n }),\n },\n ],\n },\n },\n response: {\n modelId: this.modelId,\n timestamp: currentDate,\n headers: responseHeaders,\n },\n };\n }\n\n private async pollForImageUrl({\n pollUrl,\n requestId,\n headers,\n abortSignal,\n pollOverrides,\n }: {\n pollUrl: string;\n requestId: string;\n headers: Record<string, string | undefined>;\n abortSignal: AbortSignal | undefined;\n pollOverrides?: {\n pollIntervalMillis?: number;\n pollTimeoutMillis?: number;\n };\n }): Promise<{\n imageUrl: string;\n seed?: number;\n start_time?: number;\n end_time?: number;\n duration?: number;\n }> {\n const pollIntervalMillis =\n pollOverrides?.pollIntervalMillis ??\n this.config.pollIntervalMillis ??\n DEFAULT_POLL_INTERVAL_MILLIS;\n const pollTimeoutMillis =\n pollOverrides?.pollTimeoutMillis ??\n this.config.pollTimeoutMillis ??\n DEFAULT_POLL_TIMEOUT_MILLIS;\n const maxPollAttempts = Math.ceil(\n pollTimeoutMillis / Math.max(1, pollIntervalMillis),\n );\n\n const url = new URL(pollUrl);\n if (!url.searchParams.has('id')) {\n url.searchParams.set('id', requestId);\n }\n\n for (let i = 0; i < maxPollAttempts; i++) {\n const { value } = await getFromApi({\n url: url.toString(),\n // The polling URL comes from the provider response; only send\n // credentials when it stays on a trusted provider host.\n headers: isTrustedUrl(url.toString(), this.config.baseURL)\n ? headers\n : undefined,\n failedResponseHandler: bflFailedResponseHandler,\n successfulResponseHandler: createJsonResponseHandler(bflPollSchema),\n abortSignal,\n fetch: this.config.fetch,\n });\n\n const status = value.status;\n if (status === 'Ready') {\n if (typeof value.result?.sample === 'string') {\n return {\n imageUrl: value.result.sample,\n seed: value.result.seed ?? undefined,\n start_time: value.result.start_time ?? undefined,\n end_time: value.result.end_time ?? undefined,\n duration: value.result.duration ?? undefined,\n };\n }\n throw new Error(\n 'Black Forest Labs poll response is Ready but missing result.sample',\n );\n }\n if (status === 'Error' || status === 'Failed') {\n throw new Error('Black Forest Labs generation failed.');\n }\n\n await delay(pollIntervalMillis);\n }\n\n throw new Error('Black Forest Labs generation timed out.');\n }\n}\n\n/**\n * Black Forest Labs returns response-supplied URLs (polling and delivery) on\n * sibling cluster hosts of the API origin (e.g. `api.us1.bfl.ai` for a base\n * URL on `api.bfl.ai`), so a strict same-origin check against the configured\n * base URL is not enough. Credentials may also be sent to any https host under\n * the official `bfl.ai` domain.\n */\nfunction isTrustedUrl(url: string, baseUrl: string): boolean {\n if (isSameOrigin(url, baseUrl)) {\n return true;\n }\n\n try {\n const { protocol, hostname } = new URL(url);\n return (\n protocol === 'https:' &&\n (hostname === 'bfl.ai' || hostname.endsWith('.bfl.ai'))\n );\n } catch {\n return false;\n }\n}\n\nexport const blackForestLabsImageModelOptionsSchema = lazySchema(() =>\n zodSchema(\n z.object({\n imagePrompt: z.string().optional(),\n imagePromptStrength: z.number().min(0).max(1).optional(),\n /** @deprecated use prompt.images instead */\n inputImage: z.string().optional(),\n /** @deprecated use prompt.images instead */\n inputImage2: z.string().optional(),\n /** @deprecated use prompt.images instead */\n inputImage3: z.string().optional(),\n /** @deprecated use prompt.images instead */\n inputImage4: z.string().optional(),\n /** @deprecated use prompt.images instead */\n inputImage5: z.string().optional(),\n /** @deprecated use prompt.images instead */\n inputImage6: z.string().optional(),\n /** @deprecated use prompt.images instead */\n inputImage7: z.string().optional(),\n /** @deprecated use prompt.images instead */\n inputImage8: z.string().optional(),\n /** @deprecated use prompt.images instead */\n inputImage9: z.string().optional(),\n /** @deprecated use prompt.images instead */\n inputImage10: z.string().optional(),\n steps: z.number().int().positive().optional(),\n guidance: z.number().min(0).optional(),\n width: z.number().int().min(256).max(1920).optional(),\n height: z.number().int().min(256).max(1920).optional(),\n outputFormat: z.enum(['jpeg', 'png']).optional(),\n promptUpsampling: z.boolean().optional(),\n raw: z.boolean().optional(),\n safetyTolerance: z.number().int().min(0).max(6).optional(),\n webhookSecret: z.string().optional(),\n webhookUrl: z.url().optional(),\n pollIntervalMillis: z.number().int().positive().optional(),\n pollTimeoutMillis: z.number().int().positive().optional(),\n }),\n ),\n);\n\nexport type BlackForestLabsImageModelOptions = InferSchema<\n typeof blackForestLabsImageModelOptionsSchema\n>;\n\nfunction convertSizeToAspectRatio(\n size: string,\n): BlackForestLabsAspectRatio | undefined {\n const [wStr, hStr] = size.split('x');\n const width = Number(wStr);\n const height = Number(hStr);\n if (\n !Number.isFinite(width) ||\n !Number.isFinite(height) ||\n width <= 0 ||\n height <= 0\n ) {\n return undefined;\n }\n const g = gcd(width, height);\n return `${Math.round(width / g)}:${Math.round(height / g)}`;\n}\n\nfunction gcd(a: number, b: number): number {\n let x = Math.abs(a);\n let y = Math.abs(b);\n while (y !== 0) {\n const t = y;\n y = x % y;\n x = t;\n }\n return x;\n}\n\nconst bflSubmitSchema = z.object({\n id: z.string(),\n polling_url: z.url(),\n cost: z.number().nullish(),\n input_mp: z.number().nullish(),\n output_mp: z.number().nullish(),\n});\n\nconst bflStatus = z.union([\n z.literal('Pending'),\n z.literal('Ready'),\n z.literal('Error'),\n z.literal('Failed'),\n z.literal('Request Moderated'),\n]);\n\nconst bflPollSchema = z\n .object({\n status: bflStatus.optional(),\n state: bflStatus.optional(),\n details: z.unknown().optional(),\n result: z\n .object({\n sample: z.url(),\n seed: z.number().optional(),\n start_time: z.number().optional(),\n end_time: z.number().optional(),\n duration: z.number().optional(),\n })\n .nullish(),\n })\n .refine(v => v.status != null || v.state != null, {\n message: 'Missing status in Black Forest Labs poll response',\n })\n .transform(v => ({\n status: (v.status ?? v.state)!,\n result: v.result,\n }));\n\nconst bflErrorSchema = z.object({\n message: z.string().optional(),\n detail: z.any().optional(),\n});\n\nconst bflFailedResponseHandler = createJsonErrorResponseHandler({\n errorSchema: bflErrorSchema,\n errorToMessage: error =>\n bflErrorToMessage(error) ?? 'Unknown Black Forest Labs error',\n});\n\nfunction bflErrorToMessage(error: unknown): string | undefined {\n const parsed = bflErrorSchema.safeParse(error);\n if (!parsed.success) return undefined;\n const { message, detail } = parsed.data;\n if (typeof detail === 'string') return detail;\n if (detail != null) {\n try {\n return JSON.stringify(detail);\n } catch {\n // ignore\n }\n }\n return message;\n}\n","// Version string of this package injected at build time.\ndeclare const __PACKAGE_VERSION__: string | undefined;\nexport const VERSION: string =\n typeof __PACKAGE_VERSION__ !== 'undefined'\n ? __PACKAGE_VERSION__\n : '0.0.0-test';\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/black-forest-labs-provider.ts","../src/black-forest-labs-image-model.ts","../src/black-forest-labs-api.ts","../src/black-forest-labs-video-model.ts","../src/black-forest-labs-video-model-options.ts","../src/black-forest-labs-video-settings.ts","../src/version.ts"],"sourcesContent":["import {\n NoSuchModelError,\n type Experimental_VideoModelV3,\n type ImageModelV3,\n type ProviderV3,\n} from '@ai-sdk/provider';\nimport {\n loadApiKey,\n withoutTrailingSlash,\n withUserAgentSuffix,\n type FetchFunction,\n} from '@ai-sdk/provider-utils';\nimport { BlackForestLabsImageModel } from './black-forest-labs-image-model';\nimport type { BlackForestLabsImageModelId } from './black-forest-labs-image-settings';\nimport { BlackForestLabsVideoModel } from './black-forest-labs-video-model';\nimport type { BlackForestLabsVideoModelId } from './black-forest-labs-video-settings';\nimport { VERSION } from './version';\n\nexport interface BlackForestLabsProviderSettings {\n /**\n * Black Forest Labs API key. Default value is taken from the `BFL_API_KEY` environment variable.\n */\n apiKey?: string;\n\n /**\n * Base URL for the API calls. Defaults to `https://api.bfl.ai/v1`.\n */\n baseURL?: string;\n\n /**\n * Custom headers to include in the requests.\n */\n headers?: Record<string, string>;\n\n /**\n * Custom fetch implementation. You can use it as a middleware to intercept\n * requests, or to provide a custom fetch implementation for e.g. testing.\n */\n fetch?: FetchFunction;\n\n /**\n * Poll interval in milliseconds between status checks. Defaults to 500ms for\n * images and 2s for video.\n */\n pollIntervalMillis?: number;\n\n /**\n * Overall timeout in milliseconds for polling before giving up. Defaults to\n * 60s for images and 10 minutes for video.\n */\n pollTimeoutMillis?: number;\n}\n\nexport interface BlackForestLabsProvider extends ProviderV3 {\n /**\n * Creates a model for image generation.\n */\n image(modelId: BlackForestLabsImageModelId): ImageModelV3;\n\n /**\n * Creates a model for image generation.\n */\n imageModel(modelId: BlackForestLabsImageModelId): ImageModelV3;\n\n /**\n * Creates a model for video generation.\n */\n video(modelId: BlackForestLabsVideoModelId): Experimental_VideoModelV3;\n\n /**\n * Creates a model for video generation.\n */\n videoModel(modelId: BlackForestLabsVideoModelId): Experimental_VideoModelV3;\n\n /**\n * @deprecated Use `embeddingModel` instead.\n */\n textEmbeddingModel(modelId: string): never;\n}\n\nconst defaultBaseURL = 'https://api.bfl.ai/v1';\n\nexport function createBlackForestLabs(\n options: BlackForestLabsProviderSettings = {},\n): BlackForestLabsProvider {\n const baseURL = withoutTrailingSlash(options.baseURL ?? defaultBaseURL);\n const getHeaders = () =>\n withUserAgentSuffix(\n {\n 'x-key': loadApiKey({\n apiKey: options.apiKey,\n environmentVariableName: 'BFL_API_KEY',\n description: 'Black Forest Labs',\n }),\n ...options.headers,\n },\n `ai-sdk/black-forest-labs/${VERSION}`,\n );\n\n const createImageModel = (modelId: BlackForestLabsImageModelId) =>\n new BlackForestLabsImageModel(modelId, {\n provider: 'black-forest-labs.image',\n baseURL: baseURL ?? defaultBaseURL,\n headers: getHeaders,\n fetch: options.fetch,\n pollIntervalMillis: options.pollIntervalMillis,\n pollTimeoutMillis: options.pollTimeoutMillis,\n });\n\n const createVideoModel = (modelId: BlackForestLabsVideoModelId) =>\n new BlackForestLabsVideoModel(modelId, {\n provider: 'black-forest-labs.video',\n baseURL: baseURL ?? defaultBaseURL,\n headers: getHeaders,\n fetch: options.fetch,\n pollIntervalMillis: options.pollIntervalMillis,\n pollTimeoutMillis: options.pollTimeoutMillis,\n });\n\n const embeddingModel = (modelId: string) => {\n throw new NoSuchModelError({\n modelId,\n modelType: 'embeddingModel',\n });\n };\n\n return {\n specificationVersion: 'v3',\n imageModel: createImageModel,\n image: createImageModel,\n videoModel: createVideoModel,\n video: createVideoModel,\n languageModel: (modelId: string) => {\n throw new NoSuchModelError({\n modelId,\n modelType: 'languageModel',\n });\n },\n embeddingModel,\n textEmbeddingModel: embeddingModel,\n };\n}\n\nexport const blackForestLabs = createBlackForestLabs();\n","import type { ImageModelV3, SharedV3Warning } from '@ai-sdk/provider';\nimport {\n combineHeaders,\n createBinaryResponseHandler,\n createJsonResponseHandler,\n createStatusCodeErrorResponseHandler,\n delay,\n getFromApi,\n lazySchema,\n parseProviderOptions,\n postJsonToApi,\n resolve,\n zodSchema,\n type InferSchema,\n type Resolvable,\n type FetchFunction,\n} from '@ai-sdk/provider-utils';\nimport { z } from 'zod/v4';\nimport {\n bflFailedResponseHandler,\n isTrustedUrl,\n} from './black-forest-labs-api';\nimport {\n type BlackForestLabsAspectRatio,\n type BlackForestLabsImageModelId,\n} from './black-forest-labs-image-settings';\n\nconst DEFAULT_POLL_INTERVAL_MILLIS = 500;\nconst DEFAULT_POLL_TIMEOUT_MILLIS = 60000;\n\ninterface BlackForestLabsImageModelConfig {\n provider: string;\n baseURL: string;\n headers?: Resolvable<Record<string, string | undefined>>;\n fetch?: FetchFunction;\n /**\n * Poll interval in milliseconds between status checks. Defaults to 500ms.\n */\n pollIntervalMillis?: number;\n /**\n * Overall timeout in milliseconds for polling before giving up. Defaults to 60s.\n */\n pollTimeoutMillis?: number;\n _internal?: {\n currentDate?: () => Date;\n };\n}\n\nexport class BlackForestLabsImageModel implements ImageModelV3 {\n readonly specificationVersion = 'v3';\n readonly maxImagesPerCall = 1;\n\n get provider(): string {\n return this.config.provider;\n }\n\n constructor(\n readonly modelId: BlackForestLabsImageModelId,\n private readonly config: BlackForestLabsImageModelConfig,\n ) {}\n\n private async getArgs({\n prompt,\n files,\n mask,\n size,\n aspectRatio,\n seed,\n providerOptions,\n }: Parameters<ImageModelV3['doGenerate']>[0]) {\n const warnings: Array<SharedV3Warning> = [];\n\n const finalAspectRatio =\n aspectRatio ?? (size ? convertSizeToAspectRatio(size) : undefined);\n\n if (size && !aspectRatio) {\n warnings.push({\n type: 'unsupported',\n feature: 'size',\n details:\n 'Deriving aspect_ratio from size. Use the width and height provider options to specify dimensions for models that support them.',\n });\n } else if (size && aspectRatio) {\n warnings.push({\n type: 'unsupported',\n feature: 'size',\n details:\n 'Black Forest Labs ignores size when aspectRatio is provided. Use the width and height provider options to specify dimensions for models that support them',\n });\n }\n\n const bflOptions = await parseProviderOptions({\n provider: 'blackForestLabs',\n providerOptions,\n schema: blackForestLabsImageModelOptionsSchema,\n });\n\n const [widthStr, heightStr] = size?.split('x') ?? [];\n\n const inputImages: string[] =\n files?.map(file => {\n if (file.type === 'url') {\n return file.url;\n }\n\n if (typeof file.data === 'string') {\n return file.data;\n }\n\n return Buffer.from(file.data).toString('base64');\n }) || [];\n\n if (inputImages.length > 10) {\n throw new Error('Black Forest Labs supports up to 10 input images.');\n }\n\n const inputImageField =\n this.modelId === 'flux-pro-1.0-fill' ? 'image' : 'input_image';\n const inputImagesObj: Record<string, string> = inputImages.reduce<\n Record<string, string>\n >((acc, img, index) => {\n acc[`${inputImageField}${index === 0 ? '' : `_${index + 1}`}`] = img;\n return acc;\n }, {});\n\n let maskValue: string | undefined;\n if (mask) {\n if (mask.type === 'url') {\n maskValue = mask.url;\n } else {\n if (typeof mask.data === 'string') {\n maskValue = mask.data;\n } else {\n maskValue = Buffer.from(mask.data).toString('base64');\n }\n }\n }\n\n const body: Record<string, unknown> = {\n prompt,\n seed,\n aspect_ratio: finalAspectRatio,\n width: bflOptions?.width ?? (size ? Number(widthStr) : undefined),\n height: bflOptions?.height ?? (size ? Number(heightStr) : undefined),\n steps: bflOptions?.steps,\n guidance: bflOptions?.guidance,\n image_prompt_strength: bflOptions?.imagePromptStrength,\n image_prompt: bflOptions?.imagePrompt,\n ...inputImagesObj,\n mask: maskValue,\n output_format: bflOptions?.outputFormat,\n prompt_upsampling: bflOptions?.promptUpsampling,\n raw: bflOptions?.raw,\n safety_tolerance: bflOptions?.safetyTolerance,\n webhook_secret: bflOptions?.webhookSecret,\n webhook_url: bflOptions?.webhookUrl,\n };\n\n return { body, warnings, bflOptions };\n }\n\n async doGenerate({\n prompt,\n files,\n mask,\n size,\n aspectRatio,\n seed,\n providerOptions,\n headers,\n abortSignal,\n }: Parameters<ImageModelV3['doGenerate']>[0]): Promise<\n Awaited<ReturnType<ImageModelV3['doGenerate']>>\n > {\n const { body, warnings, bflOptions } = await this.getArgs({\n prompt,\n files,\n mask,\n size,\n aspectRatio,\n seed,\n providerOptions,\n n: 1,\n headers,\n abortSignal,\n } as Parameters<ImageModelV3['doGenerate']>[0]);\n\n const currentDate = this.config._internal?.currentDate?.() ?? new Date();\n const combinedHeaders = combineHeaders(\n await resolve(this.config.headers),\n headers,\n );\n\n const submit = await postJsonToApi({\n url: `${this.config.baseURL}/${this.modelId}`,\n headers: combinedHeaders,\n body,\n failedResponseHandler: bflFailedResponseHandler,\n successfulResponseHandler: createJsonResponseHandler(bflSubmitSchema),\n abortSignal,\n fetch: this.config.fetch,\n });\n\n const pollUrl = submit.value.polling_url;\n const requestId = submit.value.id;\n\n const {\n imageUrl,\n seed: resultSeed,\n start_time: resultStartTime,\n end_time: resultEndTime,\n duration: resultDuration,\n } = await this.pollForImageUrl({\n pollUrl,\n requestId,\n headers: combinedHeaders,\n abortSignal,\n pollOverrides: {\n pollIntervalMillis: bflOptions?.pollIntervalMillis,\n pollTimeoutMillis: bflOptions?.pollTimeoutMillis,\n },\n });\n\n const { value: imageBytes, responseHeaders } = await getFromApi({\n url: imageUrl,\n // Only send credentials if the response-supplied URL points back at the\n // provider; the image is typically delivered from a CDN, so the API key\n // must not travel to a foreign host.\n headers: isTrustedUrl(imageUrl, this.config.baseURL)\n ? combinedHeaders\n : undefined,\n abortSignal,\n failedResponseHandler: createStatusCodeErrorResponseHandler(),\n successfulResponseHandler: createBinaryResponseHandler(),\n fetch: this.config.fetch,\n });\n\n return {\n images: [imageBytes],\n warnings,\n providerMetadata: {\n blackForestLabs: {\n images: [\n {\n ...(resultSeed != null && { seed: resultSeed }),\n ...(resultStartTime != null && { start_time: resultStartTime }),\n ...(resultEndTime != null && { end_time: resultEndTime }),\n ...(resultDuration != null && { duration: resultDuration }),\n ...(submit.value.cost != null && { cost: submit.value.cost }),\n ...(submit.value.input_mp != null && {\n inputMegapixels: submit.value.input_mp,\n }),\n ...(submit.value.output_mp != null && {\n outputMegapixels: submit.value.output_mp,\n }),\n },\n ],\n },\n },\n response: {\n modelId: this.modelId,\n timestamp: currentDate,\n headers: responseHeaders,\n },\n };\n }\n\n private async pollForImageUrl({\n pollUrl,\n requestId,\n headers,\n abortSignal,\n pollOverrides,\n }: {\n pollUrl: string;\n requestId: string;\n headers: Record<string, string | undefined>;\n abortSignal: AbortSignal | undefined;\n pollOverrides?: {\n pollIntervalMillis?: number;\n pollTimeoutMillis?: number;\n };\n }): Promise<{\n imageUrl: string;\n seed?: number;\n start_time?: number;\n end_time?: number;\n duration?: number;\n }> {\n const pollIntervalMillis =\n pollOverrides?.pollIntervalMillis ??\n this.config.pollIntervalMillis ??\n DEFAULT_POLL_INTERVAL_MILLIS;\n const pollTimeoutMillis =\n pollOverrides?.pollTimeoutMillis ??\n this.config.pollTimeoutMillis ??\n DEFAULT_POLL_TIMEOUT_MILLIS;\n const maxPollAttempts = Math.ceil(\n pollTimeoutMillis / Math.max(1, pollIntervalMillis),\n );\n\n const url = new URL(pollUrl);\n if (!url.searchParams.has('id')) {\n url.searchParams.set('id', requestId);\n }\n\n for (let i = 0; i < maxPollAttempts; i++) {\n const { value } = await getFromApi({\n url: url.toString(),\n // The polling URL comes from the provider response; only send\n // credentials when it stays on a trusted provider host.\n headers: isTrustedUrl(url.toString(), this.config.baseURL)\n ? headers\n : undefined,\n failedResponseHandler: bflFailedResponseHandler,\n successfulResponseHandler: createJsonResponseHandler(bflPollSchema),\n abortSignal,\n fetch: this.config.fetch,\n });\n\n const status = value.status;\n if (status === 'Ready') {\n if (typeof value.result?.sample === 'string') {\n return {\n imageUrl: value.result.sample,\n seed: value.result.seed ?? undefined,\n start_time: value.result.start_time ?? undefined,\n end_time: value.result.end_time ?? undefined,\n duration: value.result.duration ?? undefined,\n };\n }\n throw new Error(\n 'Black Forest Labs poll response is Ready but missing result.sample',\n );\n }\n if (status === 'Error' || status === 'Failed') {\n throw new Error('Black Forest Labs generation failed.');\n }\n\n await delay(pollIntervalMillis);\n }\n\n throw new Error('Black Forest Labs generation timed out.');\n }\n}\n\nexport const blackForestLabsImageModelOptionsSchema = lazySchema(() =>\n zodSchema(\n z.object({\n imagePrompt: z.string().optional(),\n imagePromptStrength: z.number().min(0).max(1).optional(),\n /** @deprecated use prompt.images instead */\n inputImage: z.string().optional(),\n /** @deprecated use prompt.images instead */\n inputImage2: z.string().optional(),\n /** @deprecated use prompt.images instead */\n inputImage3: z.string().optional(),\n /** @deprecated use prompt.images instead */\n inputImage4: z.string().optional(),\n /** @deprecated use prompt.images instead */\n inputImage5: z.string().optional(),\n /** @deprecated use prompt.images instead */\n inputImage6: z.string().optional(),\n /** @deprecated use prompt.images instead */\n inputImage7: z.string().optional(),\n /** @deprecated use prompt.images instead */\n inputImage8: z.string().optional(),\n /** @deprecated use prompt.images instead */\n inputImage9: z.string().optional(),\n /** @deprecated use prompt.images instead */\n inputImage10: z.string().optional(),\n steps: z.number().int().positive().optional(),\n guidance: z.number().min(0).optional(),\n width: z.number().int().min(256).max(1920).optional(),\n height: z.number().int().min(256).max(1920).optional(),\n outputFormat: z.enum(['jpeg', 'png']).optional(),\n promptUpsampling: z.boolean().optional(),\n raw: z.boolean().optional(),\n safetyTolerance: z.number().int().min(0).max(6).optional(),\n webhookSecret: z.string().optional(),\n webhookUrl: z.url().optional(),\n pollIntervalMillis: z.number().int().positive().optional(),\n pollTimeoutMillis: z.number().int().positive().optional(),\n }),\n ),\n);\n\nexport type BlackForestLabsImageModelOptions = InferSchema<\n typeof blackForestLabsImageModelOptionsSchema\n>;\n\nfunction convertSizeToAspectRatio(\n size: string,\n): BlackForestLabsAspectRatio | undefined {\n const [wStr, hStr] = size.split('x');\n const width = Number(wStr);\n const height = Number(hStr);\n if (\n !Number.isFinite(width) ||\n !Number.isFinite(height) ||\n width <= 0 ||\n height <= 0\n ) {\n return undefined;\n }\n const g = gcd(width, height);\n return `${Math.round(width / g)}:${Math.round(height / g)}`;\n}\n\nfunction gcd(a: number, b: number): number {\n let x = Math.abs(a);\n let y = Math.abs(b);\n while (y !== 0) {\n const t = y;\n y = x % y;\n x = t;\n }\n return x;\n}\n\nconst bflSubmitSchema = z.object({\n id: z.string(),\n polling_url: z.url(),\n cost: z.number().nullish(),\n input_mp: z.number().nullish(),\n output_mp: z.number().nullish(),\n});\n\nconst bflStatus = z.union([\n z.literal('Pending'),\n z.literal('Ready'),\n z.literal('Error'),\n z.literal('Failed'),\n z.literal('Request Moderated'),\n]);\n\nconst bflPollSchema = z\n .object({\n status: bflStatus.optional(),\n state: bflStatus.optional(),\n details: z.unknown().optional(),\n result: z\n .object({\n sample: z.url(),\n seed: z.number().optional(),\n start_time: z.number().optional(),\n end_time: z.number().optional(),\n duration: z.number().optional(),\n })\n .nullish(),\n })\n .refine(v => v.status != null || v.state != null, {\n message: 'Missing status in Black Forest Labs poll response',\n })\n .transform(v => ({\n status: (v.status ?? v.state)!,\n result: v.result,\n }));\n","import {\n createJsonErrorResponseHandler,\n isSameOrigin,\n} from '@ai-sdk/provider-utils';\nimport { z } from 'zod/v4';\n\n/**\n * Transport concerns shared by every Black Forest Labs model\n */\n\nexport const bflErrorSchema = z.object({\n message: z.string().optional(),\n detail: z.any().optional(),\n});\n\nfunction bflErrorToMessage(error: unknown): string | undefined {\n const parsed = bflErrorSchema.safeParse(error);\n if (!parsed.success) return undefined;\n const { message, detail } = parsed.data;\n if (typeof detail === 'string') return detail;\n if (detail != null) {\n try {\n return JSON.stringify(detail);\n } catch {\n // ignore\n }\n }\n return message;\n}\n\nexport const bflFailedResponseHandler = createJsonErrorResponseHandler({\n errorSchema: bflErrorSchema,\n errorToMessage: error =>\n bflErrorToMessage(error) ?? 'Unknown Black Forest Labs error',\n});\n\n/**\n * Black Forest Labs returns response-supplied URLs (polling and delivery) on\n * sibling cluster hosts of the API origin (e.g. `api.us1.bfl.ai` for a base\n * URL on `api.bfl.ai`), so a strict same-origin check against the configured\n * base URL is not enough. Credentials may also be sent to any https host under\n * the official `bfl.ai` domain.\n */\nexport function isTrustedUrl(url: string, baseUrl: string): boolean {\n if (isSameOrigin(url, baseUrl)) {\n return true;\n }\n\n try {\n const { protocol, hostname } = new URL(url);\n return (\n protocol === 'https:' &&\n (hostname === 'bfl.ai' || hostname.endsWith('.bfl.ai'))\n );\n } catch {\n return false;\n }\n}\n","import {\n AISDKError,\n InvalidArgumentError,\n type Experimental_VideoModelV3 as VideoModelV3,\n type Experimental_VideoModelV3CallOptions as VideoModelV3CallOptions,\n type Experimental_VideoModelV3File as VideoModelV3File,\n type SharedV3Warning,\n} from '@ai-sdk/provider';\nimport {\n combineHeaders,\n createJsonResponseHandler,\n delay,\n getFromApi,\n parseProviderOptions,\n postJsonToApi,\n resolve,\n type FetchFunction,\n type Resolvable,\n} from '@ai-sdk/provider-utils';\nimport { z } from 'zod/v4';\nimport {\n bflFailedResponseHandler,\n isTrustedUrl,\n} from './black-forest-labs-api';\nimport {\n blackForestLabsVideoModelOptionsSchema,\n type BlackForestLabsVideoModelOptions,\n} from './black-forest-labs-video-model-options';\nimport {\n blackForestLabsVideoAspectRatios,\n blackForestLabsVideoResolutions,\n type BlackForestLabsVideoModelId,\n} from './black-forest-labs-video-settings';\n\nconst DEFAULT_POLL_INTERVAL_MILLIS = 2_000;\nconst DEFAULT_POLL_TIMEOUT_MILLIS = 600_000;\nconst MIN_DURATION_SECONDS = 5;\nconst MAX_DURATION_SECONDS = 20;\n/** Keyframe counts above this need an explicit duration when untimed. */\nconst UNTIMED_KEYFRAMES_NEEDING_DURATION = 3;\n\nconst allowedAspectRatios = new Set<string>(blackForestLabsVideoAspectRatios);\nconst allowedResolutions = new Set<string>(blackForestLabsVideoResolutions);\n\n/**\n * Statuses that end the poll without a video.\n */\nconst TERMINAL_FAILURE_STATUSES = new Set([\n 'Error',\n 'Failed',\n 'Request Moderated',\n 'Content Moderated',\n 'Task not found',\n]);\n\ntype BlackForestLabsVideoKeyframe = string | [number, string];\n\ninterface BlackForestLabsVideoModelConfig {\n provider: string;\n baseURL: string;\n headers?: Resolvable<Record<string, string | undefined>>;\n fetch?: FetchFunction;\n pollIntervalMillis?: number;\n pollTimeoutMillis?: number;\n _internal?: {\n currentDate?: () => Date;\n };\n}\n\ntype BlackForestLabsVideoOperation = {\n requestId: string;\n pollingUrl: string;\n cost?: number;\n inputMegapixels?: number;\n outputMegapixels?: number;\n};\n\ntype BlackForestLabsVideoDoGenerateOptions = VideoModelV3CallOptions;\n\nfunction getTopLevelMediaType(mediaType: string): string {\n return mediaType.split('/')[0];\n}\n\n/**\n * The API takes a named tier (`hd`/`fhd`) while the top-level `resolution` is\n * `{width}x{height}`, so a caller may reasonably pass either.\n */\nfunction resolveTopLevelResolution(\n resolution: string,\n): { tier: string; derived: boolean } | undefined {\n const named = resolution.toLowerCase();\n if (allowedResolutions.has(named)) {\n return { tier: named, derived: false };\n }\n\n const match = resolution.match(/^(\\d+)x(\\d+)$/);\n if (match == null) {\n return undefined;\n }\n\n const shorterSide = Math.min(Number(match[1]), Number(match[2]));\n return {\n tier: shorterSide <= 720 ? 'hd' : 'fhd',\n derived: shorterSide !== 720 && shorterSide !== 1080,\n };\n}\n\nfunction nonImageFrameMediaType(file: VideoModelV3File): string | undefined {\n if (file.mediaType == null) {\n return undefined;\n }\n\n const topLevelMediaType = getTopLevelMediaType(file.mediaType);\n return topLevelMediaType === 'image' ? undefined : topLevelMediaType;\n}\n\n/**\n * Draft-enhance replays an encrypted bundle from a prior `draft` generation at\n * full quality. The bundle pins the original mode, prompt, seed, and\n * conditioning media, and the API accepts nothing alongside it but\n * `safety_tolerance` — so this is a separate body rather than one more field,\n * and everything else the caller set is reported as dropped.\n */\nfunction getDraftEnhanceArgs(\n options: BlackForestLabsVideoDoGenerateOptions,\n bflOptions: BlackForestLabsVideoModelOptions,\n) {\n const warnings: Array<SharedV3Warning> = [];\n\n const pinnedByBundle: Array<[feature: string, isSet: boolean]> = [\n ['prompt', (options.prompt?.trim().length ?? 0) > 0],\n [\n 'aspectRatio',\n options.aspectRatio != null || bflOptions.aspectRatio != null,\n ],\n ['resolution', options.resolution != null || bflOptions.resolution != null],\n ['duration', options.duration != null],\n ['fps', options.fps != null],\n ['seed', options.seed != null],\n ['generateAudio', options.generateAudio != null],\n ['image', options.image != null],\n ['frameImages', (options.frameImages?.length ?? 0) > 0],\n ['inputReferences', (options.inputReferences?.length ?? 0) > 0],\n ['keyframes', (bflOptions.keyframes?.length ?? 0) > 0],\n ['version', bflOptions.version != null],\n ];\n\n for (const [feature, isSet] of pinnedByBundle) {\n if (isSet) {\n warnings.push({\n type: 'unsupported',\n feature,\n details:\n `FLUX 3 draft enhance replays the draft bundle as it was generated, so \"${feature}\" ` +\n 'was ignored. Set it on the original draft request instead.',\n });\n }\n }\n\n if (bflOptions.draft != null) {\n warnings.push({\n type: 'unsupported',\n feature: 'draft',\n details:\n 'FLUX 3 draft enhance always renders at full quality. The draft option was ignored.',\n });\n }\n\n if (options.n != null && options.n > 1) {\n warnings.push({\n type: 'unsupported',\n feature: 'n',\n details:\n 'FLUX 3 video generates a single video per call. Only 1 video will be generated.',\n });\n }\n\n return {\n body: {\n mode: 'draft_enhance',\n draft_cache: bflOptions.draftCache,\n safety_tolerance: bflOptions.safetyTolerance,\n } as Record<string, unknown>,\n warnings,\n };\n}\n\n/**\n * A failed poll carries a `details` payload that is a plain string for\n * moderation refusals and an object for everything else.\n */\nfunction describePollDetails(details: unknown): string | undefined {\n if (details == null) {\n return undefined;\n }\n\n if (typeof details === 'string') {\n return details;\n }\n\n try {\n return JSON.stringify(details);\n } catch {\n return undefined;\n }\n}\n\n/**\n * The API takes conditioning media as an http(s) URL or a bare base64 string —\n * not a data URI.\n */\nfunction toBlackForestLabsFile(file: VideoModelV3File): string {\n if (file.type === 'url') {\n return file.url;\n }\n\n if (typeof file.data === 'string') {\n return file.data;\n }\n\n return Buffer.from(file.data).toString('base64');\n}\n\nexport class BlackForestLabsVideoModel implements VideoModelV3 {\n readonly specificationVersion = 'v3';\n readonly maxVideosPerCall = 1;\n\n get provider(): string {\n return this.config.provider;\n }\n\n constructor(\n readonly modelId: BlackForestLabsVideoModelId,\n private readonly config: BlackForestLabsVideoModelConfig,\n ) {}\n\n private async getArgs(options: BlackForestLabsVideoDoGenerateOptions) {\n const warnings: Array<SharedV3Warning> = [];\n\n const bflOptions = (await parseProviderOptions({\n provider: 'blackForestLabs',\n providerOptions: options.providerOptions,\n schema: blackForestLabsVideoModelOptionsSchema,\n })) as BlackForestLabsVideoModelOptions | undefined;\n\n if (bflOptions?.draftCache != null) {\n return getDraftEnhanceArgs(options, bflOptions);\n }\n\n if (options.fps != null) {\n warnings.push({\n type: 'unsupported',\n feature: 'fps',\n details: 'FLUX 3 video does not support a custom frame rate.',\n });\n }\n\n if (options.seed != null) {\n warnings.push({\n type: 'unsupported',\n feature: 'seed',\n details: 'FLUX 3 video does not accept a seed.',\n });\n }\n\n if (options.n != null && options.n > 1) {\n warnings.push({\n type: 'unsupported',\n feature: 'n',\n details:\n 'FLUX 3 video generates a single video per call. Only 1 video will be generated.',\n });\n }\n\n // Resolution: an explicit provider option is already a tier, so it wins and\n // a top-level value only has to be resolved when it is the sole source.\n let resolution: string | undefined = bflOptions?.resolution;\n if (options.resolution != null) {\n const resolved = resolveTopLevelResolution(options.resolution);\n if (resolution != null) {\n if (resolved == null) {\n warnings.push({\n type: 'unsupported',\n feature: 'resolution',\n details:\n `Unrecognized resolution \"${options.resolution}\". FLUX 3 video supports \"hd\" and \"fhd\", ` +\n `so providerOptions.blackForestLabs.resolution (\"${resolution}\") was used instead.`,\n });\n }\n } else if (resolved == null) {\n warnings.push({\n type: 'unsupported',\n feature: 'resolution',\n details:\n `Unrecognized resolution \"${options.resolution}\". FLUX 3 video supports ` +\n '\"hd\" and \"fhd\", or a {width}x{height} value to map onto one.',\n });\n } else {\n resolution = resolved.tier;\n if (resolved.derived) {\n warnings.push({\n type: 'compatibility',\n feature: 'resolution',\n details:\n `FLUX 3 video renders at \"hd\" or \"fhd\"; the requested resolution ` +\n `\"${options.resolution}\" was mapped to \"${resolved.tier}\".`,\n });\n }\n }\n }\n\n // Aspect ratio: the provider option can also express `auto`, so it wins.\n let aspectRatio: string | undefined = bflOptions?.aspectRatio;\n if (aspectRatio == null && options.aspectRatio != null) {\n if (allowedAspectRatios.has(options.aspectRatio)) {\n aspectRatio = options.aspectRatio;\n } else {\n warnings.push({\n type: 'unsupported',\n feature: 'aspectRatio',\n details:\n `FLUX 3 video does not support the aspect ratio \"${options.aspectRatio}\". ` +\n 'Using the provider default (auto).',\n });\n }\n }\n\n // Resolve first/last frame inputs. A standalone `image` is treated as the\n // first frame (image-to-video). The core sets `image` to the `first_frame`\n // frame image when there is one, so the frame-image entry is tracked\n // separately to report which input a warning came from.\n const firstFrameImage = options.frameImages?.find(\n frame => frame.frameType === 'first_frame',\n )?.image;\n let firstFrame = firstFrameImage ?? options.image;\n let lastFrame = options.frameImages?.find(\n frame => frame.frameType === 'last_frame',\n )?.image;\n\n const firstFrameMediaType =\n firstFrame != null ? nonImageFrameMediaType(firstFrame) : undefined;\n if (firstFrame != null && firstFrameMediaType != null) {\n warnings.push({\n type: 'unsupported',\n feature: firstFrameImage != null ? 'frameImages' : 'image',\n details:\n firstFrameMediaType === 'video'\n ? 'FLUX 3 video does not accept a video as a keyframe. Pass it as an inputReference to continue from it instead.'\n : `FLUX 3 video only accepts an image as a keyframe; the \"${firstFrame.mediaType}\" file was ignored.`,\n });\n firstFrame = undefined;\n }\n\n if (lastFrame != null) {\n if (firstFrame == null) {\n // Keyframes are positional: the first entry opens the clip, so there is\n // no way to send a closing frame on its own.\n warnings.push({\n type: 'unsupported',\n feature: 'frameImages',\n details:\n 'FLUX 3 video requires a first_frame when a last_frame is provided. The last_frame was ignored.',\n });\n lastFrame = undefined;\n } else {\n const lastFrameMediaType = nonImageFrameMediaType(lastFrame);\n if (lastFrameMediaType != null) {\n warnings.push({\n type: 'unsupported',\n feature: 'frameImages',\n details:\n lastFrameMediaType === 'video'\n ? 'FLUX 3 video does not accept a video as a keyframe. The last_frame video was ignored.'\n : `FLUX 3 video only accepts an image as a keyframe; the \"${lastFrame.mediaType}\" last_frame was ignored.`,\n });\n lastFrame = undefined;\n }\n }\n }\n\n // Keyframes: the provider option covers the shapes the top-level fields\n // cannot express (3+ images, images pinned to a second), so it wins.\n let keyframes: BlackForestLabsVideoKeyframe[] | undefined =\n bflOptions?.keyframes != null && bflOptions.keyframes.length > 0\n ? [...bflOptions.keyframes]\n : undefined;\n\n if (keyframes != null) {\n if (firstFrame != null || lastFrame != null) {\n warnings.push({\n type: 'unsupported',\n feature: options.frameImages != null ? 'frameImages' : 'image',\n details:\n 'FLUX 3 video takes a single keyframe list. providerOptions.blackForestLabs.keyframes ' +\n 'was used and the top-level frame images were ignored.',\n });\n }\n } else if (firstFrame != null) {\n keyframes = [toBlackForestLabsFile(firstFrame)];\n if (lastFrame != null) {\n keyframes.push(toBlackForestLabsFile(lastFrame));\n }\n }\n\n // Video continuation. FLUX 3 takes a single `start_video` and has no\n // reference-image concept, so image references cannot be honored.\n let startVideo: string | undefined;\n const referenceFiles = options.inputReferences ?? [];\n const referenceVideos: VideoModelV3File[] = [];\n\n for (const file of referenceFiles) {\n const topLevelMediaType =\n file.mediaType != null\n ? getTopLevelMediaType(file.mediaType)\n : undefined;\n\n if (topLevelMediaType === 'video') {\n referenceVideos.push(file);\n } else if (topLevelMediaType == null) {\n warnings.push({\n type: 'compatibility',\n feature: 'inputReferences',\n details:\n 'FLUX 3 video only accepts a video reference, so the reference with no mediaType ' +\n 'was treated as the video to continue from. Pass { url, mediaType: \"video/mp4\" } to be explicit.',\n });\n referenceVideos.push(file);\n } else if (topLevelMediaType === 'image') {\n warnings.push({\n type: 'unsupported',\n feature: 'inputReferences',\n details:\n 'FLUX 3 video has no reference-image input. Pass images as `image`, `frameImages`, or ' +\n 'providerOptions.blackForestLabs.keyframes instead. The reference was ignored.',\n });\n } else {\n warnings.push({\n type: 'unsupported',\n feature: 'inputReferences',\n details: `FLUX 3 video only accepts a video reference; the \"${file.mediaType}\" reference was ignored.`,\n });\n }\n }\n\n if (referenceVideos.length > 0) {\n if (keyframes != null) {\n // Continuation and keyframes are mutually exclusive modes.\n warnings.push({\n type: 'unsupported',\n feature: 'inputReferences',\n details:\n 'FLUX 3 video cannot combine keyframes with a video to continue from. The video reference was ignored.',\n });\n } else {\n startVideo = toBlackForestLabsFile(referenceVideos[0]);\n if (referenceVideos.length > 1) {\n warnings.push({\n type: 'unsupported',\n feature: 'inputReferences',\n details:\n 'FLUX 3 video continues from a single video. Only the first video reference was used.',\n });\n }\n }\n }\n\n // Duration: whole seconds between 5 and 20, or omitted to let the API pick\n // one that matches the content.\n let duration = options.duration;\n if (duration != null) {\n if (!Number.isInteger(duration)) {\n const rounded = Math.round(duration);\n warnings.push({\n type: 'unsupported',\n feature: 'duration',\n details: `FLUX 3 video requires a whole number of seconds. The requested duration of ${duration} was rounded to ${rounded}.`,\n });\n duration = rounded;\n }\n\n if (duration > MAX_DURATION_SECONDS) {\n warnings.push({\n type: 'unsupported',\n feature: 'duration',\n details: `FLUX 3 video supports at most ${MAX_DURATION_SECONDS} seconds. The requested duration of ${options.duration} was clamped to ${MAX_DURATION_SECONDS}.`,\n });\n duration = MAX_DURATION_SECONDS;\n } else if (duration < MIN_DURATION_SECONDS) {\n warnings.push({\n type: 'unsupported',\n feature: 'duration',\n details: `FLUX 3 video requires at least ${MIN_DURATION_SECONDS} seconds. The requested duration of ${options.duration} was clamped to ${MIN_DURATION_SECONDS}.`,\n });\n duration = MIN_DURATION_SECONDS;\n }\n }\n\n const untimedKeyframeCount =\n keyframes?.filter(keyframe => typeof keyframe === 'string').length ?? 0;\n if (\n duration == null &&\n untimedKeyframeCount >= UNTIMED_KEYFRAMES_NEEDING_DURATION\n ) {\n throw new InvalidArgumentError({\n argument: 'duration',\n message:\n `FLUX 3 video requires an explicit duration when ${UNTIMED_KEYFRAMES_NEEDING_DURATION} or more ` +\n 'keyframes are sent without a timestamp.',\n });\n }\n\n const mode = keyframes != null ? 'i2v' : startVideo != null ? 'v2v' : 't2v';\n\n const body: Record<string, unknown> = {\n mode,\n prompt: options.prompt ?? '',\n aspect_ratio: aspectRatio,\n duration,\n resolution,\n version: bflOptions?.version,\n generate_audio: options.generateAudio,\n safety_tolerance: bflOptions?.safetyTolerance,\n draft: bflOptions?.draft,\n ...(mode === 'i2v' && { keyframes }),\n ...(mode === 'v2v' && { start_video: startVideo }),\n };\n\n return { body, warnings };\n }\n\n private async start(options: VideoModelV3CallOptions) {\n const { body, warnings } = await this.getArgs(options);\n\n const currentDate = this.config._internal?.currentDate?.() ?? new Date();\n const combinedHeaders = combineHeaders(\n await resolve(this.config.headers),\n options.headers,\n );\n\n const { value: submit, responseHeaders } = await postJsonToApi({\n url: `${this.config.baseURL}/${this.modelId}`,\n headers: combinedHeaders,\n body,\n failedResponseHandler: bflFailedResponseHandler,\n successfulResponseHandler:\n createJsonResponseHandler(bflVideoSubmitSchema),\n abortSignal: options.abortSignal,\n fetch: this.config.fetch,\n });\n\n return {\n operation: {\n requestId: submit.id,\n pollingUrl: submit.polling_url,\n ...(submit.cost != null && { cost: submit.cost }),\n ...(submit.input_mp != null && {\n inputMegapixels: submit.input_mp,\n }),\n ...(submit.output_mp != null && {\n outputMegapixels: submit.output_mp,\n }),\n } satisfies BlackForestLabsVideoOperation,\n warnings,\n response: {\n modelId: this.modelId,\n timestamp: currentDate,\n headers: responseHeaders,\n },\n };\n }\n\n private async getStatus(options: {\n operation: BlackForestLabsVideoOperation;\n headers?: Record<string, string | undefined>;\n abortSignal?: AbortSignal;\n }) {\n const currentDate = this.config._internal?.currentDate?.() ?? new Date();\n const operation = options.operation;\n const url = new URL(operation.pollingUrl);\n if (!url.searchParams.has('id')) {\n url.searchParams.set('id', operation.requestId);\n }\n\n const combinedHeaders = combineHeaders(\n await resolve(this.config.headers),\n options.headers,\n );\n\n const pollingUrl = url.toString();\n if (!isTrustedUrl(pollingUrl, this.config.baseURL)) {\n throw new AISDKError({\n name: 'BLACK_FOREST_LABS_VIDEO_GENERATION_ERROR',\n message: `Black Forest Labs returned an untrusted polling URL: ${pollingUrl}`,\n });\n }\n\n const { value, responseHeaders } = await getFromApi({\n url: pollingUrl,\n headers: combinedHeaders,\n failedResponseHandler: bflFailedResponseHandler,\n successfulResponseHandler: createJsonResponseHandler(bflVideoPollSchema),\n abortSignal: options.abortSignal,\n fetch: this.config.fetch,\n });\n\n const response = {\n modelId: this.modelId,\n timestamp: currentDate,\n headers: responseHeaders,\n };\n const { status, result } = value;\n\n const cost = value.cost ?? operation.cost;\n\n if (status === 'Ready') {\n const parsed = bflVideoResultSchema.safeParse(result);\n if (!parsed.success) {\n throw new AISDKError({\n name: 'BLACK_FOREST_LABS_VIDEO_GENERATION_ERROR',\n message:\n 'Black Forest Labs reported the video as Ready but returned no result.sample URL. ' +\n `Request id: ${operation.requestId}`,\n });\n }\n\n return {\n status: 'completed' as const,\n videos: [\n {\n type: 'url' as const,\n url: parsed.data.sample,\n mediaType: 'video/mp4',\n },\n ],\n warnings: [],\n providerMetadata: {\n blackForestLabs: {\n videos: [\n {\n id: operation.requestId,\n videoUrl: parsed.data.sample,\n ...(parsed.data.seed != null && { seed: parsed.data.seed }),\n ...(parsed.data.start_time != null && {\n start_time: parsed.data.start_time,\n }),\n ...(parsed.data.end_time != null && {\n end_time: parsed.data.end_time,\n }),\n ...(parsed.data.duration != null && {\n duration: parsed.data.duration,\n }),\n ...(parsed.data.draft_cache != null && {\n draftCache: parsed.data.draft_cache,\n }),\n ...(cost != null && { cost }),\n ...(operation.inputMegapixels != null && {\n inputMegapixels: operation.inputMegapixels,\n }),\n ...(operation.outputMegapixels != null && {\n outputMegapixels: operation.outputMegapixels,\n }),\n },\n ],\n },\n },\n response,\n };\n }\n\n if (TERMINAL_FAILURE_STATUSES.has(status)) {\n const detail = describePollDetails(value.details);\n return {\n status: 'error' as const,\n error:\n `Black Forest Labs video generation failed with status \"${status}\"` +\n `${detail != null ? `: ${detail}` : ''}. Request id: ${operation.requestId}`,\n response,\n };\n }\n\n return { status: 'pending' as const, response };\n }\n\n async doGenerate(\n options: BlackForestLabsVideoDoGenerateOptions,\n ): Promise<Awaited<ReturnType<VideoModelV3['doGenerate']>>> {\n const startResult = await this.start(options);\n const operation = startResult.operation;\n const pollIntervalMillis =\n this.config.pollIntervalMillis ?? DEFAULT_POLL_INTERVAL_MILLIS;\n const pollTimeoutMillis =\n this.config.pollTimeoutMillis ?? DEFAULT_POLL_TIMEOUT_MILLIS;\n const startTime = Date.now();\n\n while (true) {\n await delay(pollIntervalMillis, { abortSignal: options.abortSignal });\n\n if (Date.now() - startTime > pollTimeoutMillis) {\n throw new AISDKError({\n name: 'BLACK_FOREST_LABS_VIDEO_GENERATION_TIMEOUT',\n message:\n `Black Forest Labs video generation timed out after ${pollTimeoutMillis}ms. ` +\n `Request id: ${operation.requestId}`,\n });\n }\n\n const statusResult = await this.getStatus({\n operation,\n headers: options.headers,\n abortSignal: options.abortSignal,\n });\n\n if (statusResult.status === 'pending') {\n continue;\n }\n\n if (statusResult.status === 'error') {\n throw new AISDKError({\n name: 'BLACK_FOREST_LABS_VIDEO_GENERATION_FAILED',\n message: statusResult.error,\n });\n }\n\n return {\n videos: statusResult.videos,\n warnings: [...startResult.warnings, ...statusResult.warnings],\n providerMetadata: statusResult.providerMetadata,\n response: statusResult.response,\n };\n }\n }\n}\n\nconst bflVideoSubmitSchema = z.object({\n id: z.string(),\n polling_url: z.url(),\n cost: z.number().nullish(),\n input_mp: z.number().nullish(),\n output_mp: z.number().nullish(),\n});\n\nconst bflVideoResultSchema = z.object({\n sample: z.url(),\n seed: z.number().nullish(),\n start_time: z.number().nullish(),\n end_time: z.number().nullish(),\n duration: z.number().nullish(),\n draft_cache: z.string().nullish(),\n});\n\nconst bflVideoPollSchema = z\n .object({\n status: z.string().optional(),\n state: z.string().optional(),\n details: z.unknown().optional(),\n result: z.unknown().optional(),\n // `SettledCostResultResponse.cost` — the price actually charged, which the\n // API can only know once generation finishes. Absent on the plain\n // `ResultResponse` variant.\n cost: z.number().nullish(),\n })\n .refine(v => v.status != null || v.state != null, {\n message: 'Missing status in Black Forest Labs poll response',\n })\n .transform(v => ({\n status: (v.status ?? v.state)!,\n details: v.details,\n result: v.result,\n cost: v.cost,\n }));\n","import {\n lazySchema,\n zodSchema,\n type InferSchema,\n} from '@ai-sdk/provider-utils';\nimport { z } from 'zod/v4';\nimport {\n blackForestLabsVideoAspectRatios,\n blackForestLabsVideoResolutions,\n} from './black-forest-labs-video-settings';\n\nconst blackForestLabsTimedVideoKeyframeSchema = z.tuple([\n z.number().min(0).max(20),\n z.string(),\n]);\n\nexport const blackForestLabsVideoKeyframesSchema = z.union([\n z.array(z.string()).min(1).max(10),\n z\n .array(blackForestLabsTimedVideoKeyframeSchema)\n .min(1)\n .max(10)\n .refine(\n keyframes =>\n keyframes.every(\n (keyframe, index) =>\n index === 0 || keyframe[0] > keyframes[index - 1][0],\n ),\n { message: 'Timed keyframes must be in chronological order.' },\n ),\n]);\n\nexport const blackForestLabsVideoProviderOptions = z.object({\n /**\n * Output resolution tier. Takes precedence over the top-level `resolution`,\n * which is expressed as `{width}x{height}` and has to be mapped onto a tier.\n */\n resolution: z.enum(blackForestLabsVideoResolutions).optional(),\n\n /**\n * Aspect ratio of the generated video. Takes precedence over the top-level\n * `aspectRatio`, and unlike it can be set to `auto`.\n */\n aspectRatio: z.enum(blackForestLabsVideoAspectRatios).optional(),\n\n /**\n * Keyframes for image-to-video generation, for the shapes the top-level\n * `image` and `frameImages` options cannot express: more than two images, or\n * images pinned to a specific second. Takes precedence over both.\n *\n * One image opens the clip, two open and close it, and with more the extras\n * are spaced evenly in between. Three or more plain images require an\n * explicit `duration`.\n */\n keyframes: blackForestLabsVideoKeyframesSchema.optional(),\n\n /**\n * Moderation strictness from 0 (strictest) to 4. Defaults to 2. Sexual\n * content is capped at 3 and hate content at 2 regardless of the request,\n * and any request carrying conditioning media is capped at 2.\n */\n safetyTolerance: z.number().int().min(0).max(4).optional(),\n\n /**\n * Render a fast, lower-quality preview instead of the finished video.\n * Defaults to `false`.\n */\n draft: z.boolean().optional(),\n\n /**\n * Encrypted draft-cache bundle from a prior `draft` generation, which\n * switches the request to draft-enhance mode: the bundle is replayed at full\n * quality.\n *\n * Either the base64-encoded `.bin` downloaded from the draft's `draftCache`\n * URL, or that URL itself while it is still in its expiry window.\n */\n draftCache: z.string().optional(),\n\n /**\n * Model version to pin. Only `latest` is available today.\n */\n version: z.literal('latest').optional(),\n});\n\nexport const blackForestLabsVideoModelOptionsSchema = lazySchema(() =>\n zodSchema(blackForestLabsVideoProviderOptions),\n);\n\nexport type BlackForestLabsVideoModelOptions = InferSchema<\n typeof blackForestLabsVideoModelOptionsSchema\n>;\n","// https://docs.bfl.ai/api-reference/utility/generate-a-video-with-flux-3\nexport type BlackForestLabsVideoModelId = 'flux-3-video' | (string & {});\n\n/**\n * Aspect ratios FLUX 3 video accepts. `auto` lets the model infer the ratio\n * from the prompt and any conditioning media, and is the API default.\n */\nexport const blackForestLabsVideoAspectRatios = [\n '21:9',\n '2:1',\n '16:9',\n '4:3',\n '1:1',\n '3:4',\n '9:16',\n 'auto',\n] as const;\n\n/**\n * Output resolution tiers FLUX 3 video accepts.\n */\nexport const blackForestLabsVideoResolutions = ['hd', 'fhd'] as const;\n","// Version string of this package injected at build time.\ndeclare const __PACKAGE_VERSION__: string | undefined;\nexport const VERSION: string =\n typeof __PACKAGE_VERSION__ !== 'undefined'\n ? __PACKAGE_VERSION__\n : '0.0.0-test';\n"],"mappings":"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","names":["z","z","combineHeaders","createJsonResponseHandler","delay","getFromApi","parseProviderOptions","postJsonToApi","resolve","z","lazySchema","zodSchema","z","z","lazySchema","zodSchema","DEFAULT_POLL_INTERVAL_MILLIS","DEFAULT_POLL_TIMEOUT_MILLIS","parseProviderOptions","combineHeaders","resolve","postJsonToApi","createJsonResponseHandler","getFromApi","delay","z"]}
@@ -73,13 +73,13 @@ You can use the following optional settings to customize the Black Forest Labs p
73
73
 
74
74
  - **pollIntervalMillis** _number_
75
75
 
76
- Interval in milliseconds between polling attempts when waiting for image generation to complete.
77
- Defaults to 500ms.
76
+ Interval in milliseconds between polling attempts when waiting for generation to complete.
77
+ Defaults to 500ms for image models and 2000ms for video models.
78
78
 
79
79
  - **pollTimeoutMillis** _number_
80
80
 
81
81
  Overall timeout in milliseconds for polling before giving up.
82
- Defaults to 60000ms (60 seconds).
82
+ Defaults to 60000ms (60 seconds) for image models and 600000ms (10 minutes) for video models.
83
83
 
84
84
  ## Image Models
85
85
 
@@ -257,3 +257,245 @@ const blackForestLabs = createBlackForestLabs({
257
257
  baseURL: 'https://api.eu.bfl.ai/v1', // or https://api.us.bfl.ai/v1
258
258
  });
259
259
  ```
260
+ ## Video Models
261
+
262
+ You can generate videos with the FLUX 3 video model using the
263
+ [`experimental_generateVideo`](/docs/reference/ai-sdk-core/generate-video)
264
+ function:
265
+
266
+ ```ts
267
+ import {
268
+ blackForestLabs,
269
+ type BlackForestLabsVideoModelOptions,
270
+ } from '@ai-sdk/black-forest-labs';
271
+ import { experimental_generateVideo as generateVideo } from 'ai';
272
+
273
+ const { video } = await generateVideo({
274
+ model: blackForestLabs.video('flux-3-video'),
275
+ prompt: 'A white kitten chases a butterfly across a sunlit garden.',
276
+ aspectRatio: '16:9',
277
+ duration: 8,
278
+ providerOptions: {
279
+ blackForestLabs: {
280
+ resolution: 'fhd',
281
+ } satisfies BlackForestLabsVideoModelOptions,
282
+ },
283
+ });
284
+ ```
285
+
286
+ FLUX 3 generates one video per call. Generation is asynchronous — the model
287
+ submits a job and polls until it completes, then passes the signed MP4 URL to AI
288
+ SDK Core. `generateVideo` downloads it before resolving, so `video` is a
289
+ `GeneratedFile`. The signed URL remains available in
290
+ `providerMetadata.blackForestLabs.videos[0].videoUrl`.
291
+
292
+ Polling is handled by the provider. Configure `pollIntervalMillis` and
293
+ `pollTimeoutMillis` on a custom `createBlackForestLabs` provider instance when
294
+ the 2-second interval or 10-minute timeout defaults need to be changed.
295
+
296
+ `duration` accepts a whole number of seconds from 5 to 20. A fractional value is
297
+ rounded and an out-of-range value is clamped, each with a warning. Omit it to let
298
+ FLUX 3 fit the duration to the content.
299
+
300
+ Audio is generated by default, so `generateAudio` only has to be set to turn it
301
+ off. `fps` and `seed` are not supported by the API and are reported as warnings.
302
+
303
+ <Note>
304
+ The URL in provider metadata is time-limited. Persist the returned `video`
305
+ bytes to your own storage.
306
+ </Note>
307
+
308
+ ### Resolution and aspect ratio
309
+
310
+ The API takes a named resolution tier, `hd` or `fhd` (the default is `hd`), where
311
+ `fhd` is finished by the video upsampler. The exact frame size depends on the
312
+ aspect ratio.
313
+
314
+ The top-level `resolution` option is `{width}x{height}`, so it is mapped onto a
315
+ tier by its shorter side — `1280x720` becomes `hd` and `1920x1080` becomes `fhd`.
316
+ Other values map to `hd` when the shorter side is at most 720 pixels, and to
317
+ `fhd` above 720, with a warning reporting the mapping. Use
318
+ `providerOptions.blackForestLabs.resolution` to set the tier directly.
319
+
320
+ `aspectRatio` accepts `21:9`, `2:1`, `16:9`, `4:3`, `1:1`, `3:4`, and `9:16`. The
321
+ API default is `auto`, which infers the ratio from the prompt and any
322
+ conditioning media; because the top-level option must be `{width}:{height}`,
323
+ `auto` can only be requested through
324
+ `providerOptions.blackForestLabs.aspectRatio`.
325
+
326
+ ### Generation modes
327
+
328
+ FLUX 3 is a single endpoint with a `mode` discriminator. The mode is inferred
329
+ from the inputs you pass:
330
+
331
+ - **Text-to-video** — `prompt` only.
332
+ - **Image-to-video** — pass `image` (or a `frameImages` entry with
333
+ `frameType: 'first_frame'`) to animate a starting image. Adding a `last_frame`
334
+ closes the clip on that image. A `last_frame` without a `first_frame` cannot be
335
+ expressed, and is dropped with a warning.
336
+ - **Keyframes** — for more than two images, or images pinned to a specific
337
+ second, pass `providerOptions.blackForestLabs.keyframes`. It takes precedence
338
+ over `image` and `frameImages`.
339
+ - **Video continuation** — pass a video-typed entry in `inputReferences` to
340
+ continue from the final frames of an existing MP4. FLUX 3 accepts a single
341
+ video; keyframes and continuation are mutually exclusive.
342
+ - **Draft enhance** — pass `providerOptions.blackForestLabs.draftCache`. See
343
+ [Draft mode](#draft-mode).
344
+
345
+ FLUX 3 has no reference-image input, so an image passed in `inputReferences` is
346
+ ignored with a warning pointing at `image`, `frameImages`, or `keyframes`.
347
+
348
+ ### Keyframes
349
+
350
+ Keyframes are positional: one image opens the clip, two open and close it, and
351
+ with more the first and last are the endpoints while the others are spaced evenly
352
+ between them. Each image is an `http(s)` URL or a base64 string, and a request
353
+ accepts 1 to 10 of them.
354
+
355
+ Three or more untimed keyframes require an explicit `duration`; the provider
356
+ throws an error when it is omitted, because the API rejects that combination.
357
+
358
+ Pass `[seconds, image]` pairs in chronological order to pin each image to a
359
+ second of the clip instead:
360
+
361
+ ```ts
362
+ import {
363
+ blackForestLabs,
364
+ type BlackForestLabsVideoModelOptions,
365
+ } from '@ai-sdk/black-forest-labs';
366
+ import { experimental_generateVideo as generateVideo } from 'ai';
367
+ import { readFileSync } from 'node:fs';
368
+
369
+ const asBase64 = (file: string) => readFileSync(file).toString('base64');
370
+
371
+ const { video } = await generateVideo({
372
+ model: blackForestLabs.video('flux-3-video'),
373
+ prompt: 'The cat, then the dog, then the owl each take a turn in the room.',
374
+ duration: 12,
375
+ providerOptions: {
376
+ blackForestLabs: {
377
+ keyframes: [
378
+ [0, asBase64('cat.png')],
379
+ [4.5, asBase64('dog.png')],
380
+ [9, asBase64('owl.png')],
381
+ ],
382
+ } satisfies BlackForestLabsVideoModelOptions,
383
+ },
384
+ });
385
+ ```
386
+
387
+ ### Draft mode
388
+
389
+ Setting `draft: true` renders a fast, lower-quality preview and leaves behind an
390
+ encrypted bundle, reported as
391
+ `providerMetadata.blackForestLabs.videos[0].draftCache`. Passing that bundle back
392
+ as `draftCache` reproduces the same generation at full quality.
393
+
394
+ The bundle pins the original mode, prompt, seed, and conditioning media, so an
395
+ enhance request accepts nothing besides `safetyTolerance`. Any other option set
396
+ on the call is reported as an `unsupported` warning. `generateVideo` requires a
397
+ `prompt` argument, so pass an empty string to say there is nothing to add.
398
+
399
+ ```ts
400
+ import {
401
+ blackForestLabs,
402
+ type BlackForestLabsVideoModelOptions,
403
+ } from '@ai-sdk/black-forest-labs';
404
+ import { experimental_generateVideo as generateVideo } from 'ai';
405
+
406
+ const draft = await generateVideo({
407
+ model: blackForestLabs.video('flux-3-video'),
408
+ prompt: 'A white kitten chases a butterfly across a sunlit garden.',
409
+ duration: 6,
410
+ providerOptions: {
411
+ blackForestLabs: { draft: true } satisfies BlackForestLabsVideoModelOptions,
412
+ },
413
+ });
414
+
415
+ const draftCacheUrl = (
416
+ draft.providerMetadata.blackForestLabs?.videos as
417
+ | Array<{ draftCache?: string }>
418
+ | undefined
419
+ )?.[0]?.draftCache;
420
+
421
+ // The download URL expires; sending the base64 `.bin` is the durable path,
422
+ // though the URL itself also works while the link is still valid.
423
+ const response = await fetch(draftCacheUrl!);
424
+ const arrayBuffer = await response.arrayBuffer();
425
+
426
+ const enhanced = await generateVideo({
427
+ model: blackForestLabs.video('flux-3-video'),
428
+ prompt: '',
429
+ providerOptions: {
430
+ blackForestLabs: {
431
+ draftCache: Buffer.from(arrayBuffer).toString('base64'),
432
+ } satisfies BlackForestLabsVideoModelOptions,
433
+ },
434
+ });
435
+ ```
436
+
437
+ <Note>
438
+ A draft and its enhance are two separate generations, and each is billed
439
+ separately.
440
+ </Note>
441
+
442
+ ### Video Provider Options
443
+
444
+ The following optional provider options are available for FLUX 3 video:
445
+
446
+ - **resolution** _'hd' | 'fhd'_
447
+
448
+ Output resolution tier. Takes precedence over the top-level `resolution`.
449
+
450
+ - **aspectRatio** _'21:9' | '2:1' | '16:9' | '4:3' | '1:1' | '3:4' | '9:16' | 'auto'_
451
+
452
+ Aspect ratio of the generated video. Takes precedence over the top-level
453
+ `aspectRatio`, and unlike it can be set to `auto`.
454
+
455
+ - **keyframes** _Array&lt;string | [number, string]&gt;_
456
+
457
+ Keyframes for image-to-video generation, for the shapes `image` and
458
+ `frameImages` cannot express: more than two images, or images pinned to a
459
+ specific second. Takes precedence over both.
460
+
461
+ - **safetyTolerance** _number_
462
+
463
+ Moderation strictness from 0 (strictest) to 4. Defaults to 2. Sexual content is
464
+ capped at 3 and hate content at 2 regardless of the request, and any request
465
+ carrying conditioning media is capped at 2.
466
+
467
+ - **draft** _boolean_
468
+
469
+ Render a fast, lower-quality preview instead of the finished video. Defaults to
470
+ `false`.
471
+
472
+ - **draftCache** _string_
473
+
474
+ Encrypted draft-cache bundle from a prior `draft` generation, which switches the
475
+ request to draft-enhance mode.
476
+
477
+ - **version** _string_
478
+
479
+ Model version to pin. Only `latest` is available today.
480
+
481
+ ### Video Provider Metadata
482
+
483
+ FLUX 3 video results include `providerMetadata.blackForestLabs.videos[]`. Each
484
+ video object may contain the following properties:
485
+
486
+ - **id** _string_ - ID of the Black Forest Labs generation request.
487
+ - **videoUrl** _string_ - The signed, time-limited MP4 URL used to download `video`.
488
+ - **draftCache** _string_ - Download URL for the draft bundle. Present only on a `draft` generation.
489
+ - **seed** _number_ - The seed used for generation, when reported by the API.
490
+ - **start_time** _number_ - Unix timestamp when generation started.
491
+ - **end_time** _number_ - Unix timestamp when generation completed.
492
+ - **duration** _number_ - Duration reported by the API, in seconds.
493
+ - **cost** _number_ - Cost of the generation request in credits.
494
+ - **inputMegapixels** _number_ - Input size in megapixels.
495
+ - **outputMegapixels** _number_ - Output size in megapixels.
496
+
497
+ ### Video Model Capabilities
498
+
499
+ | Model | Description |
500
+ | -------------- | -------------------------------------------------------------------------------------------------------- |
501
+ | `flux-3-video` | Up to full-HD and 20 seconds, with synchronized audio. Text-to-video, keyframes, and video continuation. |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/black-forest-labs",
3
- "version": "1.0.49",
3
+ "version": "1.0.51",
4
4
  "license": "Apache-2.0",
5
5
  "sideEffects": false,
6
6
  "main": "./dist/index.js",
@@ -0,0 +1,58 @@
1
+ import {
2
+ createJsonErrorResponseHandler,
3
+ isSameOrigin,
4
+ } from '@ai-sdk/provider-utils';
5
+ import { z } from 'zod/v4';
6
+
7
+ /**
8
+ * Transport concerns shared by every Black Forest Labs model
9
+ */
10
+
11
+ export const bflErrorSchema = z.object({
12
+ message: z.string().optional(),
13
+ detail: z.any().optional(),
14
+ });
15
+
16
+ function bflErrorToMessage(error: unknown): string | undefined {
17
+ const parsed = bflErrorSchema.safeParse(error);
18
+ if (!parsed.success) return undefined;
19
+ const { message, detail } = parsed.data;
20
+ if (typeof detail === 'string') return detail;
21
+ if (detail != null) {
22
+ try {
23
+ return JSON.stringify(detail);
24
+ } catch {
25
+ // ignore
26
+ }
27
+ }
28
+ return message;
29
+ }
30
+
31
+ export const bflFailedResponseHandler = createJsonErrorResponseHandler({
32
+ errorSchema: bflErrorSchema,
33
+ errorToMessage: error =>
34
+ bflErrorToMessage(error) ?? 'Unknown Black Forest Labs error',
35
+ });
36
+
37
+ /**
38
+ * Black Forest Labs returns response-supplied URLs (polling and delivery) on
39
+ * sibling cluster hosts of the API origin (e.g. `api.us1.bfl.ai` for a base
40
+ * URL on `api.bfl.ai`), so a strict same-origin check against the configured
41
+ * base URL is not enough. Credentials may also be sent to any https host under
42
+ * the official `bfl.ai` domain.
43
+ */
44
+ export function isTrustedUrl(url: string, baseUrl: string): boolean {
45
+ if (isSameOrigin(url, baseUrl)) {
46
+ return true;
47
+ }
48
+
49
+ try {
50
+ const { protocol, hostname } = new URL(url);
51
+ return (
52
+ protocol === 'https:' &&
53
+ (hostname === 'bfl.ai' || hostname.endsWith('.bfl.ai'))
54
+ );
55
+ } catch {
56
+ return false;
57
+ }
58
+ }