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

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/dist/index.js CHANGED
@@ -27,12 +27,53 @@ __export(index_exports, {
27
27
  module.exports = __toCommonJS(index_exports);
28
28
 
29
29
  // src/black-forest-labs-provider.ts
30
- var import_provider = require("@ai-sdk/provider");
31
- var import_provider_utils2 = require("@ai-sdk/provider-utils");
30
+ var import_provider2 = require("@ai-sdk/provider");
31
+ var import_provider_utils5 = require("@ai-sdk/provider-utils");
32
32
 
33
33
  // src/black-forest-labs-image-model.ts
34
+ var import_provider_utils2 = require("@ai-sdk/provider-utils");
35
+ var import_v42 = require("zod/v4");
36
+
37
+ // src/black-forest-labs-api.ts
34
38
  var import_provider_utils = require("@ai-sdk/provider-utils");
35
39
  var import_v4 = require("zod/v4");
40
+ var bflErrorSchema = import_v4.z.object({
41
+ message: import_v4.z.string().optional(),
42
+ detail: import_v4.z.any().optional()
43
+ });
44
+ function bflErrorToMessage(error) {
45
+ const parsed = bflErrorSchema.safeParse(error);
46
+ if (!parsed.success) return void 0;
47
+ const { message, detail } = parsed.data;
48
+ if (typeof detail === "string") return detail;
49
+ if (detail != null) {
50
+ try {
51
+ return JSON.stringify(detail);
52
+ } catch (e) {
53
+ }
54
+ }
55
+ return message;
56
+ }
57
+ var bflFailedResponseHandler = (0, import_provider_utils.createJsonErrorResponseHandler)({
58
+ errorSchema: bflErrorSchema,
59
+ errorToMessage: (error) => {
60
+ var _a;
61
+ return (_a = bflErrorToMessage(error)) != null ? _a : "Unknown Black Forest Labs error";
62
+ }
63
+ });
64
+ function isTrustedUrl(url, baseUrl) {
65
+ if ((0, import_provider_utils.isSameOrigin)(url, baseUrl)) {
66
+ return true;
67
+ }
68
+ try {
69
+ const { protocol, hostname } = new URL(url);
70
+ return protocol === "https:" && (hostname === "bfl.ai" || hostname.endsWith(".bfl.ai"));
71
+ } catch (e) {
72
+ return false;
73
+ }
74
+ }
75
+
76
+ // src/black-forest-labs-image-model.ts
36
77
  var DEFAULT_POLL_INTERVAL_MILLIS = 500;
37
78
  var DEFAULT_POLL_TIMEOUT_MILLIS = 6e4;
38
79
  var BlackForestLabsImageModel = class {
@@ -70,7 +111,7 @@ var BlackForestLabsImageModel = class {
70
111
  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"
71
112
  });
72
113
  }
73
- const bflOptions = await (0, import_provider_utils.parseProviderOptions)({
114
+ const bflOptions = await (0, import_provider_utils2.parseProviderOptions)({
74
115
  provider: "blackForestLabs",
75
116
  providerOptions,
76
117
  schema: blackForestLabsImageModelOptionsSchema
@@ -151,16 +192,16 @@ var BlackForestLabsImageModel = class {
151
192
  abortSignal
152
193
  });
153
194
  const currentDate = (_c = (_b = (_a = this.config._internal) == null ? void 0 : _a.currentDate) == null ? void 0 : _b.call(_a)) != null ? _c : /* @__PURE__ */ new Date();
154
- const combinedHeaders = (0, import_provider_utils.combineHeaders)(
155
- await (0, import_provider_utils.resolve)(this.config.headers),
195
+ const combinedHeaders = (0, import_provider_utils2.combineHeaders)(
196
+ await (0, import_provider_utils2.resolve)(this.config.headers),
156
197
  headers
157
198
  );
158
- const submit = await (0, import_provider_utils.postJsonToApi)({
199
+ const submit = await (0, import_provider_utils2.postJsonToApi)({
159
200
  url: `${this.config.baseURL}/${this.modelId}`,
160
201
  headers: combinedHeaders,
161
202
  body,
162
203
  failedResponseHandler: bflFailedResponseHandler,
163
- successfulResponseHandler: (0, import_provider_utils.createJsonResponseHandler)(bflSubmitSchema),
204
+ successfulResponseHandler: (0, import_provider_utils2.createJsonResponseHandler)(bflSubmitSchema),
164
205
  abortSignal,
165
206
  fetch: this.config.fetch
166
207
  });
@@ -182,15 +223,15 @@ var BlackForestLabsImageModel = class {
182
223
  pollTimeoutMillis: bflOptions == null ? void 0 : bflOptions.pollTimeoutMillis
183
224
  }
184
225
  });
185
- const { value: imageBytes, responseHeaders } = await (0, import_provider_utils.getFromApi)({
226
+ const { value: imageBytes, responseHeaders } = await (0, import_provider_utils2.getFromApi)({
186
227
  url: imageUrl,
187
228
  // Only send credentials if the response-supplied URL points back at the
188
229
  // provider; the image is typically delivered from a CDN, so the API key
189
230
  // must not travel to a foreign host.
190
231
  headers: isTrustedUrl(imageUrl, this.config.baseURL) ? combinedHeaders : void 0,
191
232
  abortSignal,
192
- failedResponseHandler: (0, import_provider_utils.createStatusCodeErrorResponseHandler)(),
193
- successfulResponseHandler: (0, import_provider_utils.createBinaryResponseHandler)(),
233
+ failedResponseHandler: (0, import_provider_utils2.createStatusCodeErrorResponseHandler)(),
234
+ successfulResponseHandler: (0, import_provider_utils2.createBinaryResponseHandler)(),
194
235
  fetch: this.config.fetch
195
236
  });
196
237
  return {
@@ -240,13 +281,13 @@ var BlackForestLabsImageModel = class {
240
281
  url.searchParams.set("id", requestId);
241
282
  }
242
283
  for (let i = 0; i < maxPollAttempts; i++) {
243
- const { value } = await (0, import_provider_utils.getFromApi)({
284
+ const { value } = await (0, import_provider_utils2.getFromApi)({
244
285
  url: url.toString(),
245
286
  // The polling URL comes from the provider response; only send
246
287
  // credentials when it stays on a trusted provider host.
247
288
  headers: isTrustedUrl(url.toString(), this.config.baseURL) ? headers : void 0,
248
289
  failedResponseHandler: bflFailedResponseHandler,
249
- successfulResponseHandler: (0, import_provider_utils.createJsonResponseHandler)(bflPollSchema),
290
+ successfulResponseHandler: (0, import_provider_utils2.createJsonResponseHandler)(bflPollSchema),
250
291
  abortSignal,
251
292
  fetch: this.config.fetch
252
293
  });
@@ -268,59 +309,48 @@ var BlackForestLabsImageModel = class {
268
309
  if (status === "Error" || status === "Failed") {
269
310
  throw new Error("Black Forest Labs generation failed.");
270
311
  }
271
- await (0, import_provider_utils.delay)(pollIntervalMillis);
312
+ await (0, import_provider_utils2.delay)(pollIntervalMillis);
272
313
  }
273
314
  throw new Error("Black Forest Labs generation timed out.");
274
315
  }
275
316
  };
276
- function isTrustedUrl(url, baseUrl) {
277
- if ((0, import_provider_utils.isSameOrigin)(url, baseUrl)) {
278
- return true;
279
- }
280
- try {
281
- const { protocol, hostname } = new URL(url);
282
- return protocol === "https:" && (hostname === "bfl.ai" || hostname.endsWith(".bfl.ai"));
283
- } catch (e) {
284
- return false;
285
- }
286
- }
287
- var blackForestLabsImageModelOptionsSchema = (0, import_provider_utils.lazySchema)(
288
- () => (0, import_provider_utils.zodSchema)(
289
- import_v4.z.object({
290
- imagePrompt: import_v4.z.string().optional(),
291
- imagePromptStrength: import_v4.z.number().min(0).max(1).optional(),
317
+ var blackForestLabsImageModelOptionsSchema = (0, import_provider_utils2.lazySchema)(
318
+ () => (0, import_provider_utils2.zodSchema)(
319
+ import_v42.z.object({
320
+ imagePrompt: import_v42.z.string().optional(),
321
+ imagePromptStrength: import_v42.z.number().min(0).max(1).optional(),
292
322
  /** @deprecated use prompt.images instead */
293
- inputImage: import_v4.z.string().optional(),
323
+ inputImage: import_v42.z.string().optional(),
294
324
  /** @deprecated use prompt.images instead */
295
- inputImage2: import_v4.z.string().optional(),
325
+ inputImage2: import_v42.z.string().optional(),
296
326
  /** @deprecated use prompt.images instead */
297
- inputImage3: import_v4.z.string().optional(),
327
+ inputImage3: import_v42.z.string().optional(),
298
328
  /** @deprecated use prompt.images instead */
299
- inputImage4: import_v4.z.string().optional(),
329
+ inputImage4: import_v42.z.string().optional(),
300
330
  /** @deprecated use prompt.images instead */
301
- inputImage5: import_v4.z.string().optional(),
331
+ inputImage5: import_v42.z.string().optional(),
302
332
  /** @deprecated use prompt.images instead */
303
- inputImage6: import_v4.z.string().optional(),
333
+ inputImage6: import_v42.z.string().optional(),
304
334
  /** @deprecated use prompt.images instead */
305
- inputImage7: import_v4.z.string().optional(),
335
+ inputImage7: import_v42.z.string().optional(),
306
336
  /** @deprecated use prompt.images instead */
307
- inputImage8: import_v4.z.string().optional(),
337
+ inputImage8: import_v42.z.string().optional(),
308
338
  /** @deprecated use prompt.images instead */
309
- inputImage9: import_v4.z.string().optional(),
339
+ inputImage9: import_v42.z.string().optional(),
310
340
  /** @deprecated use prompt.images instead */
311
- inputImage10: import_v4.z.string().optional(),
312
- steps: import_v4.z.number().int().positive().optional(),
313
- guidance: import_v4.z.number().min(0).optional(),
314
- width: import_v4.z.number().int().min(256).max(1920).optional(),
315
- height: import_v4.z.number().int().min(256).max(1920).optional(),
316
- outputFormat: import_v4.z.enum(["jpeg", "png"]).optional(),
317
- promptUpsampling: import_v4.z.boolean().optional(),
318
- raw: import_v4.z.boolean().optional(),
319
- safetyTolerance: import_v4.z.number().int().min(0).max(6).optional(),
320
- webhookSecret: import_v4.z.string().optional(),
321
- webhookUrl: import_v4.z.url().optional(),
322
- pollIntervalMillis: import_v4.z.number().int().positive().optional(),
323
- pollTimeoutMillis: import_v4.z.number().int().positive().optional()
341
+ inputImage10: import_v42.z.string().optional(),
342
+ steps: import_v42.z.number().int().positive().optional(),
343
+ guidance: import_v42.z.number().min(0).optional(),
344
+ width: import_v42.z.number().int().min(256).max(1920).optional(),
345
+ height: import_v42.z.number().int().min(256).max(1920).optional(),
346
+ outputFormat: import_v42.z.enum(["jpeg", "png"]).optional(),
347
+ promptUpsampling: import_v42.z.boolean().optional(),
348
+ raw: import_v42.z.boolean().optional(),
349
+ safetyTolerance: import_v42.z.number().int().min(0).max(6).optional(),
350
+ webhookSecret: import_v42.z.string().optional(),
351
+ webhookUrl: import_v42.z.url().optional(),
352
+ pollIntervalMillis: import_v42.z.number().int().positive().optional(),
353
+ pollTimeoutMillis: import_v42.z.number().int().positive().optional()
324
354
  })
325
355
  )
326
356
  );
@@ -344,30 +374,30 @@ function gcd(a, b) {
344
374
  }
345
375
  return x;
346
376
  }
347
- var bflSubmitSchema = import_v4.z.object({
348
- id: import_v4.z.string(),
349
- polling_url: import_v4.z.url(),
350
- cost: import_v4.z.number().nullish(),
351
- input_mp: import_v4.z.number().nullish(),
352
- output_mp: import_v4.z.number().nullish()
377
+ var bflSubmitSchema = import_v42.z.object({
378
+ id: import_v42.z.string(),
379
+ polling_url: import_v42.z.url(),
380
+ cost: import_v42.z.number().nullish(),
381
+ input_mp: import_v42.z.number().nullish(),
382
+ output_mp: import_v42.z.number().nullish()
353
383
  });
354
- var bflStatus = import_v4.z.union([
355
- import_v4.z.literal("Pending"),
356
- import_v4.z.literal("Ready"),
357
- import_v4.z.literal("Error"),
358
- import_v4.z.literal("Failed"),
359
- import_v4.z.literal("Request Moderated")
384
+ var bflStatus = import_v42.z.union([
385
+ import_v42.z.literal("Pending"),
386
+ import_v42.z.literal("Ready"),
387
+ import_v42.z.literal("Error"),
388
+ import_v42.z.literal("Failed"),
389
+ import_v42.z.literal("Request Moderated")
360
390
  ]);
361
- var bflPollSchema = import_v4.z.object({
391
+ var bflPollSchema = import_v42.z.object({
362
392
  status: bflStatus.optional(),
363
393
  state: bflStatus.optional(),
364
- details: import_v4.z.unknown().optional(),
365
- result: import_v4.z.object({
366
- sample: import_v4.z.url(),
367
- seed: import_v4.z.number().optional(),
368
- start_time: import_v4.z.number().optional(),
369
- end_time: import_v4.z.number().optional(),
370
- duration: import_v4.z.number().optional()
394
+ details: import_v42.z.unknown().optional(),
395
+ result: import_v42.z.object({
396
+ sample: import_v42.z.url(),
397
+ seed: import_v42.z.number().optional(),
398
+ start_time: import_v42.z.number().optional(),
399
+ end_time: import_v42.z.number().optional(),
400
+ duration: import_v42.z.number().optional()
371
401
  }).nullish()
372
402
  }).refine((v) => v.status != null || v.state != null, {
373
403
  message: "Missing status in Black Forest Labs poll response"
@@ -378,42 +408,647 @@ var bflPollSchema = import_v4.z.object({
378
408
  result: v.result
379
409
  };
380
410
  });
381
- var bflErrorSchema = import_v4.z.object({
382
- message: import_v4.z.string().optional(),
383
- detail: import_v4.z.any().optional()
411
+
412
+ // src/black-forest-labs-video-model.ts
413
+ var import_provider = require("@ai-sdk/provider");
414
+ var import_provider_utils4 = require("@ai-sdk/provider-utils");
415
+ var import_v44 = require("zod/v4");
416
+
417
+ // src/black-forest-labs-video-model-options.ts
418
+ var import_provider_utils3 = require("@ai-sdk/provider-utils");
419
+ var import_v43 = require("zod/v4");
420
+
421
+ // src/black-forest-labs-video-settings.ts
422
+ var blackForestLabsVideoAspectRatios = [
423
+ "21:9",
424
+ "2:1",
425
+ "16:9",
426
+ "4:3",
427
+ "1:1",
428
+ "3:4",
429
+ "9:16",
430
+ "auto"
431
+ ];
432
+ var blackForestLabsVideoResolutions = ["hd", "fhd"];
433
+
434
+ // src/black-forest-labs-video-model-options.ts
435
+ var blackForestLabsTimedVideoKeyframeSchema = import_v43.z.tuple([
436
+ import_v43.z.number().min(0).max(20),
437
+ import_v43.z.string()
438
+ ]);
439
+ var blackForestLabsVideoKeyframesSchema = import_v43.z.union([
440
+ import_v43.z.array(import_v43.z.string()).min(1).max(10),
441
+ import_v43.z.array(blackForestLabsTimedVideoKeyframeSchema).min(1).max(10).refine(
442
+ (keyframes) => keyframes.every(
443
+ (keyframe, index) => index === 0 || keyframe[0] > keyframes[index - 1][0]
444
+ ),
445
+ { message: "Timed keyframes must be in chronological order." }
446
+ )
447
+ ]);
448
+ var blackForestLabsVideoProviderOptions = import_v43.z.object({
449
+ /**
450
+ * Output resolution tier. Takes precedence over the top-level `resolution`,
451
+ * which is expressed as `{width}x{height}` and has to be mapped onto a tier.
452
+ */
453
+ resolution: import_v43.z.enum(blackForestLabsVideoResolutions).optional(),
454
+ /**
455
+ * Aspect ratio of the generated video. Takes precedence over the top-level
456
+ * `aspectRatio`, and unlike it can be set to `auto`.
457
+ */
458
+ aspectRatio: import_v43.z.enum(blackForestLabsVideoAspectRatios).optional(),
459
+ /**
460
+ * Keyframes for image-to-video generation, for the shapes the top-level
461
+ * `image` and `frameImages` options cannot express: more than two images, or
462
+ * images pinned to a specific second. Takes precedence over both.
463
+ *
464
+ * One image opens the clip, two open and close it, and with more the extras
465
+ * are spaced evenly in between. Three or more plain images require an
466
+ * explicit `duration`.
467
+ */
468
+ keyframes: blackForestLabsVideoKeyframesSchema.optional(),
469
+ /**
470
+ * Moderation strictness from 0 (strictest) to 4. Defaults to 2. Sexual
471
+ * content is capped at 3 and hate content at 2 regardless of the request,
472
+ * and any request carrying conditioning media is capped at 2.
473
+ */
474
+ safetyTolerance: import_v43.z.number().int().min(0).max(4).optional(),
475
+ /**
476
+ * Render a fast, lower-quality preview instead of the finished video.
477
+ * Defaults to `false`.
478
+ */
479
+ draft: import_v43.z.boolean().optional(),
480
+ /**
481
+ * Encrypted draft-cache bundle from a prior `draft` generation, which
482
+ * switches the request to draft-enhance mode: the bundle is replayed at full
483
+ * quality.
484
+ *
485
+ * Either the base64-encoded `.bin` downloaded from the draft's `draftCache`
486
+ * URL, or that URL itself while it is still in its expiry window.
487
+ */
488
+ draftCache: import_v43.z.string().optional(),
489
+ /**
490
+ * Model version to pin. Only `latest` is available today.
491
+ */
492
+ version: import_v43.z.literal("latest").optional()
384
493
  });
385
- var bflFailedResponseHandler = (0, import_provider_utils.createJsonErrorResponseHandler)({
386
- errorSchema: bflErrorSchema,
387
- errorToMessage: (error) => {
388
- var _a;
389
- return (_a = bflErrorToMessage(error)) != null ? _a : "Unknown Black Forest Labs error";
494
+ var blackForestLabsVideoModelOptionsSchema = (0, import_provider_utils3.lazySchema)(
495
+ () => (0, import_provider_utils3.zodSchema)(blackForestLabsVideoProviderOptions)
496
+ );
497
+
498
+ // src/black-forest-labs-video-model.ts
499
+ var DEFAULT_POLL_INTERVAL_MILLIS2 = 2e3;
500
+ var DEFAULT_POLL_TIMEOUT_MILLIS2 = 6e5;
501
+ var MIN_DURATION_SECONDS = 5;
502
+ var MAX_DURATION_SECONDS = 20;
503
+ var UNTIMED_KEYFRAMES_NEEDING_DURATION = 3;
504
+ var allowedAspectRatios = new Set(blackForestLabsVideoAspectRatios);
505
+ var allowedResolutions = new Set(blackForestLabsVideoResolutions);
506
+ var TERMINAL_FAILURE_STATUSES = /* @__PURE__ */ new Set([
507
+ "Error",
508
+ "Failed",
509
+ "Request Moderated",
510
+ "Content Moderated",
511
+ "Task not found"
512
+ ]);
513
+ function getTopLevelMediaType(mediaType) {
514
+ return mediaType.split("/")[0];
515
+ }
516
+ function resolveTopLevelResolution(resolution) {
517
+ const named = resolution.toLowerCase();
518
+ if (allowedResolutions.has(named)) {
519
+ return { tier: named, derived: false };
390
520
  }
391
- });
392
- function bflErrorToMessage(error) {
393
- const parsed = bflErrorSchema.safeParse(error);
394
- if (!parsed.success) return void 0;
395
- const { message, detail } = parsed.data;
396
- if (typeof detail === "string") return detail;
397
- if (detail != null) {
398
- try {
399
- return JSON.stringify(detail);
400
- } catch (e) {
521
+ const match = resolution.match(/^(\d+)x(\d+)$/);
522
+ if (match == null) {
523
+ return void 0;
524
+ }
525
+ const shorterSide = Math.min(Number(match[1]), Number(match[2]));
526
+ return {
527
+ tier: shorterSide <= 720 ? "hd" : "fhd",
528
+ derived: shorterSide !== 720 && shorterSide !== 1080
529
+ };
530
+ }
531
+ function nonImageFrameMediaType(file) {
532
+ if (file.mediaType == null) {
533
+ return void 0;
534
+ }
535
+ const topLevelMediaType = getTopLevelMediaType(file.mediaType);
536
+ return topLevelMediaType === "image" ? void 0 : topLevelMediaType;
537
+ }
538
+ function getDraftEnhanceArgs(options, bflOptions) {
539
+ var _a, _b, _c, _d, _e, _f, _g, _h;
540
+ const warnings = [];
541
+ const pinnedByBundle = [
542
+ ["prompt", ((_b = (_a = options.prompt) == null ? void 0 : _a.trim().length) != null ? _b : 0) > 0],
543
+ [
544
+ "aspectRatio",
545
+ options.aspectRatio != null || bflOptions.aspectRatio != null
546
+ ],
547
+ ["resolution", options.resolution != null || bflOptions.resolution != null],
548
+ ["duration", options.duration != null],
549
+ ["fps", options.fps != null],
550
+ ["seed", options.seed != null],
551
+ ["generateAudio", options.generateAudio != null],
552
+ ["image", options.image != null],
553
+ ["frameImages", ((_d = (_c = options.frameImages) == null ? void 0 : _c.length) != null ? _d : 0) > 0],
554
+ ["inputReferences", ((_f = (_e = options.inputReferences) == null ? void 0 : _e.length) != null ? _f : 0) > 0],
555
+ ["keyframes", ((_h = (_g = bflOptions.keyframes) == null ? void 0 : _g.length) != null ? _h : 0) > 0],
556
+ ["version", bflOptions.version != null]
557
+ ];
558
+ for (const [feature, isSet] of pinnedByBundle) {
559
+ if (isSet) {
560
+ warnings.push({
561
+ type: "unsupported",
562
+ feature,
563
+ details: `FLUX 3 draft enhance replays the draft bundle as it was generated, so "${feature}" was ignored. Set it on the original draft request instead.`
564
+ });
401
565
  }
402
566
  }
403
- return message;
567
+ if (bflOptions.draft != null) {
568
+ warnings.push({
569
+ type: "unsupported",
570
+ feature: "draft",
571
+ details: "FLUX 3 draft enhance always renders at full quality. The draft option was ignored."
572
+ });
573
+ }
574
+ if (options.n != null && options.n > 1) {
575
+ warnings.push({
576
+ type: "unsupported",
577
+ feature: "n",
578
+ details: "FLUX 3 video generates a single video per call. Only 1 video will be generated."
579
+ });
580
+ }
581
+ return {
582
+ body: {
583
+ mode: "draft_enhance",
584
+ draft_cache: bflOptions.draftCache,
585
+ safety_tolerance: bflOptions.safetyTolerance
586
+ },
587
+ warnings
588
+ };
404
589
  }
590
+ function describePollDetails(details) {
591
+ if (details == null) {
592
+ return void 0;
593
+ }
594
+ if (typeof details === "string") {
595
+ return details;
596
+ }
597
+ try {
598
+ return JSON.stringify(details);
599
+ } catch (e) {
600
+ return void 0;
601
+ }
602
+ }
603
+ function toBlackForestLabsFile(file) {
604
+ if (file.type === "url") {
605
+ return file.url;
606
+ }
607
+ if (typeof file.data === "string") {
608
+ return file.data;
609
+ }
610
+ return Buffer.from(file.data).toString("base64");
611
+ }
612
+ var BlackForestLabsVideoModel = class {
613
+ constructor(modelId, config) {
614
+ this.modelId = modelId;
615
+ this.config = config;
616
+ this.specificationVersion = "v3";
617
+ this.maxVideosPerCall = 1;
618
+ }
619
+ get provider() {
620
+ return this.config.provider;
621
+ }
622
+ async getArgs(options) {
623
+ var _a, _b, _c, _d, _e, _f, _g;
624
+ const warnings = [];
625
+ const bflOptions = await (0, import_provider_utils4.parseProviderOptions)({
626
+ provider: "blackForestLabs",
627
+ providerOptions: options.providerOptions,
628
+ schema: blackForestLabsVideoModelOptionsSchema
629
+ });
630
+ if ((bflOptions == null ? void 0 : bflOptions.draftCache) != null) {
631
+ return getDraftEnhanceArgs(options, bflOptions);
632
+ }
633
+ if (options.fps != null) {
634
+ warnings.push({
635
+ type: "unsupported",
636
+ feature: "fps",
637
+ details: "FLUX 3 video does not support a custom frame rate."
638
+ });
639
+ }
640
+ if (options.seed != null) {
641
+ warnings.push({
642
+ type: "unsupported",
643
+ feature: "seed",
644
+ details: "FLUX 3 video does not accept a seed."
645
+ });
646
+ }
647
+ if (options.n != null && options.n > 1) {
648
+ warnings.push({
649
+ type: "unsupported",
650
+ feature: "n",
651
+ details: "FLUX 3 video generates a single video per call. Only 1 video will be generated."
652
+ });
653
+ }
654
+ let resolution = bflOptions == null ? void 0 : bflOptions.resolution;
655
+ if (options.resolution != null) {
656
+ const resolved = resolveTopLevelResolution(options.resolution);
657
+ if (resolution != null) {
658
+ if (resolved == null) {
659
+ warnings.push({
660
+ type: "unsupported",
661
+ feature: "resolution",
662
+ details: `Unrecognized resolution "${options.resolution}". FLUX 3 video supports "hd" and "fhd", so providerOptions.blackForestLabs.resolution ("${resolution}") was used instead.`
663
+ });
664
+ }
665
+ } else if (resolved == null) {
666
+ warnings.push({
667
+ type: "unsupported",
668
+ feature: "resolution",
669
+ details: `Unrecognized resolution "${options.resolution}". FLUX 3 video supports "hd" and "fhd", or a {width}x{height} value to map onto one.`
670
+ });
671
+ } else {
672
+ resolution = resolved.tier;
673
+ if (resolved.derived) {
674
+ warnings.push({
675
+ type: "compatibility",
676
+ feature: "resolution",
677
+ details: `FLUX 3 video renders at "hd" or "fhd"; the requested resolution "${options.resolution}" was mapped to "${resolved.tier}".`
678
+ });
679
+ }
680
+ }
681
+ }
682
+ let aspectRatio = bflOptions == null ? void 0 : bflOptions.aspectRatio;
683
+ if (aspectRatio == null && options.aspectRatio != null) {
684
+ if (allowedAspectRatios.has(options.aspectRatio)) {
685
+ aspectRatio = options.aspectRatio;
686
+ } else {
687
+ warnings.push({
688
+ type: "unsupported",
689
+ feature: "aspectRatio",
690
+ details: `FLUX 3 video does not support the aspect ratio "${options.aspectRatio}". Using the provider default (auto).`
691
+ });
692
+ }
693
+ }
694
+ const firstFrameImage = (_b = (_a = options.frameImages) == null ? void 0 : _a.find(
695
+ (frame) => frame.frameType === "first_frame"
696
+ )) == null ? void 0 : _b.image;
697
+ let firstFrame = firstFrameImage != null ? firstFrameImage : options.image;
698
+ let lastFrame = (_d = (_c = options.frameImages) == null ? void 0 : _c.find(
699
+ (frame) => frame.frameType === "last_frame"
700
+ )) == null ? void 0 : _d.image;
701
+ const firstFrameMediaType = firstFrame != null ? nonImageFrameMediaType(firstFrame) : void 0;
702
+ if (firstFrame != null && firstFrameMediaType != null) {
703
+ warnings.push({
704
+ type: "unsupported",
705
+ feature: firstFrameImage != null ? "frameImages" : "image",
706
+ details: firstFrameMediaType === "video" ? "FLUX 3 video does not accept a video as a keyframe. Pass it as an inputReference to continue from it instead." : `FLUX 3 video only accepts an image as a keyframe; the "${firstFrame.mediaType}" file was ignored.`
707
+ });
708
+ firstFrame = void 0;
709
+ }
710
+ if (lastFrame != null) {
711
+ if (firstFrame == null) {
712
+ warnings.push({
713
+ type: "unsupported",
714
+ feature: "frameImages",
715
+ details: "FLUX 3 video requires a first_frame when a last_frame is provided. The last_frame was ignored."
716
+ });
717
+ lastFrame = void 0;
718
+ } else {
719
+ const lastFrameMediaType = nonImageFrameMediaType(lastFrame);
720
+ if (lastFrameMediaType != null) {
721
+ warnings.push({
722
+ type: "unsupported",
723
+ feature: "frameImages",
724
+ details: lastFrameMediaType === "video" ? "FLUX 3 video does not accept a video as a keyframe. The last_frame video was ignored." : `FLUX 3 video only accepts an image as a keyframe; the "${lastFrame.mediaType}" last_frame was ignored.`
725
+ });
726
+ lastFrame = void 0;
727
+ }
728
+ }
729
+ }
730
+ let keyframes = (bflOptions == null ? void 0 : bflOptions.keyframes) != null && bflOptions.keyframes.length > 0 ? [...bflOptions.keyframes] : void 0;
731
+ if (keyframes != null) {
732
+ if (firstFrame != null || lastFrame != null) {
733
+ warnings.push({
734
+ type: "unsupported",
735
+ feature: options.frameImages != null ? "frameImages" : "image",
736
+ details: "FLUX 3 video takes a single keyframe list. providerOptions.blackForestLabs.keyframes was used and the top-level frame images were ignored."
737
+ });
738
+ }
739
+ } else if (firstFrame != null) {
740
+ keyframes = [toBlackForestLabsFile(firstFrame)];
741
+ if (lastFrame != null) {
742
+ keyframes.push(toBlackForestLabsFile(lastFrame));
743
+ }
744
+ }
745
+ let startVideo;
746
+ const referenceFiles = (_e = options.inputReferences) != null ? _e : [];
747
+ const referenceVideos = [];
748
+ for (const file of referenceFiles) {
749
+ const topLevelMediaType = file.mediaType != null ? getTopLevelMediaType(file.mediaType) : void 0;
750
+ if (topLevelMediaType === "video") {
751
+ referenceVideos.push(file);
752
+ } else if (topLevelMediaType == null) {
753
+ warnings.push({
754
+ type: "compatibility",
755
+ feature: "inputReferences",
756
+ details: 'FLUX 3 video only accepts a video reference, so the reference with no mediaType was treated as the video to continue from. Pass { url, mediaType: "video/mp4" } to be explicit.'
757
+ });
758
+ referenceVideos.push(file);
759
+ } else if (topLevelMediaType === "image") {
760
+ warnings.push({
761
+ type: "unsupported",
762
+ feature: "inputReferences",
763
+ details: "FLUX 3 video has no reference-image input. Pass images as `image`, `frameImages`, or providerOptions.blackForestLabs.keyframes instead. The reference was ignored."
764
+ });
765
+ } else {
766
+ warnings.push({
767
+ type: "unsupported",
768
+ feature: "inputReferences",
769
+ details: `FLUX 3 video only accepts a video reference; the "${file.mediaType}" reference was ignored.`
770
+ });
771
+ }
772
+ }
773
+ if (referenceVideos.length > 0) {
774
+ if (keyframes != null) {
775
+ warnings.push({
776
+ type: "unsupported",
777
+ feature: "inputReferences",
778
+ details: "FLUX 3 video cannot combine keyframes with a video to continue from. The video reference was ignored."
779
+ });
780
+ } else {
781
+ startVideo = toBlackForestLabsFile(referenceVideos[0]);
782
+ if (referenceVideos.length > 1) {
783
+ warnings.push({
784
+ type: "unsupported",
785
+ feature: "inputReferences",
786
+ details: "FLUX 3 video continues from a single video. Only the first video reference was used."
787
+ });
788
+ }
789
+ }
790
+ }
791
+ let duration = options.duration;
792
+ if (duration != null) {
793
+ if (!Number.isInteger(duration)) {
794
+ const rounded = Math.round(duration);
795
+ warnings.push({
796
+ type: "unsupported",
797
+ feature: "duration",
798
+ details: `FLUX 3 video requires a whole number of seconds. The requested duration of ${duration} was rounded to ${rounded}.`
799
+ });
800
+ duration = rounded;
801
+ }
802
+ if (duration > MAX_DURATION_SECONDS) {
803
+ warnings.push({
804
+ type: "unsupported",
805
+ feature: "duration",
806
+ details: `FLUX 3 video supports at most ${MAX_DURATION_SECONDS} seconds. The requested duration of ${options.duration} was clamped to ${MAX_DURATION_SECONDS}.`
807
+ });
808
+ duration = MAX_DURATION_SECONDS;
809
+ } else if (duration < MIN_DURATION_SECONDS) {
810
+ warnings.push({
811
+ type: "unsupported",
812
+ feature: "duration",
813
+ details: `FLUX 3 video requires at least ${MIN_DURATION_SECONDS} seconds. The requested duration of ${options.duration} was clamped to ${MIN_DURATION_SECONDS}.`
814
+ });
815
+ duration = MIN_DURATION_SECONDS;
816
+ }
817
+ }
818
+ const untimedKeyframeCount = (_f = keyframes == null ? void 0 : keyframes.filter((keyframe) => typeof keyframe === "string").length) != null ? _f : 0;
819
+ if (duration == null && untimedKeyframeCount >= UNTIMED_KEYFRAMES_NEEDING_DURATION) {
820
+ throw new import_provider.InvalidArgumentError({
821
+ argument: "duration",
822
+ message: `FLUX 3 video requires an explicit duration when ${UNTIMED_KEYFRAMES_NEEDING_DURATION} or more keyframes are sent without a timestamp.`
823
+ });
824
+ }
825
+ const mode = keyframes != null ? "i2v" : startVideo != null ? "v2v" : "t2v";
826
+ const body = {
827
+ mode,
828
+ prompt: (_g = options.prompt) != null ? _g : "",
829
+ aspect_ratio: aspectRatio,
830
+ duration,
831
+ resolution,
832
+ version: bflOptions == null ? void 0 : bflOptions.version,
833
+ generate_audio: options.generateAudio,
834
+ safety_tolerance: bflOptions == null ? void 0 : bflOptions.safetyTolerance,
835
+ draft: bflOptions == null ? void 0 : bflOptions.draft,
836
+ ...mode === "i2v" && { keyframes },
837
+ ...mode === "v2v" && { start_video: startVideo }
838
+ };
839
+ return { body, warnings };
840
+ }
841
+ async start(options) {
842
+ var _a, _b, _c;
843
+ const { body, warnings } = await this.getArgs(options);
844
+ const currentDate = (_c = (_b = (_a = this.config._internal) == null ? void 0 : _a.currentDate) == null ? void 0 : _b.call(_a)) != null ? _c : /* @__PURE__ */ new Date();
845
+ const combinedHeaders = (0, import_provider_utils4.combineHeaders)(
846
+ await (0, import_provider_utils4.resolve)(this.config.headers),
847
+ options.headers
848
+ );
849
+ const { value: submit, responseHeaders } = await (0, import_provider_utils4.postJsonToApi)({
850
+ url: `${this.config.baseURL}/${this.modelId}`,
851
+ headers: combinedHeaders,
852
+ body,
853
+ failedResponseHandler: bflFailedResponseHandler,
854
+ successfulResponseHandler: (0, import_provider_utils4.createJsonResponseHandler)(bflVideoSubmitSchema),
855
+ abortSignal: options.abortSignal,
856
+ fetch: this.config.fetch
857
+ });
858
+ return {
859
+ operation: {
860
+ requestId: submit.id,
861
+ pollingUrl: submit.polling_url,
862
+ ...submit.cost != null && { cost: submit.cost },
863
+ ...submit.input_mp != null && {
864
+ inputMegapixels: submit.input_mp
865
+ },
866
+ ...submit.output_mp != null && {
867
+ outputMegapixels: submit.output_mp
868
+ }
869
+ },
870
+ warnings,
871
+ response: {
872
+ modelId: this.modelId,
873
+ timestamp: currentDate,
874
+ headers: responseHeaders
875
+ }
876
+ };
877
+ }
878
+ async getStatus(options) {
879
+ var _a, _b, _c;
880
+ const currentDate = (_c = (_b = (_a = this.config._internal) == null ? void 0 : _a.currentDate) == null ? void 0 : _b.call(_a)) != null ? _c : /* @__PURE__ */ new Date();
881
+ const operation = options.operation;
882
+ const url = new URL(operation.pollingUrl);
883
+ if (!url.searchParams.has("id")) {
884
+ url.searchParams.set("id", operation.requestId);
885
+ }
886
+ const combinedHeaders = (0, import_provider_utils4.combineHeaders)(
887
+ await (0, import_provider_utils4.resolve)(this.config.headers),
888
+ options.headers
889
+ );
890
+ const pollingUrl = url.toString();
891
+ if (!isTrustedUrl(pollingUrl, this.config.baseURL)) {
892
+ throw new import_provider.AISDKError({
893
+ name: "BLACK_FOREST_LABS_VIDEO_GENERATION_ERROR",
894
+ message: `Black Forest Labs returned an untrusted polling URL: ${pollingUrl}`
895
+ });
896
+ }
897
+ const { value, responseHeaders } = await (0, import_provider_utils4.getFromApi)({
898
+ url: pollingUrl,
899
+ headers: combinedHeaders,
900
+ failedResponseHandler: bflFailedResponseHandler,
901
+ successfulResponseHandler: (0, import_provider_utils4.createJsonResponseHandler)(bflVideoPollSchema),
902
+ abortSignal: options.abortSignal,
903
+ fetch: this.config.fetch
904
+ });
905
+ const response = {
906
+ modelId: this.modelId,
907
+ timestamp: currentDate,
908
+ headers: responseHeaders
909
+ };
910
+ const { status, result } = value;
911
+ if (status === "Ready") {
912
+ const parsed = bflVideoResultSchema.safeParse(result);
913
+ if (!parsed.success) {
914
+ throw new import_provider.AISDKError({
915
+ name: "BLACK_FOREST_LABS_VIDEO_GENERATION_ERROR",
916
+ message: `Black Forest Labs reported the video as Ready but returned no result.sample URL. Request id: ${operation.requestId}`
917
+ });
918
+ }
919
+ return {
920
+ status: "completed",
921
+ videos: [
922
+ {
923
+ type: "url",
924
+ url: parsed.data.sample,
925
+ mediaType: "video/mp4"
926
+ }
927
+ ],
928
+ warnings: [],
929
+ providerMetadata: {
930
+ blackForestLabs: {
931
+ videos: [
932
+ {
933
+ id: operation.requestId,
934
+ videoUrl: parsed.data.sample,
935
+ ...parsed.data.seed != null && { seed: parsed.data.seed },
936
+ ...parsed.data.start_time != null && {
937
+ start_time: parsed.data.start_time
938
+ },
939
+ ...parsed.data.end_time != null && {
940
+ end_time: parsed.data.end_time
941
+ },
942
+ ...parsed.data.duration != null && {
943
+ duration: parsed.data.duration
944
+ },
945
+ ...parsed.data.draft_cache != null && {
946
+ draftCache: parsed.data.draft_cache
947
+ },
948
+ ...operation.cost != null && { cost: operation.cost },
949
+ ...operation.inputMegapixels != null && {
950
+ inputMegapixels: operation.inputMegapixels
951
+ },
952
+ ...operation.outputMegapixels != null && {
953
+ outputMegapixels: operation.outputMegapixels
954
+ }
955
+ }
956
+ ]
957
+ }
958
+ },
959
+ response
960
+ };
961
+ }
962
+ if (TERMINAL_FAILURE_STATUSES.has(status)) {
963
+ const detail = describePollDetails(value.details);
964
+ return {
965
+ status: "error",
966
+ error: `Black Forest Labs video generation failed with status "${status}"${detail != null ? `: ${detail}` : ""}. Request id: ${operation.requestId}`,
967
+ response
968
+ };
969
+ }
970
+ return { status: "pending", response };
971
+ }
972
+ async doGenerate(options) {
973
+ var _a, _b;
974
+ const startResult = await this.start(options);
975
+ const operation = startResult.operation;
976
+ const pollIntervalMillis = (_a = this.config.pollIntervalMillis) != null ? _a : DEFAULT_POLL_INTERVAL_MILLIS2;
977
+ const pollTimeoutMillis = (_b = this.config.pollTimeoutMillis) != null ? _b : DEFAULT_POLL_TIMEOUT_MILLIS2;
978
+ const startTime = Date.now();
979
+ while (true) {
980
+ await (0, import_provider_utils4.delay)(pollIntervalMillis, { abortSignal: options.abortSignal });
981
+ if (Date.now() - startTime > pollTimeoutMillis) {
982
+ throw new import_provider.AISDKError({
983
+ name: "BLACK_FOREST_LABS_VIDEO_GENERATION_TIMEOUT",
984
+ message: `Black Forest Labs video generation timed out after ${pollTimeoutMillis}ms. Request id: ${operation.requestId}`
985
+ });
986
+ }
987
+ const statusResult = await this.getStatus({
988
+ operation,
989
+ headers: options.headers,
990
+ abortSignal: options.abortSignal
991
+ });
992
+ if (statusResult.status === "pending") {
993
+ continue;
994
+ }
995
+ if (statusResult.status === "error") {
996
+ throw new import_provider.AISDKError({
997
+ name: "BLACK_FOREST_LABS_VIDEO_GENERATION_FAILED",
998
+ message: statusResult.error
999
+ });
1000
+ }
1001
+ return {
1002
+ videos: statusResult.videos,
1003
+ warnings: [...startResult.warnings, ...statusResult.warnings],
1004
+ providerMetadata: statusResult.providerMetadata,
1005
+ response: statusResult.response
1006
+ };
1007
+ }
1008
+ }
1009
+ };
1010
+ var bflVideoSubmitSchema = import_v44.z.object({
1011
+ id: import_v44.z.string(),
1012
+ polling_url: import_v44.z.url(),
1013
+ cost: import_v44.z.number().nullish(),
1014
+ input_mp: import_v44.z.number().nullish(),
1015
+ output_mp: import_v44.z.number().nullish()
1016
+ });
1017
+ var bflVideoResultSchema = import_v44.z.object({
1018
+ sample: import_v44.z.url(),
1019
+ seed: import_v44.z.number().nullish(),
1020
+ start_time: import_v44.z.number().nullish(),
1021
+ end_time: import_v44.z.number().nullish(),
1022
+ duration: import_v44.z.number().nullish(),
1023
+ draft_cache: import_v44.z.string().nullish()
1024
+ });
1025
+ var bflVideoPollSchema = import_v44.z.object({
1026
+ status: import_v44.z.string().optional(),
1027
+ state: import_v44.z.string().optional(),
1028
+ details: import_v44.z.unknown().optional(),
1029
+ result: import_v44.z.unknown().optional()
1030
+ }).refine((v) => v.status != null || v.state != null, {
1031
+ message: "Missing status in Black Forest Labs poll response"
1032
+ }).transform((v) => {
1033
+ var _a;
1034
+ return {
1035
+ status: (_a = v.status) != null ? _a : v.state,
1036
+ details: v.details,
1037
+ result: v.result
1038
+ };
1039
+ });
405
1040
 
406
1041
  // src/version.ts
407
- var VERSION = true ? "1.0.49" : "0.0.0-test";
1042
+ var VERSION = true ? "1.0.50" : "0.0.0-test";
408
1043
 
409
1044
  // src/black-forest-labs-provider.ts
410
1045
  var defaultBaseURL = "https://api.bfl.ai/v1";
411
1046
  function createBlackForestLabs(options = {}) {
412
1047
  var _a;
413
- const baseURL = (0, import_provider_utils2.withoutTrailingSlash)((_a = options.baseURL) != null ? _a : defaultBaseURL);
414
- const getHeaders = () => (0, import_provider_utils2.withUserAgentSuffix)(
1048
+ const baseURL = (0, import_provider_utils5.withoutTrailingSlash)((_a = options.baseURL) != null ? _a : defaultBaseURL);
1049
+ const getHeaders = () => (0, import_provider_utils5.withUserAgentSuffix)(
415
1050
  {
416
- "x-key": (0, import_provider_utils2.loadApiKey)({
1051
+ "x-key": (0, import_provider_utils5.loadApiKey)({
417
1052
  apiKey: options.apiKey,
418
1053
  environmentVariableName: "BFL_API_KEY",
419
1054
  description: "Black Forest Labs"
@@ -430,8 +1065,16 @@ function createBlackForestLabs(options = {}) {
430
1065
  pollIntervalMillis: options.pollIntervalMillis,
431
1066
  pollTimeoutMillis: options.pollTimeoutMillis
432
1067
  });
1068
+ const createVideoModel = (modelId) => new BlackForestLabsVideoModel(modelId, {
1069
+ provider: "black-forest-labs.video",
1070
+ baseURL: baseURL != null ? baseURL : defaultBaseURL,
1071
+ headers: getHeaders,
1072
+ fetch: options.fetch,
1073
+ pollIntervalMillis: options.pollIntervalMillis,
1074
+ pollTimeoutMillis: options.pollTimeoutMillis
1075
+ });
433
1076
  const embeddingModel = (modelId) => {
434
- throw new import_provider.NoSuchModelError({
1077
+ throw new import_provider2.NoSuchModelError({
435
1078
  modelId,
436
1079
  modelType: "embeddingModel"
437
1080
  });
@@ -440,8 +1083,10 @@ function createBlackForestLabs(options = {}) {
440
1083
  specificationVersion: "v3",
441
1084
  imageModel: createImageModel,
442
1085
  image: createImageModel,
1086
+ videoModel: createVideoModel,
1087
+ video: createVideoModel,
443
1088
  languageModel: (modelId) => {
444
- throw new import_provider.NoSuchModelError({
1089
+ throw new import_provider2.NoSuchModelError({
445
1090
  modelId,
446
1091
  modelType: "languageModel"
447
1092
  });