@nodaro/prompts 1.16.0 → 1.17.1
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.cjs +181 -49
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +121 -2
- package/dist/index.d.ts +121 -2
- package/dist/index.js +178 -50
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/assemble-image-input.test.ts +30 -0
- package/src/__tests__/described-references-video.test.ts +250 -0
- package/src/__tests__/described-references.test.ts +595 -0
- package/src/__tests__/factory-presets.test.ts +8 -2
- package/src/__tests__/node-prompt-fields.test.ts +4 -2
- package/src/assemble-image-input.ts +11 -1
- package/src/described-references.ts +138 -0
- package/src/index.ts +1 -0
- package/src/node-prompt-fields.ts +2 -0
- package/src/prompt-builder.ts +196 -19
- package/src/video-reference-resolver.ts +85 -10
package/dist/index.cjs
CHANGED
|
@@ -10344,32 +10344,6 @@ function resolveBrandInput(brand) {
|
|
|
10344
10344
|
return brand;
|
|
10345
10345
|
}
|
|
10346
10346
|
|
|
10347
|
-
// src/prompt-templates.ts
|
|
10348
|
-
var DEFAULT_TEMPLATES = {
|
|
10349
|
-
"character-description": "Include character '{name}': {description}.",
|
|
10350
|
-
"object-description": "Include object '{name}': {description}.",
|
|
10351
|
-
"location-description": "Include location '{name}': {description}.",
|
|
10352
|
-
"face-description": "Include the exact face and facial features of '{name}' from the reference image. Maintain perfect likeness and facial identity.",
|
|
10353
|
-
// `-generation` templates drive standalone entity generation routes
|
|
10354
|
-
// (`/v1/generate-character`, `/v1/generate-face`, etc.). Duplicated between
|
|
10355
|
-
// frontend and backend historically; consolidated here so the backend DAG
|
|
10356
|
-
// orchestrator produces the same prompt as a single-node HTTP call.
|
|
10357
|
-
"character-generation": "Create a full-body character portrait: {description}. Style: {style}. Gender: {gender}. High quality, detailed, consistent lighting, neutral background.",
|
|
10358
|
-
"object-generation": "Create a product photo of: {description}. Category: {category}. Clean background, professional studio lighting, high detail.",
|
|
10359
|
-
"location-generation": "Create a cinematic scene of: {description}. Category: {category}. Atmospheric lighting, high detail, wide angle.",
|
|
10360
|
-
"face-generation": "Create a professional close-up face portrait headshot: {description}. Style: {style}. Looking directly at camera, sharp focus on facial features, clean background, studio lighting, high resolution. Maintain exact facial identity and features from the reference image.",
|
|
10361
|
-
"generate-image-wrapper": "{userPrompt}\n{assetDescriptions}"
|
|
10362
|
-
};
|
|
10363
|
-
function resolveTemplate(key, userTemplates, flowTemplates) {
|
|
10364
|
-
return flowTemplates?.[key] ?? userTemplates?.[key] ?? DEFAULT_TEMPLATES[key] ?? "";
|
|
10365
|
-
}
|
|
10366
|
-
function applyTemplate(template, vars) {
|
|
10367
|
-
return Object.entries(vars).reduce(
|
|
10368
|
-
(result, [key, value]) => result.replaceAll(`{${key}}`, value || ""),
|
|
10369
|
-
template
|
|
10370
|
-
);
|
|
10371
|
-
}
|
|
10372
|
-
|
|
10373
10347
|
// src/prompt-hint-join.ts
|
|
10374
10348
|
var PROMPT_HINT_SEPARATOR = ". ";
|
|
10375
10349
|
function joinPromptHints(userPrompt, hints) {
|
|
@@ -10581,6 +10555,87 @@ function sectionedClauseCosts(userPrompt, clauses, structuredFragment) {
|
|
|
10581
10555
|
}
|
|
10582
10556
|
return costs;
|
|
10583
10557
|
}
|
|
10558
|
+
|
|
10559
|
+
// src/described-references.ts
|
|
10560
|
+
var CHARACTER_BLOCK_HEADER = "Use these characters:";
|
|
10561
|
+
function referenceDescriptionLine(subject, description) {
|
|
10562
|
+
const s = subject.trim();
|
|
10563
|
+
const d = description?.trim();
|
|
10564
|
+
if (!s || !d) return "";
|
|
10565
|
+
return `${s} \u2014 ${d}.`;
|
|
10566
|
+
}
|
|
10567
|
+
function renderDescribedReferenceLines(refs) {
|
|
10568
|
+
if (!refs || refs.length === 0) return [];
|
|
10569
|
+
const lines = [];
|
|
10570
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10571
|
+
for (const r of refs) {
|
|
10572
|
+
const key = r.name?.trim().toLowerCase();
|
|
10573
|
+
if (!key || seen.has(key)) continue;
|
|
10574
|
+
const line = referenceDescriptionLine(r.name, r.description);
|
|
10575
|
+
if (!line) continue;
|
|
10576
|
+
seen.add(key);
|
|
10577
|
+
lines.push(line);
|
|
10578
|
+
}
|
|
10579
|
+
return lines;
|
|
10580
|
+
}
|
|
10581
|
+
function renderReferenceCaptionLines(videoCaptions, audioCaptions, counts) {
|
|
10582
|
+
const lines = [];
|
|
10583
|
+
const render = (captions, kind, cap) => {
|
|
10584
|
+
if (!captions) return;
|
|
10585
|
+
for (let i = 0; i < captions.length && i < cap; i++) {
|
|
10586
|
+
const text = captions[i]?.trim();
|
|
10587
|
+
if (!text) continue;
|
|
10588
|
+
lines.push(`@${kind}_${i + 1}: ${text}.`);
|
|
10589
|
+
}
|
|
10590
|
+
};
|
|
10591
|
+
render(videoCaptions, "video", counts.video);
|
|
10592
|
+
render(audioCaptions, "audio", counts.audio);
|
|
10593
|
+
return lines;
|
|
10594
|
+
}
|
|
10595
|
+
function appendReferenceLines(prompt, lines, format) {
|
|
10596
|
+
if (lines.length === 0) return prompt;
|
|
10597
|
+
if (format === "hybrid") return insertBeforeStyleSection(prompt, lines);
|
|
10598
|
+
const bullets = lines.map((l) => `- ${l}`).join("\n");
|
|
10599
|
+
if (prompt.startsWith(`${CHARACTER_BLOCK_HEADER}
|
|
10600
|
+
`)) {
|
|
10601
|
+
const splitIdx = prompt.indexOf("\n\n");
|
|
10602
|
+
if (splitIdx === -1) return `${prompt}
|
|
10603
|
+
${bullets}`;
|
|
10604
|
+
return `${prompt.slice(0, splitIdx)}
|
|
10605
|
+
${bullets}${prompt.slice(splitIdx)}`;
|
|
10606
|
+
}
|
|
10607
|
+
const block = `${CHARACTER_BLOCK_HEADER}
|
|
10608
|
+
${bullets}`;
|
|
10609
|
+
return prompt ? `${block}
|
|
10610
|
+
|
|
10611
|
+
${prompt}` : block;
|
|
10612
|
+
}
|
|
10613
|
+
|
|
10614
|
+
// src/prompt-templates.ts
|
|
10615
|
+
var DEFAULT_TEMPLATES = {
|
|
10616
|
+
"character-description": "Include character '{name}': {description}.",
|
|
10617
|
+
"object-description": "Include object '{name}': {description}.",
|
|
10618
|
+
"location-description": "Include location '{name}': {description}.",
|
|
10619
|
+
"face-description": "Include the exact face and facial features of '{name}' from the reference image. Maintain perfect likeness and facial identity.",
|
|
10620
|
+
// `-generation` templates drive standalone entity generation routes
|
|
10621
|
+
// (`/v1/generate-character`, `/v1/generate-face`, etc.). Duplicated between
|
|
10622
|
+
// frontend and backend historically; consolidated here so the backend DAG
|
|
10623
|
+
// orchestrator produces the same prompt as a single-node HTTP call.
|
|
10624
|
+
"character-generation": "Create a full-body character portrait: {description}. Style: {style}. Gender: {gender}. High quality, detailed, consistent lighting, neutral background.",
|
|
10625
|
+
"object-generation": "Create a product photo of: {description}. Category: {category}. Clean background, professional studio lighting, high detail.",
|
|
10626
|
+
"location-generation": "Create a cinematic scene of: {description}. Category: {category}. Atmospheric lighting, high detail, wide angle.",
|
|
10627
|
+
"face-generation": "Create a professional close-up face portrait headshot: {description}. Style: {style}. Looking directly at camera, sharp focus on facial features, clean background, studio lighting, high resolution. Maintain exact facial identity and features from the reference image.",
|
|
10628
|
+
"generate-image-wrapper": "{userPrompt}\n{assetDescriptions}"
|
|
10629
|
+
};
|
|
10630
|
+
function resolveTemplate(key, userTemplates, flowTemplates) {
|
|
10631
|
+
return flowTemplates?.[key] ?? userTemplates?.[key] ?? DEFAULT_TEMPLATES[key] ?? "";
|
|
10632
|
+
}
|
|
10633
|
+
function applyTemplate(template, vars) {
|
|
10634
|
+
return Object.entries(vars).reduce(
|
|
10635
|
+
(result, [key, value]) => result.replaceAll(`{${key}}`, value || ""),
|
|
10636
|
+
template
|
|
10637
|
+
);
|
|
10638
|
+
}
|
|
10584
10639
|
function composeIdentityDescPart(subject, canonicalDesc, elementInjection) {
|
|
10585
10640
|
const parts = [];
|
|
10586
10641
|
const c = canonicalDesc?.trim();
|
|
@@ -10589,6 +10644,10 @@ function composeIdentityDescPart(subject, canonicalDesc, elementInjection) {
|
|
|
10589
10644
|
if (e) parts.push(e);
|
|
10590
10645
|
return parts.length > 0 ? `${subject} \u2014 ${parts.join(". ")}` : subject;
|
|
10591
10646
|
}
|
|
10647
|
+
function pushOverrideDirective(out, ref, binding) {
|
|
10648
|
+
const line = referenceDescriptionLine(binding, ref.descriptionOverride);
|
|
10649
|
+
if (line) out.push(line);
|
|
10650
|
+
}
|
|
10592
10651
|
function resolveCharacterMentions(prompt, tokens, refs) {
|
|
10593
10652
|
const bySlug = /* @__PURE__ */ new Map();
|
|
10594
10653
|
const byVariant = /* @__PURE__ */ new Map();
|
|
@@ -10629,7 +10688,7 @@ function resolveCharacterMentions(prompt, tokens, refs) {
|
|
|
10629
10688
|
const includeCanonicalDesc = effectiveMode === "identical" || effectiveMode === "face-pose";
|
|
10630
10689
|
const descPart = composeIdentityDescPart(
|
|
10631
10690
|
subject,
|
|
10632
|
-
includeCanonicalDesc ? match.characterCanonicalDescription : void 0,
|
|
10691
|
+
match.descriptionOverride?.trim() || (includeCanonicalDesc ? match.characterCanonicalDescription : void 0),
|
|
10633
10692
|
match.elementInjection
|
|
10634
10693
|
);
|
|
10635
10694
|
directiveLines.push(`- ${descPart}.${directive ? ` ${directive}` : ""}`);
|
|
@@ -10707,6 +10766,7 @@ function resolveCharacterMentionsHybrid(prompt, tokens, refs, existingUrls) {
|
|
|
10707
10766
|
const binding = bindingFor(m.url);
|
|
10708
10767
|
const lock = buildIdentityLockLine(withForcedIdentityLock(ref, lockOverrideByUrl.get(m.url)), binding);
|
|
10709
10768
|
if (lock) lockLines.push(lock);
|
|
10769
|
+
pushOverrideDirective(elementDirectives, ref, binding);
|
|
10710
10770
|
const inject = ref.elementInjection?.trim();
|
|
10711
10771
|
if (inject) elementDirectives.push(inject);
|
|
10712
10772
|
}
|
|
@@ -10780,7 +10840,8 @@ function resolveLocationMentions(prompt, tokens, refs) {
|
|
|
10780
10840
|
const subject = `Image ${t.imageIndex} (${displayName})`;
|
|
10781
10841
|
const includeCanonicalDesc = effectiveMode === "identical";
|
|
10782
10842
|
const canonicalDesc = match.locationCanonicalDescription?.trim();
|
|
10783
|
-
const
|
|
10843
|
+
const shownDesc = match.descriptionOverride?.trim() || (includeCanonicalDesc ? canonicalDesc : void 0);
|
|
10844
|
+
const descPart = shownDesc ? `${subject} \u2014 ${shownDesc}` : subject;
|
|
10784
10845
|
directiveLines.push(`- ${descPart}.${directive ? ` ${directive}` : ""}`);
|
|
10785
10846
|
if (t.bucket && t.variant && match.locationVariantDisplayName && match.locationVariantDisplayName !== "canonical") {
|
|
10786
10847
|
directiveLines.push(` (in this image: ${match.locationVariantDisplayName})`);
|
|
@@ -10848,6 +10909,7 @@ function resolveLocationMentionsHybrid(prompt, tokens, refs, existingUrls) {
|
|
|
10848
10909
|
const binding = bindingFor(m.url);
|
|
10849
10910
|
const lock = buildIdentityLockLine(withForcedIdentityLock(ref, lockOverrideByUrl.get(m.url)), binding);
|
|
10850
10911
|
if (lock) lockLines.push(lock);
|
|
10912
|
+
pushOverrideDirective(elementDirectives, ref, binding);
|
|
10851
10913
|
const inject = ref.elementInjection?.trim();
|
|
10852
10914
|
if (inject) elementDirectives.push(inject);
|
|
10853
10915
|
}
|
|
@@ -10897,10 +10959,11 @@ function resolveImageMentionsHybrid(prompt, tokens, refs, existingUrls) {
|
|
|
10897
10959
|
const binding = bindingFor(m.url);
|
|
10898
10960
|
const lock = buildIdentityLockLine(withForcedIdentityLock(ref, lockOverrideByUrl.get(m.url)), binding);
|
|
10899
10961
|
if (lock) lockLines.push(lock);
|
|
10962
|
+
pushOverrideDirective(elementDirectives, ref, binding);
|
|
10900
10963
|
const inject = ref.elementInjection?.trim();
|
|
10901
10964
|
if (inject) elementDirectives.push(inject);
|
|
10902
10965
|
}
|
|
10903
|
-
return { prompt: resolvedPrompt, additionalUrls, lockLines, elementDirectives };
|
|
10966
|
+
return { prompt: resolvedPrompt, additionalUrls, mentionedUrls: seenUrls, lockLines, elementDirectives };
|
|
10904
10967
|
}
|
|
10905
10968
|
function resolveEntityMentionsHybrid(prompt, tokens, refs, existingUrls) {
|
|
10906
10969
|
const bySlug = /* @__PURE__ */ new Map();
|
|
@@ -10951,6 +11014,7 @@ function resolveEntityMentionsHybrid(prompt, tokens, refs, existingUrls) {
|
|
|
10951
11014
|
const binding = bindingFor(m.url);
|
|
10952
11015
|
const lock = buildIdentityLockLine(withForcedIdentityLock(ref, lockOverrideByUrl.get(m.url)), binding);
|
|
10953
11016
|
if (lock) lockLines.push(lock);
|
|
11017
|
+
pushOverrideDirective(elementDirectives, ref, binding);
|
|
10954
11018
|
const inject = ref.elementInjection?.trim();
|
|
10955
11019
|
if (inject) elementDirectives.push(inject);
|
|
10956
11020
|
}
|
|
@@ -10986,7 +11050,7 @@ function buildCanonicalFallback(refs, mentionedSlugs, startIndex) {
|
|
|
10986
11050
|
const subject = `Image ${cursor} (${displayName})`;
|
|
10987
11051
|
const descPart = composeIdentityDescPart(
|
|
10988
11052
|
subject,
|
|
10989
|
-
includeCanonicalDesc ? r.characterCanonicalDescription : void 0,
|
|
11053
|
+
r.descriptionOverride?.trim() || (includeCanonicalDesc ? r.characterCanonicalDescription : void 0),
|
|
10990
11054
|
r.elementInjection
|
|
10991
11055
|
);
|
|
10992
11056
|
directiveLines.push(`- ${descPart}.${directive ? ` ${directive}` : ""}`);
|
|
@@ -11002,7 +11066,7 @@ function buildExtraRefDirectives(refs, emittedCharacterPositions, startIndex) {
|
|
|
11002
11066
|
for (const r of refs) {
|
|
11003
11067
|
if (!r.isExtraRef) continue;
|
|
11004
11068
|
if (!r.url) continue;
|
|
11005
|
-
const description = (r.description ?? r.variantDescription ?? "").trim();
|
|
11069
|
+
const description = (r.descriptionOverride ?? "").trim() || (r.description ?? r.variantDescription ?? "").trim();
|
|
11006
11070
|
if (r.source === "wired-character" && r.characterSlug) {
|
|
11007
11071
|
const effectiveMode = r.defaultUsageMode ?? shared.DEFAULT_USAGE_MODE;
|
|
11008
11072
|
const earlierPos = positionsByChar.get(r.characterSlug);
|
|
@@ -11066,6 +11130,7 @@ function renderCanonicalFallbackHybrid(refs, letterForUrl) {
|
|
|
11066
11130
|
phrases.push(shared.roleToPhrase(shared.resolveDefaultRole(r.defaultRole, r.defaultUsageMode, r.source), binding));
|
|
11067
11131
|
const lock = buildIdentityLockLine(r, binding);
|
|
11068
11132
|
if (lock) lockLines.push(lock);
|
|
11133
|
+
pushOverrideDirective(elementDirectives, r, binding);
|
|
11069
11134
|
const inject = r.elementInjection?.trim();
|
|
11070
11135
|
if (inject) elementDirectives.push(inject);
|
|
11071
11136
|
}
|
|
@@ -11080,7 +11145,7 @@ function renderExtraRefsHybrid(extraRefs, letterForUrl, seedLetterByChar) {
|
|
|
11080
11145
|
if (!r.url) continue;
|
|
11081
11146
|
const letter = letterForUrl(r.url);
|
|
11082
11147
|
const binding = `reference image ${letter}`;
|
|
11083
|
-
const description = (r.description ?? r.variantDescription ?? "").trim();
|
|
11148
|
+
const description = (r.descriptionOverride ?? "").trim() || (r.description ?? r.variantDescription ?? "").trim();
|
|
11084
11149
|
if (r.source === "wired-character" && r.characterSlug) {
|
|
11085
11150
|
const earlier = firstLetterByChar.get(r.characterSlug);
|
|
11086
11151
|
if (earlier !== void 0 && earlier !== letter) {
|
|
@@ -11117,10 +11182,11 @@ function renderLocationCanonicalHybrid(nonCharacterRefs, finalIndexByUrl, covere
|
|
|
11117
11182
|
phrases.push(shared.roleToPhrase(resolveLocationRole(null, null, r), binding));
|
|
11118
11183
|
const lock = buildIdentityLockLine(r, binding);
|
|
11119
11184
|
if (lock) lockLines.push(lock);
|
|
11185
|
+
pushOverrideDirective(elementDirectives, r, binding);
|
|
11120
11186
|
const inject = r.elementInjection?.trim();
|
|
11121
11187
|
if (inject) elementDirectives.push(inject);
|
|
11122
11188
|
}
|
|
11123
|
-
return { phrases, lockLines, elementDirectives };
|
|
11189
|
+
return { phrases, lockLines, elementDirectives, renderedUrls: seenUrls };
|
|
11124
11190
|
}
|
|
11125
11191
|
function renderObjectCreatureCanonicalHybrid(nonCharacterRefs, finalIndexByUrl, coveredUrls) {
|
|
11126
11192
|
const phrases = [];
|
|
@@ -11137,10 +11203,24 @@ function renderObjectCreatureCanonicalHybrid(nonCharacterRefs, finalIndexByUrl,
|
|
|
11137
11203
|
phrases.push(shared.roleToPhrase(shared.defaultRoleForSource(r.source), binding));
|
|
11138
11204
|
const lock = buildIdentityLockLine(r, binding);
|
|
11139
11205
|
if (lock) lockLines.push(lock);
|
|
11206
|
+
pushOverrideDirective(elementDirectives, r, binding);
|
|
11140
11207
|
const inject = r.elementInjection?.trim();
|
|
11141
11208
|
if (inject) elementDirectives.push(inject);
|
|
11142
11209
|
}
|
|
11143
|
-
return { phrases, lockLines, elementDirectives };
|
|
11210
|
+
return { phrases, lockLines, elementDirectives, renderedUrls: seenUrls };
|
|
11211
|
+
}
|
|
11212
|
+
function renderUntoldOverridesHybrid(nonCharacterRefs, finalIndexByUrl, toldUrls) {
|
|
11213
|
+
const lines = [];
|
|
11214
|
+
const sweptUrls = /* @__PURE__ */ new Set();
|
|
11215
|
+
for (const r of nonCharacterRefs) {
|
|
11216
|
+
if (!r.url || toldUrls.has(r.url) || sweptUrls.has(r.url)) continue;
|
|
11217
|
+
const slot = finalIndexByUrl.get(r.url);
|
|
11218
|
+
if (!slot) continue;
|
|
11219
|
+
const before = lines.length;
|
|
11220
|
+
pushOverrideDirective(lines, r, `reference image ${slotToLetter(slot)}`);
|
|
11221
|
+
if (lines.length > before) sweptUrls.add(r.url);
|
|
11222
|
+
}
|
|
11223
|
+
return lines;
|
|
11144
11224
|
}
|
|
11145
11225
|
function buildTileIdForUrl(urls, refs, prompt, sourceNodeIdById) {
|
|
11146
11226
|
const knownSlugs = Array.from(
|
|
@@ -11313,8 +11393,10 @@ function buildImagePromptInternal(config2, marks) {
|
|
|
11313
11393
|
);
|
|
11314
11394
|
const suppressedCanonicalLocationIds = config2.suppressedCanonicalLocationIds ?? [];
|
|
11315
11395
|
const isHybrid = config2.referenceFormat === "hybrid";
|
|
11396
|
+
const describedLines = renderDescribedReferenceLines(config2.describedReferences);
|
|
11316
11397
|
let hybridBodyConverged = false;
|
|
11317
11398
|
const mentionedEntityUrls = /* @__PURE__ */ new Set();
|
|
11399
|
+
const mentionedImageUrls = /* @__PURE__ */ new Set();
|
|
11318
11400
|
if (config2.skipCharacterMentions) {
|
|
11319
11401
|
config2 = {
|
|
11320
11402
|
...config2,
|
|
@@ -11432,6 +11514,7 @@ function buildImagePromptInternal(config2, marks) {
|
|
|
11432
11514
|
resolved.additionalUrls = [...resolved.additionalUrls, ...hi.additionalUrls];
|
|
11433
11515
|
hybridImageLockLines = hi.lockLines;
|
|
11434
11516
|
hybridImageElementDirectives = hi.elementDirectives;
|
|
11517
|
+
for (const u of hi.mentionedUrls) mentionedImageUrls.add(u);
|
|
11435
11518
|
if (hi.additionalUrls.length > 0) hybridBodyConverged = true;
|
|
11436
11519
|
}
|
|
11437
11520
|
}
|
|
@@ -11562,9 +11645,13 @@ ${promptForNext}`;
|
|
|
11562
11645
|
referenceImageUrls = config2.referenceImageUrls || [];
|
|
11563
11646
|
}
|
|
11564
11647
|
}
|
|
11565
|
-
if (connectedReferences) {
|
|
11648
|
+
if (connectedReferences || describedLines.length > 0) {
|
|
11649
|
+
const structuredRefs = connectedReferences ?? [];
|
|
11566
11650
|
let prompt2 = config2.prompt;
|
|
11567
|
-
|
|
11651
|
+
if (!isHybrid && describedLines.length > 0) {
|
|
11652
|
+
prompt2 = appendReferenceLines(prompt2, describedLines, "legacy");
|
|
11653
|
+
}
|
|
11654
|
+
const nonCharacterRefs = structuredRefs.filter(
|
|
11568
11655
|
(r) => r.source !== "wired-character" && r.isExtraRef !== true
|
|
11569
11656
|
);
|
|
11570
11657
|
const nonCharacterUrls = nonCharacterRefs.map((r) => r.url).filter((u) => Boolean(u));
|
|
@@ -11594,11 +11681,23 @@ ${promptForNext}`;
|
|
|
11594
11681
|
const canonLockBlock = canonLockLines.length > 0 ? `${canonLockLines.join("\n")}
|
|
11595
11682
|
|
|
11596
11683
|
` : "";
|
|
11684
|
+
const toldOverrideUrls = /* @__PURE__ */ new Set([
|
|
11685
|
+
...locCanon.renderedUrls,
|
|
11686
|
+
...objCanon.renderedUrls,
|
|
11687
|
+
...mentionedEntityUrls,
|
|
11688
|
+
...mentionedImageUrls
|
|
11689
|
+
]);
|
|
11690
|
+
const untoldOverrides = renderUntoldOverridesHybrid(
|
|
11691
|
+
nonCharacterRefs,
|
|
11692
|
+
finalIndexByUrl,
|
|
11693
|
+
toldOverrideUrls
|
|
11694
|
+
);
|
|
11597
11695
|
const canonTrailingLines = [
|
|
11598
11696
|
...locCanon.phrases,
|
|
11599
11697
|
...objCanon.phrases,
|
|
11600
11698
|
...locCanon.elementDirectives,
|
|
11601
|
-
...objCanon.elementDirectives
|
|
11699
|
+
...objCanon.elementDirectives,
|
|
11700
|
+
...untoldOverrides
|
|
11602
11701
|
];
|
|
11603
11702
|
const composedScene = `${canonLockBlock}${insertBeforeStyleSection(scene, canonTrailingLines)}`;
|
|
11604
11703
|
prompt2 = config2.referenceLockSnippet ? `${config2.referenceLockSnippet}
|
|
@@ -11625,6 +11724,9 @@ ${directives}`;
|
|
|
11625
11724
|
}
|
|
11626
11725
|
}
|
|
11627
11726
|
}
|
|
11727
|
+
if (isHybrid && describedLines.length > 0) {
|
|
11728
|
+
prompt2 = appendReferenceLines(prompt2, describedLines, "hybrid");
|
|
11729
|
+
}
|
|
11628
11730
|
const styleText2 = style?.trim();
|
|
11629
11731
|
const styleLine2 = styleText2 && !isDeniedStyleId(styleText2) ? `Style: ${getStylePromptHint(styleText2) || styleText2}` : "";
|
|
11630
11732
|
const negPrompt2 = negativePrompt?.trim();
|
|
@@ -11665,7 +11767,7 @@ ${directives}`;
|
|
|
11665
11767
|
const reordered = applyReferenceOrder(
|
|
11666
11768
|
assembledUrls,
|
|
11667
11769
|
prompt2,
|
|
11668
|
-
|
|
11770
|
+
structuredRefs,
|
|
11669
11771
|
referenceOrder,
|
|
11670
11772
|
sourceNodeIdById
|
|
11671
11773
|
);
|
|
@@ -11790,7 +11892,10 @@ function collectIdentities(prompt, refs, meta3) {
|
|
|
11790
11892
|
label,
|
|
11791
11893
|
fidelity: m?.fidelity ?? defaultFidelityForSource(ref?.source),
|
|
11792
11894
|
customText: m?.customText?.trim() || void 0,
|
|
11793
|
-
|
|
11895
|
+
// Per-use override ahead of the ref's own description; the directive
|
|
11896
|
+
// builder's location-canonical fallback only fires when BOTH are absent,
|
|
11897
|
+
// so an override outranks the stored location wording too.
|
|
11898
|
+
description: ref?.descriptionOverride?.trim() || ref?.description,
|
|
11794
11899
|
source: ref?.source,
|
|
11795
11900
|
locationCanonicalDescription: ref?.locationCanonicalDescription,
|
|
11796
11901
|
locationSlug: ref?.locationSlug,
|
|
@@ -11898,7 +12003,7 @@ function buildNonCharacterDirectives(prompt, nonCharacterRefs, identityMeta, fin
|
|
|
11898
12003
|
// wired-object falls through to the strict "match exactly" verb.
|
|
11899
12004
|
label: ref.source === "wired-location" ? "location" : ref.source === "wired-creature" ? "creature" : "object",
|
|
11900
12005
|
fidelity: defaultFidelityForSource(ref.source),
|
|
11901
|
-
description: ref.description?.trim() || void 0,
|
|
12006
|
+
description: ref.descriptionOverride?.trim() || ref.description?.trim() || void 0,
|
|
11902
12007
|
source: ref.source,
|
|
11903
12008
|
locationCanonicalDescription: ref.locationCanonicalDescription,
|
|
11904
12009
|
locationSlug: ref.locationSlug,
|
|
@@ -12425,6 +12530,8 @@ function resolveVideoCharacterMentionsHybrid(prompt, tokens, refs, offset) {
|
|
|
12425
12530
|
const binding = bindingFor(m.url);
|
|
12426
12531
|
const lock = buildIdentityLockLine(withForcedIdentityLock(ref, lockOverrideByUrl.get(m.url)), binding);
|
|
12427
12532
|
if (lock) lockLines.push(lock);
|
|
12533
|
+
const overrideLine = referenceDescriptionLine(binding, ref.descriptionOverride);
|
|
12534
|
+
if (overrideLine) elementDirectives.push(overrideLine);
|
|
12428
12535
|
const inject = ref.elementInjection?.trim();
|
|
12429
12536
|
if (inject) elementDirectives.push(inject);
|
|
12430
12537
|
}
|
|
@@ -12450,6 +12557,13 @@ function resolveVideoReferenceCore(args) {
|
|
|
12450
12557
|
video: args.videoRefCount ?? 0,
|
|
12451
12558
|
audio: args.audioRefCount ?? 0
|
|
12452
12559
|
});
|
|
12560
|
+
const describedAndCaptionLines = [
|
|
12561
|
+
...renderDescribedReferenceLines(args.describedReferences),
|
|
12562
|
+
...renderReferenceCaptionLines(args.videoCaptions, args.audioCaptions, {
|
|
12563
|
+
video: args.videoRefCount ?? 0,
|
|
12564
|
+
audio: args.audioRefCount ?? 0
|
|
12565
|
+
})
|
|
12566
|
+
];
|
|
12453
12567
|
let wiredCharRefs = [...args.wiredCharRefs];
|
|
12454
12568
|
const suppressedSlugs = new Set(args.suppressedCanonicalCharacterIds ?? []);
|
|
12455
12569
|
if (suppressedSlugs.size > 0) {
|
|
@@ -12474,14 +12588,15 @@ function resolveVideoReferenceCore(args) {
|
|
|
12474
12588
|
const slotByRefId = /* @__PURE__ */ new Map();
|
|
12475
12589
|
if (wiredCharRefs.length === 0 && !hasExtras) {
|
|
12476
12590
|
const counts = tokenCounts(leadingRefUrls.length);
|
|
12591
|
+
const resolved2 = resolveReferenceTokens(
|
|
12592
|
+
resolveRefIdTokens(args.prompt, { slotById: slotByRefId, nameById: nameByRefId, imageCount: counts.image }),
|
|
12593
|
+
counts
|
|
12594
|
+
);
|
|
12477
12595
|
return {
|
|
12478
|
-
//
|
|
12479
|
-
//
|
|
12480
|
-
//
|
|
12481
|
-
prompt:
|
|
12482
|
-
resolveRefIdTokens(args.prompt, { slotById: slotByRefId, nameById: nameByRefId, imageCount: counts.image }),
|
|
12483
|
-
counts
|
|
12484
|
-
),
|
|
12596
|
+
// Described references and rail captions are the ONE thing this branch can
|
|
12597
|
+
// still contribute: they need no seat, so a request that carries only them
|
|
12598
|
+
// (a story landing before any entity exists) reaches the model here.
|
|
12599
|
+
prompt: describedAndCaptionLines.length > 0 ? appendReferenceLines(resolved2 ?? "", describedAndCaptionLines, args.hybridRoles === true ? "hybrid" : "legacy") : resolved2,
|
|
12485
12600
|
additionalUrls: [...leadingRefUrls]
|
|
12486
12601
|
};
|
|
12487
12602
|
}
|
|
@@ -12539,6 +12654,8 @@ function resolveVideoReferenceCore(args) {
|
|
|
12539
12654
|
canonicalPhrases.push(shared.roleToPhrase(shared.resolveDefaultRole(r.defaultRole, r.defaultUsageMode, r.source), binding));
|
|
12540
12655
|
const lock = buildIdentityLockLine(r, binding);
|
|
12541
12656
|
if (lock) canonicalLockLines.push(lock);
|
|
12657
|
+
const overrideLine = referenceDescriptionLine(binding, r.descriptionOverride);
|
|
12658
|
+
if (overrideLine) canonicalElementDirectives.push(overrideLine);
|
|
12542
12659
|
const inject = r.elementInjection?.trim();
|
|
12543
12660
|
if (inject) canonicalElementDirectives.push(inject);
|
|
12544
12661
|
continue;
|
|
@@ -12555,7 +12672,10 @@ function resolveVideoReferenceCore(args) {
|
|
|
12555
12672
|
const directive = shared.usageModeDirective(effectiveMode);
|
|
12556
12673
|
const includeCanonicalDesc = effectiveMode === "identical" || effectiveMode === "face-pose";
|
|
12557
12674
|
const descBodyParts = [];
|
|
12558
|
-
|
|
12675
|
+
const canonicalOverride = r.descriptionOverride?.trim();
|
|
12676
|
+
if (canonicalOverride) {
|
|
12677
|
+
descBodyParts.push(canonicalOverride);
|
|
12678
|
+
} else if (includeCanonicalDesc && r.characterCanonicalDescription?.trim()) {
|
|
12559
12679
|
descBodyParts.push(r.characterCanonicalDescription.trim());
|
|
12560
12680
|
}
|
|
12561
12681
|
if (r.elementInjection?.trim()) descBodyParts.push(r.elementInjection.trim());
|
|
@@ -12572,7 +12692,7 @@ function resolveVideoReferenceCore(args) {
|
|
|
12572
12692
|
if (!ex.url) continue;
|
|
12573
12693
|
position += 1;
|
|
12574
12694
|
if (ex.id && !slotByRefId.has(ex.id)) slotByRefId.set(ex.id, position);
|
|
12575
|
-
const desc = (ex.description ?? "").trim();
|
|
12695
|
+
const desc = (ex.descriptionOverride ?? "").trim() || (ex.description ?? "").trim();
|
|
12576
12696
|
if (ex.characterSlug) {
|
|
12577
12697
|
const meta3 = args.lookupCharacterBySlug?.(ex.characterSlug);
|
|
12578
12698
|
const charDefaultMode = meta3?.defaultUsageMode;
|
|
@@ -12716,6 +12836,11 @@ ${finalPrompt}` : block;
|
|
|
12716
12836
|
merged.push(u);
|
|
12717
12837
|
}
|
|
12718
12838
|
}
|
|
12839
|
+
finalPrompt = appendReferenceLines(
|
|
12840
|
+
finalPrompt,
|
|
12841
|
+
describedAndCaptionLines,
|
|
12842
|
+
hybrid ? "hybrid" : "legacy"
|
|
12843
|
+
);
|
|
12719
12844
|
finalPrompt = resolveRefIdTokens(finalPrompt, {
|
|
12720
12845
|
slotById: slotByRefId,
|
|
12721
12846
|
nameById: nameByRefId,
|
|
@@ -12930,6 +13055,7 @@ function assembleImageInput(input) {
|
|
|
12930
13055
|
prompt: composePromptText(input.userPrompt, pieces, keptHintClauses),
|
|
12931
13056
|
provider: input.provider,
|
|
12932
13057
|
...input.connectedReferences !== void 0 ? { connectedReferences: input.connectedReferences } : {},
|
|
13058
|
+
...input.describedReferences !== void 0 ? { describedReferences: input.describedReferences } : {},
|
|
12933
13059
|
// Manual uploads / direct refs ride the builder's reference-URL channel so
|
|
12934
13060
|
// the per-provider reference gate filters them alongside bound entities.
|
|
12935
13061
|
// Omit the field entirely when absent so the builder's default ([]) kicks
|
|
@@ -29355,6 +29481,8 @@ var NODE_PROMPT_FIELDS = {
|
|
|
29355
29481
|
// ── Composition / FX (compact, no media-result preview → no inline editor) ──
|
|
29356
29482
|
"image-critic": { prompt: "prompt", promptLabel: "Criteria", media: "image", inline: false },
|
|
29357
29483
|
"motion-graphics": { prompt: "motionPrompt", promptLabel: "Motion prompt", media: "video", inline: false },
|
|
29484
|
+
"generate-3d-scene": { prompt: "scenePrompt", promptLabel: "Scene", media: "text", inline: false },
|
|
29485
|
+
"edit-3d-scene": { prompt: "editPrompt", promptLabel: "Edit instruction", media: "text", inline: false },
|
|
29358
29486
|
"3d-title": { prompt: "titlePrompt", promptLabel: "Title", media: "text", inline: false },
|
|
29359
29487
|
// ── Script / alignment (their primary text field) ──
|
|
29360
29488
|
"generate-script": { prompt: "styleGuide", promptLabel: "Style guide", media: "text", inline: false },
|
|
@@ -34866,6 +34994,7 @@ exports.WARDROBE_FIELD_BY_DIMENSION = WARDROBE_FIELD_BY_DIMENSION;
|
|
|
34866
34994
|
exports.__resetCatalogIdGuardForTests = __resetCatalogIdGuardForTests;
|
|
34867
34995
|
exports.appendField = appendField;
|
|
34868
34996
|
exports.appendMusicMeta = appendMusicMeta;
|
|
34997
|
+
exports.appendReferenceLines = appendReferenceLines;
|
|
34869
34998
|
exports.applyMinorAgeFloorToPickerValues = applyMinorAgeFloorToPickerValues;
|
|
34870
34999
|
exports.applyPickerJson = applyPickerJson;
|
|
34871
35000
|
exports.applyPromptAffixes = applyPromptAffixes;
|
|
@@ -35192,11 +35321,14 @@ exports.promptPartSeparator = promptPartSeparator;
|
|
|
35192
35321
|
exports.readDirectionFields = readDirectionFields;
|
|
35193
35322
|
exports.readStructuredFields = readStructuredFields;
|
|
35194
35323
|
exports.readSubjectFields = readSubjectFields;
|
|
35324
|
+
exports.referenceDescriptionLine = referenceDescriptionLine;
|
|
35195
35325
|
exports.referenceRulesBlock = referenceRulesBlock;
|
|
35196
35326
|
exports.registerCatalogPack = registerCatalogPack;
|
|
35197
35327
|
exports.registerPersonPack = registerPersonPack;
|
|
35328
|
+
exports.renderDescribedReferenceLines = renderDescribedReferenceLines;
|
|
35198
35329
|
exports.renderDirectionHintClauses = renderDirectionHintClauses;
|
|
35199
35330
|
exports.renderDirectionHints = renderDirectionHints;
|
|
35331
|
+
exports.renderReferenceCaptionLines = renderReferenceCaptionLines;
|
|
35200
35332
|
exports.renderStructuredFields = renderStructuredFields;
|
|
35201
35333
|
exports.renderStyleSection = renderStyleSection;
|
|
35202
35334
|
exports.renderSubjectHints = renderSubjectHints;
|