@nodaro/prompts 1.38.0 → 1.40.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 (130) hide show
  1. package/dist/chunk-2EW5B7ZV.cjs +86 -0
  2. package/dist/chunk-2EW5B7ZV.cjs.map +1 -0
  3. package/dist/chunk-2P26SZX5.cjs +414 -0
  4. package/dist/chunk-2P26SZX5.cjs.map +1 -0
  5. package/dist/{chunk-7XKHDXCL.cjs → chunk-3U7X6JZN.cjs} +13 -12
  6. package/dist/chunk-3U7X6JZN.cjs.map +1 -0
  7. package/dist/chunk-4GKTOVFM.cjs +8 -0
  8. package/dist/chunk-4GKTOVFM.cjs.map +1 -0
  9. package/dist/{chunk-HRBBNODV.js → chunk-6GVFJLDL.js} +4 -3
  10. package/dist/chunk-6GVFJLDL.js.map +1 -0
  11. package/dist/{chunk-LVSH7K7R.cjs → chunk-C3NHNECH.cjs} +165 -88
  12. package/dist/chunk-C3NHNECH.cjs.map +1 -0
  13. package/dist/{chunk-CEPVQQVO.js → chunk-C46256GZ.js} +43 -5
  14. package/dist/chunk-C46256GZ.js.map +1 -0
  15. package/dist/{chunk-JKCR6WRZ.cjs → chunk-DQFQJECU.cjs} +43 -5
  16. package/dist/chunk-DQFQJECU.cjs.map +1 -0
  17. package/dist/{chunk-QDEWBBUR.js → chunk-DUXX6CBX.js} +12 -143
  18. package/dist/chunk-DUXX6CBX.js.map +1 -0
  19. package/dist/chunk-EAYEZXWT.js +388 -0
  20. package/dist/chunk-EAYEZXWT.js.map +1 -0
  21. package/dist/chunk-GILUVQQJ.js +6 -0
  22. package/dist/chunk-GILUVQQJ.js.map +1 -0
  23. package/dist/{chunk-KIYNOOPJ.js → chunk-GTDKDD7Y.js} +12 -6
  24. package/dist/chunk-GTDKDD7Y.js.map +1 -0
  25. package/dist/{chunk-QBEZMR2F.js → chunk-HQTHDTHN.js} +137 -62
  26. package/dist/chunk-HQTHDTHN.js.map +1 -0
  27. package/dist/{chunk-TLVX5PXD.cjs → chunk-IUCNJAHW.cjs} +13 -7
  28. package/dist/chunk-IUCNJAHW.cjs.map +1 -0
  29. package/dist/{chunk-ZFIXQRBZ.cjs → chunk-LXPKTI2K.cjs} +12 -83
  30. package/dist/chunk-LXPKTI2K.cjs.map +1 -0
  31. package/dist/{chunk-CVPB2N3Z.cjs → chunk-LZ53F5BN.cjs} +103 -5
  32. package/dist/chunk-LZ53F5BN.cjs.map +1 -0
  33. package/dist/{chunk-4FDNVNJE.js → chunk-N6VMPG5S.js} +12 -79
  34. package/dist/chunk-N6VMPG5S.js.map +1 -0
  35. package/dist/{chunk-LK2CZK5U.cjs → chunk-PWWM7Q3T.cjs} +7 -7
  36. package/dist/{chunk-LK2CZK5U.cjs.map → chunk-PWWM7Q3T.cjs.map} +1 -1
  37. package/dist/{chunk-N7TOWXDJ.js → chunk-QDUTMOF4.js} +3 -3
  38. package/dist/{chunk-N7TOWXDJ.js.map → chunk-QDUTMOF4.js.map} +1 -1
  39. package/dist/{chunk-NO6XHX4R.js → chunk-RB2F5JQF.js} +100 -7
  40. package/dist/chunk-RB2F5JQF.js.map +1 -0
  41. package/dist/{chunk-MENBHEAY.cjs → chunk-WRM52ZBN.cjs} +19 -161
  42. package/dist/chunk-WRM52ZBN.cjs.map +1 -0
  43. package/dist/chunk-YS6HOWMW.js +80 -0
  44. package/dist/chunk-YS6HOWMW.js.map +1 -0
  45. package/dist/entries/assembly.cjs +34 -25
  46. package/dist/entries/assembly.d.cts +121 -37
  47. package/dist/entries/assembly.d.ts +121 -37
  48. package/dist/entries/assembly.js +5 -4
  49. package/dist/entries/doctrine.cjs +46 -46
  50. package/dist/entries/doctrine.d.cts +3 -3
  51. package/dist/entries/doctrine.d.ts +3 -3
  52. package/dist/entries/doctrine.js +1 -1
  53. package/dist/entries/picker-catalogs.cjs +42 -42
  54. package/dist/entries/picker-catalogs.js +3 -3
  55. package/dist/entries/presets.cjs +49 -26
  56. package/dist/entries/presets.d.cts +53 -1
  57. package/dist/entries/presets.d.ts +53 -1
  58. package/dist/entries/presets.js +4 -1
  59. package/dist/entries/prompt-builder.cjs +135 -98
  60. package/dist/entries/prompt-builder.d.cts +22 -11
  61. package/dist/entries/prompt-builder.d.ts +22 -11
  62. package/dist/entries/prompt-builder.js +4 -3
  63. package/dist/entries/prompt-fields.cjs +41 -40
  64. package/dist/entries/prompt-fields.d.cts +2 -1
  65. package/dist/entries/prompt-fields.d.ts +2 -1
  66. package/dist/entries/prompt-fields.js +2 -1
  67. package/dist/index.cjs +339 -273
  68. package/dist/index.d.cts +4 -4
  69. package/dist/index.d.ts +4 -4
  70. package/dist/index.js +11 -9
  71. package/dist/{subject-registry-BUswuEVD.d.cts → subject-registry-CQi_CZfJ.d.cts} +78 -9
  72. package/dist/{subject-registry-D7V8PEG-.d.ts → subject-registry-DFiGx49v.d.ts} +78 -9
  73. package/package.json +2 -2
  74. package/src/__tests__/assemble-image-input-style-references.test.ts +173 -0
  75. package/src/__tests__/catalog-id-guard.test.ts +30 -0
  76. package/src/__tests__/factory-preset-previews.test.ts +123 -0
  77. package/src/__tests__/factory-preset-references.test.ts +222 -0
  78. package/src/__tests__/factory-presets-prototype-keys.test.ts +43 -0
  79. package/src/__tests__/frame-reference-slots.test.ts +43 -0
  80. package/src/__tests__/gemini-omni-inputs.test.ts +12 -10
  81. package/src/__tests__/provider-prompt-doctrine.test.ts +14 -0
  82. package/src/__tests__/user-direction-refs.test.ts +180 -0
  83. package/src/__tests__/veo-i2v-inputs.test.ts +16 -11
  84. package/src/assemble-image-input.ts +114 -13
  85. package/src/catalog-id-guard.ts +18 -2
  86. package/src/color-names.ts +192 -0
  87. package/src/direction-registry.ts +66 -5
  88. package/src/entries/assembly.ts +1 -0
  89. package/src/entries/prompt-builder.ts +2 -0
  90. package/src/factory-presets/generate-image.ts +29 -0
  91. package/src/factory-presets/index.ts +6 -1
  92. package/src/factory-presets/preview-files.generated.ts +4 -0
  93. package/src/factory-presets/previews.ts +40 -0
  94. package/src/factory-presets/references.ts +81 -0
  95. package/src/factory-presets/shared-image.ts +4 -0
  96. package/src/factory-presets/types.ts +8 -0
  97. package/src/frame-reference-slots.ts +92 -0
  98. package/src/gemini-omni-inputs.ts +23 -22
  99. package/src/image-reference-doctrine.ts +3 -3
  100. package/src/image-token-pattern.ts +13 -0
  101. package/src/node-prompt-fields.ts +5 -3
  102. package/src/own-entry.ts +11 -0
  103. package/src/prompt-builder.ts +4 -5
  104. package/src/prompt-style-section.ts +3 -3
  105. package/src/prompt-wizard-categories.ts +2 -0
  106. package/src/provider-prompt-doctrine.ts +45 -3
  107. package/src/ref-binding.ts +28 -3
  108. package/src/resolve-prompt.ts +2 -1
  109. package/src/seedance-2-inputs.ts +15 -40
  110. package/src/user-direction-refs.ts +110 -0
  111. package/src/veo-i2v-inputs.ts +24 -17
  112. package/src/video-reference-resolver.ts +1 -1
  113. package/dist/chunk-4FDNVNJE.js.map +0 -1
  114. package/dist/chunk-7XKHDXCL.cjs.map +0 -1
  115. package/dist/chunk-CEPVQQVO.js.map +0 -1
  116. package/dist/chunk-CVPB2N3Z.cjs.map +0 -1
  117. package/dist/chunk-HRBBNODV.js.map +0 -1
  118. package/dist/chunk-JKCR6WRZ.cjs.map +0 -1
  119. package/dist/chunk-KIYNOOPJ.js.map +0 -1
  120. package/dist/chunk-LVSH7K7R.cjs.map +0 -1
  121. package/dist/chunk-MENBHEAY.cjs.map +0 -1
  122. package/dist/chunk-NO6XHX4R.js.map +0 -1
  123. package/dist/chunk-QBEZMR2F.js.map +0 -1
  124. package/dist/chunk-QDEWBBUR.js.map +0 -1
  125. package/dist/chunk-TLVX5PXD.cjs.map +0 -1
  126. package/dist/chunk-UJKFHPZ7.js +0 -37
  127. package/dist/chunk-UJKFHPZ7.js.map +0 -1
  128. package/dist/chunk-W5SCZIOB.cjs +0 -43
  129. package/dist/chunk-W5SCZIOB.cjs.map +0 -1
  130. package/dist/chunk-ZFIXQRBZ.cjs.map +0 -1
@@ -1,15 +1,16 @@
1
- import { tidyReferenceTokenGaps, unboundReferenceTokenText, renderDescribedReferenceLines, renderReferenceCaptionLines, appendReferenceLines, resolveCharacterMentions, referenceDescriptionLine, insertBeforeStyleSection, applyReferenceOrderToVideo, sectionedClauseCosts, asBodyClauses, renderSubjectHints, SUBJECT_VIDEO_HINT_MODE_DEFAULT, partitionStyleClauses, VIDEO_HINT_MODE_DEFAULT, renderStructuredFields, buildImagePromptWithOverflow, composeSectionedPrompt, SUBJECT_IMAGE_HINT_MODE_DEFAULT, IMAGE_HINT_MODE_DEFAULT } from './chunk-QDEWBBUR.js';
1
+ import { tidyReferenceTokenGaps, unboundReferenceTokenText, renderDescribedReferenceLines, renderReferenceCaptionLines, appendReferenceLines, resolveCharacterMentions, referenceDescriptionLine, insertBeforeStyleSection, applyReferenceOrderToVideo, sectionedClauseCosts, asBodyClauses, renderSubjectHints, SUBJECT_VIDEO_HINT_MODE_DEFAULT, partitionStyleClauses, renderStructuredFields, composeSectionedPrompt, buildImagePromptWithOverflow, SUBJECT_IMAGE_HINT_MODE_DEFAULT } from './chunk-DUXX6CBX.js';
2
2
  import { keepableDirectionHints } from './chunk-JZOPMVGY.js';
3
3
  import { buildIdentityLockLine, withForcedIdentityLock } from './chunk-BQWIPLLR.js';
4
- import { getParameterPromptHint } from './chunk-N7TOWXDJ.js';
4
+ import { getParameterPromptHint } from './chunk-QDUTMOF4.js';
5
+ import { styleReferenceDescription, VIDEO_HINT_MODE_DEFAULT, IMAGE_HINT_MODE_DEFAULT } from './chunk-EAYEZXWT.js';
5
6
  import { getMusicEra, getMusicGenre, buildMusicMoodHints } from './chunk-SXXW4LCR.js';
6
7
  import { findCharacterMentionTokens, roleToPhrase, resolveDefaultRole, DEFAULT_USAGE_MODE, usageModeDirective, REFERENCE_ROLE_PRESETS } from '@nodaro/shared/entities';
7
- import { SEEDANCE_2_REF_LIMITS, VIDEO_REF_LIMITS_BY_PROVIDER } from '@nodaro/shared/models';
8
+ import { imageReferenceLimit, SEEDANCE_2_REF_LIMITS, VIDEO_REF_LIMITS_BY_PROVIDER } from '@nodaro/shared/models';
8
9
  import { resolveFrameDelivery } from '@nodaro/shared/video';
9
10
 
10
11
  // src/ref-binding.ts
11
- function identityRefsSentence(firstOrdinal, lastOrdinal) {
12
- return firstOrdinal === lastOrdinal ? `${REF_BINDING.ordinal(firstOrdinal)} is an identity reference for this shot's subjects \u2014 match its subject's exact appearance; it is not a frame.` : `${REF_BINDING.ordinal(firstOrdinal)} through ${REF_BINDING.ordinal(lastOrdinal)} are identity references for this shot's subjects \u2014 match each subject's exact appearance; they are not frames.`;
12
+ function identityRefsSentence(firstOrdinal, lastOrdinal, ordinal = REF_BINDING.ordinal) {
13
+ return firstOrdinal === lastOrdinal ? `${ordinal(firstOrdinal)} is an identity reference for this shot's subjects \u2014 match its subject's exact appearance; it is not a frame.` : `${ordinal(firstOrdinal)} through ${ordinal(lastOrdinal)} are identity references for this shot's subjects \u2014 match each subject's exact appearance; they are not frames.`;
13
14
  }
14
15
  var REF_BINDING = {
15
16
  image: (label, n) => `the ${label} from @image_${n}`,
@@ -19,6 +20,14 @@ var REF_BINDING = {
19
20
  ordinal: (n) => `@image_${n}`,
20
21
  frame: (n, role) => `Use @image_${n} as the ${role} (${role === "opening" ? "first" : "last"}) frame of the video.`
21
22
  };
23
+ function imageBindingFor(syntax) {
24
+ if (syntax === "@image_N") return { ordinal: REF_BINDING.ordinal, frame: REF_BINDING.frame };
25
+ const ordinal = syntax === "@image(n)" ? (n) => `@image(${n})` : (n) => `[Image ${n}]`;
26
+ return {
27
+ ordinal,
28
+ frame: (n, role) => `Use ${ordinal(n)} as the ${role} (${role === "opening" ? "first" : "last"}) frame of the video.`
29
+ };
30
+ }
22
31
  var SEEDANCE_VIDEO_EDIT_PREFIX = "edit {video:1} as follows:\n";
23
32
  function buildSeedanceVideoEditPrompt(prompt) {
24
33
  const body = (prompt ?? "").trim();
@@ -616,9 +625,7 @@ function assembleSunoInput(input) {
616
625
  ...input.persona ?? {}
617
626
  };
618
627
  }
619
-
620
- // src/assemble-image-input.ts
621
- function renderImageHintPieces(subject, direction, structured) {
628
+ function renderImageHintPieces(subject, direction, structured, directionRefs) {
622
629
  return {
623
630
  hintClauses: [
624
631
  ...asBodyClauses(
@@ -629,7 +636,8 @@ function renderImageHintPieces(subject, direction, structured) {
629
636
  ),
630
637
  ...partitionStyleClauses(direction, {
631
638
  surface: "image",
632
- mode: IMAGE_HINT_MODE_DEFAULT
639
+ mode: IMAGE_HINT_MODE_DEFAULT,
640
+ ...directionRefs !== void 0 ? { refs: directionRefs } : {}
633
641
  })
634
642
  ].filter((c) => c.text.length > 0),
635
643
  structuredFragment: structured ? renderStructuredFields(structured) : ""
@@ -643,7 +651,51 @@ function composePromptText(userPrompt, pieces, keptHintClauses) {
643
651
  );
644
652
  }
645
653
  function assembleImageInput(input) {
646
- const pieces = renderImageHintPieces(input.subject, input.direction, input.structured);
654
+ const style = input.styleReferences;
655
+ const result = style !== void 0 && style.length > 0 ? fillStyleReferences(input, style) : assembleOnce(input);
656
+ if (input.throwOnEmpty && !result.prompt.trim()) {
657
+ throw new Error(
658
+ "No prompt \u2014 type one, bind a character, or pick a cinematography direction"
659
+ );
660
+ }
661
+ return result;
662
+ }
663
+ function fillStyleReferences(input, style) {
664
+ const base = assembleOnce(input);
665
+ const own = base.referenceImageUrls ?? [];
666
+ const seats = imageReferenceLimit(input.provider) - own.length;
667
+ const seen = new Set(own);
668
+ const candidates = [];
669
+ for (const s of style) {
670
+ if (typeof s.url !== "string" || s.url.length === 0 || seen.has(s.url)) continue;
671
+ seen.add(s.url);
672
+ candidates.push(s);
673
+ }
674
+ for (let k = Math.min(seats, candidates.length); k > 0; k--) {
675
+ const extras = candidates.slice(0, k).map(styleConnectedReference);
676
+ const filled = assembleOnce({
677
+ ...input,
678
+ connectedReferences: [...input.connectedReferences ?? [], ...extras]
679
+ });
680
+ const urls = filled.referenceImageUrls ?? [];
681
+ const keepsOwn = urls.length === own.length + k && own.every((url, i) => urls[i] === url) && extras.every((ref, j) => urls[own.length + j] === ref.url);
682
+ if (keepsOwn) return { ...filled, styleReferencesSent: k };
683
+ }
684
+ return { ...base, styleReferencesSent: 0 };
685
+ }
686
+ function styleConnectedReference(s, index) {
687
+ return {
688
+ id: `style-reference-${index + 1}`,
689
+ defaultName: `Style reference ${index + 1}`,
690
+ source: "manual",
691
+ url: s.url,
692
+ isExtraRef: true,
693
+ defaultRole: "style",
694
+ description: styleReferenceDescription(index, s.caption)
695
+ };
696
+ }
697
+ function assembleOnce(input) {
698
+ const pieces = renderImageHintPieces(input.subject, input.direction, input.structured, input.directionRefs);
647
699
  const assembleWith = (keptHintClauses) => buildImagePromptWithOverflow({
648
700
  prompt: composePromptText(input.userPrompt, pieces, keptHintClauses),
649
701
  provider: input.provider,
@@ -684,11 +736,6 @@ function assembleImageInput(input) {
684
736
  }
685
737
  }
686
738
  const { overflowChars, ...result } = fitted;
687
- if (input.throwOnEmpty && !result.prompt.trim()) {
688
- throw new Error(
689
- "No prompt \u2014 type one, bind a character, or pick a cinematography direction"
690
- );
691
- }
692
739
  return result;
693
740
  }
694
741
 
@@ -724,15 +771,50 @@ function composeVideoPromptText(userPrompt, direction, structured, opts) {
724
771
  }
725
772
  return body;
726
773
  }
774
+
775
+ // src/frame-reference-slots.ts
776
+ function placeFramesAfterReferences(args) {
777
+ const refs = (args.refImageUrls ?? []).filter((u) => typeof u === "string" && u.trim().length > 0);
778
+ const frameCount = (args.firstFrameUrl ? 1 : 0) + (args.lastFrameUrl ? 1 : 0);
779
+ const kept = refs.slice(0, Math.max(0, args.imageCap - frameCount));
780
+ const droppedRefImages = refs.length - kept.length;
781
+ const imageUrls = [...kept];
782
+ let firstFrameOrdinal = 0;
783
+ let lastFrameOrdinal = 0;
784
+ if (args.firstFrameUrl) {
785
+ imageUrls.push(args.firstFrameUrl);
786
+ firstFrameOrdinal = imageUrls.length;
787
+ }
788
+ if (args.lastFrameUrl) {
789
+ imageUrls.push(args.lastFrameUrl);
790
+ lastFrameOrdinal = imageUrls.length;
791
+ }
792
+ const syntax = args.syntax ?? "@image_N";
793
+ const binding = imageBindingFor(syntax);
794
+ const promptBindsStart = syntax === "@image_N" && promptBindsFirstFrame(args.prompt);
795
+ let frameSentence = "";
796
+ if (promptBindsStart && firstFrameOrdinal > 0 && lastFrameOrdinal === 0) ; else if (firstFrameOrdinal > 0 && lastFrameOrdinal > 0) {
797
+ frameSentence = `Use ${binding.ordinal(firstFrameOrdinal)} as the opening (first) frame and ${binding.ordinal(lastFrameOrdinal)} as the closing (last) frame of the video.`;
798
+ } else if (firstFrameOrdinal > 0) {
799
+ frameSentence = binding.frame(firstFrameOrdinal, "opening");
800
+ } else if (lastFrameOrdinal > 0) {
801
+ frameSentence = binding.frame(lastFrameOrdinal, "closing");
802
+ }
803
+ const identitySentence = args.bindIdentities && kept.length > 0 && frameCount > 0 ? identityRefsSentence(1, kept.length, binding.ordinal) : "";
804
+ const promptSuffix = [frameSentence, identitySentence].filter(Boolean).join(" ");
805
+ return { imageUrls, promptSuffix, droppedRefImages, firstFrameOrdinal, lastFrameOrdinal };
806
+ }
807
+ function promptBindsFirstFrame(prompt) {
808
+ if (!prompt) return false;
809
+ return /@image_\d+\s+as\s+the\s+(first|opening)\s*(\(first\))?\s*frame/i.test(prompt);
810
+ }
811
+
812
+ // src/seedance-2-inputs.ts
727
813
  var clean = (u) => {
728
814
  const t = u?.trim();
729
815
  return t && t.length > 0 ? t : void 0;
730
816
  };
731
817
  var cleanList = (xs) => (xs ?? []).map(clean).filter((x) => x !== void 0);
732
- function promptBindsFirstFrame(prompt) {
733
- if (!prompt) return false;
734
- return /@image_\d+\s+as\s+the\s+(first|opening)\s*(\(first\))?\s*frame/i.test(prompt);
735
- }
736
818
  function resolveSeedance2Inputs(args) {
737
819
  const limits = args.limits ?? SEEDANCE_2_REF_LIMITS;
738
820
  const firstFrameUrl = clean(args.firstFrameUrl);
@@ -748,30 +830,16 @@ function resolveSeedance2Inputs(args) {
748
830
  }
749
831
  return { mode: "first-frame", firstFrameUrl, lastFrameUrl: void 0, referenceImageUrls: [], referenceVideoUrls: [], referenceAudioUrls: [], promptSuffix: "", droppedRefImages: 0 };
750
832
  }
751
- const frameCount = (firstFrameUrl ? 1 : 0) + (lastFrameUrl ? 1 : 0);
752
- const userImageSlots = Math.max(0, limits.images - frameCount);
753
- const keptUserImages = refImages.slice(0, userImageSlots);
754
- const droppedRefImages = refImages.length - keptUserImages.length;
755
- const referenceImageUrls = [...keptUserImages];
756
- let firstOrdinal = 0;
757
- let lastOrdinal = 0;
758
- if (firstFrameUrl) {
759
- referenceImageUrls.push(firstFrameUrl);
760
- firstOrdinal = referenceImageUrls.length;
761
- }
762
- if (lastFrameUrl) {
763
- referenceImageUrls.push(lastFrameUrl);
764
- lastOrdinal = referenceImageUrls.length;
765
- }
766
- let promptSuffix = "";
767
- const suppressFrameSentence = promptBindsFirstFrame(args.prompt);
768
- if (suppressFrameSentence && firstOrdinal > 0 && lastOrdinal === 0) ; else if (firstOrdinal > 0 && lastOrdinal > 0) {
769
- promptSuffix = `Use ${REF_BINDING.ordinal(firstOrdinal)} as the opening (first) frame and ${REF_BINDING.ordinal(lastOrdinal)} as the closing (last) frame of the video.`;
770
- } else if (firstOrdinal > 0) {
771
- promptSuffix = REF_BINDING.frame(firstOrdinal, "opening");
772
- } else if (lastOrdinal > 0) {
773
- promptSuffix = REF_BINDING.frame(lastOrdinal, "closing");
774
- }
833
+ const placed = placeFramesAfterReferences({
834
+ prompt: args.prompt,
835
+ firstFrameUrl,
836
+ lastFrameUrl,
837
+ refImageUrls: refImages,
838
+ imageCap: limits.images
839
+ });
840
+ const referenceImageUrls = placed.imageUrls;
841
+ const promptSuffix = placed.promptSuffix;
842
+ const droppedRefImages = placed.droppedRefImages;
775
843
  return {
776
844
  mode: "reference",
777
845
  firstFrameUrl: void 0,
@@ -788,16 +856,18 @@ function geminiOmniInputSlots(provider) {
788
856
  return VIDEO_REF_LIMITS_BY_PROVIDER[provider ?? DEFAULT_GEMINI_OMNI_PROVIDER]?.images ?? 7;
789
857
  }
790
858
  function resolveGeminiOmniI2vInputs(args) {
791
- const refs = (args.refImageUrls ?? []).filter((u) => typeof u === "string" && u.length > 0);
792
859
  const slots = geminiOmniInputSlots(args.provider) - (args.videoConnected ? 2 : 0);
793
- const refSlots = Math.max(0, slots - 1);
794
- const kept = refs.slice(0, refSlots);
795
- const droppedRefImages = refs.length - kept.length;
796
- const imageUrls = [args.firstFrameUrl, ...kept];
797
- if (kept.length === 0) return { imageUrls, promptSuffix: "", droppedRefImages };
798
- const frameSentence = promptBindsFirstFrame(args.prompt) ? "" : REF_BINDING.frame(1, "opening");
799
- const promptSuffix = [frameSentence, identityRefsSentence(2, kept.length + 1)].filter(Boolean).join(" ");
800
- return { imageUrls, promptSuffix, droppedRefImages };
860
+ const placed = placeFramesAfterReferences({
861
+ prompt: args.prompt,
862
+ firstFrameUrl: args.firstFrameUrl,
863
+ refImageUrls: args.refImageUrls,
864
+ imageCap: Math.max(1, slots),
865
+ bindIdentities: true
866
+ });
867
+ if (placed.imageUrls.length === 1) {
868
+ return { imageUrls: placed.imageUrls, promptSuffix: "", droppedRefImages: placed.droppedRefImages };
869
+ }
870
+ return { imageUrls: placed.imageUrls, promptSuffix: placed.promptSuffix, droppedRefImages: placed.droppedRefImages };
801
871
  }
802
872
 
803
873
  // src/veo-i2v-inputs.ts
@@ -812,15 +882,20 @@ function resolveVeoI2vInputs(args) {
812
882
  droppedEndFrame: false
813
883
  };
814
884
  }
815
- const kept = refs.slice(0, VEO_INGREDIENT_SLOTS - 1);
816
- const droppedRefImages = refs.length - kept.length;
817
- const frameSentence = promptBindsFirstFrame(args.prompt) ? "" : REF_BINDING.frame(1, "opening");
885
+ const placed = placeFramesAfterReferences({
886
+ prompt: args.prompt,
887
+ firstFrameUrl: args.firstFrameUrl,
888
+ lastFrameUrl: args.endFrameUrl,
889
+ refImageUrls: refs,
890
+ imageCap: VEO_INGREDIENT_SLOTS,
891
+ bindIdentities: true
892
+ });
818
893
  return {
819
- imageUrls: [args.firstFrameUrl, ...kept],
894
+ imageUrls: placed.imageUrls,
820
895
  generationType: "REFERENCE_2_VIDEO",
821
- promptSuffix: [frameSentence, identityRefsSentence(2, kept.length + 1)].filter(Boolean).join(" "),
822
- droppedRefImages,
823
- droppedEndFrame: Boolean(args.endFrameUrl)
896
+ promptSuffix: placed.promptSuffix,
897
+ droppedRefImages: placed.droppedRefImages,
898
+ droppedEndFrame: false
824
899
  };
825
900
  }
826
901
 
@@ -888,6 +963,6 @@ function planFrameDelivery(args) {
888
963
  return { delivery: "reference", referenceImageUrls, promptSuffix: sentences.join(" ") };
889
964
  }
890
965
 
891
- export { REF_BINDING, SEEDANCE_VIDEO_EDIT_PREFIX, appendField, appendMusicMeta, assembleImageInput, assembleSunoInput, buildSeedanceVideoEditPrompt, buildSurroundFillPrompt, composeSoundHintFromConnections, composeVideoPromptText, getEffectiveSunoCustomMode, identityRefsSentence, planFrameDelivery, promptBindsFirstFrame, resolveGeminiOmniI2vInputs, resolveRefIdTokens, resolveReferenceTokens, resolveSeedance2Inputs, resolveVeoI2vInputs, resolveVideoReferenceCore, truncateForField };
892
- //# sourceMappingURL=chunk-QBEZMR2F.js.map
893
- //# sourceMappingURL=chunk-QBEZMR2F.js.map
966
+ export { REF_BINDING, SEEDANCE_VIDEO_EDIT_PREFIX, appendField, appendMusicMeta, assembleImageInput, assembleSunoInput, buildSeedanceVideoEditPrompt, buildSurroundFillPrompt, composeSoundHintFromConnections, composeVideoPromptText, getEffectiveSunoCustomMode, identityRefsSentence, imageBindingFor, placeFramesAfterReferences, planFrameDelivery, promptBindsFirstFrame, resolveGeminiOmniI2vInputs, resolveRefIdTokens, resolveReferenceTokens, resolveSeedance2Inputs, resolveVeoI2vInputs, resolveVideoReferenceCore, truncateForField };
967
+ //# sourceMappingURL=chunk-HQTHDTHN.js.map
968
+ //# sourceMappingURL=chunk-HQTHDTHN.js.map