@picsart/ai-sdk 6.18.1 → 6.20.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.
@@ -149,7 +149,7 @@ interface ChatCompletionsCommand$1 {
149
149
  tools?: FunctionTool[];
150
150
  service_tier?: ServiceTier;
151
151
  }
152
- type ChatCompletionModels = "gpt-6-astra" | "gpt-6-sol" | "gpt-6-luna" | "gpt-5" | "gpt-5.1" | "gpt-5.2" | "gpt-5.2-pro" | "gpt-5.3-codex" | "gpt-5.4" | "gpt-5.4-pro" | "gpt-5.4-mini" | "gpt-5.4-nano" | "gpt-5.5" | "gpt-5.5-pro" | "gpt-5.6-sol" | "gpt-5.6-terra" | "gpt-5.6-luna" | "gpt-5-pro" | "gpt-5-mini" | "gpt-5-nano" | "gpt-5-search-api" | "gpt-4o" | "gpt-4o-mini" | "gpt-4.1" | "gpt-4.1-mini" | "gpt-4.1-nano" | "claude-sonnet-4-5" | "claude-sonnet-4-6" | "claude-sonnet-5" | "claude-opus-4-8" | "claude-opus-5" | "claude-haiku-4-5" | "claude-fable-5" | "claude-fable-5-1" | "gemini-3.1-pro-preview" | "gemini-3-flash-preview" | "gemini-3.8-flash" | "gemini-3.7-flash" | "gemini-3.6-flash" | "gemini-3.5-flash" | "gemini-3.5-flash-lite" | "gemini-3.1-flash-lite" | "gemini-2.5-flash" | "gemini-2.5-pro";
152
+ type ChatCompletionModels = "gpt-6-astra" | "gpt-6-sol" | "gpt-6-luna" | "gpt-5" | "gpt-5.1" | "gpt-5.2" | "gpt-5.2-pro" | "gpt-5.3-codex" | "gpt-5.4" | "gpt-5.4-pro" | "gpt-5.4-mini" | "gpt-5.4-nano" | "gpt-5.5" | "gpt-5.5-pro" | "gpt-5.6-sol" | "gpt-5.6-terra" | "gpt-5.6-luna" | "gpt-5-pro" | "gpt-5-mini" | "gpt-5-nano" | "gpt-5-search-api" | "gpt-4o" | "gpt-4o-mini" | "gpt-4.1" | "gpt-4.1-mini" | "gpt-4.1-nano" | "claude-sonnet-4-5" | "claude-sonnet-4-6" | "claude-sonnet-5" | "claude-opus-4-8" | "claude-opus-5" | "claude-opus-5-5" | "claude-haiku-4-5" | "claude-fable-5" | "claude-fable-5-1" | "gemini-3.1-pro-preview" | "gemini-3-flash-preview" | "gemini-3.8-flash" | "gemini-3.7-flash" | "gemini-3.6-flash" | "gemini-3.5-flash" | "gemini-3.5-flash-lite" | "gemini-3.1-flash-lite" | "gemini-2.5-flash" | "gemini-2.5-pro";
153
153
  interface MessageParam {
154
154
  name?: string;
155
155
  role: "developer" | "system" | "user" | "assistant" | "tool";
@@ -206,7 +206,7 @@ interface ChatCompletionResponse {
206
206
  interface ChatCompletionResult {
207
207
  id: string;
208
208
  created: number;
209
- model: "gpt-6-astra" | "gpt-6-sol" | "gpt-6-luna" | "gpt-5" | "gpt-5.1" | "gpt-5.2" | "gpt-5.2-pro" | "gpt-5.3-codex" | "gpt-5.4" | "gpt-5.4-pro" | "gpt-5.4-mini" | "gpt-5.4-nano" | "gpt-5.5" | "gpt-5.5-pro" | "gpt-5.6-sol" | "gpt-5.6-terra" | "gpt-5.6-luna" | "gpt-5-pro" | "gpt-5-mini" | "gpt-5-nano" | "gpt-5-search-api" | "gpt-4o" | "gpt-4o-mini" | "gpt-4.1" | "gpt-4.1-mini" | "gpt-4.1-nano" | "claude-sonnet-4-5" | "claude-sonnet-4-6" | "claude-sonnet-5" | "claude-opus-4-8" | "claude-opus-5" | "claude-haiku-4-5" | "claude-fable-5" | "claude-fable-5-1" | "gemini-3.1-pro-preview" | "gemini-3-flash-preview" | "gemini-3.8-flash" | "gemini-3.7-flash" | "gemini-3.6-flash" | "gemini-3.5-flash" | "gemini-3.5-flash-lite" | "gemini-3.1-flash-lite" | "gemini-2.5-flash" | "gemini-2.5-pro";
209
+ model: "gpt-6-astra" | "gpt-6-sol" | "gpt-6-luna" | "gpt-5" | "gpt-5.1" | "gpt-5.2" | "gpt-5.2-pro" | "gpt-5.3-codex" | "gpt-5.4" | "gpt-5.4-pro" | "gpt-5.4-mini" | "gpt-5.4-nano" | "gpt-5.5" | "gpt-5.5-pro" | "gpt-5.6-sol" | "gpt-5.6-terra" | "gpt-5.6-luna" | "gpt-5-pro" | "gpt-5-mini" | "gpt-5-nano" | "gpt-5-search-api" | "gpt-4o" | "gpt-4o-mini" | "gpt-4.1" | "gpt-4.1-mini" | "gpt-4.1-nano" | "claude-sonnet-4-5" | "claude-sonnet-4-6" | "claude-sonnet-5" | "claude-opus-4-8" | "claude-opus-5" | "claude-opus-5-5" | "claude-haiku-4-5" | "claude-fable-5" | "claude-fable-5-1" | "gemini-3.1-pro-preview" | "gemini-3-flash-preview" | "gemini-3.8-flash" | "gemini-3.7-flash" | "gemini-3.6-flash" | "gemini-3.5-flash" | "gemini-3.5-flash-lite" | "gemini-3.1-flash-lite" | "gemini-2.5-flash" | "gemini-2.5-pro";
210
210
  choices: Choice[];
211
211
  usage: Usage$1;
212
212
  }
@@ -776,7 +776,7 @@ interface ClaudeV1MessagesCommand {
776
776
  context_management?: ClaudeContextManagement;
777
777
  options?: GenAIOptions$2E;
778
778
  }
779
- type ClaudeV1Models = "claude-opus-4-8" | "claude-opus-5" | "claude-sonnet-4-5" | "claude-sonnet-4-6" | "claude-sonnet-5" | "claude-haiku-4-5" | "claude-fable-5" | "claude-fable-5-1";
779
+ type ClaudeV1Models = "claude-opus-4-8" | "claude-opus-5" | "claude-opus-5-5" | "claude-sonnet-4-5" | "claude-sonnet-4-6" | "claude-sonnet-5" | "claude-haiku-4-5" | "claude-fable-5" | "claude-fable-5-1";
780
780
  interface ClaudeMessageParam {
781
781
  role: string;
782
782
  content: ClaudeContentBlock[];
@@ -9603,7 +9603,7 @@ interface CatalogPreviewModel {
9603
9603
 
9604
9604
  interface ImageSegmentationCommand {
9605
9605
  image_url: string;
9606
- model: "picsart-multimatting-v13" | "picsart-sky-v1" | "preview-picsart-multimatting-v13" | "preview-picsart-sky-v1";
9606
+ model?: "picsart-multimatting-v13" | "picsart-sky-v1";
9607
9607
  segmentation_class?: "all" | "background" | "hair" | "skin" | "lips" | "eyes" | "clothes" | "glasses" | "teeth" | "foreground";
9608
9608
  options?: GenAIOptions$C;
9609
9609
  }
package/index.d.ts CHANGED
@@ -1754,6 +1754,7 @@ type ModelInputById = {
1754
1754
  video_input: boolean;
1755
1755
  signature: string;
1756
1756
  };
1757
+ omniReferenceTaskType?: "auto" | "reference" | "edit" | "extend";
1757
1758
  imageUrls?: string[];
1758
1759
  videoUrls?: string[];
1759
1760
  audioUrls?: string[];
@@ -1798,6 +1799,7 @@ type ModelInputById = {
1798
1799
  video_input: boolean;
1799
1800
  signature: string;
1800
1801
  };
1802
+ omniReferenceTaskType?: "auto" | "reference" | "edit" | "extend";
1801
1803
  imageUrls?: string[];
1802
1804
  videoUrls?: string[];
1803
1805
  audioUrls?: string[];
@@ -2274,6 +2276,8 @@ interface EntryMeta {
2274
2276
  catalogOptions?: readonly unknown[];
2275
2277
  disabled?: boolean;
2276
2278
  disabledReason?: string;
2279
+ /** Why the param is required, when a constraint made it so (see `Restriction`). */
2280
+ requiredReason?: string;
2277
2281
  }
2278
2282
  type EnumEntry = EntryMeta & EnumDescriptor<string | number>;
2279
2283
  type CatalogEntry = EntryMeta & CatalogDescriptor;
@@ -2553,6 +2557,12 @@ type ConstraintCondition = Record<string, ConditionOperator>;
2553
2557
  * - `disabled`: param is flagged as constrained — UI interprets per-param kind
2554
2558
  * (dropdowns grey out; text inputs like `prompt` stay editable but surface
2555
2559
  * the reason as an info banner).
2560
+ * - `required`: param becomes required while the condition holds. Expresses
2561
+ * cross-field rules a static `required` flag cannot, e.g. "a prompt or a
2562
+ * first-frame image": `when` both are absent, `then` the prompt is required.
2563
+ * Enforced by `validate()` and at submit, and reported by `paramsFor()` as
2564
+ * `required: true` with `requiredReason`, so a UI gate reads it like any
2565
+ * other required param.
2556
2566
  */
2557
2567
  type Restriction = {
2558
2568
  allowed: unknown[];
@@ -2560,6 +2570,9 @@ type Restriction = {
2560
2570
  } | {
2561
2571
  disabled: true;
2562
2572
  reason?: string;
2573
+ } | {
2574
+ required: true;
2575
+ reason?: string;
2563
2576
  };
2564
2577
  /** Declarative rule: when condition matches, apply restrictions to params. */
2565
2578
  interface Constraint {
package/index.js CHANGED
@@ -416,6 +416,63 @@ var require_build = __commonJS({
416
416
  }
417
417
  });
418
418
 
419
+ // src/core/constraints.ts
420
+ function normalize(r) {
421
+ if ("required" in r) return null;
422
+ if ("disabled" in r) return { kind: "disabled", reason: r.reason };
423
+ return { kind: "allowed", allowed: r.allowed, reason: r.reason };
424
+ }
425
+ function matchOperator(op, actual) {
426
+ if ("exists" in op) {
427
+ const has = actual != null && (!Array.isArray(actual) || actual.length > 0) && (typeof actual !== "string" || actual.trim().length > 0);
428
+ return op.exists ? has : !has;
429
+ }
430
+ if ("is" in op) return actual === op.is;
431
+ return false;
432
+ }
433
+ function matchCondition(when, values) {
434
+ return Object.entries(when).every(
435
+ ([key, op]) => matchOperator(op, values[key])
436
+ );
437
+ }
438
+ function merge(prev, next) {
439
+ if (!prev) return next;
440
+ if (prev.kind === "disabled" || next.kind === "disabled") {
441
+ return { kind: "disabled", reason: next.kind === "disabled" ? next.reason : prev.kind === "disabled" ? prev.reason : void 0 };
442
+ }
443
+ const allowed = new Set(next.allowed.map(String));
444
+ return {
445
+ kind: "allowed",
446
+ allowed: prev.allowed.filter((o) => allowed.has(String(o))),
447
+ reason: next.reason ?? prev.reason
448
+ };
449
+ }
450
+ function evaluateConstraints(constraints, values) {
451
+ const effects = /* @__PURE__ */ new Map();
452
+ if (!constraints?.length) return effects;
453
+ for (const rule of constraints) {
454
+ if (!matchCondition(rule.when, values)) continue;
455
+ for (const [key, restriction] of Object.entries(rule.then)) {
456
+ const normalized = normalize(restriction);
457
+ if (normalized) effects.set(key, merge(effects.get(key), normalized));
458
+ }
459
+ }
460
+ return effects;
461
+ }
462
+ function evaluateRequirements(constraints, values) {
463
+ const requirements = /* @__PURE__ */ new Map();
464
+ if (!constraints?.length) return requirements;
465
+ for (const rule of constraints) {
466
+ if (!matchCondition(rule.when, values)) continue;
467
+ for (const [key, restriction] of Object.entries(rule.then)) {
468
+ if ("required" in restriction && !requirements.has(key)) {
469
+ requirements.set(key, { reason: restriction.reason });
470
+ }
471
+ }
472
+ }
473
+ return requirements;
474
+ }
475
+
419
476
  // src/core/descriptors/utils.ts
420
477
  function extractDefaults(params2) {
421
478
  const defaults = {};
@@ -521,10 +578,18 @@ function validateDescriptor(key, d, val, required) {
521
578
  }
522
579
  }
523
580
  }
524
- function validateAll(params2, input) {
581
+ function isAbsent(val) {
582
+ return val == null || typeof val === "string" && val.trim().length === 0 || Array.isArray(val) && val.length === 0;
583
+ }
584
+ function validateAll(params2, input, constraints) {
525
585
  for (const [key, entry] of Object.entries(params2)) {
526
586
  validateDescriptor(key, entry.descriptor, input[key], entry.required);
527
587
  }
588
+ for (const [key, requirement] of evaluateRequirements(constraints, input)) {
589
+ if (isAbsent(input[key])) {
590
+ throw new Error(requirement.reason ? `"${key}" is required: ${requirement.reason}` : `"${key}" is required`);
591
+ }
592
+ }
528
593
  }
529
594
  function descriptorsToSchema(params2) {
530
595
  const schema = {};
@@ -2368,6 +2433,14 @@ var { MODELS: MODELS2 } = defineModels("ltx", [
2368
2433
  inputType: "a2v",
2369
2434
  description: "Generate video driven by an audio track \u2014 2-20s, optional image for first frame.",
2370
2435
  features: [feat("Audio Input", "audio"), feat("Image Input", "input"), feat("2\u201320 sec", "duration")],
2436
+ // Vendor: a prompt is required unless a first-frame image drives the scene.
2437
+ // Declared here so `validate()` and a UI gate see it; the builder's own
2438
+ // throw stays for callers that build a payload without validating.
2439
+ constraints: [
2440
+ { when: { prompt: { exists: false }, imageUrls: { exists: false } }, then: {
2441
+ prompt: { required: true, reason: "Add a prompt or a first-frame image." }
2442
+ } }
2443
+ ],
2371
2444
  paramConfig: {
2372
2445
  ...params.prompt({ required: false, maxLength: LTX_PROMPT_MAX }),
2373
2446
  ...params.audioInput("Audio Track", true),
@@ -3510,11 +3583,23 @@ var wanV3Constraints = [
3510
3583
  imageUrls: { disabled: true, reason: WAN_V3_FRAME_REF_REASON },
3511
3584
  videoUrls: { disabled: true, reason: WAN_V3_FRAME_REF_REASON },
3512
3585
  audioUrls: { disabled: true, reason: WAN_V3_FRAME_REF_REASON }
3586
+ } },
3587
+ // Vendor: either a prompt or media. With no media at all, the prompt is
3588
+ // required (the payload builder enforces the same rule for direct callers).
3589
+ { when: {
3590
+ prompt: { exists: false },
3591
+ startFrame: { exists: false },
3592
+ endFrame: { exists: false },
3593
+ imageUrls: { exists: false },
3594
+ videoUrls: { exists: false },
3595
+ audioUrls: { exists: false }
3596
+ }, then: {
3597
+ prompt: { required: true, reason: "Add a prompt or at least one frame or reference." }
3513
3598
  } }
3514
3599
  ];
3515
3600
  var wanV3Features = [feat("Image Input", "input"), feat("Video Input", "input"), feat("Audio", "audio"), feat("Start/End Frame", "frame"), feat("1080P", "resolution"), feat("Adaptive Ratio", "resolution")];
3516
3601
  var wanV3ParamConfig = {
3517
- // Vendor: 'either prompt or media' — the builder enforces the cross-field rule.
3602
+ // Vendor: 'either prompt or media' — declared in wanV3Constraints.
3518
3603
  ...params.prompt({ required: false, maxLength: 5e3 }),
3519
3604
  // Vendor: integer 2-30, or -1 = Smart duration mode (model picks the length).
3520
3605
  duration: {
@@ -4424,6 +4509,20 @@ var seedance25DraftConstraints = [
4424
4509
  then: { resolution: { allowed: [SEEDANCE_25_DRAFT_RESOLUTION], reason: SEEDANCE_25_DRAFT_RESOLUTION_REASON } }
4425
4510
  }
4426
4511
  ];
4512
+ var seedance25ContentRequiredConstraints = [
4513
+ {
4514
+ when: {
4515
+ prompt: { exists: false },
4516
+ imageUrls: { exists: false },
4517
+ videoUrls: { exists: false },
4518
+ audioUrls: { exists: false },
4519
+ startFrame: { exists: false },
4520
+ endFrame: { exists: false },
4521
+ draftTask: { exists: false }
4522
+ },
4523
+ then: { prompt: { required: true, reason: "Add a prompt or at least one image, video, or audio." } }
4524
+ }
4525
+ ];
4427
4526
  var seedance25DraftFinalConstraints = [
4428
4527
  ...seedance25DraftConstraints,
4429
4528
  {
@@ -4453,6 +4552,7 @@ var buildSeedance25PayloadFor = (modelAlias) => withSeedance25DraftMode(modelAli
4453
4552
  const refVideos = ctx.videoUrls ?? [];
4454
4553
  const refAudios = ctx.audioUrls ?? [];
4455
4554
  const usesFrame = Boolean(ctx.startFrame || ctx.endFrame);
4555
+ const { omniReferenceTaskType } = ctx;
4456
4556
  return {
4457
4557
  model: modelAlias,
4458
4558
  content: [
@@ -4482,7 +4582,8 @@ var buildSeedance25PayloadFor = (modelAlias) => withSeedance25DraftMode(modelAli
4482
4582
  resolution: ctx.resolution ?? "1080p",
4483
4583
  generate_audio: ctx.generateAudio ?? true,
4484
4584
  output_format: seedance25OutputFormat(ctx),
4485
- ...ctx.returnLastFrame ? { return_last_frame: true } : {}
4585
+ ...ctx.returnLastFrame ? { return_last_frame: true } : {},
4586
+ ...omniReferenceTaskType !== void 0 ? { omni_reference_task_type: omniReferenceTaskType } : {}
4486
4587
  };
4487
4588
  });
4488
4589
  var buildSeedance25VideoEditPayloadFor = (modelAlias) => withSeedance25DraftMode(modelAlias, (ctx) => ({
@@ -4501,6 +4602,7 @@ var buildSeedance25VideoEditPayloadFor = (modelAlias) => withSeedance25DraftMode
4501
4602
  resolution: ctx.resolution ?? "1080p",
4502
4603
  generate_audio: ctx.generateAudio ?? true,
4503
4604
  output_format: seedance25OutputFormat(ctx),
4605
+ omni_reference_task_type: "edit",
4504
4606
  ...ctx.returnLastFrame ? { return_last_frame: true } : {}
4505
4607
  }));
4506
4608
  var buildSeedance25VideoExtendPayloadFor = (modelAlias) => withSeedance25DraftMode(modelAlias, (ctx) => ({
@@ -4517,7 +4619,8 @@ var buildSeedance25VideoExtendPayloadFor = (modelAlias) => withSeedance25DraftMo
4517
4619
  duration: ctx.duration ?? 15,
4518
4620
  resolution: ctx.resolution ?? "1080p",
4519
4621
  generate_audio: ctx.generateAudio ?? true,
4520
- output_format: seedance25OutputFormat(ctx)
4622
+ output_format: seedance25OutputFormat(ctx),
4623
+ omni_reference_task_type: "extend"
4521
4624
  }));
4522
4625
  var SEEDANCE_AR = ["16:9", "9:16", "1:1", "4:3", "3:4", "21:9", "adaptive"];
4523
4626
  var SEEDANCE_25_FORMATS = ["mp4", "mov"];
@@ -4545,6 +4648,23 @@ var seedance25DraftTaskParam = {
4545
4648
  }
4546
4649
  }
4547
4650
  };
4651
+ var seedance25TaskTypeParam = {
4652
+ omniReferenceTaskType: {
4653
+ label: "Task Type",
4654
+ required: false,
4655
+ descriptor: {
4656
+ kind: "enum",
4657
+ valueType: "string",
4658
+ options: [
4659
+ { id: "auto", label: "Auto" },
4660
+ { id: "reference", label: "Reference" },
4661
+ { id: "edit", label: "Edit" },
4662
+ { id: "extend", label: "Extend" }
4663
+ ],
4664
+ default: "auto"
4665
+ }
4666
+ }
4667
+ };
4548
4668
  var { MODELS: MODELS13 } = defineModels("seedance", [
4549
4669
  {
4550
4670
  id: "seedance-2.5",
@@ -4553,7 +4673,7 @@ var { MODELS: MODELS13 } = defineModels("seedance", [
4553
4673
  addedAt: "2026-08-06",
4554
4674
  workflow: "seedance",
4555
4675
  buildPayload: buildSeedance25PayloadFor("seedance_2_5"),
4556
- constraints: [...seedance25Constraints, ...seedance25DraftFinalConstraints],
4676
+ constraints: [...seedance25Constraints, ...seedance25DraftFinalConstraints, ...seedance25ContentRequiredConstraints],
4557
4677
  estimatedTime: 20,
4558
4678
  mode: "video",
4559
4679
  inputType: "t2v",
@@ -4573,6 +4693,7 @@ var { MODELS: MODELS13 } = defineModels("seedance", [
4573
4693
  ...p.enum("colorDepth", SEEDANCE_25_COLOR_DEPTHS, "10bit", { label: "Color Depth" }),
4574
4694
  ...seedance25DraftParam,
4575
4695
  ...seedance25DraftTaskParam,
4696
+ ...seedance25TaskTypeParam,
4576
4697
  // 2.5 lifts the reference caps to 30 images / 10 videos / 10 audios.
4577
4698
  ...params.imageInput(30, "Reference Images", false, "reference", SEEDANCE_IMAGE_BOUNDS),
4578
4699
  ...params.videoInputs(10, "Reference Videos", false, SEEDANCE_25_VIDEO_BOUNDS),
@@ -4592,7 +4713,7 @@ var { MODELS: MODELS13 } = defineModels("seedance", [
4592
4713
  release: "preview",
4593
4714
  workflow: "seedance",
4594
4715
  buildPayload: buildSeedance25PayloadFor("seedance_2_5_without_moderation"),
4595
- constraints: [...seedance25Constraints, ...seedance25DraftFinalConstraints],
4716
+ constraints: [...seedance25Constraints, ...seedance25DraftFinalConstraints, ...seedance25ContentRequiredConstraints],
4596
4717
  estimatedTime: 20,
4597
4718
  mode: "video",
4598
4719
  inputType: "t2v",
@@ -4612,6 +4733,7 @@ var { MODELS: MODELS13 } = defineModels("seedance", [
4612
4733
  ...p.enum("colorDepth", SEEDANCE_25_COLOR_DEPTHS, "10bit", { label: "Color Depth" }),
4613
4734
  ...seedance25DraftParam,
4614
4735
  ...seedance25DraftTaskParam,
4736
+ ...seedance25TaskTypeParam,
4615
4737
  // 2.5 lifts the reference caps to 30 images / 10 videos / 10 audios.
4616
4738
  ...params.imageInput(30, "Reference Images", false, "reference", SEEDANCE_IMAGE_BOUNDS),
4617
4739
  ...params.videoInputs(10, "Reference Videos", false, SEEDANCE_25_VIDEO_BOUNDS),
@@ -10688,7 +10810,7 @@ function buildInputSchema(model) {
10688
10810
  parse(input) {
10689
10811
  requireObject(input, `Invalid input for model "${model.id}"`);
10690
10812
  try {
10691
- validateAll(model.paramConfig, input);
10813
+ validateAll(model.paramConfig, input, model.constraints);
10692
10814
  } catch (err) {
10693
10815
  if (err instanceof ApiError) throw err;
10694
10816
  throw new ApiError(err instanceof Error ? err.message : String(err), {
@@ -13819,48 +13941,6 @@ var Models = {
13819
13941
  Wan30VideoPrime
13820
13942
  };
13821
13943
 
13822
- // src/core/constraints.ts
13823
- function normalize(r) {
13824
- if ("disabled" in r) return { kind: "disabled", reason: r.reason };
13825
- return { kind: "allowed", allowed: r.allowed, reason: r.reason };
13826
- }
13827
- function matchOperator(op, actual) {
13828
- if ("exists" in op) {
13829
- const has = actual != null && (!Array.isArray(actual) || actual.length > 0) && (typeof actual !== "string" || actual.length > 0);
13830
- return op.exists ? has : !has;
13831
- }
13832
- if ("is" in op) return actual === op.is;
13833
- return false;
13834
- }
13835
- function matchCondition(when, values) {
13836
- return Object.entries(when).every(
13837
- ([key, op]) => matchOperator(op, values[key])
13838
- );
13839
- }
13840
- function merge(prev, next) {
13841
- if (!prev) return next;
13842
- if (prev.kind === "disabled" || next.kind === "disabled") {
13843
- return { kind: "disabled", reason: next.kind === "disabled" ? next.reason : prev.kind === "disabled" ? prev.reason : void 0 };
13844
- }
13845
- const allowed = new Set(next.allowed.map(String));
13846
- return {
13847
- kind: "allowed",
13848
- allowed: prev.allowed.filter((o) => allowed.has(String(o))),
13849
- reason: next.reason ?? prev.reason
13850
- };
13851
- }
13852
- function evaluateConstraints(constraints, values) {
13853
- const effects = /* @__PURE__ */ new Map();
13854
- if (!constraints?.length) return effects;
13855
- for (const rule of constraints) {
13856
- if (!matchCondition(rule.when, values)) continue;
13857
- for (const [key, restriction] of Object.entries(rule.then)) {
13858
- effects.set(key, merge(effects.get(key), normalize(restriction)));
13859
- }
13860
- }
13861
- return effects;
13862
- }
13863
-
13864
13944
  // src/core/descriptors/pricing.ts
13865
13945
  var import_pa_model_pricing_sdk = __toESM(require_build(), 1);
13866
13946
  var _client = null;
@@ -14031,64 +14111,64 @@ var ModelParamsAccessorImpl = class {
14031
14111
  var ConstrainedParamsAccessor = class {
14032
14112
  inner;
14033
14113
  effects;
14034
- constructor(inner, effects) {
14114
+ requirements;
14115
+ constructor(inner, effects, requirements = /* @__PURE__ */ new Map()) {
14035
14116
  this.inner = inner;
14036
14117
  this.effects = effects;
14118
+ this.requirements = requirements;
14037
14119
  }
14038
14120
  // ── Decorated accessors ──────────────────────────────────────────
14039
14121
  enum(key) {
14040
- return this.applyEnum(key, this.inner.enum(key));
14122
+ return this.require(key, this.applyEnum(key, this.inner.enum(key)));
14041
14123
  }
14042
14124
  catalog(key) {
14043
- return this.applyEntry(key, this.inner.catalog(key));
14125
+ return this.require(key, this.applyEntry(key, this.inner.catalog(key)));
14044
14126
  }
14045
14127
  range(key) {
14046
- return this.applyEntry(key, this.inner.range(key));
14128
+ return this.require(key, this.applyEntry(key, this.inner.range(key)));
14047
14129
  }
14048
14130
  boolean(key) {
14049
- return this.applyEntry(key, this.inner.boolean(key));
14131
+ return this.require(key, this.applyEntry(key, this.inner.boolean(key)));
14050
14132
  }
14051
14133
  text(key) {
14052
- return this.applyEntry(key, this.inner.text(key));
14134
+ return this.require(key, this.applyEntry(key, this.inner.text(key)));
14053
14135
  }
14054
14136
  file(key) {
14055
- return this.applyEntry(key, this.inner.file(key));
14137
+ return this.require(key, this.applyEntry(key, this.inner.file(key)));
14056
14138
  }
14057
14139
  prompt() {
14058
- return this.applyEntry("prompt", this.inner.prompt());
14140
+ return this.require("prompt", this.applyEntry("prompt", this.inner.prompt()));
14059
14141
  }
14060
14142
  aspectRatio() {
14061
- return this.applyEnum("aspectRatio", this.inner.aspectRatio());
14143
+ return this.require("aspectRatio", this.applyEnum("aspectRatio", this.inner.aspectRatio()));
14062
14144
  }
14063
14145
  duration() {
14064
14146
  const entry = this.inner.duration();
14065
- return entry?.kind === "enum" ? this.applyEnum("duration", entry) : this.applyEntry("duration", entry);
14147
+ return this.require("duration", entry?.kind === "enum" ? this.applyEnum("duration", entry) : this.applyEntry("duration", entry));
14066
14148
  }
14067
14149
  resolution() {
14068
- return this.applyEnum("resolution", this.inner.resolution());
14150
+ return this.require("resolution", this.applyEnum("resolution", this.inner.resolution()));
14069
14151
  }
14070
14152
  generateAudio() {
14071
- return this.applyEntry("generateAudio", this.inner.generateAudio());
14153
+ return this.require("generateAudio", this.applyEntry("generateAudio", this.inner.generateAudio()));
14072
14154
  }
14073
14155
  startFrame() {
14074
- return this.applyEntry("startFrame", this.inner.startFrame());
14156
+ return this.require("startFrame", this.applyEntry("startFrame", this.inner.startFrame()));
14075
14157
  }
14076
14158
  endFrame() {
14077
- return this.applyEntry("endFrame", this.inner.endFrame());
14159
+ return this.require("endFrame", this.applyEntry("endFrame", this.inner.endFrame()));
14078
14160
  }
14079
14161
  all() {
14080
- return this.inner.all().map((e) => {
14081
- const r = this.effects.get(e.key);
14082
- if (!r) return e;
14083
- if (e.kind === "enum") return this.decorateEnumFlat(e, r);
14084
- if (r.kind === "disabled") return { ...e, disabled: true, disabledReason: r.reason };
14085
- return e;
14086
- });
14162
+ return this.inner.all().map((e) => this.decorateFlat(e.key, e));
14087
14163
  }
14088
- // ── Pass-through delegates ───────────────────────────────────────
14164
+ /** Generic lookup, decorated exactly as `all()` decorates the same key, so a
14165
+ * caller that reads params by key sees the same restrictions and
14166
+ * requirements as one that iterates them. */
14089
14167
  param(key) {
14090
- return this.inner.param(key);
14168
+ const entry = this.inner.param(key);
14169
+ return entry && this.decorateFlat(key, entry);
14091
14170
  }
14171
+ // ── Pass-through delegates ───────────────────────────────────────
14092
14172
  hasParam(key) {
14093
14173
  return this.inner.hasParam(key);
14094
14174
  }
@@ -14108,6 +14188,20 @@ var ConstrainedParamsAccessor = class {
14108
14188
  return this.inner.transferValues(prev);
14109
14189
  }
14110
14190
  // ── Private helpers ──────────────────────────────────────────────
14191
+ decorateFlat(key, entry) {
14192
+ const r = this.effects.get(key);
14193
+ let decorated = entry;
14194
+ if (r && entry.kind === "enum") decorated = this.decorateEnumFlat(entry, r);
14195
+ else if (r?.kind === "disabled") decorated = { ...entry, disabled: true, disabledReason: r.reason };
14196
+ return this.require(key, decorated);
14197
+ }
14198
+ /** Mark the entry required when a matching `required` restriction names it. */
14199
+ require(key, entry) {
14200
+ if (!entry) return void 0;
14201
+ const requirement = this.requirements.get(key);
14202
+ if (!requirement) return entry;
14203
+ return { ...entry, required: true, requiredReason: requirement.reason };
14204
+ }
14111
14205
  applyEntry(key, entry) {
14112
14206
  if (!entry) return void 0;
14113
14207
  const r = this.effects.get(key);
@@ -14190,15 +14284,16 @@ var ModelDescriptorImpl = class {
14190
14284
  paramsFor(values) {
14191
14285
  const inner = this.params();
14192
14286
  const effects = evaluateConstraints(this.def.constraints, values);
14193
- if (!effects.size) return inner;
14194
- return new ConstrainedParamsAccessor(inner, effects);
14287
+ const requirements = evaluateRequirements(this.def.constraints, values);
14288
+ if (!effects.size && !requirements.size) return inner;
14289
+ return new ConstrainedParamsAccessor(inner, effects, requirements);
14195
14290
  }
14196
14291
  validate(input) {
14197
14292
  if (!input || typeof input !== "object" || Array.isArray(input)) {
14198
14293
  return { valid: false, errors: [`Invalid input for model "${this.def.id}"`] };
14199
14294
  }
14200
14295
  try {
14201
- validateAll(this.def.paramConfig, input);
14296
+ validateAll(this.def.paramConfig, input, this.def.constraints);
14202
14297
  return { valid: true };
14203
14298
  } catch (err) {
14204
14299
  return { valid: false, errors: [err instanceof Error ? err.message : String(err)] };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@picsart/ai-sdk",
3
- "version": "6.18.1",
3
+ "version": "6.20.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",