@sogni-ai/sogni-intelligence-client 3.0.4 → 3.0.6

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 (35) hide show
  1. package/dist/billing/spendGate.d.ts.map +1 -1
  2. package/dist/billing/spendGate.js.map +1 -1
  3. package/dist/contracts/data/promptContracts.d.ts.map +1 -1
  4. package/dist/contracts/data/promptContracts.js +4 -1
  5. package/dist/contracts/data/promptContracts.js.map +1 -1
  6. package/dist/events/runEvent.d.ts.map +1 -1
  7. package/dist/events/runEvent.js.map +1 -1
  8. package/dist/index.d.ts +2 -2
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +13 -1
  11. package/dist/index.js.map +1 -1
  12. package/dist/public-skill-runtime/index.d.ts.map +1 -1
  13. package/dist/public-skill-runtime/index.js +143 -6
  14. package/dist/public-skill-runtime/index.js.map +1 -1
  15. package/dist/workflows/index.d.ts +2 -2
  16. package/dist/workflows/index.d.ts.map +1 -1
  17. package/dist/workflows/index.js +13 -1
  18. package/dist/workflows/index.js.map +1 -1
  19. package/dist/workflows/primitives/sanitizer.d.ts +21 -0
  20. package/dist/workflows/primitives/sanitizer.d.ts.map +1 -1
  21. package/dist/workflows/primitives/sanitizer.js +68 -3
  22. package/dist/workflows/primitives/sanitizer.js.map +1 -1
  23. package/dist-esm/billing/spendGate.js.map +1 -1
  24. package/dist-esm/contracts/data/promptContracts.js +4 -1
  25. package/dist-esm/contracts/data/promptContracts.js.map +1 -1
  26. package/dist-esm/events/runEvent.js.map +1 -1
  27. package/dist-esm/index.js +1 -1
  28. package/dist-esm/index.js.map +1 -1
  29. package/dist-esm/public-skill-runtime/index.js +143 -6
  30. package/dist-esm/public-skill-runtime/index.js.map +1 -1
  31. package/dist-esm/workflows/index.js +1 -1
  32. package/dist-esm/workflows/index.js.map +1 -1
  33. package/dist-esm/workflows/primitives/sanitizer.js +67 -2
  34. package/dist-esm/workflows/primitives/sanitizer.js.map +1 -1
  35. package/package.json +7 -1
@@ -4600,6 +4600,118 @@ function splitStoryboardSections(text) {
4600
4600
  return inlineSections;
4601
4601
  return sectionHeadings.length > 0 ? sectionHeadings : tableSections;
4602
4602
  }
4603
+ function extractPlainNarrationScriptText(text) {
4604
+ const source = text.trim();
4605
+ if (!source)
4606
+ return '';
4607
+ const markers = Array.from(source.matchAll(/^\s*(?:#{1,6}\s*)?(?:voice[-\s]?over\s+|narration\s+)?script\s*:\s*$/gim));
4608
+ const marker = markers[markers.length - 1];
4609
+ if (!marker || marker.index === undefined)
4610
+ return '';
4611
+ const body = source.slice(marker.index + marker[0].length).trim();
4612
+ return body
4613
+ .split(/\r?\n/)
4614
+ .map(line => stripStoryboardMarkup(line).trim())
4615
+ .filter(Boolean)
4616
+ .join('\n\n')
4617
+ .trim();
4618
+ }
4619
+ function splitPlainNarrationPhrases(text) {
4620
+ const normalized = text
4621
+ .replace(/\s+/g, ' ')
4622
+ .trim();
4623
+ if (!normalized)
4624
+ return [];
4625
+ const sentenceMatches = normalized.match(/[^.!?]+[.!?]+(?:["')\]]+)?|[^.!?]+$/g) ?? [normalized];
4626
+ return sentenceMatches
4627
+ .flatMap(sentence => sentence
4628
+ .split(/\s*(?:;|:\s+|,\s+(?=(?:and|but|so|whether|from|across|under|while|as)\b))\s*/i)
4629
+ .map(part => compactStoryboardLine(part)))
4630
+ .filter(part => countWords(part) > 0);
4631
+ }
4632
+ function splitPhraseAtWordMidpoint(value) {
4633
+ const words = value.match(/\S+/g) ?? [];
4634
+ if (words.length < 8)
4635
+ return null;
4636
+ const midpoint = Math.floor(words.length / 2);
4637
+ const left = words.slice(0, midpoint).join(' ').trim();
4638
+ const right = words.slice(midpoint).join(' ').trim();
4639
+ return left && right ? [left, right] : null;
4640
+ }
4641
+ function normalizeNarrationSegmentCount(phrases, frameCount) {
4642
+ if (frameCount <= 0)
4643
+ return [];
4644
+ let segments = phrases.slice();
4645
+ while (segments.length < frameCount) {
4646
+ let longestIndex = -1;
4647
+ let longestCount = 0;
4648
+ for (let index = 0; index < segments.length; index += 1) {
4649
+ const words = countWords(segments[index]);
4650
+ if (words > longestCount) {
4651
+ longestCount = words;
4652
+ longestIndex = index;
4653
+ }
4654
+ }
4655
+ if (longestIndex < 0)
4656
+ break;
4657
+ const split = splitPhraseAtWordMidpoint(segments[longestIndex]);
4658
+ if (!split)
4659
+ break;
4660
+ segments.splice(longestIndex, 1, split[0], split[1]);
4661
+ }
4662
+ if (segments.length <= frameCount)
4663
+ return segments;
4664
+ const merged = [];
4665
+ for (let index = 0; index < frameCount; index += 1) {
4666
+ const start = Math.floor(index * segments.length / frameCount);
4667
+ const end = Math.floor((index + 1) * segments.length / frameCount);
4668
+ const chunk = segments.slice(start, Math.max(start + 1, end)).join(' ');
4669
+ if (chunk.trim())
4670
+ merged.push(chunk.trim());
4671
+ }
4672
+ return merged;
4673
+ }
4674
+ function titleFromNarrationSegment(segment, index) {
4675
+ const words = compactStoryboardLine(segment)
4676
+ .replace(/["'()]/g, '')
4677
+ .split(/\s+/)
4678
+ .filter(Boolean)
4679
+ .slice(0, 6)
4680
+ .join(' ');
4681
+ return words || `Narration Beat ${index + 1}`;
4682
+ }
4683
+ function synthesizeStoryboardSectionsFromPlainNarration(sourceText, frameCount, references) {
4684
+ const script = extractPlainNarrationScriptText(sourceText);
4685
+ if (!script || countWords(script) < 8)
4686
+ return [];
4687
+ const phrases = splitPlainNarrationPhrases(script);
4688
+ const segments = normalizeNarrationSegmentCount(phrases, frameCount).slice(0, frameCount);
4689
+ if (segments.length === 0)
4690
+ return [];
4691
+ const referenceLine = references.length > 0
4692
+ ? `Reference usage: ${references.map(ref => `Image ${ref.index ?? references.indexOf(ref) + 1}`).join(', ')}.`
4693
+ : '';
4694
+ const cameraPresets = [
4695
+ 'Wide establishing composition that introduces the setting, subject, or idea named in the narration.',
4696
+ 'Medium composition focused on the active subject, action, or relationship in this beat.',
4697
+ 'Detail insert on concrete objects, gestures, text, environment, or visual evidence named in the narration.',
4698
+ 'Tracking or reveal-style composition that moves the story into the next idea.',
4699
+ ];
4700
+ return segments.map((segment, index) => ({
4701
+ number: index + 1,
4702
+ heading: `Scene ${index + 1} - ${titleFromNarrationSegment(segment, index)}`,
4703
+ body: [
4704
+ `Purpose: Translate narration beat ${index + 1} into a concrete ordered storyboard moment.`,
4705
+ `Visual/Action: Create a concrete visual moment using only this narration beat and the supplied references: ${segment}`,
4706
+ `Camera/Motion: ${cameraPresets[index % cameraPresets.length]}`,
4707
+ 'Lighting/Style: Match the visual style, genre, and tone implied by the user request and supplied references; keep the frame cinematic but readable as a storyboard panel.',
4708
+ 'Transition: Maintain continuity from the previous beat through subject, setting, gesture, camera direction, color, or motion when those cues are present.',
4709
+ `Dialogue/VO: ${segment}`,
4710
+ 'Audio/SFX: Use only audio cues implied by the narration or user request; otherwise keep ambience or music generic and unobtrusive.',
4711
+ referenceLine,
4712
+ ].filter(Boolean).join('\n'),
4713
+ }));
4714
+ }
4603
4715
  function storyboardSectionsHavePreservableExplicitTiming(sections) {
4604
4716
  return sections.length > 1
4605
4717
  && sections.some(section => extractStoryboardTiming(`${section.heading}\n${section.body}`) !== null);
@@ -5434,8 +5546,14 @@ export function buildStoryboardProject(options) {
5434
5546
  : assistantDraftUndercounted || assistantApprovedDraftUndercounted
5435
5547
  ? []
5436
5548
  : sourceSections;
5437
- const parsedScenes = sections.length > 0
5438
- ? sections.map((section) => {
5549
+ const selectedSectionsHaveExplicitTiming = sections.length > 0 && storyboardSectionsHavePreservableExplicitTiming(sections);
5550
+ const preserveAssistantExplicitTiming = options.promptAuthorship === 'assistant' && selectedSectionsHaveExplicitTiming;
5551
+ const synthesizedSections = sections.length === 0
5552
+ ? synthesizeStoryboardSectionsFromPlainNarration(`${sourceText}\n\n${narrativeUserIntentText}`, options.frameCount, references)
5553
+ : [];
5554
+ const storyboardSections = sections.length > 0 ? sections : synthesizedSections;
5555
+ const parsedScenes = storyboardSections.length > 0
5556
+ ? storyboardSections.map((section) => {
5439
5557
  return buildSceneFromSection(section, references, null, storyboardScenePlanningContractForIndex(options.planningContract, section.number));
5440
5558
  })
5441
5559
  : [];
@@ -5445,12 +5563,17 @@ export function buildStoryboardProject(options) {
5445
5563
  }));
5446
5564
  const timingNormalizedScenes = normalizeAssistantStoryboardSceneTiming(scenes, durationSec, options.promptAuthorship);
5447
5565
  const dialogueAlignment = alignAssistantStoryboardDialogueWithUserSource(timingNormalizedScenes, userIntentText, options.promptAuthorship);
5448
- const dialogueTimedScenes = (options.promptAuthorship === 'assistant' || dialogueAlignment.shouldRetime)
5566
+ const canPreserveAssistantExplicitTiming = preserveAssistantExplicitTiming && !dialogueAlignment.shouldRetime;
5567
+ const dialogueTimedScenes = (!canPreserveAssistantExplicitTiming
5568
+ && (options.promptAuthorship === 'assistant' || dialogueAlignment.shouldRetime))
5449
5569
  ? retimeStoryboardScenesForDialogue(dialogueAlignment.scenes, durationSec)
5450
5570
  : dialogueAlignment.scenes;
5451
5571
  const userConstraintSource = buildStoryboardUserConstraintSource(narrativeUserIntentText, cleanStoryboardNarrativeSourceText(primarySourceBrief), options);
5452
5572
  const { mustIncludeText, endCardText } = storyboardRequiredTextForProject(options, userConstraintSource, dialogueTimedScenes);
5453
- const normalizedScenes = retimeStoryboardScenesForDialogue(applyStoryboardEndCardTextToScenes(dialogueTimedScenes, endCardText), durationSec);
5573
+ const scenesWithEndCardText = applyStoryboardEndCardTextToScenes(dialogueTimedScenes, endCardText);
5574
+ const normalizedScenes = canPreserveAssistantExplicitTiming
5575
+ ? scenesWithEndCardText
5576
+ : retimeStoryboardScenesForDialogue(scenesWithEndCardText, durationSec);
5454
5577
  const voiceLines = assignVoiceLinesToScenes(normalizedScenes, sourceText);
5455
5578
  const storySpineFallback = approvedScriptContext
5456
5579
  || (options.promptAuthorship === 'assistant' ? narrativeUserIntentText : cleanStoryboardNarrativeSourceText(primarySourceBrief))
@@ -5480,8 +5603,8 @@ export function buildStoryboardProject(options) {
5480
5603
  }
5481
5604
  const recognizedSectionCount = directBeatMarkerCount > 0
5482
5605
  ? directBeatMarkerCount
5483
- : sections.length > 0
5484
- ? sections.length
5606
+ : storyboardSections.length > 0
5607
+ ? storyboardSections.length
5485
5608
  : Math.max(approvedSections.length, sourceSections.length);
5486
5609
  return {
5487
5610
  title: inferStoryboardTitle(allText),
@@ -5819,6 +5942,19 @@ function storyboardLayoutSpecFromProject(project, frameCount) {
5819
5942
  ...(project.boardDimensions ? { boardDimensions: project.boardDimensions } : {}),
5820
5943
  };
5821
5944
  }
5945
+ function compileStoryboardFrameGeometrySection(layout) {
5946
+ const cellOrientation = parseAspectRatioOrientation(layout.cellAspectRatio);
5947
+ if (cellOrientation === 'portrait') {
5948
+ return [
5949
+ 'PORTRAIT FRAME GEOMETRY:',
5950
+ `Every cinematic artwork area inside a panel must remain a ${layout.cellAspectRatio} portrait video-frame rectangle matching the final video frame.`,
5951
+ `Inside every numbered scene slot, draw one identical upright ${layout.cellAspectRatio} video-frame rectangle whose height is visibly greater than its width.`,
5952
+ `Square cells violate the requested ${layout.targetVideoAspectRatio} final video format.`,
5953
+ 'Unused grid slots must remain blank margin/notes space only; do not fill them with extra scenes, duplicate frames, or decorative artwork.',
5954
+ ];
5955
+ }
5956
+ return [];
5957
+ }
5822
5958
  export function compileVideoStoryboardImagePrompt(options) {
5823
5959
  const rawUserIntentText = options.userIntentText.trim();
5824
5960
  const userIntentText = canonicalStoryboardScriptContext(rawUserIntentText) || rawUserIntentText;
@@ -5852,6 +5988,7 @@ export function compileVideoStoryboardImagePrompt(options) {
5852
5988
  `Each panel must contain one distinct ${layout.cellAspectRatio} cinematic video-frame rectangle with compact notes outside the frame.`,
5853
5989
  'Keep scene numbers, timecodes, titles, dialogue/VO, audio notes, and production notes outside the video-frame rectangles.',
5854
5990
  'Do not merge panels, create inset thumbnails, make panels square, or overlay storyboard metadata inside the artwork frames.',
5991
+ ...compileStoryboardFrameGeometrySection(layout),
5855
5992
  '',
5856
5993
  ...compileStoryboardReferenceSection(project),
5857
5994
  '',