@picsart/ai-sdk 6.40.0 → 6.42.0

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.
Files changed (3) hide show
  1. package/index.d.ts +23 -0
  2. package/index.js +170 -8
  3. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -650,6 +650,8 @@ type ModelInputById = {
650
650
  "gpt-image-2.5-flare": {
651
651
  prompt: string;
652
652
  aspectRatio?: "1:1" | "3:2" | "2:3" | "16:9" | "9:16" | "4:3" | "3:4" | "auto";
653
+ resolution?: "1K" | "2K" | "4K";
654
+ size?: string;
653
655
  quality?: "max" | "xhigh" | "high" | "medium" | "low";
654
656
  background?: "opaque" | "transparent";
655
657
  outputFormat?: "png" | "jpeg" | "webp";
@@ -659,6 +661,8 @@ type ModelInputById = {
659
661
  "gpt-image-2.5-sunburst": {
660
662
  prompt: string;
661
663
  aspectRatio?: "1:1" | "3:2" | "2:3" | "16:9" | "9:16" | "4:3" | "3:4" | "auto";
664
+ resolution?: "1K" | "2K" | "4K";
665
+ size?: string;
662
666
  quality?: "max" | "xhigh" | "high" | "medium" | "low";
663
667
  background?: "opaque" | "transparent";
664
668
  outputFormat?: "png" | "jpeg" | "webp";
@@ -728,6 +732,15 @@ type ModelInputById = {
728
732
  prompt: string;
729
733
  voiceId?: string;
730
734
  };
735
+ "hailuo-02": {
736
+ prompt: string;
737
+ enhancePrompt?: boolean;
738
+ resolution?: "512P" | "768P" | "1080P";
739
+ duration?: 6 | 10;
740
+ startFrame?: string;
741
+ endFrame?: string;
742
+ imageUrls?: string[];
743
+ };
731
744
  "hailuo-2.3": {
732
745
  prompt: string;
733
746
  enhancePrompt?: boolean;
@@ -2637,6 +2650,8 @@ interface GenerationContext {
2637
2650
  /** Qwen 3.0 family — thinking mode (requires prompt_extend), sent as `enable_thinking`. */
2638
2651
  enableThinking?: boolean;
2639
2652
  }
2653
+ /** See `ModelDefinition.validateInput`. */
2654
+ type InputValidator = (input: Record<string, unknown>) => void;
2640
2655
  type PayloadBuilder<TContext extends GenerationContext = GenerationContext> = (ctx: TContext) => object;
2641
2656
  /** Lightweight runtime schema contract used by SDK integrations. */
2642
2657
  interface RuntimeSchema<T = unknown> {
@@ -2727,6 +2742,13 @@ interface ModelDefinition {
2727
2742
  paramConfig: ModelParams;
2728
2743
  /** Declarative inter-parameter constraints (e.g. "1080p requires 8s duration"). */
2729
2744
  constraints?: Constraint[];
2745
+ /**
2746
+ * Model-specific input check that the declarative layer cannot express —
2747
+ * a value format, or a "this OR those, never both" rule. Runs after the
2748
+ * per-param and constraint validation, on the raw input (no defaults
2749
+ * merged), and throws an `Error` whose message names the offending param.
2750
+ */
2751
+ validateInput?: InputValidator;
2730
2752
  /** Payload builder. Optional — omit for pass-through (param values sent as-is). */
2731
2753
  buildPayload?: PayloadBuilder;
2732
2754
  /** I2V/edit payload builder when different from buildPayload. */
@@ -3565,6 +3587,7 @@ declare const Models: {
3565
3587
  readonly GrokImagineVideo15: "grok-imagine-video-1.5";
3566
3588
  readonly GrokImagineVideo15Lite: "grok-imagine-video-1.5-lite";
3567
3589
  readonly GrokTts: "grok-tts";
3590
+ readonly Hailuo02: "hailuo-02";
3568
3591
  readonly Hailuo23: "hailuo-2.3";
3569
3592
  readonly Hailuo23Fast: "hailuo-2.3-fast";
3570
3593
  readonly Hailuo23FastPro: "hailuo-2.3-fast-pro";
package/index.js CHANGED
@@ -591,7 +591,7 @@ function validateDescriptor(key, d, val, required) {
591
591
  function isAbsent(val) {
592
592
  return val == null || typeof val === "string" && val.trim().length === 0 || Array.isArray(val) && val.length === 0;
593
593
  }
594
- function validateAll(params2, input, constraints) {
594
+ function validateAll(params2, input, constraints, validateInput) {
595
595
  for (const [key, entry] of Object.entries(params2)) {
596
596
  validateDescriptor(key, entry.descriptor, input[key], entry.required);
597
597
  }
@@ -600,6 +600,7 @@ function validateAll(params2, input, constraints) {
600
600
  throw new Error(requirement.reason ? `"${key}" is required: ${requirement.reason}` : `"${key}" is required`);
601
601
  }
602
602
  }
603
+ validateInput?.(input);
603
604
  }
604
605
  function descriptorsToSchema(params2) {
605
606
  const schema = {};
@@ -1209,6 +1210,7 @@ function defineModels(provider, configs) {
1209
1210
  if (c.release !== void 0) model.release = c.release;
1210
1211
  if (c.modelId !== void 0) model.modelId = c.modelId;
1211
1212
  if (c.constraints !== void 0) model.constraints = c.constraints;
1213
+ if (c.validateInput !== void 0) model.validateInput = c.validateInput;
1212
1214
  const contract = createModelContract(model);
1213
1215
  model.outputSchema = c.outputSchema ?? contract.output;
1214
1216
  MODELS40.push(model);
@@ -3437,10 +3439,70 @@ var minimaxH3Constraints = [
3437
3439
  audioUrls: { disabled: true, reason: AUDIO_NEEDS_VISUAL2 }
3438
3440
  } }
3439
3441
  ];
3442
+ var HAILUO_02_1080P_6S = "1080P supports a 6s duration only.";
3443
+ var HAILUO_02_512P_I2V = "512P needs a start frame and has no end frame.";
3444
+ var HAILUO_02_ONE_SOURCE = "Use either the start frame or the start image.";
3445
+ var hailuo02Constraints = [
3446
+ { when: { resolution: { is: "1080P" } }, then: {
3447
+ duration: { allowed: [6], reason: HAILUO_02_1080P_6S }
3448
+ } },
3449
+ { when: { duration: { is: 10 } }, then: {
3450
+ resolution: { allowed: ["512P", "768P"], reason: HAILUO_02_1080P_6S }
3451
+ } },
3452
+ { when: { startFrame: { exists: false }, imageUrls: { exists: false } }, then: {
3453
+ endFrame: { disabled: true, reason: LAST_NEEDS_FIRST },
3454
+ resolution: { allowed: ["768P", "1080P"], reason: HAILUO_02_512P_I2V }
3455
+ } },
3456
+ { when: { startFrame: { exists: true } }, then: {
3457
+ imageUrls: { disabled: true, reason: HAILUO_02_ONE_SOURCE }
3458
+ } },
3459
+ { when: { imageUrls: { exists: true } }, then: {
3460
+ startFrame: { disabled: true, reason: HAILUO_02_ONE_SOURCE }
3461
+ } },
3462
+ { when: { endFrame: { exists: true } }, then: {
3463
+ resolution: { allowed: ["768P", "1080P"], reason: HAILUO_02_512P_I2V }
3464
+ } },
3465
+ { when: { resolution: { is: "512P" } }, then: {
3466
+ endFrame: { disabled: true, reason: HAILUO_02_512P_I2V }
3467
+ } }
3468
+ ];
3440
3469
  var base = {
3441
3470
  mode: "video"
3442
3471
  };
3443
3472
  var { MODELS: MODELS10 } = defineModels("minimax", [
3473
+ {
3474
+ // Builder lives in hailuo.payloads.ts. One task for every mode and
3475
+ // resolution — the worker picks text- or image-to-video from image_url
3476
+ // and resolves pricing per mode and resolution.
3477
+ // Preview until minimax/hailuo-02/video-generation is deployed.
3478
+ ...base,
3479
+ id: "hailuo-02",
3480
+ name: "Hailuo 02",
3481
+ modelId: "minimax-hailuo-02",
3482
+ addedAt: "2026-08-15",
3483
+ release: "preview",
3484
+ inputType: "t2v",
3485
+ workflow: "minimax/hailuo-02/video-generation",
3486
+ estimatedTime: 300,
3487
+ description: "Up to 1080p video from text or a start/end frame, with strong physics and instruction following.",
3488
+ features: [
3489
+ feat("Start Frame", "frame"),
3490
+ feat("End Frame", "frame"),
3491
+ feat("1080p", "resolution"),
3492
+ feat("10 sec", "duration")
3493
+ ],
3494
+ paramConfig: {
3495
+ ...params.prompt({ maxLength: 2e3 }),
3496
+ ...params.enhancePrompt(),
3497
+ ...params.resolution(["512P", "768P", "1080P"], "768P"),
3498
+ ...params.duration([6, 10]),
3499
+ ...params.startFrame(),
3500
+ ...params.endFrame(),
3501
+ // Same first frame for callers that send images as imageUrls.
3502
+ ...params.imageInput(1, "Start Image")
3503
+ },
3504
+ constraints: hailuo02Constraints
3505
+ },
3444
3506
  {
3445
3507
  ...base,
3446
3508
  id: "hailuo-2.3",
@@ -3556,6 +3618,25 @@ var { MODELS: MODELS10 } = defineModels("minimax", [
3556
3618
  }
3557
3619
  ]);
3558
3620
 
3621
+ // src/vendors/catalog/hailuo.payloads.ts
3622
+ var buildHailuo02Payload = (input) => {
3623
+ const startFrame = input.startFrame || input.imageUrls?.[0];
3624
+ if (input.endFrame && !startFrame) {
3625
+ throw new ApiError("Hailuo 02: an end frame requires a start frame.", { status: 400, code: "validation_error" });
3626
+ }
3627
+ return {
3628
+ prompt: input.prompt,
3629
+ ...input.enhancePrompt !== void 0 ? { prompt_optimizer: input.enhancePrompt } : {},
3630
+ ...input.resolution ? { resolution: input.resolution } : {},
3631
+ ...input.duration ? { duration: input.duration } : {},
3632
+ ...startFrame ? { image_url: startFrame } : {},
3633
+ ...input.endFrame ? { end_image_url: input.endFrame } : {}
3634
+ };
3635
+ };
3636
+ registerPayloads(MODELS10, {
3637
+ "hailuo-02": buildHailuo02Payload
3638
+ });
3639
+
3559
3640
  // src/vendors/catalog/wan.ts
3560
3641
  var buildWanT2VPayload = (ctx) => ({
3561
3642
  prompt: ctx.prompt,
@@ -7076,6 +7157,54 @@ var GPT_IMAGE_2_AR_TO_SIZE = {
7076
7157
  "4:3": "1360x1024",
7077
7158
  "3:4": "1024x1360"
7078
7159
  };
7160
+ var GPT_IMAGE_25_SIZES = {
7161
+ "1K": GPT_IMAGE_2_AR_TO_SIZE,
7162
+ "2K": {
7163
+ "1:1": "2048x2048",
7164
+ "3:2": "2496x1664",
7165
+ "2:3": "1664x2496",
7166
+ "16:9": "2560x1440",
7167
+ "9:16": "1440x2560",
7168
+ "4:3": "2304x1728",
7169
+ "3:4": "1728x2304"
7170
+ },
7171
+ "4K": {
7172
+ "1:1": "2880x2880",
7173
+ "3:2": "3504x2336",
7174
+ "2:3": "2336x3504",
7175
+ "16:9": "3840x2160",
7176
+ "9:16": "2160x3840",
7177
+ "4:3": "3264x2448",
7178
+ "3:4": "2448x3264"
7179
+ }
7180
+ };
7181
+ var GPT_IMAGE_SIZE_PATTERN = /^([1-9]\d*)x([1-9]\d*)$/;
7182
+ var GPT_IMAGE_SIZE_GRID = 16;
7183
+ var GPT_IMAGE_MAX_ASPECT_RATIO = 3;
7184
+ var GPT_IMAGE_MAX_EDGE = 3840;
7185
+ var GPT_IMAGE_MIN_PIXELS = 655360;
7186
+ var GPT_IMAGE_MAX_PIXELS = 8294400;
7187
+ function gptImageSizeViolation(size) {
7188
+ const match = GPT_IMAGE_SIZE_PATTERN.exec(size);
7189
+ if (!match) return "must be WIDTHxHEIGHT, e.g. 2048x1152";
7190
+ const width = Number(match[1]);
7191
+ const height = Number(match[2]);
7192
+ if (width % GPT_IMAGE_SIZE_GRID !== 0 || height % GPT_IMAGE_SIZE_GRID !== 0) {
7193
+ return `both dimensions must be divisible by ${GPT_IMAGE_SIZE_GRID}`;
7194
+ }
7195
+ const ratio = width / height;
7196
+ if (ratio > GPT_IMAGE_MAX_ASPECT_RATIO || ratio < 1 / GPT_IMAGE_MAX_ASPECT_RATIO) {
7197
+ return "the aspect ratio must be between 1:3 and 3:1";
7198
+ }
7199
+ if (Math.max(width, height) > GPT_IMAGE_MAX_EDGE) {
7200
+ return `the longest edge must be at most ${GPT_IMAGE_MAX_EDGE}`;
7201
+ }
7202
+ const pixels = width * height;
7203
+ if (pixels < GPT_IMAGE_MIN_PIXELS || pixels > GPT_IMAGE_MAX_PIXELS) {
7204
+ return `the total pixel count must be between ${GPT_IMAGE_MIN_PIXELS} and ${GPT_IMAGE_MAX_PIXELS}`;
7205
+ }
7206
+ return null;
7207
+ }
7079
7208
  var buildGptImage1Payload = (ctx) => ({
7080
7209
  prompt: ctx.prompt,
7081
7210
  model: "gpt-image-1",
@@ -7140,6 +7269,7 @@ var buildGptImage2EditPayload = (ctx) => ({
7140
7269
  var GPT_IMAGE_PROMPT_MAX = 32e3;
7141
7270
  var GPT_IMAGE_25_QUALITIES = ["max", "xhigh", "high", "medium", "low"];
7142
7271
  var GPT_IMAGE_25_ASPECT_RATIOS = ["1:1", "3:2", "2:3", "16:9", "9:16", "4:3", "3:4", "auto"];
7272
+ var GPT_IMAGE_25_RESOLUTIONS = Object.keys(GPT_IMAGE_25_SIZES);
7143
7273
  var GPT_IMAGE_25_MAX_INPUT_IMAGES = 16;
7144
7274
  var gptImage2Constraints = [
7145
7275
  {
@@ -7157,6 +7287,25 @@ var gptImageBgConstraints = [
7157
7287
  then: { outputFormat: { allowed: ["png", "webp"], reason: "Transparent background needs PNG or WEBP \u2014 JPEG has no alpha channel." } }
7158
7288
  }
7159
7289
  ];
7290
+ var gptImage25SizeConstraints = [
7291
+ {
7292
+ when: { size: { exists: true } },
7293
+ then: {
7294
+ aspectRatio: { disabled: true, reason: "A custom size sets the output size." },
7295
+ resolution: { disabled: true, reason: "A custom size sets the output size." }
7296
+ }
7297
+ },
7298
+ {
7299
+ when: { aspectRatio: { is: "auto" } },
7300
+ then: { resolution: { disabled: true, reason: "Auto lets the model pick the size." } }
7301
+ }
7302
+ ];
7303
+ var isGiven = (value) => value != null && !(typeof value === "string" && value.trim().length === 0);
7304
+ var validateGptImage25Input = (input) => {
7305
+ if (!isGiven(input.size)) return;
7306
+ const violation = gptImageSizeViolation(String(input.size).trim());
7307
+ if (violation) throw new Error(`"size" ${violation}`);
7308
+ };
7160
7309
  var { MODELS: MODELS23 } = defineModels("openai", [
7161
7310
  // ── Image ─────────────────────────────────────────
7162
7311
  {
@@ -7173,13 +7322,16 @@ var { MODELS: MODELS23 } = defineModels("openai", [
7173
7322
  paramConfig: {
7174
7323
  ...params.prompt({ maxLength: GPT_IMAGE_PROMPT_MAX }),
7175
7324
  ...params.aspectRatio(GPT_IMAGE_25_ASPECT_RATIOS, "1:1"),
7325
+ ...params.resolution(GPT_IMAGE_25_RESOLUTIONS, "1K"),
7326
+ ...p.text("size", { label: "Custom Size", placeholder: "WIDTHxHEIGHT, e.g. 2048x1152" }),
7176
7327
  ...p.quality(GPT_IMAGE_25_QUALITIES, "high"),
7177
7328
  ...p.enum("background", ["opaque", "transparent"], "opaque", { label: "Background" }),
7178
7329
  ...p.enum("outputFormat", ["png", "jpeg", "webp"], "png", { label: "Format" }),
7179
7330
  ...params.count(),
7180
7331
  ...params.imageInput(GPT_IMAGE_25_MAX_INPUT_IMAGES, "Source Images")
7181
7332
  },
7182
- constraints: gptImageBgConstraints
7333
+ constraints: [...gptImageBgConstraints, ...gptImage25SizeConstraints],
7334
+ validateInput: validateGptImage25Input
7183
7335
  },
7184
7336
  {
7185
7337
  id: "gpt-image-2.5-flare",
@@ -7195,13 +7347,16 @@ var { MODELS: MODELS23 } = defineModels("openai", [
7195
7347
  paramConfig: {
7196
7348
  ...params.prompt({ maxLength: GPT_IMAGE_PROMPT_MAX }),
7197
7349
  ...params.aspectRatio(GPT_IMAGE_25_ASPECT_RATIOS, "1:1"),
7350
+ ...params.resolution(GPT_IMAGE_25_RESOLUTIONS, "1K"),
7351
+ ...p.text("size", { label: "Custom Size", placeholder: "WIDTHxHEIGHT, e.g. 2048x1152" }),
7198
7352
  ...p.quality(GPT_IMAGE_25_QUALITIES, "high"),
7199
7353
  ...p.enum("background", ["opaque", "transparent"], "opaque", { label: "Background" }),
7200
7354
  ...p.enum("outputFormat", ["png", "jpeg", "webp"], "png", { label: "Format" }),
7201
7355
  ...params.count(),
7202
7356
  ...params.imageInput(GPT_IMAGE_25_MAX_INPUT_IMAGES, "Source Images")
7203
7357
  },
7204
- constraints: gptImageBgConstraints
7358
+ constraints: [...gptImageBgConstraints, ...gptImage25SizeConstraints],
7359
+ validateInput: validateGptImage25Input
7205
7360
  },
7206
7361
  {
7207
7362
  id: "gpt-image-2",
@@ -7284,12 +7439,17 @@ var { MODELS: MODELS23 } = defineModels("openai", [
7284
7439
  ]);
7285
7440
 
7286
7441
  // src/vendors/catalog/openai.payloads.ts
7287
- var resolveSize = (aspectRatio, fallback) => aspectRatio === "auto" ? "auto" : GPT_IMAGE_2_AR_TO_SIZE[aspectRatio ?? ""] ?? fallback;
7442
+ var resolveSize = (input, defaultAspectRatio) => {
7443
+ if (input.size?.trim()) return input.size.trim();
7444
+ const aspectRatio = input.aspectRatio ?? defaultAspectRatio;
7445
+ if (aspectRatio === "auto") return "auto";
7446
+ return GPT_IMAGE_25_SIZES[input.resolution ?? "1K"]?.[aspectRatio] ?? "1024x1024";
7447
+ };
7288
7448
  var generateFor = (model) => (input) => ({
7289
7449
  prompt: input.prompt,
7290
7450
  model,
7291
7451
  n: input.count ?? 1,
7292
- size: resolveSize(input.aspectRatio, "1024x1024"),
7452
+ size: resolveSize(input, "1:1"),
7293
7453
  quality: input.quality ?? "high",
7294
7454
  ...input.background ? { background: input.background } : {},
7295
7455
  ...input.outputFormat ? { output_format: input.outputFormat } : {}
@@ -7299,7 +7459,7 @@ var editFor = (model) => (input) => ({
7299
7459
  model,
7300
7460
  images: input.imageUrls ?? [],
7301
7461
  n: input.count ?? 1,
7302
- size: resolveSize(input.aspectRatio, "auto"),
7462
+ size: resolveSize(input, "auto"),
7303
7463
  quality: input.quality ?? "high",
7304
7464
  ...input.background ? { background: input.background } : {},
7305
7465
  ...input.outputFormat ? { output_format: input.outputFormat } : {}
@@ -11296,7 +11456,7 @@ function buildInputSchema(model) {
11296
11456
  parse(input) {
11297
11457
  requireObject(input, `Invalid input for model "${model.id}"`);
11298
11458
  try {
11299
- validateAll(model.paramConfig, input, model.constraints);
11459
+ validateAll(model.paramConfig, input, model.constraints, model.validateInput);
11300
11460
  } catch (err) {
11301
11461
  if (err instanceof ApiError) throw err;
11302
11462
  throw new ApiError(err instanceof Error ? err.message : String(err), {
@@ -12074,7 +12234,7 @@ var ModelDescriptorImpl = class {
12074
12234
  return { valid: false, errors: [`Invalid input for model "${this.def.id}"`] };
12075
12235
  }
12076
12236
  try {
12077
- validateAll(this.def.paramConfig, input, this.def.constraints);
12237
+ validateAll(this.def.paramConfig, input, this.def.constraints, this.def.validateInput);
12078
12238
  return { valid: true };
12079
12239
  } catch (err) {
12080
12240
  return { valid: false, errors: [err instanceof Error ? err.message : String(err)] };
@@ -14870,6 +15030,7 @@ var GrokImagineVideo = "grok-imagine-video";
14870
15030
  var GrokImagineVideo15 = "grok-imagine-video-1.5";
14871
15031
  var GrokImagineVideo15Lite = "grok-imagine-video-1.5-lite";
14872
15032
  var GrokTts = "grok-tts";
15033
+ var Hailuo02 = "hailuo-02";
14873
15034
  var Hailuo23 = "hailuo-2.3";
14874
15035
  var Hailuo23Fast = "hailuo-2.3-fast";
14875
15036
  var Hailuo23FastPro = "hailuo-2.3-fast-pro";
@@ -15136,6 +15297,7 @@ var Models = {
15136
15297
  GrokImagineVideo15,
15137
15298
  GrokImagineVideo15Lite,
15138
15299
  GrokTts,
15300
+ Hailuo02,
15139
15301
  Hailuo23,
15140
15302
  Hailuo23Fast,
15141
15303
  Hailuo23FastPro,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@picsart/ai-sdk",
3
- "version": "6.40.0",
3
+ "version": "6.42.0",
4
4
  "type": "module",
5
5
  "description": "Type-safe SDK for 100+ AI models — image, video, audio, and text generation with Picsart",
6
6
  "license": "MIT",