@ai-sdk/black-forest-labs 2.0.53 → 2.0.55

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # @ai-sdk/black-forest-labs
2
2
 
3
+ ## 2.0.55
4
+
5
+ ### Patch Changes
6
+
7
+ - 612cb53: Add FLUX 3 image generation and editing support with resolution, grounding, and version options. Handle reasoning and generating poll statuses, stop on terminal task failures, and download signed image URLs without API credentials.
8
+
9
+ Normalize size-derived aspect ratios to the accepted FLUX 3 values and omit unsupported ratios with a warning. Preserve provider and request headers for image downloads on a custom base URL's origin.
10
+
11
+ - Updated dependencies [2959d35]
12
+ - Updated dependencies [59116e6]
13
+ - @ai-sdk/provider@4.0.22
14
+ - @ai-sdk/provider-utils@5.0.54
15
+
16
+ ## 2.0.54
17
+
18
+ ### Patch Changes
19
+
20
+ - Updated dependencies [8c65988]
21
+ - Updated dependencies [527a163]
22
+ - @ai-sdk/provider@4.0.21
23
+ - @ai-sdk/provider-utils@5.0.53
24
+
3
25
  ## 2.0.53
4
26
 
5
27
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@ import { Experimental_VideoModelV4, ImageModelV4, ProviderV4 } from "@ai-sdk/pro
2
2
  import { FetchFunction, InferSchema } from "@ai-sdk/provider-utils";
3
3
  import { z } from "zod/v4";
4
4
  //#region src/black-forest-labs-image-settings.d.ts
5
- type BlackForestLabsImageModelId = 'flux-kontext-pro' | 'flux-kontext-max' | 'flux-pro-1.1-ultra' | 'flux-pro-1.1' | 'flux-pro-1.0-fill' | (string & {});
5
+ type BlackForestLabsImageModelId = 'flux-3-image' | 'flux-kontext-pro' | 'flux-kontext-max' | 'flux-pro-1.1-ultra' | 'flux-pro-1.1' | 'flux-pro-1.0-fill' | (string & {});
6
6
  type BlackForestLabsAspectRatio = `${number}:${number}`;
7
7
  //#endregion
8
8
  //#region src/black-forest-labs-video-settings.d.ts
@@ -65,6 +65,9 @@ export declare const blackForestLabs: BlackForestLabsProvider;
65
65
  //#endregion
66
66
  //#region src/black-forest-labs-image-model-options.d.ts
67
67
  declare const blackForestLabsImageModelOptionsSchema: import("@ai-sdk/provider-utils").LazySchema<{
68
+ resolution?: "768sq" | "1k" | "1.5k" | "2k" | "4k" | undefined;
69
+ grounding?: boolean | undefined;
70
+ version?: "latest" | undefined;
68
71
  imagePrompt?: string | undefined;
69
72
  imagePromptStrength?: number | undefined;
70
73
  inputImage?: string | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/black-forest-labs-image-settings.ts","../src/black-forest-labs-video-settings.ts","../src/black-forest-labs-provider.ts","../src/black-forest-labs-image-model-options.ts","../src/black-forest-labs-video-model-options.ts","../src/version.ts"],"mappings":";;;;KAAY;KAQA;;;KCPA;;;UCiBK;;;;EAIf;;;;EAKA;;;;EAKA,UAAU;;;;;EAMV,QAAQ;;;;;EAMR;;;;;EAMA;;UAGe,gCAAgC;;;;EAI/C,MAAM,SAAS,8BAA8B;;;;EAK7C,WAAW,SAAS,8BAA8B;;;;EAKlD,MAAM,SAAS,8BAA8B;;;;EAK7C,WAAW,SAAS,8BAA8B;;;;EAKlD,mBAAmB;;wBAKL,sBACd,UAAS,kCACR;qBA2DU,iBAAe;;;cCxIf,yEAAsC;;;;;;;;;;;;;;;;;;;;;;;;;;KAyCvC,mCAAmC,mBACtC;;;cCoCI,yEAAsC;;;;;;;;;KAIvC,mCAAmC,mBACtC;;;qBCxFI"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/black-forest-labs-image-settings.ts","../src/black-forest-labs-video-settings.ts","../src/black-forest-labs-provider.ts","../src/black-forest-labs-image-model-options.ts","../src/black-forest-labs-video-model-options.ts","../src/version.ts"],"mappings":";;;;KAAY;KASA;;;KCRA;;;UCiBK;;;;EAIf;;;;EAKA;;;;EAKA,UAAU;;;;;EAMV,QAAQ;;;;;EAMR;;;;;EAMA;;UAGe,gCAAgC;;;;EAI/C,MAAM,SAAS,8BAA8B;;;;EAK7C,WAAW,SAAS,8BAA8B;;;;EAKlD,MAAM,SAAS,8BAA8B;;;;EAK7C,WAAW,SAAS,8BAA8B;;;;EAKlD,mBAAmB;;wBAKL,sBACd,UAAS,kCACR;qBA2DU,iBAAe;;;cChGf,yEAAsC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAYvC,mCAAmC,mBACtC;;;cCyBI,yEAAsC;;;;;;;;;KAIvC,mCAAmC,mBACtC;;;qBCxFI"}
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { AISDKError, InvalidArgumentError, NoSuchModelError } from "@ai-sdk/provider";
1
+ import { AISDKError, InvalidArgumentError, NoSuchModelError, UnsupportedFunctionalityError } from "@ai-sdk/provider";
2
2
  import { WORKFLOW_DESERIALIZE, WORKFLOW_SERIALIZE, combineHeaders, createBinaryResponseHandler, createJsonErrorResponseHandler, createJsonResponseHandler, createStatusCodeErrorResponseHandler, delay, getFromApi, getTopLevelMediaType, isSameOrigin, lazySchema, loadApiKey, parseProviderOptions, postJsonToApi, resolve, serializeModelOptions, withUserAgentSuffix, withoutTrailingSlash, zodSchema } from "@ai-sdk/provider-utils";
3
3
  import { z } from "zod/v4";
4
4
  //#region src/black-forest-labs-api.ts
@@ -7,7 +7,9 @@ import { z } from "zod/v4";
7
7
  */
8
8
  const bflErrorSchema = z.object({
9
9
  message: z.string().optional(),
10
- detail: z.any().optional()
10
+ detail: z.any().optional(),
11
+ status: z.string().nullish(),
12
+ state: z.string().nullish()
11
13
  });
12
14
  function bflErrorToMessage(error) {
13
15
  const parsed = bflErrorSchema.safeParse(error);
@@ -21,10 +23,20 @@ function bflErrorToMessage(error) {
21
23
  }
22
24
  const bflFailedResponseHandler = createJsonErrorResponseHandler({
23
25
  errorSchema: bflErrorSchema,
24
- errorToMessage: (error) => bflErrorToMessage(error) ?? "Unknown Black Forest Labs error"
26
+ errorToMessage: (error) => bflErrorToMessage(error) ?? ((error.status ?? error.state) != null ? `Black Forest Labs generation failed: ${error.status ?? error.state}.` : "Unknown Black Forest Labs error"),
27
+ isRetryable: (response, error) => {
28
+ if ([
29
+ "Content Moderated",
30
+ "Error",
31
+ "Failed",
32
+ "Request Moderated",
33
+ "Task not found"
34
+ ].includes(error?.status ?? error?.state ?? "")) return false;
35
+ return response.status === 408 || response.status === 409 || response.status === 429 || response.status >= 500;
36
+ }
25
37
  });
26
38
  /**
27
- * Black Forest Labs returns response-supplied URLs (polling and delivery) on
39
+ * Black Forest Labs returns response-supplied polling URLs on
28
40
  * sibling cluster hosts of the API origin (e.g. `api.us1.bfl.ai` for a base
29
41
  * URL on `api.bfl.ai`), so a strict same-origin check against the configured
30
42
  * base URL is not enough. Credentials may also be sent to any https host under
@@ -41,7 +53,16 @@ function isTrustedUrl(url, baseUrl) {
41
53
  }
42
54
  //#endregion
43
55
  //#region src/black-forest-labs-image-model-options.ts
44
- const blackForestLabsImageModelOptionsSchema = lazySchema(() => zodSchema(z.object({
56
+ const blackForestLabsImageProviderOptions = z.object({
57
+ resolution: z.enum([
58
+ "768sq",
59
+ "1k",
60
+ "1.5k",
61
+ "2k",
62
+ "4k"
63
+ ]).optional(),
64
+ grounding: z.boolean().optional(),
65
+ version: z.literal("latest").optional(),
45
66
  imagePrompt: z.string().optional(),
46
67
  imagePromptStrength: z.number().min(0).max(1).optional(),
47
68
  /** @deprecated use prompt.images instead */
@@ -76,7 +97,9 @@ const blackForestLabsImageModelOptionsSchema = lazySchema(() => zodSchema(z.obje
76
97
  webhookUrl: z.url().optional(),
77
98
  pollIntervalMillis: z.number().int().positive().optional(),
78
99
  pollTimeoutMillis: z.number().int().positive().optional()
79
- })));
100
+ });
101
+ const blackForestLabsImageModelOptionsSchema = lazySchema(() => zodSchema(blackForestLabsImageProviderOptions));
102
+ const blackForestLabsFlux3ImageModelOptionsSchema = lazySchema(() => zodSchema(blackForestLabsImageProviderOptions.extend({ safetyTolerance: z.number().int().min(0).max(4).optional() })));
80
103
  //#endregion
81
104
  //#region src/black-forest-labs-image-model.ts
82
105
  const DEFAULT_POLL_INTERVAL_MILLIS$1 = 500;
@@ -84,6 +107,7 @@ const DEFAULT_POLL_TIMEOUT_MILLIS$1 = 6e4;
84
107
  var BlackForestLabsImageModel = class BlackForestLabsImageModel {
85
108
  get supportsFileInputs() {
86
109
  if ([
110
+ "flux-3-image",
87
111
  "flux-kontext-pro",
88
112
  "flux-kontext-max",
89
113
  "flux-pro-1.0-fill"
@@ -118,17 +142,17 @@ var BlackForestLabsImageModel = class BlackForestLabsImageModel {
118
142
  if (size && !aspectRatio) warnings.push({
119
143
  type: "unsupported",
120
144
  feature: "size",
121
- details: "Deriving aspect_ratio from size. Use the width and height provider options to specify dimensions for models that support them."
145
+ details: this.modelId === "flux-3-image" ? "Deriving aspect_ratio from size. FLUX 3 uses the resolution provider option to select output resolution." : "Deriving aspect_ratio from size. Use the width and height provider options to specify dimensions for models that support them."
122
146
  });
123
147
  else if (size && aspectRatio) warnings.push({
124
148
  type: "unsupported",
125
149
  feature: "size",
126
- details: "Black Forest Labs ignores size when aspectRatio is provided. Use the width and height provider options to specify dimensions for models that support them"
150
+ details: this.modelId === "flux-3-image" ? "FLUX 3 ignores size when aspectRatio is provided. Use the resolution provider option to select output resolution." : "Black Forest Labs ignores size when aspectRatio is provided. Use the width and height provider options to specify dimensions for models that support them"
127
151
  });
128
152
  const bflOptions = await parseProviderOptions({
129
153
  provider: "blackForestLabs",
130
154
  providerOptions,
131
- schema: blackForestLabsImageModelOptionsSchema
155
+ schema: this.modelId === "flux-3-image" ? blackForestLabsFlux3ImageModelOptionsSchema : blackForestLabsImageModelOptionsSchema
132
156
  });
133
157
  const [widthStr, heightStr] = size?.split("x") ?? [];
134
158
  const inputImages = files?.map((file) => {
@@ -137,6 +161,62 @@ var BlackForestLabsImageModel = class BlackForestLabsImageModel {
137
161
  return Buffer.from(file.data).toString("base64");
138
162
  }) || [];
139
163
  if (inputImages.length > 10) throw new Error("Black Forest Labs supports up to 10 input images.");
164
+ if (this.modelId === "flux-3-image") {
165
+ let flux3AspectRatio = finalAspectRatio === "7:3" ? "21:9" : finalAspectRatio === "3:7" ? "9:21" : finalAspectRatio;
166
+ if (flux3AspectRatio != null && ![
167
+ "21:9",
168
+ "2:1",
169
+ "16:9",
170
+ "3:2",
171
+ "7:5",
172
+ "4:3",
173
+ "5:4",
174
+ "1:1",
175
+ "4:5",
176
+ "3:4",
177
+ "5:7",
178
+ "2:3",
179
+ "9:16",
180
+ "1:2",
181
+ "9:21"
182
+ ].includes(flux3AspectRatio)) {
183
+ warnings.push({
184
+ type: "unsupported",
185
+ feature: "aspectRatio",
186
+ details: `FLUX 3 does not support aspect ratio ${finalAspectRatio}. Using the endpoint's default auto aspect ratio.`
187
+ });
188
+ flux3AspectRatio = void 0;
189
+ }
190
+ if (mask != null) throw new UnsupportedFunctionalityError({ functionality: "FLUX 3 image masks" });
191
+ if (seed != null) warnings.push({
192
+ type: "unsupported",
193
+ feature: "seed"
194
+ });
195
+ for (const [key, value] of Object.entries(bflOptions ?? {})) if (value != null && ![
196
+ "grounding",
197
+ "pollIntervalMillis",
198
+ "pollTimeoutMillis",
199
+ "resolution",
200
+ "safetyTolerance",
201
+ "version"
202
+ ].includes(key)) warnings.push({
203
+ type: "unsupported",
204
+ feature: `blackForestLabs.${key}`
205
+ });
206
+ return {
207
+ body: {
208
+ prompt,
209
+ aspect_ratio: flux3AspectRatio,
210
+ images: inputImages.length > 0 ? inputImages : void 0,
211
+ resolution: bflOptions?.resolution,
212
+ grounding: bflOptions?.grounding,
213
+ safety_tolerance: bflOptions?.safetyTolerance,
214
+ version: bflOptions?.version
215
+ },
216
+ warnings,
217
+ bflOptions
218
+ };
219
+ }
140
220
  const inputImageField = this.modelId === "flux-pro-1.0-fill" ? "image" : "input_image";
141
221
  const inputImagesObj = inputImages.reduce((acc, img, index) => {
142
222
  acc[`${inputImageField}${index === 0 ? "" : `_${index + 1}`}`] = img;
@@ -208,11 +288,14 @@ var BlackForestLabsImageModel = class BlackForestLabsImageModel {
208
288
  pollTimeoutMillis: bflOptions?.pollTimeoutMillis
209
289
  }
210
290
  });
291
+ const baseHostname = new URL(this.config.baseURL).hostname;
292
+ const useCustomDownloadHeaders = isSameOrigin(imageUrl, this.config.baseURL) && baseHostname !== "bfl.ai" && !baseHostname.endsWith(".bfl.ai");
211
293
  const { value: imageBytes, responseHeaders } = await getFromApi({
212
294
  url: imageUrl,
213
295
  validateUrl: true,
214
296
  trustedOrigin: this.config.baseURL,
215
- headers: isTrustedUrl(imageUrl, this.config.baseURL) ? combinedHeaders : void 0,
297
+ credentialedOrigin: useCustomDownloadHeaders ? this.config.baseURL : void 0,
298
+ headers: useCustomDownloadHeaders ? combinedHeaders : { "user-agent": combinedHeaders["user-agent"] },
216
299
  abortSignal,
217
300
  failedResponseHandler: createStatusCodeErrorResponseHandler(),
218
301
  successfulResponseHandler: createBinaryResponseHandler(),
@@ -273,6 +356,7 @@ var BlackForestLabsImageModel = class BlackForestLabsImageModel {
273
356
  throw new Error("Black Forest Labs poll response is Ready but missing result.sample");
274
357
  }
275
358
  if (status === "Error" || status === "Failed") throw new Error("Black Forest Labs generation failed.");
359
+ if (status === "Request Moderated" || status === "Content Moderated" || status === "Task not found") throw new Error(`Black Forest Labs generation failed: ${status}.`);
276
360
  await delay(pollIntervalMillis, { abortSignal: pollingAbortSignal });
277
361
  }
278
362
  } catch (error) {
@@ -309,11 +393,15 @@ const bflSubmitSchema = z.object({
309
393
  output_mp: z.number().nullish()
310
394
  });
311
395
  const bflStatus = z.union([
396
+ z.literal("Content Moderated"),
397
+ z.literal("Generating"),
312
398
  z.literal("Pending"),
399
+ z.literal("Reasoning"),
313
400
  z.literal("Ready"),
314
401
  z.literal("Error"),
315
402
  z.literal("Failed"),
316
- z.literal("Request Moderated")
403
+ z.literal("Request Moderated"),
404
+ z.literal("Task not found")
317
405
  ]);
318
406
  const bflPollSchema = z.object({
319
407
  status: bflStatus.optional(),
@@ -873,7 +961,7 @@ const bflVideoPollSchema = z.object({
873
961
  }));
874
962
  //#endregion
875
963
  //#region src/version.ts
876
- const VERSION = "2.0.53";
964
+ const VERSION = "2.0.55";
877
965
  //#endregion
878
966
  //#region src/black-forest-labs-provider.ts
879
967
  const defaultBaseURL = "https://api.bfl.ai/v1";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["DEFAULT_POLL_INTERVAL_MILLIS","DEFAULT_POLL_TIMEOUT_MILLIS"],"sources":["../src/black-forest-labs-api.ts","../src/black-forest-labs-image-model-options.ts","../src/black-forest-labs-image-model.ts","../src/black-forest-labs-video-settings.ts","../src/black-forest-labs-video-model-options.ts","../src/black-forest-labs-video-model.ts","../src/version.ts","../src/black-forest-labs-provider.ts"],"sourcesContent":["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 lazySchema,\n zodSchema,\n type InferSchema,\n} from '@ai-sdk/provider-utils';\nimport { z } from 'zod/v4';\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","import type { ImageModelV4, SharedV4Warning } from '@ai-sdk/provider';\nimport {\n combineHeaders,\n createBinaryResponseHandler,\n createJsonResponseHandler,\n createStatusCodeErrorResponseHandler,\n delay,\n getFromApi,\n parseProviderOptions,\n postJsonToApi,\n resolve,\n serializeModelOptions,\n WORKFLOW_SERIALIZE,\n WORKFLOW_DESERIALIZE,\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 { blackForestLabsImageModelOptionsSchema } from './black-forest-labs-image-model-options';\nimport type {\n BlackForestLabsAspectRatio,\n 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 ImageModelV4 {\n readonly specificationVersion = 'v4';\n readonly maxImagesPerCall = 1;\n\n get supportsFileInputs(): boolean | undefined {\n if (\n ['flux-kontext-pro', 'flux-kontext-max', 'flux-pro-1.0-fill'].includes(\n this.modelId,\n )\n ) {\n return true;\n }\n\n if (['flux-pro-1.1-ultra', 'flux-pro-1.1'].includes(this.modelId)) {\n return false;\n }\n\n return undefined;\n }\n\n get supportsMaskInputs(): boolean | undefined {\n if (this.modelId === 'flux-pro-1.0-fill') {\n return true;\n }\n\n return this.supportsFileInputs == null ? undefined : false;\n }\n\n get provider(): string {\n return this.config.provider;\n }\n\n static [WORKFLOW_SERIALIZE](model: BlackForestLabsImageModel) {\n return serializeModelOptions({\n modelId: model.modelId,\n config: model.config,\n });\n }\n\n static [WORKFLOW_DESERIALIZE](options: {\n modelId: BlackForestLabsImageModelId;\n config: BlackForestLabsImageModelConfig;\n }) {\n return new BlackForestLabsImageModel(options.modelId, options.config);\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<ImageModelV4['doGenerate']>[0]) {\n const warnings: Array<SharedV4Warning> = [];\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<ImageModelV4['doGenerate']>[0]): Promise<\n Awaited<ReturnType<ImageModelV4['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<ImageModelV4['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 // imageUrl comes from the provider response body; validate it.\n validateUrl: true,\n trustedOrigin: this.config.baseURL,\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\n const url = new URL(pollUrl);\n if (!url.searchParams.has('id')) {\n url.searchParams.set('id', requestId);\n }\n\n const timeoutController = new AbortController();\n let didTimeout = false;\n const timeoutId = setTimeout(() => {\n didTimeout = true;\n timeoutController.abort();\n }, pollTimeoutMillis);\n const pollingAbortSignal =\n abortSignal == null\n ? timeoutController.signal\n : AbortSignal.any([abortSignal, timeoutController.signal]);\n\n try {\n while (true) {\n const { value } = await getFromApi({\n url: url.toString(),\n // The polling URL comes from the provider response; validate it.\n validateUrl: true,\n trustedOrigin: this.config.baseURL,\n // Only send 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: pollingAbortSignal,\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 abortSignal: pollingAbortSignal,\n });\n }\n } catch (error) {\n if (didTimeout) {\n throw new Error('Black Forest Labs generation timed out.');\n }\n throw error;\n } finally {\n clearTimeout(timeoutId);\n }\n }\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","// 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","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","import {\n AISDKError,\n InvalidArgumentError,\n type Experimental_VideoModelV4 as VideoModelV4,\n type Experimental_VideoModelV4CallOptions as VideoModelV4CallOptions,\n type Experimental_VideoModelV4File as VideoModelV4File,\n type Experimental_VideoModelV4OperationStartResult as VideoModelV4OperationStartResult,\n type Experimental_VideoModelV4OperationStatusResult as VideoModelV4OperationStatusResult,\n type Experimental_VideoModelV4Result as VideoModelV4Result,\n type SharedV4Warning,\n} from '@ai-sdk/provider';\nimport {\n combineHeaders,\n createJsonResponseHandler,\n delay,\n getFromApi,\n getTopLevelMediaType,\n parseProviderOptions,\n postJsonToApi,\n resolve,\n serializeModelOptions,\n WORKFLOW_DESERIALIZE,\n WORKFLOW_SERIALIZE,\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 = VideoModelV4CallOptions;\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: VideoModelV4File): 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<SharedV4Warning> = [];\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: VideoModelV4File): 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 VideoModelV4 {\n readonly specificationVersion = 'v4';\n readonly maxVideosPerCall = 1;\n\n get provider(): string {\n return this.config.provider;\n }\n\n static [WORKFLOW_SERIALIZE](model: BlackForestLabsVideoModel) {\n return serializeModelOptions({\n modelId: model.modelId,\n config: model.config,\n });\n }\n\n static [WORKFLOW_DESERIALIZE](options: {\n modelId: BlackForestLabsVideoModelId;\n config: BlackForestLabsVideoModelConfig;\n }) {\n return new BlackForestLabsVideoModel(options.modelId, options.config);\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<SharedV4Warning> = [];\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: VideoModelV4File[] = [];\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 async doStart(\n options: Parameters<NonNullable<VideoModelV4['doStart']>>[0],\n ): Promise<VideoModelV4OperationStartResult> {\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 async doStatus(\n options: Parameters<NonNullable<VideoModelV4['doStatus']>>[0],\n ): Promise<VideoModelV4OperationStatusResult> {\n const currentDate = this.config._internal?.currentDate?.() ?? new Date();\n const operation = options.operation as BlackForestLabsVideoOperation;\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 { value, responseHeaders } = await getFromApi({\n url: url.toString(),\n // The polling URL comes from the provider response; validate it.\n validateUrl: true,\n trustedOrigin: this.config.baseURL,\n // Only send credentials when it stays on a trusted provider host.\n headers: isTrustedUrl(url.toString(), this.config.baseURL)\n ? combinedHeaders\n : undefined,\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',\n videos: [\n {\n type: 'url',\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',\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', response };\n }\n\n async doGenerate(\n options: BlackForestLabsVideoDoGenerateOptions,\n ): Promise<VideoModelV4Result> {\n const startResult = await this.doStart(options);\n const operation = startResult.operation as BlackForestLabsVideoOperation;\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.doStatus({\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","// 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","import {\n NoSuchModelError,\n type Experimental_VideoModelV4,\n type ImageModelV4,\n type ProviderV4,\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 ProviderV4 {\n /**\n * Creates a model for image generation.\n */\n image(modelId: BlackForestLabsImageModelId): ImageModelV4;\n\n /**\n * Creates a model for image generation.\n */\n imageModel(modelId: BlackForestLabsImageModelId): ImageModelV4;\n\n /**\n * Creates a model for video generation.\n */\n video(modelId: BlackForestLabsVideoModelId): Experimental_VideoModelV4;\n\n /**\n * Creates a model for video generation.\n */\n videoModel(modelId: BlackForestLabsVideoModelId): Experimental_VideoModelV4;\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: 'v4',\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"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["DEFAULT_POLL_INTERVAL_MILLIS","DEFAULT_POLL_TIMEOUT_MILLIS"],"sources":["../src/black-forest-labs-api.ts","../src/black-forest-labs-image-model-options.ts","../src/black-forest-labs-image-model.ts","../src/black-forest-labs-video-settings.ts","../src/black-forest-labs-video-model-options.ts","../src/black-forest-labs-video-model.ts","../src/version.ts","../src/black-forest-labs-provider.ts"],"sourcesContent":["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 status: z.string().nullish(),\n state: z.string().nullish(),\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) ??\n ((error.status ?? error.state) != null\n ? `Black Forest Labs generation failed: ${error.status ?? error.state}.`\n : 'Unknown Black Forest Labs error'),\n isRetryable: (response, error) => {\n // Failed tasks can use HTTP 503; resubmitting them starts a new generation.\n if (\n [\n 'Content Moderated',\n 'Error',\n 'Failed',\n 'Request Moderated',\n 'Task not found',\n ].includes(error?.status ?? error?.state ?? '')\n ) {\n return false;\n }\n return (\n response.status === 408 ||\n response.status === 409 ||\n response.status === 429 ||\n response.status >= 500\n );\n },\n});\n\n/**\n * Black Forest Labs returns response-supplied polling URLs 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 lazySchema,\n zodSchema,\n type InferSchema,\n} from '@ai-sdk/provider-utils';\nimport { z } from 'zod/v4';\n\nconst blackForestLabsImageProviderOptions = z.object({\n resolution: z.enum(['768sq', '1k', '1.5k', '2k', '4k']).optional(),\n grounding: z.boolean().optional(),\n version: z.literal('latest').optional(),\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\nexport const blackForestLabsImageModelOptionsSchema = lazySchema(() =>\n zodSchema(blackForestLabsImageProviderOptions),\n);\n\nexport const blackForestLabsFlux3ImageModelOptionsSchema = lazySchema(() =>\n zodSchema(\n blackForestLabsImageProviderOptions.extend({\n safetyTolerance: z.number().int().min(0).max(4).optional(),\n }),\n ),\n);\n\nexport type BlackForestLabsImageModelOptions = InferSchema<\n typeof blackForestLabsImageModelOptionsSchema\n>;\n","import {\n UnsupportedFunctionalityError,\n type ImageModelV4,\n type SharedV4Warning,\n} from '@ai-sdk/provider';\nimport {\n combineHeaders,\n createBinaryResponseHandler,\n createJsonResponseHandler,\n createStatusCodeErrorResponseHandler,\n delay,\n getFromApi,\n isSameOrigin,\n parseProviderOptions,\n postJsonToApi,\n resolve,\n serializeModelOptions,\n WORKFLOW_SERIALIZE,\n WORKFLOW_DESERIALIZE,\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 blackForestLabsFlux3ImageModelOptionsSchema,\n blackForestLabsImageModelOptionsSchema,\n} from './black-forest-labs-image-model-options';\nimport type {\n BlackForestLabsAspectRatio,\n 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 ImageModelV4 {\n readonly specificationVersion = 'v4';\n readonly maxImagesPerCall = 1;\n\n get supportsFileInputs(): boolean | undefined {\n if (\n [\n 'flux-3-image',\n 'flux-kontext-pro',\n 'flux-kontext-max',\n 'flux-pro-1.0-fill',\n ].includes(this.modelId)\n ) {\n return true;\n }\n\n if (['flux-pro-1.1-ultra', 'flux-pro-1.1'].includes(this.modelId)) {\n return false;\n }\n\n return undefined;\n }\n\n get supportsMaskInputs(): boolean | undefined {\n if (this.modelId === 'flux-pro-1.0-fill') {\n return true;\n }\n\n return this.supportsFileInputs == null ? undefined : false;\n }\n\n get provider(): string {\n return this.config.provider;\n }\n\n static [WORKFLOW_SERIALIZE](model: BlackForestLabsImageModel) {\n return serializeModelOptions({\n modelId: model.modelId,\n config: model.config,\n });\n }\n\n static [WORKFLOW_DESERIALIZE](options: {\n modelId: BlackForestLabsImageModelId;\n config: BlackForestLabsImageModelConfig;\n }) {\n return new BlackForestLabsImageModel(options.modelId, options.config);\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<ImageModelV4['doGenerate']>[0]) {\n const warnings: Array<SharedV4Warning> = [];\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 this.modelId === 'flux-3-image'\n ? 'Deriving aspect_ratio from size. FLUX 3 uses the resolution provider option to select output resolution.'\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 this.modelId === 'flux-3-image'\n ? 'FLUX 3 ignores size when aspectRatio is provided. Use the resolution provider option to select output resolution.'\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:\n this.modelId === 'flux-3-image'\n ? blackForestLabsFlux3ImageModelOptionsSchema\n : 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 if (this.modelId === 'flux-3-image') {\n // The endpoint uses 21:9 and 9:21 instead of their reduced forms.\n let flux3AspectRatio =\n finalAspectRatio === '7:3'\n ? '21:9'\n : finalAspectRatio === '3:7'\n ? '9:21'\n : finalAspectRatio;\n if (\n flux3AspectRatio != null &&\n ![\n '21:9',\n '2:1',\n '16:9',\n '3:2',\n '7:5',\n '4:3',\n '5:4',\n '1:1',\n '4:5',\n '3:4',\n '5:7',\n '2:3',\n '9:16',\n '1:2',\n '9:21',\n ].includes(flux3AspectRatio)\n ) {\n warnings.push({\n type: 'unsupported',\n feature: 'aspectRatio',\n details: `FLUX 3 does not support aspect ratio ${finalAspectRatio}. Using the endpoint's default auto aspect ratio.`,\n });\n flux3AspectRatio = undefined;\n }\n if (mask != null) {\n throw new UnsupportedFunctionalityError({\n functionality: 'FLUX 3 image masks',\n });\n }\n if (seed != null) {\n warnings.push({ type: 'unsupported', feature: 'seed' });\n }\n for (const [key, value] of Object.entries(bflOptions ?? {})) {\n if (\n value != null &&\n ![\n 'grounding',\n 'pollIntervalMillis',\n 'pollTimeoutMillis',\n 'resolution',\n 'safetyTolerance',\n 'version',\n ].includes(key)\n ) {\n warnings.push({\n type: 'unsupported',\n feature: `blackForestLabs.${key}`,\n });\n }\n }\n\n return {\n body: {\n prompt,\n aspect_ratio: flux3AspectRatio,\n images: inputImages.length > 0 ? inputImages : undefined,\n resolution: bflOptions?.resolution,\n grounding: bflOptions?.grounding,\n safety_tolerance: bflOptions?.safetyTolerance,\n version: bflOptions?.version,\n },\n warnings,\n bflOptions,\n };\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<ImageModelV4['doGenerate']>[0]): Promise<\n Awaited<ReturnType<ImageModelV4['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<ImageModelV4['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 baseHostname = new URL(this.config.baseURL).hostname;\n const useCustomDownloadHeaders =\n isSameOrigin(imageUrl, this.config.baseURL) &&\n baseHostname !== 'bfl.ai' &&\n !baseHostname.endsWith('.bfl.ai');\n const { value: imageBytes, responseHeaders } = await getFromApi({\n url: imageUrl,\n // imageUrl comes from the provider response body; validate it.\n validateUrl: true,\n trustedOrigin: this.config.baseURL,\n credentialedOrigin: useCustomDownloadHeaders\n ? this.config.baseURL\n : undefined,\n // Signed BFL downloads need no credentials; custom proxies may need them.\n headers: useCustomDownloadHeaders\n ? combinedHeaders\n : { 'user-agent': combinedHeaders['user-agent'] },\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\n const url = new URL(pollUrl);\n if (!url.searchParams.has('id')) {\n url.searchParams.set('id', requestId);\n }\n\n const timeoutController = new AbortController();\n let didTimeout = false;\n const timeoutId = setTimeout(() => {\n didTimeout = true;\n timeoutController.abort();\n }, pollTimeoutMillis);\n const pollingAbortSignal =\n abortSignal == null\n ? timeoutController.signal\n : AbortSignal.any([abortSignal, timeoutController.signal]);\n\n try {\n while (true) {\n const { value } = await getFromApi({\n url: url.toString(),\n // The polling URL comes from the provider response; validate it.\n validateUrl: true,\n trustedOrigin: this.config.baseURL,\n // Only send 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: pollingAbortSignal,\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 if (\n status === 'Request Moderated' ||\n status === 'Content Moderated' ||\n status === 'Task not found'\n ) {\n throw new Error(`Black Forest Labs generation failed: ${status}.`);\n }\n\n await delay(pollIntervalMillis, {\n abortSignal: pollingAbortSignal,\n });\n }\n } catch (error) {\n if (didTimeout) {\n throw new Error('Black Forest Labs generation timed out.');\n }\n throw error;\n } finally {\n clearTimeout(timeoutId);\n }\n }\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('Content Moderated'),\n z.literal('Generating'),\n z.literal('Pending'),\n z.literal('Reasoning'),\n z.literal('Ready'),\n z.literal('Error'),\n z.literal('Failed'),\n z.literal('Request Moderated'),\n z.literal('Task not found'),\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","// 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","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","import {\n AISDKError,\n InvalidArgumentError,\n type Experimental_VideoModelV4 as VideoModelV4,\n type Experimental_VideoModelV4CallOptions as VideoModelV4CallOptions,\n type Experimental_VideoModelV4File as VideoModelV4File,\n type Experimental_VideoModelV4OperationStartResult as VideoModelV4OperationStartResult,\n type Experimental_VideoModelV4OperationStatusResult as VideoModelV4OperationStatusResult,\n type Experimental_VideoModelV4Result as VideoModelV4Result,\n type SharedV4Warning,\n} from '@ai-sdk/provider';\nimport {\n combineHeaders,\n createJsonResponseHandler,\n delay,\n getFromApi,\n getTopLevelMediaType,\n parseProviderOptions,\n postJsonToApi,\n resolve,\n serializeModelOptions,\n WORKFLOW_DESERIALIZE,\n WORKFLOW_SERIALIZE,\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 = VideoModelV4CallOptions;\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: VideoModelV4File): 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<SharedV4Warning> = [];\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: VideoModelV4File): 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 VideoModelV4 {\n readonly specificationVersion = 'v4';\n readonly maxVideosPerCall = 1;\n\n get provider(): string {\n return this.config.provider;\n }\n\n static [WORKFLOW_SERIALIZE](model: BlackForestLabsVideoModel) {\n return serializeModelOptions({\n modelId: model.modelId,\n config: model.config,\n });\n }\n\n static [WORKFLOW_DESERIALIZE](options: {\n modelId: BlackForestLabsVideoModelId;\n config: BlackForestLabsVideoModelConfig;\n }) {\n return new BlackForestLabsVideoModel(options.modelId, options.config);\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<SharedV4Warning> = [];\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: VideoModelV4File[] = [];\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 async doStart(\n options: Parameters<NonNullable<VideoModelV4['doStart']>>[0],\n ): Promise<VideoModelV4OperationStartResult> {\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 async doStatus(\n options: Parameters<NonNullable<VideoModelV4['doStatus']>>[0],\n ): Promise<VideoModelV4OperationStatusResult> {\n const currentDate = this.config._internal?.currentDate?.() ?? new Date();\n const operation = options.operation as BlackForestLabsVideoOperation;\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 { value, responseHeaders } = await getFromApi({\n url: url.toString(),\n // The polling URL comes from the provider response; validate it.\n validateUrl: true,\n trustedOrigin: this.config.baseURL,\n // Only send credentials when it stays on a trusted provider host.\n headers: isTrustedUrl(url.toString(), this.config.baseURL)\n ? combinedHeaders\n : undefined,\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',\n videos: [\n {\n type: 'url',\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',\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', response };\n }\n\n async doGenerate(\n options: BlackForestLabsVideoDoGenerateOptions,\n ): Promise<VideoModelV4Result> {\n const startResult = await this.doStart(options);\n const operation = startResult.operation as BlackForestLabsVideoOperation;\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.doStatus({\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","// 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","import {\n NoSuchModelError,\n type Experimental_VideoModelV4,\n type ImageModelV4,\n type ProviderV4,\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 ProviderV4 {\n /**\n * Creates a model for image generation.\n */\n image(modelId: BlackForestLabsImageModelId): ImageModelV4;\n\n /**\n * Creates a model for image generation.\n */\n imageModel(modelId: BlackForestLabsImageModelId): ImageModelV4;\n\n /**\n * Creates a model for video generation.\n */\n video(modelId: BlackForestLabsVideoModelId): Experimental_VideoModelV4;\n\n /**\n * Creates a model for video generation.\n */\n videoModel(modelId: BlackForestLabsVideoModelId): Experimental_VideoModelV4;\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: 'v4',\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"],"mappings":"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"}
@@ -5,7 +5,7 @@ description: Learn how to use Black Forest Labs models with the AI SDK.
5
5
 
6
6
  # Black Forest Labs Provider
7
7
 
8
- [Black Forest Labs](https://bfl.ai/) provides a generative image platform for developers with FLUX-based models. Their platform offers fast, high quality, and in-context image generation and editing with precise and coherent results.
8
+ [Black Forest Labs](https://bfl.ai/) provides a generative media platform for developers with FLUX-based models. Their platform offers fast, high quality, and in-context image generation and editing, plus video generation with FLUX 3.
9
9
 
10
10
  ## Setup
11
11
 
@@ -95,13 +95,90 @@ Black Forest Labs offers many models optimized for different use cases. Here are
95
95
 
96
96
  | Model | Description |
97
97
  | -------------------- | -------------------------------------------------------------------------------------------------------------------------- |
98
+ | `flux-3-image` | FLUX 3 for text-to-image and editing with up to ten reference images and optional web grounding |
99
+ | `flux-2-pro` | FLUX.2 [pro] for text-to-image and reference-based editing in one endpoint |
100
+ | `flux-2-max` | FLUX.2 [max] for the highest prompt adherence and detail in the FLUX.2 family |
101
+ | `flux-2-flex` | FLUX.2 [flex] exposes `steps` and `guidance` so you can trade speed against quality |
102
+ | `flux-2-klein-9b` | FLUX.2 [klein] 9B, an open-weight distilled model |
103
+ | `flux-2-klein-4b` | FLUX.2 [klein] 4B, the smallest and cheapest open-weight FLUX.2 model |
98
104
  | `flux-kontext-pro` | FLUX.1 Kontext [pro] handles both text and reference images as inputs, enabling targeted edits and complex transformations |
99
105
  | `flux-kontext-max` | FLUX.1 Kontext [max] with improved prompt adherence and typography generation |
100
106
  | `flux-pro-1.1-ultra` | Ultra-fast, ultra high-resolution image creation |
101
107
  | `flux-pro-1.1` | Fast, high-quality image generation from text. |
102
108
  | `flux-pro-1.0-fill` | Inpainting model for filling masked regions of images with new content |
103
109
 
104
- Black Forest Labs models support aspect ratios from 3:7 (portrait) to 7:3 (landscape).
110
+ FLUX.1 and FLUX.2 models support aspect ratios from 3:7 (portrait) to 7:3 (landscape).
111
+ FLUX 3 accepts only `21:9`, `2:1`, `16:9`, `3:2`, `7:5`, `4:3`, `5:4`,
112
+ `1:1`, `4:5`, `3:4`, `5:7`, `2:3`, `9:16`, `1:2`, and `9:21`.
113
+ Omit `aspectRatio` to use the endpoint's `auto` default. Unsupported ratios
114
+ are omitted with a warning.
115
+
116
+ FLUX.2 models take reference images on the same `prompt.images` field as the
117
+ Kontext models, so a single model ID covers both text-to-image and editing. See
118
+ [Image Editing](#image-editing) below.
119
+
120
+ <Note>
121
+ FLUX.2 generations can take longer than the 60 second default polling timeout,
122
+ especially with reference images. Raise `pollTimeoutMillis` when a request
123
+ reports `Black Forest Labs generation timed out.`
124
+ </Note>
125
+
126
+ ### FLUX 3 Image Generation and Editing
127
+
128
+ The `flux-3-image` model generates images from text and edits reference images
129
+ through the same endpoint. Pass reference images through `prompt.images` and
130
+ select the output resolution with `providerOptions.blackForestLabs.resolution`:
131
+
132
+ ```ts
133
+ import {
134
+ blackForestLabs,
135
+ type BlackForestLabsImageModelOptions,
136
+ } from '@ai-sdk/black-forest-labs';
137
+ import { generateImage } from 'ai';
138
+
139
+ const { image } = await generateImage({
140
+ model: blackForestLabs.image('flux-3-image'),
141
+ prompt: 'A watercolor illustration of a coastal village at dawn',
142
+ aspectRatio: '16:9',
143
+ providerOptions: {
144
+ blackForestLabs: {
145
+ resolution: '2k',
146
+ grounding: false,
147
+ version: 'latest',
148
+ pollTimeoutMillis: 240000,
149
+ } satisfies BlackForestLabsImageModelOptions,
150
+ },
151
+ });
152
+ ```
153
+
154
+ For editing, use a prompt such as:
155
+
156
+ ```ts
157
+ const { image } = await generateImage({
158
+ model: blackForestLabs.image('flux-3-image'),
159
+ prompt: {
160
+ text: 'Change the sky to sunset while preserving the buildings',
161
+ images: ['https://example.com/village.png'],
162
+ },
163
+ });
164
+ ```
165
+
166
+ FLUX 3 accepts up to ten reference images as URLs or base64-encoded data. Each
167
+ reference image must be at least 256 × 256 pixels and no larger than 16 megapixels.
168
+ Omitting `aspectRatio` lets the endpoint choose the ratio from the prompt or the
169
+ first reference image. The default resolution is `1k`, and grounding is enabled
170
+ by default.
171
+
172
+ FLUX 3 does not accept `seed`, masks, explicit `width`/`height`, or the legacy
173
+ image options such as `outputFormat`, `steps`, and `promptUpsampling`. A `size`
174
+ is used only to derive a supported aspect ratio; ratios outside the list above
175
+ are omitted with a warning. Use `resolution` to select the pixel-area
176
+ tier. Unsupported options are omitted with warnings; masks are rejected.
177
+
178
+ The provider polls through `Pending`, `Reasoning`, and `Generating` until the
179
+ image is ready. Increase `pollTimeoutMillis` for requests that exceed the default
180
+ 60 second polling timeout. It stops on moderation or task failures and downloads the signed
181
+ image URL without sending API credentials.
105
182
 
106
183
  ### Image Editing
107
184
 
@@ -160,6 +237,49 @@ const { images } = await generateImage({
160
237
  up to 20MB or 20 megapixels per image.
161
238
  </Note>
162
239
 
240
+ #### FLUX.2 Editing
241
+
242
+ FLUX.2 models accept reference images on the same `prompt.images` field, so no
243
+ separate editing model ID is needed:
244
+
245
+ ```ts
246
+ import { blackForestLabs } from '@ai-sdk/black-forest-labs';
247
+ import { generateImage } from 'ai';
248
+
249
+ const { image } = await generateImage({
250
+ model: blackForestLabs.image('flux-2-pro'),
251
+ prompt: {
252
+ text: 'Place this logo on a plain ceramic mug.',
253
+ images: ['https://example.com/logo.png'],
254
+ },
255
+ providerOptions: {
256
+ blackForestLabs: {
257
+ pollTimeoutMillis: 240000,
258
+ },
259
+ },
260
+ });
261
+ ```
262
+
263
+ `flux-2-flex` additionally accepts `steps` and `guidance`, which let you trade
264
+ generation time against quality:
265
+
266
+ ```ts
267
+ import { blackForestLabs } from '@ai-sdk/black-forest-labs';
268
+ import { generateImage } from 'ai';
269
+
270
+ const { image } = await generateImage({
271
+ model: blackForestLabs.image('flux-2-flex'),
272
+ prompt: 'A detailed macro shot of a dew-covered leaf',
273
+ providerOptions: {
274
+ blackForestLabs: {
275
+ steps: 50,
276
+ guidance: 4,
277
+ pollTimeoutMillis: 240000,
278
+ },
279
+ },
280
+ });
281
+ ```
282
+
163
283
  #### Inpainting
164
284
 
165
285
  The `flux-pro-1.0-fill` model supports inpainting, which allows you to fill masked regions of an image with new content. Pass the source image via `prompt.images` and a mask image via `prompt.mask`:
@@ -184,6 +304,9 @@ The mask image should be a grayscale image where white areas indicate regions to
184
304
 
185
305
  Black Forest Labs image models support flexible provider options through the `providerOptions.blackForestLabs` object. The supported parameters depend on the used model ID:
186
306
 
307
+ - **resolution** _"768sq" | "1k" | "1.5k" | "2k" | "4k"_ - FLUX 3 output resolution class. Defaults to `"1k"`; exact dimensions vary with aspect ratio.
308
+ - **grounding** _boolean_ - FLUX 3 web and image search grounding. Defaults to `true`.
309
+ - **version** _"latest"_ - FLUX 3 endpoint version. Only `"latest"` is currently available.
187
310
  - **width** _number_ - Output width in pixels (256–1920). When set, this overrides any width derived from `size`.
188
311
  - **height** _number_ - Output height in pixels (256–1920). When set, this overrides any height derived from `size`.
189
312
  - **outputFormat** _string_ - Desired format of the output image (`"jpeg"` or `"png"`).
@@ -193,7 +316,7 @@ Black Forest Labs image models support flexible provider options through the `pr
193
316
  - **imagePromptStrength** _number_ - Strength of the image prompt influence on generation (0.0 to 1.0).
194
317
  - **promptUpsampling** _boolean_ - If true, performs upsampling on the prompt.
195
318
  - **raw** _boolean_ - Enable raw mode for more natural, authentic aesthetics.
196
- - **safetyTolerance** _number_ - Moderation level for inputs and outputs (0 = most strict, 6 = more permissive).
319
+ - **safetyTolerance** _number_ - Moderation level for inputs and outputs (0 = most strict, 6 = more permissive). FLUX 3 accepts only 0–4 and defaults to 2.
197
320
  - **pollIntervalMillis** _number_ - Interval in milliseconds between polling attempts (default 500ms).
198
321
  - **pollTimeoutMillis** _number_ - Overall timeout in milliseconds for polling before timing out (default 60s).
199
322
  - **webhookUrl** _string_ - URL for asynchronous completion notification. Must be a valid HTTP/HTTPS URL.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/black-forest-labs",
3
- "version": "2.0.53",
3
+ "version": "2.0.55",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "sideEffects": false,
@@ -28,8 +28,8 @@
28
28
  }
29
29
  },
30
30
  "dependencies": {
31
- "@ai-sdk/provider": "4.0.20",
32
- "@ai-sdk/provider-utils": "5.0.52"
31
+ "@ai-sdk/provider": "4.0.22",
32
+ "@ai-sdk/provider-utils": "5.0.54"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@ai-sdk/test-server": "2.0.3",
@@ -11,6 +11,8 @@ import { z } from 'zod/v4';
11
11
  export const bflErrorSchema = z.object({
12
12
  message: z.string().optional(),
13
13
  detail: z.any().optional(),
14
+ status: z.string().nullish(),
15
+ state: z.string().nullish(),
14
16
  });
15
17
 
16
18
  function bflErrorToMessage(error: unknown): string | undefined {
@@ -31,11 +33,34 @@ function bflErrorToMessage(error: unknown): string | undefined {
31
33
  export const bflFailedResponseHandler = createJsonErrorResponseHandler({
32
34
  errorSchema: bflErrorSchema,
33
35
  errorToMessage: error =>
34
- bflErrorToMessage(error) ?? 'Unknown Black Forest Labs error',
36
+ bflErrorToMessage(error) ??
37
+ ((error.status ?? error.state) != null
38
+ ? `Black Forest Labs generation failed: ${error.status ?? error.state}.`
39
+ : 'Unknown Black Forest Labs error'),
40
+ isRetryable: (response, error) => {
41
+ // Failed tasks can use HTTP 503; resubmitting them starts a new generation.
42
+ if (
43
+ [
44
+ 'Content Moderated',
45
+ 'Error',
46
+ 'Failed',
47
+ 'Request Moderated',
48
+ 'Task not found',
49
+ ].includes(error?.status ?? error?.state ?? '')
50
+ ) {
51
+ return false;
52
+ }
53
+ return (
54
+ response.status === 408 ||
55
+ response.status === 409 ||
56
+ response.status === 429 ||
57
+ response.status >= 500
58
+ );
59
+ },
35
60
  });
36
61
 
37
62
  /**
38
- * Black Forest Labs returns response-supplied URLs (polling and delivery) on
63
+ * Black Forest Labs returns response-supplied polling URLs on
39
64
  * sibling cluster hosts of the API origin (e.g. `api.us1.bfl.ai` for a base
40
65
  * URL on `api.bfl.ai`), so a strict same-origin check against the configured
41
66
  * base URL is not enough. Credentials may also be sent to any https host under
@@ -5,43 +5,54 @@ import {
5
5
  } from '@ai-sdk/provider-utils';
6
6
  import { z } from 'zod/v4';
7
7
 
8
+ const blackForestLabsImageProviderOptions = z.object({
9
+ resolution: z.enum(['768sq', '1k', '1.5k', '2k', '4k']).optional(),
10
+ grounding: z.boolean().optional(),
11
+ version: z.literal('latest').optional(),
12
+ imagePrompt: z.string().optional(),
13
+ imagePromptStrength: z.number().min(0).max(1).optional(),
14
+ /** @deprecated use prompt.images instead */
15
+ inputImage: z.string().optional(),
16
+ /** @deprecated use prompt.images instead */
17
+ inputImage2: z.string().optional(),
18
+ /** @deprecated use prompt.images instead */
19
+ inputImage3: z.string().optional(),
20
+ /** @deprecated use prompt.images instead */
21
+ inputImage4: z.string().optional(),
22
+ /** @deprecated use prompt.images instead */
23
+ inputImage5: z.string().optional(),
24
+ /** @deprecated use prompt.images instead */
25
+ inputImage6: z.string().optional(),
26
+ /** @deprecated use prompt.images instead */
27
+ inputImage7: z.string().optional(),
28
+ /** @deprecated use prompt.images instead */
29
+ inputImage8: z.string().optional(),
30
+ /** @deprecated use prompt.images instead */
31
+ inputImage9: z.string().optional(),
32
+ /** @deprecated use prompt.images instead */
33
+ inputImage10: z.string().optional(),
34
+ steps: z.number().int().positive().optional(),
35
+ guidance: z.number().min(0).optional(),
36
+ width: z.number().int().min(256).max(1920).optional(),
37
+ height: z.number().int().min(256).max(1920).optional(),
38
+ outputFormat: z.enum(['jpeg', 'png']).optional(),
39
+ promptUpsampling: z.boolean().optional(),
40
+ raw: z.boolean().optional(),
41
+ safetyTolerance: z.number().int().min(0).max(6).optional(),
42
+ webhookSecret: z.string().optional(),
43
+ webhookUrl: z.url().optional(),
44
+ pollIntervalMillis: z.number().int().positive().optional(),
45
+ pollTimeoutMillis: z.number().int().positive().optional(),
46
+ });
47
+
8
48
  export const blackForestLabsImageModelOptionsSchema = lazySchema(() =>
49
+ zodSchema(blackForestLabsImageProviderOptions),
50
+ );
51
+
52
+ export const blackForestLabsFlux3ImageModelOptionsSchema = lazySchema(() =>
9
53
  zodSchema(
10
- z.object({
11
- imagePrompt: z.string().optional(),
12
- imagePromptStrength: z.number().min(0).max(1).optional(),
13
- /** @deprecated use prompt.images instead */
14
- inputImage: z.string().optional(),
15
- /** @deprecated use prompt.images instead */
16
- inputImage2: z.string().optional(),
17
- /** @deprecated use prompt.images instead */
18
- inputImage3: z.string().optional(),
19
- /** @deprecated use prompt.images instead */
20
- inputImage4: z.string().optional(),
21
- /** @deprecated use prompt.images instead */
22
- inputImage5: z.string().optional(),
23
- /** @deprecated use prompt.images instead */
24
- inputImage6: z.string().optional(),
25
- /** @deprecated use prompt.images instead */
26
- inputImage7: z.string().optional(),
27
- /** @deprecated use prompt.images instead */
28
- inputImage8: z.string().optional(),
29
- /** @deprecated use prompt.images instead */
30
- inputImage9: z.string().optional(),
31
- /** @deprecated use prompt.images instead */
32
- inputImage10: z.string().optional(),
33
- steps: z.number().int().positive().optional(),
34
- guidance: z.number().min(0).optional(),
35
- width: z.number().int().min(256).max(1920).optional(),
36
- height: z.number().int().min(256).max(1920).optional(),
37
- outputFormat: z.enum(['jpeg', 'png']).optional(),
38
- promptUpsampling: z.boolean().optional(),
39
- raw: z.boolean().optional(),
40
- safetyTolerance: z.number().int().min(0).max(6).optional(),
41
- webhookSecret: z.string().optional(),
42
- webhookUrl: z.url().optional(),
43
- pollIntervalMillis: z.number().int().positive().optional(),
44
- pollTimeoutMillis: z.number().int().positive().optional(),
54
+ blackForestLabsImageProviderOptions.extend({
55
+ safetyTolerance: z.number().int().min(0).max(4).optional(),
45
56
  }),
46
57
  ),
47
58
  );
@@ -1,4 +1,8 @@
1
- import type { ImageModelV4, SharedV4Warning } from '@ai-sdk/provider';
1
+ import {
2
+ UnsupportedFunctionalityError,
3
+ type ImageModelV4,
4
+ type SharedV4Warning,
5
+ } from '@ai-sdk/provider';
2
6
  import {
3
7
  combineHeaders,
4
8
  createBinaryResponseHandler,
@@ -6,6 +10,7 @@ import {
6
10
  createStatusCodeErrorResponseHandler,
7
11
  delay,
8
12
  getFromApi,
13
+ isSameOrigin,
9
14
  parseProviderOptions,
10
15
  postJsonToApi,
11
16
  resolve,
@@ -20,7 +25,10 @@ import {
20
25
  bflFailedResponseHandler,
21
26
  isTrustedUrl,
22
27
  } from './black-forest-labs-api';
23
- import { blackForestLabsImageModelOptionsSchema } from './black-forest-labs-image-model-options';
28
+ import {
29
+ blackForestLabsFlux3ImageModelOptionsSchema,
30
+ blackForestLabsImageModelOptionsSchema,
31
+ } from './black-forest-labs-image-model-options';
24
32
  import type {
25
33
  BlackForestLabsAspectRatio,
26
34
  BlackForestLabsImageModelId,
@@ -53,9 +61,12 @@ export class BlackForestLabsImageModel implements ImageModelV4 {
53
61
 
54
62
  get supportsFileInputs(): boolean | undefined {
55
63
  if (
56
- ['flux-kontext-pro', 'flux-kontext-max', 'flux-pro-1.0-fill'].includes(
57
- this.modelId,
58
- )
64
+ [
65
+ 'flux-3-image',
66
+ 'flux-kontext-pro',
67
+ 'flux-kontext-max',
68
+ 'flux-pro-1.0-fill',
69
+ ].includes(this.modelId)
59
70
  ) {
60
71
  return true;
61
72
  }
@@ -117,21 +128,28 @@ export class BlackForestLabsImageModel implements ImageModelV4 {
117
128
  type: 'unsupported',
118
129
  feature: 'size',
119
130
  details:
120
- 'Deriving aspect_ratio from size. Use the width and height provider options to specify dimensions for models that support them.',
131
+ this.modelId === 'flux-3-image'
132
+ ? 'Deriving aspect_ratio from size. FLUX 3 uses the resolution provider option to select output resolution.'
133
+ : 'Deriving aspect_ratio from size. Use the width and height provider options to specify dimensions for models that support them.',
121
134
  });
122
135
  } else if (size && aspectRatio) {
123
136
  warnings.push({
124
137
  type: 'unsupported',
125
138
  feature: 'size',
126
139
  details:
127
- 'Black Forest Labs ignores size when aspectRatio is provided. Use the width and height provider options to specify dimensions for models that support them',
140
+ this.modelId === 'flux-3-image'
141
+ ? 'FLUX 3 ignores size when aspectRatio is provided. Use the resolution provider option to select output resolution.'
142
+ : 'Black Forest Labs ignores size when aspectRatio is provided. Use the width and height provider options to specify dimensions for models that support them',
128
143
  });
129
144
  }
130
145
 
131
146
  const bflOptions = await parseProviderOptions({
132
147
  provider: 'blackForestLabs',
133
148
  providerOptions,
134
- schema: blackForestLabsImageModelOptionsSchema,
149
+ schema:
150
+ this.modelId === 'flux-3-image'
151
+ ? blackForestLabsFlux3ImageModelOptionsSchema
152
+ : blackForestLabsImageModelOptionsSchema,
135
153
  });
136
154
 
137
155
  const [widthStr, heightStr] = size?.split('x') ?? [];
@@ -153,6 +171,83 @@ export class BlackForestLabsImageModel implements ImageModelV4 {
153
171
  throw new Error('Black Forest Labs supports up to 10 input images.');
154
172
  }
155
173
 
174
+ if (this.modelId === 'flux-3-image') {
175
+ // The endpoint uses 21:9 and 9:21 instead of their reduced forms.
176
+ let flux3AspectRatio =
177
+ finalAspectRatio === '7:3'
178
+ ? '21:9'
179
+ : finalAspectRatio === '3:7'
180
+ ? '9:21'
181
+ : finalAspectRatio;
182
+ if (
183
+ flux3AspectRatio != null &&
184
+ ![
185
+ '21:9',
186
+ '2:1',
187
+ '16:9',
188
+ '3:2',
189
+ '7:5',
190
+ '4:3',
191
+ '5:4',
192
+ '1:1',
193
+ '4:5',
194
+ '3:4',
195
+ '5:7',
196
+ '2:3',
197
+ '9:16',
198
+ '1:2',
199
+ '9:21',
200
+ ].includes(flux3AspectRatio)
201
+ ) {
202
+ warnings.push({
203
+ type: 'unsupported',
204
+ feature: 'aspectRatio',
205
+ details: `FLUX 3 does not support aspect ratio ${finalAspectRatio}. Using the endpoint's default auto aspect ratio.`,
206
+ });
207
+ flux3AspectRatio = undefined;
208
+ }
209
+ if (mask != null) {
210
+ throw new UnsupportedFunctionalityError({
211
+ functionality: 'FLUX 3 image masks',
212
+ });
213
+ }
214
+ if (seed != null) {
215
+ warnings.push({ type: 'unsupported', feature: 'seed' });
216
+ }
217
+ for (const [key, value] of Object.entries(bflOptions ?? {})) {
218
+ if (
219
+ value != null &&
220
+ ![
221
+ 'grounding',
222
+ 'pollIntervalMillis',
223
+ 'pollTimeoutMillis',
224
+ 'resolution',
225
+ 'safetyTolerance',
226
+ 'version',
227
+ ].includes(key)
228
+ ) {
229
+ warnings.push({
230
+ type: 'unsupported',
231
+ feature: `blackForestLabs.${key}`,
232
+ });
233
+ }
234
+ }
235
+
236
+ return {
237
+ body: {
238
+ prompt,
239
+ aspect_ratio: flux3AspectRatio,
240
+ images: inputImages.length > 0 ? inputImages : undefined,
241
+ resolution: bflOptions?.resolution,
242
+ grounding: bflOptions?.grounding,
243
+ safety_tolerance: bflOptions?.safetyTolerance,
244
+ version: bflOptions?.version,
245
+ },
246
+ warnings,
247
+ bflOptions,
248
+ };
249
+ }
250
+
156
251
  const inputImageField =
157
252
  this.modelId === 'flux-pro-1.0-fill' ? 'image' : 'input_image';
158
253
  const inputImagesObj: Record<string, string> = inputImages.reduce<
@@ -260,17 +355,23 @@ export class BlackForestLabsImageModel implements ImageModelV4 {
260
355
  },
261
356
  });
262
357
 
358
+ const baseHostname = new URL(this.config.baseURL).hostname;
359
+ const useCustomDownloadHeaders =
360
+ isSameOrigin(imageUrl, this.config.baseURL) &&
361
+ baseHostname !== 'bfl.ai' &&
362
+ !baseHostname.endsWith('.bfl.ai');
263
363
  const { value: imageBytes, responseHeaders } = await getFromApi({
264
364
  url: imageUrl,
265
365
  // imageUrl comes from the provider response body; validate it.
266
366
  validateUrl: true,
267
367
  trustedOrigin: this.config.baseURL,
268
- // Only send credentials if the response-supplied URL points back at the
269
- // provider; the image is typically delivered from a CDN, so the API key
270
- // must not travel to a foreign host.
271
- headers: isTrustedUrl(imageUrl, this.config.baseURL)
272
- ? combinedHeaders
368
+ credentialedOrigin: useCustomDownloadHeaders
369
+ ? this.config.baseURL
273
370
  : undefined,
371
+ // Signed BFL downloads need no credentials; custom proxies may need them.
372
+ headers: useCustomDownloadHeaders
373
+ ? combinedHeaders
374
+ : { 'user-agent': combinedHeaders['user-agent'] },
274
375
  abortSignal,
275
376
  failedResponseHandler: createStatusCodeErrorResponseHandler(),
276
377
  successfulResponseHandler: createBinaryResponseHandler(),
@@ -389,6 +490,13 @@ export class BlackForestLabsImageModel implements ImageModelV4 {
389
490
  if (status === 'Error' || status === 'Failed') {
390
491
  throw new Error('Black Forest Labs generation failed.');
391
492
  }
493
+ if (
494
+ status === 'Request Moderated' ||
495
+ status === 'Content Moderated' ||
496
+ status === 'Task not found'
497
+ ) {
498
+ throw new Error(`Black Forest Labs generation failed: ${status}.`);
499
+ }
392
500
 
393
501
  await delay(pollIntervalMillis, {
394
502
  abortSignal: pollingAbortSignal,
@@ -443,11 +551,15 @@ const bflSubmitSchema = z.object({
443
551
  });
444
552
 
445
553
  const bflStatus = z.union([
554
+ z.literal('Content Moderated'),
555
+ z.literal('Generating'),
446
556
  z.literal('Pending'),
557
+ z.literal('Reasoning'),
447
558
  z.literal('Ready'),
448
559
  z.literal('Error'),
449
560
  z.literal('Failed'),
450
561
  z.literal('Request Moderated'),
562
+ z.literal('Task not found'),
451
563
  ]);
452
564
 
453
565
  const bflPollSchema = z
@@ -1,4 +1,5 @@
1
1
  export type BlackForestLabsImageModelId =
2
+ | 'flux-3-image'
2
3
  | 'flux-kontext-pro'
3
4
  | 'flux-kontext-max'
4
5
  | 'flux-pro-1.1-ultra'