@nodaro/prompts 1.41.0 → 1.42.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{catalog-packs-BP21C1lp.d.cts → catalog-packs-C9CXEWfl.d.cts} +1 -1
- package/dist/{catalog-packs-3SxAVxPF.d.ts → catalog-packs-D7NJpo4k.d.ts} +1 -1
- package/dist/{chunk-3U7X6JZN.cjs → chunk-4YUXR23B.cjs} +13 -13
- package/dist/{chunk-3U7X6JZN.cjs.map → chunk-4YUXR23B.cjs.map} +1 -1
- package/dist/{chunk-DUXX6CBX.js → chunk-6JABZ5OC.js} +4 -4
- package/dist/{chunk-DUXX6CBX.js.map → chunk-6JABZ5OC.js.map} +1 -1
- package/dist/{chunk-PWWM7Q3T.cjs → chunk-AXQK7UH7.cjs} +49 -49
- package/dist/{chunk-PWWM7Q3T.cjs.map → chunk-AXQK7UH7.cjs.map} +1 -1
- package/dist/{chunk-SXXW4LCR.js → chunk-CYMIXKFT.js} +12 -8
- package/dist/chunk-CYMIXKFT.js.map +1 -0
- package/dist/{chunk-6GVFJLDL.js → chunk-GIO77YH5.js} +4 -4
- package/dist/{chunk-6GVFJLDL.js.map → chunk-GIO77YH5.js.map} +1 -1
- package/dist/{chunk-C3NHNECH.cjs → chunk-H4JMZWOE.cjs} +39 -39
- package/dist/{chunk-C3NHNECH.cjs.map → chunk-H4JMZWOE.cjs.map} +1 -1
- package/dist/{chunk-GTDKDD7Y.js → chunk-HL6PZ4A6.js} +5 -5
- package/dist/{chunk-GTDKDD7Y.js.map → chunk-HL6PZ4A6.js.map} +1 -1
- package/dist/chunk-HOMR5XFP.js +3 -0
- package/dist/{chunk-F4VO6YEJ.js.map → chunk-HOMR5XFP.js.map} +1 -1
- package/dist/{chunk-SECAGGRK.cjs → chunk-I3QS7BSY.cjs} +8 -8
- package/dist/{chunk-SECAGGRK.cjs.map → chunk-I3QS7BSY.cjs.map} +1 -1
- package/dist/{chunk-JOHYGDUU.js → chunk-IFRFYBGE.js} +3 -3
- package/dist/{chunk-JOHYGDUU.js.map → chunk-IFRFYBGE.js.map} +1 -1
- package/dist/chunk-JCYK7NSR.js +3384 -0
- package/dist/chunk-JCYK7NSR.js.map +1 -0
- package/dist/{chunk-2P26SZX5.cjs → chunk-JDNHMVEV.cjs} +35 -35
- package/dist/{chunk-2P26SZX5.cjs.map → chunk-JDNHMVEV.cjs.map} +1 -1
- package/dist/{chunk-HQTHDTHN.js → chunk-PHFOKGYS.js} +6 -6
- package/dist/{chunk-HQTHDTHN.js.map → chunk-PHFOKGYS.js.map} +1 -1
- package/dist/{chunk-EAYEZXWT.js → chunk-QJACEKMZ.js} +3 -3
- package/dist/{chunk-EAYEZXWT.js.map → chunk-QJACEKMZ.js.map} +1 -1
- package/dist/{chunk-MQEXFCNU.cjs → chunk-SB7AYE6S.cjs} +14 -10
- package/dist/chunk-SB7AYE6S.cjs.map +1 -0
- package/dist/chunk-T4OJFIJK.cjs +4 -0
- package/dist/{chunk-VIT3NKGB.cjs.map → chunk-T4OJFIJK.cjs.map} +1 -1
- package/dist/chunk-WARNUGXT.cjs +3403 -0
- package/dist/chunk-WARNUGXT.cjs.map +1 -0
- package/dist/{chunk-QDUTMOF4.js → chunk-ZFOXGNLK.js} +4 -4
- package/dist/{chunk-QDUTMOF4.js.map → chunk-ZFOXGNLK.js.map} +1 -1
- package/dist/{chunk-IUCNJAHW.cjs → chunk-ZGA72NCT.cjs} +125 -125
- package/dist/{chunk-IUCNJAHW.cjs.map → chunk-ZGA72NCT.cjs.map} +1 -1
- package/dist/{chunk-WRM52ZBN.cjs → chunk-ZLRB5BVT.cjs} +18 -18
- package/dist/{chunk-WRM52ZBN.cjs.map → chunk-ZLRB5BVT.cjs.map} +1 -1
- package/dist/entries/assembly.cjs +29 -29
- package/dist/entries/assembly.js +6 -6
- package/dist/entries/catalog-packs.d.cts +4 -4
- package/dist/entries/catalog-packs.d.ts +4 -4
- package/dist/entries/person.d.cts +3 -3
- package/dist/entries/person.d.ts +3 -3
- package/dist/entries/picker-art.cjs +29 -17
- package/dist/entries/picker-art.d.cts +1122 -447
- package/dist/entries/picker-art.d.ts +1122 -447
- package/dist/entries/picker-art.js +2 -2
- package/dist/entries/picker-catalogs.cjs +57 -57
- package/dist/entries/picker-catalogs.d.cts +3 -3
- package/dist/entries/picker-catalogs.d.ts +3 -3
- package/dist/entries/picker-catalogs.js +5 -5
- package/dist/entries/pickers.cjs +374 -374
- package/dist/entries/pickers.js +3 -3
- package/dist/entries/prompt-builder.cjs +76 -76
- package/dist/entries/prompt-builder.js +5 -5
- package/dist/images-DrbQB9Yh.d.cts +65 -0
- package/dist/images-DrbQB9Yh.d.ts +65 -0
- package/dist/index.cjs +554 -542
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +10 -10
- package/dist/{picker-catalogs-DDjtZND3.d.ts → picker-catalogs-BM8IphF1.d.ts} +1 -1
- package/dist/{picker-catalogs-CmV7r0j1.d.cts → picker-catalogs-C3utGMRB.d.cts} +1 -1
- package/package.json +2 -2
- package/src/__tests__/picker-art-images.test.ts +94 -3
- package/src/picker-art/images.ts +59 -9
- package/src/picker-art/index.ts +1 -0
- package/src/picker-art/look-preview-sets.ts +449 -445
- package/src/picker-art/sound-render-sets.ts +688 -0
- package/src/picker-catalogs.ts +12 -8
- package/dist/chunk-F4VO6YEJ.js +0 -3
- package/dist/chunk-MQEXFCNU.cjs.map +0 -1
- package/dist/chunk-QGVZXBDE.cjs +0 -2708
- package/dist/chunk-QGVZXBDE.cjs.map +0 -1
- package/dist/chunk-RZJEROA2.js +0 -2692
- package/dist/chunk-RZJEROA2.js.map +0 -1
- package/dist/chunk-SXXW4LCR.js.map +0 -1
- package/dist/chunk-VIT3NKGB.cjs +0 -4
- package/dist/images-BAnMUUmW.d.cts +0 -39
- package/dist/images-BAnMUUmW.d.ts +0 -39
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/prompt-style-section.ts","../src/described-references.ts","../src/unbound-reference-tokens.ts","../src/prompt-builder.ts","../src/prompt-builder-structured-fields.ts","../src/subject-registry.ts"],"names":["renderDirectionHintClauses","joinSentences","joinPromptHints","DEFAULT_USAGE_MODE","usageModeDirective","REFERENCE_ROLE_PRESETS","resolveDefaultRole","roleToPhrase","buildIdentityLockLine","withForcedIdentityLock","defaultRoleForSource","normalizeRoleSlug","DEFAULT_LOCATION_USAGE_MODE","imageMentionSlugForRef","entityMentionSlugForRef","findCharacterMentionTokens","imageReferenceLimit","knownImageSlugsFromRefs","findImageMentionTokens","knownEntitySlugsFromRefs","findEntityMentionTokens","findLocationMentionTokens","prompt","styleText","styleLine","isDeniedStyleId","getStylePromptHint","negPrompt","nativeNegativePrompt","avoidLine","NATIVE_NEGATIVE_PROMPT_MODELS","getMaxNegativePromptChars","maxLen","getMaxImagePromptChars","preCut","reserved","styleSuffix","avoidSuffix","supportsRefs","MODELS_WITH_REFERENCE_IMAGE_SUPPORT","refsToSend","resolveTemplate","applyTemplate","IMAGE_TOKEN_PATTERN","locationReferencePhotoKindLabel","buildPersonHints","buildStylingHints","buildHeldPropHints","buildMaterialHints","curatedAnimalPromptHint","curatedAnimalTerm","PERSON_DIMENSION_ORDER","PERSON_FIELD_BY_DIMENSION","STYLING_DIMENSION_ORDER","STYLING_FIELD_BY_DIMENSION","getRegisteredPersonFieldByDimension","getRegisteredPersonDimensionOrder","DIRECTION_ARRAY_CEILING","DIRECTION_ID_MAX_CHARS","getPersonDimensionLimit","getStylingDimensionLimit"],"mappings":"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","file":"chunk-WRM52ZBN.cjs","sourcesContent":["/**\n * THE `[style]` SECTION — the trailing block an assembled prompt carries when a\n * run selects any LOOK dimension, shared by the image (`assembleImageInput`)\n * and video (`composeVideoPromptText`) composers so the two surfaces render one\n * shape.\n *\n * <body>\n *\n * [style]:\n * <film line>\n * <scene line>\n *\n * WHY THE LOOK CLAUSES MOVED: folded inline, a broad direction buried the shot\n * — a dozen grade/lighting/era sentences between the user's prose and the\n * structured fields, all in the same register, with nothing telling the model\n * which sentences describe the ACTION and which describe the LOOK. The section\n * says it structurally instead.\n *\n * WHAT STAYS IN THE BODY: the user's prose, the subject fold, the whole MOTION\n * family, and the structured fragment last. Camera motion is part of the shot\n * prose, not the look — so the body/section boundary IS the registry's `family`\n * column, the same column the video verbosity policy splits on. Coupling them\n * is deliberate: one row cannot be shot-prose for the verbosity policy and look\n * for the section.\n *\n * THE SECTION HAS NO TERMINATOR, so \"after the section\" is not a shape a caller\n * can reach by appending: every assembler downstream of the composer (both\n * reference resolvers, the legacy character-description wrapper, `Style:` /\n * `Avoid:`) joins its text with a single `\\n`, which lands it UNDER the header.\n * Two helpers below are how they stay out — `insertBeforeStyleSection` for body\n * content, `endsInsideStyleSection` for the self-labeling control lines that\n * must stay last. A terminator instead would dangle whenever nothing follows,\n * and would break the byte parity below.\n *\n * THE ZERO-CLAUSE CONTRACT (load-bearing): with no look clause — none selected,\n * all shed, or all deduped away — there is NO header and NO extra newline, and\n * the output is byte-identical to the plain hint join. That keeps the\n * verbatim-and-untrimmed no-op alive (zero hints AND zero section → the user's\n * prompt back byte-for-byte, `undefined` included), which is what the routes'\n * `composed !== prompt` guard reads to decide whether to pin\n * `input_data.userPrompt`.\n *\n * NO INDENTATION ANYWHERE: the video reference resolver collapses 2+ horizontal\n * spaces unanchored, so an indented section line would come back flattened. The\n * section is written flush-left rather than relying on that collapse to be\n * harmless.\n */\nimport { joinPromptHints } from \"./prompt-hint-join.js\"\nimport { joinSentences } from \"./hint-join.js\"\nimport {\n renderDirectionHintClauses,\n type DirectionFamily,\n type DirectionFields,\n type DirectionRenderOptions,\n type DirectionStyleGroup,\n} from \"./direction-registry.js\"\n\n/**\n * The section header, verbatim. Lowercase and bracketed so it reads as\n * structure rather than as a sentence — and so it can be found again by\n * `buildImagePrompt`'s hybrid line-capitalizer, which must stop here\n * (`[Style]:` would be a different token, and capitalized clause lines would\n * corrupt the lowercase catalog wording).\n */\nexport const STYLE_SECTION_HEADER = \"[style]:\"\n\n/** The blank line between the body and the section. Omitted for an empty body. */\nexport const STYLE_SECTION_GAP = \"\\n\\n\"\n\n/** The section's opening bytes — the gap, the header and the newline before its\n * first clause line (the section is never emitted without one). */\nconst STYLE_SECTION_OPENING = `${STYLE_SECTION_GAP}${STYLE_SECTION_HEADER}\\n`\n\n/**\n * Split a composed prompt into the BODY and the `[style]` section it ends with\n * (`section: \"\"` when it carries none, the body then being the whole string;\n * the section comes back WITHOUT the gap).\n *\n * Matched from the RIGHT: the composer always emits the section last, and a\n * user's own prose is free to contain the same characters. A blank body drops\n * the gap with it, so the section-only form is matched on its own.\n */\nexport function splitStyleSection(prompt: string): { body: string; section: string } {\n const at = prompt.lastIndexOf(STYLE_SECTION_OPENING)\n if (at >= 0) {\n return { body: prompt.slice(0, at), section: prompt.slice(at + STYLE_SECTION_GAP.length) }\n }\n return prompt.startsWith(`${STYLE_SECTION_HEADER}\\n`)\n ? { body: \"\", section: prompt }\n : { body: prompt, section: \"\" }\n}\n\n/**\n * Extend a composed prompt's BODY with more lines, AHEAD of the `[style]`\n * section — what every assembler downstream of the composer needs, because the\n * section has no terminator: a plain append lands under the header and reads as\n * one more look clause. Reference bindings, element directives and character\n * descriptions are scene content that belongs with the prose, and leaving the\n * look clauses last is where a look tail was measured to cost nothing.\n *\n * With no section this IS the plain `\"\\n\"` join every caller emitted before —\n * the byte-parity path, down to the leading newline an empty prompt produces.\n */\nexport function insertBeforeStyleSection(prompt: string, lines: readonly string[]): string {\n if (lines.length === 0) return prompt\n const block = lines.join(\"\\n\")\n const { body, section } = splitStyleSection(prompt)\n if (section.length === 0) return `${prompt}\\n${block}`\n return `${body.length > 0 ? `${body}\\n${block}` : block}${STYLE_SECTION_GAP}${section}`\n}\n\n/**\n * True when `prompt` ends INSIDE the section — its last `\\n\\n`-delimited block\n * opens with the header. What the self-labeling control lines (`Style:`,\n * `Avoid:`) read: they stay at the END of the prompt by design, so a blank line\n * of their own is the only thing that can close the header's scope ahead of\n * them.\n */\nexport function endsInsideStyleSection(prompt: string): boolean {\n const at = prompt.lastIndexOf(STYLE_SECTION_GAP)\n const lastBlock = at >= 0 ? prompt.slice(at + STYLE_SECTION_GAP.length) : prompt\n return lastBlock.startsWith(`${STYLE_SECTION_HEADER}\\n`)\n}\n\n/** Where a rendered clause reads in the assembled prompt. */\nexport type PromptClauseSlot = \"body\" | \"film\" | \"scene\"\n\n/** A rendered clause plus the line it belongs on. */\nexport interface SlottedPromptClause {\n readonly text: string\n readonly slot: PromptClauseSlot\n}\n\n/**\n * The slot a direction row's clause takes: motion stays in the body, the five\n * `styleGroup: \"film\"` rows lead the section, every other look row follows on\n * the scene line.\n */\nexport function styleSlotFor(\n row: { readonly family: DirectionFamily; readonly styleGroup?: DirectionStyleGroup },\n): PromptClauseSlot {\n if (row.family === \"motion\") return \"body\"\n return row.styleGroup === \"film\" ? \"film\" : \"scene\"\n}\n\n/**\n * The SUBJECT channel's clauses: always body. Who is in the shot is the noun\n * phrase the look modifies, not part of the look.\n */\nexport function asBodyClauses(texts: readonly string[]): SlottedPromptClause[] {\n return texts.map((text) => ({ text, slot: \"body\" as const }))\n}\n\n/**\n * Fold a direction bag and tag each clause with its slot, in registry table\n * order. The ORDER is the fold/survival order, not the string order — the\n * composers slice this list from the tail when a cap forces a shed, and only\n * then hand the surviving prefix to `composeSectionedPrompt`.\n */\nexport function partitionStyleClauses(\n direction: DirectionFields | undefined,\n opts: DirectionRenderOptions,\n): SlottedPromptClause[] {\n return renderDirectionHintClauses(direction, opts).map((clause) => ({\n text: clause.text,\n slot: styleSlotFor(clause),\n }))\n}\n\n/**\n * The section block for a set of clauses — `\"\"` when none of them is a look\n * clause. Each line is omitted entirely when its half of the split is empty, so\n * a scene-only fold never emits a blank film line.\n */\nexport function styleSectionFromClauses(clauses: readonly SlottedPromptClause[]): string {\n const line = (slot: PromptClauseSlot) =>\n joinSentences(clauses.filter((c) => c.slot === slot).map((c) => c.text))\n const lines = [line(\"film\"), line(\"scene\")].filter((l) => l.length > 0)\n return lines.length === 0 ? \"\" : `${STYLE_SECTION_HEADER}\\n${lines.join(\"\\n\")}`\n}\n\n/**\n * The section for a raw direction bag — the entry point a client renders its\n * preview through, so the preview and the server emit the same bytes.\n */\nexport function renderStyleSection(\n direction: DirectionFields | undefined,\n opts: DirectionRenderOptions,\n): string {\n return styleSectionFromClauses(partitionStyleClauses(direction, opts))\n}\n\n/**\n * The assembled prompt for a set of clauses: body clauses `\". \"`-joined onto the\n * user's prompt, the structured fragment last in the body, then the section.\n *\n * TRIMMING follows `joinPromptHints`: the prompt is trimmed whenever ANYTHING\n * folded — a section counts, so a look-only fold trims too, or the blank line\n * would inherit the prompt's trailing whitespace. With nothing folded at all the\n * prompt is returned VERBATIM AND UNTRIMMED (`undefined` passes straight\n * through), which is the byte-parity contract every existing caller rests on.\n *\n * A blank body drops the gap with it, so the result never opens on a newline —\n * the same reason `joinPromptHints` filters a blank prompt out of its join.\n */\nexport function composeSectionedPrompt<T extends string | undefined>(\n userPrompt: T,\n clauses: readonly SlottedPromptClause[],\n structuredFragment: string,\n): string | T {\n const bodyHints = [\n ...clauses.filter((c) => c.slot === \"body\").map((c) => c.text),\n structuredFragment,\n ].filter((p) => p.length > 0)\n const section = styleSectionFromClauses(clauses)\n if (section.length === 0) {\n return bodyHints.length === 0 ? userPrompt : joinPromptHints(userPrompt ?? \"\", bodyHints)\n }\n const body =\n bodyHints.length > 0 ? joinPromptHints(userPrompt ?? \"\", bodyHints) : (userPrompt ?? \"\").trim()\n return body.length > 0 ? `${body}${STYLE_SECTION_GAP}${section}` : section\n}\n\n/**\n * What each clause costs the assembled prompt, as the EXACT composed-length\n * delta of adding it to the prefix below it. Feeds `keepableDirectionHints`,\n * which walks the list tail-first.\n *\n * Exact deltas rather than \"clause + separator\" because the section's own bytes\n * are not evenly distributed: the FIRST look clause carries the whole\n * `\"\\n\\n[style]:\\n\"` header (11 characters that only come back when the section\n * disappears), the second look clause of a line carries a `\". \"`, the first of\n * the scene line carries a `\"\\n\"`. Flat costs would under-price the header, so\n * the walk would cover a deficit with more clauses than it needs and over-shed\n * — visible as a fold that drops two clauses where one would have fit. The\n * deltas do not change between shed iterations (the walk only ever shortens the\n * prefix), so they are computed once, before the loop.\n */\nexport function sectionedClauseCosts(\n userPrompt: string | undefined,\n clauses: readonly SlottedPromptClause[],\n structuredFragment: string,\n): number[] {\n const lengthAt = (kept: number) =>\n composeSectionedPrompt(userPrompt, clauses.slice(0, kept), structuredFragment)?.length ?? 0\n const costs: number[] = []\n let below = lengthAt(0)\n for (let i = 0; i < clauses.length; i++) {\n const at = lengthAt(i + 1)\n costs.push(at - below)\n below = at\n }\n return costs\n}\n","/**\n * Described references + per-reference description overrides + rail captions —\n * the ONE place either lane phrases \"what this reference IS\".\n *\n * Three shapes, one grammar (`<subject> — <description>.`) plus the caption's\n * `<binding>: <caption>.`:\n *\n * - a DESCRIBED reference (`DescribedReference`, no media) → `Natalie — a\n * tall woman in a red coat.` The subject is the NAME, because a described\n * reference has no seat to bind to: correlation with the prose is by name,\n * which is why the caller leaves the name in the prompt rather than an\n * indexed `@slug:N` mention (that grammar is url-gated).\n * - a per-use `descriptionOverride` on a reference the HYBRID format gives no\n * description slot (a mention / canonical-fallback / location / object role\n * phrase carries none) → `reference image A — a tall woman in a red coat.`\n * Same grammar, the BINDING as the subject. Where a description slot DOES\n * exist (every legacy bullet, and the hybrid extras' `, <desc>` clause) the\n * override fills THAT slot instead, so the model is never told twice.\n * - a rail CAPTION for a video / audio reference → `@video_1: the establishing\n * drone shot.` Index-aligned with the caller's url array.\n *\n * Rendering is separate from JOINING on purpose: the lines are format-agnostic\n * text, and each lane already owns where a trailing directive goes (the image\n * hybrid's `trailingLines`, the video core's `trailingLines` /\n * `allFallbackLines`). `appendReferenceLines` is the joiner for the call sites\n * that have no such array to push into — it bullets the lines into the legacy\n * \"Use these characters:\" block or lands them ahead of the `[style]` section in\n * hybrid, matching what each lane's own assembly does.\n */\n\nimport type { DescribedReference } from \"@nodaro/shared/types\"\nimport { insertBeforeStyleSection } from \"./prompt-style-section.js\"\n\n/** Which reference-prompt format the lines are being rendered for. */\nexport type ReferenceLineFormat = \"legacy\" | \"hybrid\"\n\n/** The legacy directive block every lane consolidates its bullets into. */\nconst CHARACTER_BLOCK_HEADER = \"Use these characters:\"\n\n/**\n * The ONE phrasing for \"this subject is described as …\":\n * `<subject> — <description>.`\n *\n * `subject` is the name for a described reference and the reference's binding\n * (`reference image A` / `@image_2`) for a per-use description override. Both\n * halves are trimmed; an empty half yields `\"\"` (the caller drops the line).\n */\nexport function referenceDescriptionLine(\n subject: string,\n description: string | null | undefined,\n): string {\n const s = subject.trim()\n const d = description?.trim()\n if (!s || !d) return \"\"\n return `${s} — ${d}.`\n}\n\n/**\n * Render the described references (name + description, no media) as trailing\n * lines. Entries missing either half contribute nothing; entries repeating a\n * name (case-insensitively) render once — a description a caller sent twice\n * says nothing new to the model, and every sibling renderer in both lanes\n * dedups the same way.\n */\nexport function renderDescribedReferenceLines(\n refs: readonly DescribedReference[] | undefined,\n): string[] {\n if (!refs || refs.length === 0) return []\n const lines: string[] = []\n const seen = new Set<string>()\n for (const r of refs) {\n const key = r.name?.trim().toLowerCase()\n if (!key || seen.has(key)) continue\n const line = referenceDescriptionLine(r.name, r.description)\n if (!line) continue\n seen.add(key)\n lines.push(line)\n }\n return lines\n}\n\n/**\n * Render the video / audio rail captions as `@video_N: <caption>.` /\n * `@audio_N: <caption>.` lines, index-aligned with the caller's url arrays.\n *\n * Each list is bounded by the count of references of that kind that actually\n * ship, so a caption for a url the provider cap dropped never binds a phantom\n * `@video_N`. Blank captions are holes in an aligned array, not lines.\n */\nexport function renderReferenceCaptionLines(\n videoCaptions: readonly string[] | undefined,\n audioCaptions: readonly string[] | undefined,\n counts: { readonly video: number; readonly audio: number },\n): string[] {\n const lines: string[] = []\n const render = (captions: readonly string[] | undefined, kind: \"video\" | \"audio\", cap: number) => {\n if (!captions) return\n for (let i = 0; i < captions.length && i < cap; i++) {\n const text = captions[i]?.trim()\n if (!text) continue\n lines.push(`@${kind}_${i + 1}: ${text}.`)\n }\n }\n render(videoCaptions, \"video\", counts.video)\n render(audioCaptions, \"audio\", counts.audio)\n return lines\n}\n\n/**\n * Append reference lines to an assembled prompt the way the surrounding lane\n * would have.\n *\n * - hybrid → trailing scene directives ahead of the `[style]` section (the\n * section has no terminator, so a flat append would read as one more look\n * clause).\n * - legacy → `- ` bullets consolidated into the existing\n * \"Use these characters:\" block, or a new block prepended ahead of the\n * body — the same splice-or-create both lanes already do for their\n * canonical-fallback and extra-ref bullets.\n *\n * No lines → the prompt is returned unchanged, byte-for-byte.\n */\nexport function appendReferenceLines(\n prompt: string,\n lines: readonly string[],\n format: ReferenceLineFormat,\n): string {\n if (lines.length === 0) return prompt\n if (format === \"hybrid\") return insertBeforeStyleSection(prompt, lines)\n const bullets = lines.map((l) => `- ${l}`).join(\"\\n\")\n if (prompt.startsWith(`${CHARACTER_BLOCK_HEADER}\\n`)) {\n const splitIdx = prompt.indexOf(\"\\n\\n\")\n if (splitIdx === -1) return `${prompt}\\n${bullets}`\n return `${prompt.slice(0, splitIdx)}\\n${bullets}${prompt.slice(splitIdx)}`\n }\n const block = `${CHARACTER_BLOCK_HEADER}\\n${bullets}`\n return prompt ? `${block}\\n\\n${prompt}` : block\n}\n","/**\n * The unwired half of the editor reference-token contract — what a\n * `{image:N:label}` / `{video:N:label}` / `{audio:N:label}` token becomes when\n * no reference of its kind sits at its position. ONE rule for every surface:\n * the video resolver (`resolveReferenceTokens`) and the image prompt builder\n * (`buildImagePrompt`) both render an unwired token through these two\n * functions, so the image and video paths cannot drift apart on it.\n *\n * Each caller keeps its own token grammar and its own WIRED rendering (video:\n * `the person from @image_1`; image: `Image 1 (person)` /\n * `the person from reference image A`); only the unwired outcome is shared.\n */\n\n/**\n * The text an unwired token renders to: its label as written, or nothing for a\n * label-less token. Text a resolver does not rewrite keeps its tokens as typed\n * — on image prompts a wired token in a hybrid `Avoid:` line and the native\n * negative prompt, both on purpose (see `dropUnwiredImageTokens`).\n */\nexport function unboundReferenceTokenText(label: string | undefined): string {\n return label ?? \"\"\n}\n\n/**\n * Tidy the gap a dropped token leaves: collapse every run of 2+ HORIZONTAL\n * whitespace to one space, then trim. The class is `[^\\S\\r\\n]` (NOT `\\s`) so\n * the `\\n` / `\\n\\n` separators between assembled blocks survive — a `\\s{2,}`\n * collapse would merge paragraphs.\n */\nexport function tidyReferenceTokenGaps(prompt: string): string {\n return prompt.replace(/[^\\S\\r\\n]{2,}/g, \" \").trim()\n}\n","/**\n * Image prompt assembly logic shared between frontend and backend.\n * Handles character description expansion, style appending, negative prompt routing,\n * provider-aware prompt truncation (default 5000 chars), and reference image filtering by model support.\n */\n\nimport { joinSentences } from \"./hint-join.js\"\nimport { IMAGE_TOKEN_PATTERN } from \"./image-token-pattern.js\"\nimport { resolveTemplate, applyTemplate } from \"./prompt-templates.js\"\nimport { NATIVE_NEGATIVE_PROMPT_MODELS, MODELS_WITH_REFERENCE_IMAGE_SUPPORT, imageReferenceLimit, getMaxImagePromptChars, getMaxNegativePromptChars } from \"@nodaro/shared/models\"\nimport { getStylePromptHint, isDeniedStyleId } from \"./style.js\"\nimport {\n STYLE_SECTION_GAP,\n STYLE_SECTION_HEADER,\n endsInsideStyleSection,\n insertBeforeStyleSection,\n splitStyleSection,\n} from \"./prompt-style-section.js\"\nimport {\n findCharacterMentionTokens,\n type CharacterMentionTokenInfo,\n usageModeDirective,\n DEFAULT_USAGE_MODE,\n type UsageMode,\n roleToPhrase,\n defaultRoleForSource,\n REFERENCE_ROLE_PRESETS,\n normalizeRoleSlug,\n resolveDefaultRole,\n findLocationMentionTokens,\n DEFAULT_LOCATION_USAGE_MODE,\n type LocationMentionTokenInfo,\n type LocationUsageMode,\n findImageMentionTokens,\n imageMentionSlugForRef,\n knownImageSlugsFromRefs,\n type ImageMentionTokenInfo,\n findEntityMentionTokens,\n entityMentionSlugForRef,\n knownEntitySlugsFromRefs,\n type EntityMentionTokenInfo,\n locationReferencePhotoKindLabel,\n type LocationReferencePhotoKind\n} from \"@nodaro/shared/entities\"\nimport { buildIdentityLockLine, withForcedIdentityLock } from \"./identity-lock.js\"\nimport type { CharacterDef, ConnectedReference, DescribedReference, IdentityFidelity, IdentityMeta, ReferenceSource, SceneData } from \"@nodaro/shared/types\"\nimport { appendReferenceLines, referenceDescriptionLine, renderDescribedReferenceLines } from \"./described-references.js\"\nimport { tidyReferenceTokenGaps, unboundReferenceTokenText } from \"./unbound-reference-tokens.js\"\n\nexport interface ResolveCharacterMentionsResult {\n /** Prompt with @-tokens replaced by display names + \"Use these characters:\" directive prepended. */\n prompt: string\n /** Resolved URLs from matched mention tokens, in mention order, deduped via caller responsibility. */\n additionalUrls: string[]\n /**\n * Set of character slugs that had at least one resolved mention token.\n * Callers use this to gate the per-character \"no mention → canonical\n * fallback\" behavior so a wired character with no `@-mention` still gets\n * its canonical URL attached (existing pre-mention-feature behavior).\n */\n mentionedCharacterSlugs: Set<string>\n}\n\n/**\n * Compose the descriptive body of a character identity bullet:\n * `${subject} — ${canonicalDesc?}. ${elementInjection?}` (parts joined by \". \")\n *\n * Either part may be absent. `canonicalDesc` is mode-gated by the caller (pass\n * `undefined` to omit it for non-identity modes); `elementInjection` is the\n * mode-INDEPENDENT scene-composition fragment wired into the character node's\n * Assets/Prompt handle (held-prop / styling / text). When BOTH are absent the\n * bullet collapses to the bare `subject` — byte-identical to the\n * pre-elementInjection output, which the parity tests pin.\n */\nfunction composeIdentityDescPart(\n subject: string,\n canonicalDesc: string | null | undefined,\n elementInjection: string | null | undefined,\n): string {\n const parts: string[] = []\n const c = canonicalDesc?.trim()\n if (c) parts.push(c)\n const e = elementInjection?.trim()\n if (e) parts.push(e)\n return parts.length > 0 ? `${subject} — ${joinSentences(parts)}` : subject\n}\n\n/**\n * The trailing line a per-use `descriptionOverride` contributes in HYBRID\n * format. The hybrid role phrase (\"the person from reference image A\") carries\n * no description slot, so the override is surfaced as its own binding-subject\n * line via the ONE phrasing helper in `described-references.ts`. It is pushed\n * onto the reference's `elementDirectives` — the array every hybrid renderer\n * already uses for \"the trailing scene directives this reference contributes\" —\n * so it lands with that reference's other lines instead of threading a ninth\n * channel through eight call sites.\n *\n * The hybrid EXTRAS path does not call this: it has a real `, <desc>` clause,\n * which the override fills instead (so the model is never told twice). Nothing\n * is pushed without an override, which is what keeps every existing hybrid\n * output byte-identical.\n */\nfunction pushOverrideDirective(\n out: string[],\n ref: Pick<ConnectedReference, \"descriptionOverride\">,\n binding: string,\n): void {\n const line = referenceDescriptionLine(binding, ref.descriptionOverride)\n if (line) out.push(line)\n}\n\n/**\n * Resolve @-mention tokens in a prompt against connected references.\n * Returns: augmented prompt (with directives prepended + tokens replaced\n * by character display names) and the set of asset URLs to include as refs.\n *\n * Behavior:\n * - Build two lookup Maps: `bySlug` for canonical entries, `byVariant` for variant entries.\n * - Iterate tokens left-to-right so directives are emitted in mention order.\n * - For each token, prefer the variant match when variantSlug present; fall back to canonical.\n * - `charactersSeen` Set guards the long canonical description to appear AT MOST ONCE\n * per character even when the character is mentioned in several tokens.\n * - Build a `replacements` array (token + offset + replacement display name) and\n * apply right-to-left so earlier replacements do not shift later offsets.\n * - Prepend a \"Use these characters:\\n…\" directive section when any directives were emitted.\n * - Each directive bullet leads with the user-visible `Image N (Name)` index pulled\n * directly from the typed token (e.g. `@kira:1:smile` → `Image 1 (Kira)`).\n * This lets the user trace a literal slug in the prompt to its appearance in\n * the final assembled identity-directive block.\n */\nexport function resolveCharacterMentions(\n prompt: string,\n tokens: readonly CharacterMentionTokenInfo[],\n refs: readonly ConnectedReference[],\n): ResolveCharacterMentionsResult {\n const bySlug = new Map<string, ConnectedReference>()\n const byVariant = new Map<string, ConnectedReference>()\n for (const r of refs) {\n if (!r.characterSlug) continue\n if (!r.variantSlug) {\n bySlug.set(r.characterSlug, r)\n } else {\n byVariant.set(`${r.characterSlug}:${r.variantSlug}`, r)\n }\n }\n\n const additionalUrls: string[] = []\n // `firstBulletEmittedFor` tracks the slug of characters that have already\n // produced a non-\"none\" bullet. Each character emits AT MOST ONE primary\n // bullet (the rich identity / name-only line). \"none\" mentions don't claim\n // this slot — they emit no bullet AT ALL — so a later \"face\" mention of the\n // same character still emits its directive bullet on first sight. Without\n // this split, a `[none, face]` mention pair would suppress both bullets\n // because the first iteration would silently consume the \"first mention\"\n // slot without emitting anything.\n const firstBulletEmittedFor = new Set<string>()\n const mentionedCharacterSlugs = new Set<string>()\n const directiveLines: string[] = []\n\n const replacements: Array<{ token: string; offset: number; replacement: string }> = []\n for (const t of tokens) {\n const match = t.variantSlug\n ? byVariant.get(`${t.characterSlug}:${t.variantSlug}`)\n : bySlug.get(t.characterSlug)\n if (!match) continue\n\n additionalUrls.push(match.url)\n mentionedCharacterSlugs.add(t.characterSlug)\n\n // Per-mention effective mode. Resolution order: per-mention slug override\n // → character node default → global DEFAULT_USAGE_MODE. Used both to\n // shape the inline replacement and to decide whether (and how) to emit a\n // bullet for this mention.\n const effectiveMode: UsageMode =\n t.usageMode ?? match.defaultUsageMode ?? DEFAULT_USAGE_MODE\n\n const displayName = bySlug.get(t.characterSlug)?.defaultName ?? t.characterSlug\n // Inline replacement of `@kira:1:smile` in the user's prompt. For \"none\"\n // mode we substitute the bare positional reference (`Image 1`) so the\n // user's sentence reads \"show Image 1 dancing\" — the image is attached,\n // the model sees the position label, but no character name biases the\n // textual prompt. Every other mode (including \"name\") keeps the legacy\n // `Kira` substitution so prose flows naturally.\n const replacement = effectiveMode === \"none\"\n ? `Image ${t.imageIndex}`\n : displayName\n replacements.push({ token: t.token, offset: t.offset, replacement })\n\n // Bullet emission rules per mode:\n // - \"none\": NO bullet (zero textual intervention; only the image is\n // attached). Doesn't consume the per-character \"first bullet\" slot —\n // a later non-none mention can still emit its primary directive.\n // If EVERY mention of a character is \"none\", that character\n // contributes no bullets at all, so it won't appear under the\n // \"Use these characters:\" header.\n // - \"name\": ONE bullet on first non-none mention only —\n // `- Image N (Name)` with no trailing directive. Tells the model who\n // the character is so it can correlate, without prescribing how to\n // use the image.\n // - other modes: ONE bullet on first non-none mention only,\n // `- Image N (Name) — <canonical?>. <directive>`.\n if (effectiveMode === \"none\") {\n // Suppress everything — the inline replacement above is the only signal.\n continue\n }\n const isFirstBullet = !firstBulletEmittedFor.has(t.characterSlug)\n if (effectiveMode === \"name\") {\n if (isFirstBullet) {\n directiveLines.push(`- Image ${t.imageIndex} (${displayName})`)\n firstBulletEmittedFor.add(t.characterSlug)\n }\n } else if (isFirstBullet) {\n const directive = usageModeDirective(effectiveMode)\n const subject = `Image ${t.imageIndex} (${displayName})`\n // Canonical description is identity-context — only useful when the model\n // is being asked to lock to that identity (\"identical\" / \"face-pose\").\n // For \"emotion\" / \"style\" modes the canonical description (face/body/\n // features) is noise relative to the directive's intent, so we omit it\n // and keep the bullet focused on the mode-specific instruction.\n const includeCanonicalDesc =\n effectiveMode === \"identical\" || effectiveMode === \"face-pose\"\n // Canonical desc is mode-gated; the character's wired elements\n // (held-prop / styling / text) ride the bullet in every mode that emits\n // one. Byte-identical to the old `${subject} — ${canonical}` form when no\n // injection is present.\n // A per-use `descriptionOverride` IS the caller describing this subject\n // for this run, so it fills the identity slot ahead of the entity's stored\n // canonical description — and rides every mode that emits a bullet at all\n // (the mode gate exists to suppress STORED identity noise, not the\n // caller's own words). \"none\" still emits nothing: it returned above.\n const descPart = composeIdentityDescPart(\n subject,\n match.descriptionOverride?.trim()\n || (includeCanonicalDesc ? match.characterCanonicalDescription : undefined),\n match.elementInjection,\n )\n // `directive` is non-null here because usageModeDirective only returns\n // null for \"none\"/\"name\", both of which are already handled above.\n directiveLines.push(`- ${descPart}.${directive ? ` ${directive}` : \"\"}`)\n firstBulletEmittedFor.add(t.characterSlug)\n }\n // Variant-description sub-line only makes sense alongside an emitted\n // bullet — for \"none\"/\"name\" modes it's dropped (those modes are\n // intentionally minimal).\n if (\n t.variantSlug\n && match.variantDescription\n && effectiveMode !== \"name\"\n && isFirstBullet\n ) {\n directiveLines.push(` (in this image: ${match.variantDescription.trim()})`)\n }\n }\n\n // Apply replacements right-to-left so offsets remain valid.\n let resolvedPrompt = prompt\n for (const r of [...replacements].sort((a, b) => b.offset - a.offset)) {\n resolvedPrompt = resolvedPrompt.slice(0, r.offset)\n + r.replacement\n + resolvedPrompt.slice(r.offset + r.token.length)\n }\n\n if (directiveLines.length > 0) {\n resolvedPrompt = `Use these characters:\\n${directiveLines.join(\"\\n\")}\\n\\n${resolvedPrompt}`\n }\n\n return { prompt: resolvedPrompt, additionalUrls, mentionedCharacterSlugs }\n}\n\n/**\n * Splice one resolved mention phrase in for its token, collapsing the horizontal\n * whitespace ON EITHER SIDE OF THE SEAM to a single space. The single splice\n * primitive for every HYBRID image mention splice — the four `@`-mention\n * resolvers (character, location, named image, wired entity) and the\n * `{image:N:label}` positional-pill expansion (`expandImageRefTokensHybrid`).\n *\n * WHY: an editor serializes a mention chip as its token plus its own trailing\n * space, and the prose that follows the chip carries the space the author typed\n * — so a perfectly ordinary sentence arrives as `@panda:1 and @panda2:2 …` and\n * assembles to \"the person from reference image A and reference image C …\",\n * with the doubled space sitting exactly where the model is being told what the\n * reference IS. The VIDEO core never shows this because `resolveReferenceTokens`\n * runs a `[^\\S\\r\\n]{2,}` collapse over its fully-assembled prompt on every\n * return; the image path has no such tidy. This is that collapse, SCOPED to the\n * seam: a doubled space the author put elsewhere in their prose is theirs to\n * keep, and a prompt whose seams are already single-spaced is byte-identical\n * (the run must be 2+ to match).\n *\n * The class is `[^\\S\\r\\n]` (NOT `\\s`) for the same reason the video tidy uses\n * it: `\\n` / `\\n\\n` separate the assembled blocks, and a `\\s`-based collapse\n * would silently merge paragraphs.\n *\n * INDENTATION is structure, not a seam. The leading collapse is anchored with a\n * `(?<=\\S)` lookbehind so it only fires on a run that FOLLOWS prose on the same\n * line. A mention that opens an indented line (`\"Scene:\\n @panda:1 stands\"` —\n * a shot list, a numbered beat sheet) keeps its indent verbatim; without the\n * anchor that run IS the left seam and a 4-space indent flattened to one space,\n * which is the same class of damage as merging paragraphs and would have made\n * the \"already-single-spaced prompts are byte-identical\" claim false for every\n * multi-line prompt. The trailing collapse stays unconditional: a run AFTER a\n * chip is the reported bug itself and can never be indentation.\n *\n * OFFSET SAFETY: callers splice right-to-left over offsets taken against the\n * pre-splice string. The left-hand collapse only ever removes characters from\n * the whitespace run immediately preceding THIS token — positions at or after\n * the end of any earlier token (tokens are non-whitespace and never overlap) —\n * so every not-yet-applied (smaller) offset stays valid.\n */\nfunction spliceMentionPhrase(\n prompt: string,\n offset: number,\n tokenLength: number,\n phrase: string,\n): string {\n const before = prompt.slice(0, offset).replace(/(?<=\\S)[^\\S\\r\\n]{2,}$/, \" \")\n const after = prompt.slice(offset + tokenLength).replace(/^[^\\S\\r\\n]{2,}/, \" \")\n return before + phrase + after\n}\n\ninterface ResolveCharacterMentionsHybridResult {\n /** Body with each `@`-mention replaced INLINE by its role phrase\n * (\"the {role} from reference image {LETTER}\"). No directive block. */\n prompt: string\n /** Matched character URLs in mention order (deduped by the caller). */\n additionalUrls: string[]\n /** Slugs that had at least one resolved mention. */\n mentionedCharacterSlugs: Set<string>\n /** Per-reference identity-lock lines (non-null, deduped per URL). Caller\n * prepends them as ONE block. */\n lockLines: string[]\n /** Non-empty `elementInjection` fragments (deduped per URL). Caller appends\n * them as trailing scene directives. */\n elementDirectives: string[]\n}\n\n/**\n * HYBRID-mode character mention convergence (Unified Reference Roles, Phase A).\n *\n * Where `resolveCharacterMentions` (above) prepends the legacy\n * `\"Use these characters:\"` bullet block + replaces tokens with bare display\n * names — and is shared VERBATIM with the video resolver, so its contract must\n * NOT change — this renders each `@`-mention as the inline role phrase\n * `\"the {role} from reference image {LETTER}\"` and surfaces the optional\n * identity-lock + wired `elementInjection` SEPARATELY (the caller prepends one\n * lock block and appends element directives). No directive block is produced.\n *\n * Slot/letter: a character URL's 1-based position in\n * `dedup([...existingUrls, ...mentionUrls])`. The caller appends non-character\n * URLs AFTER this list when it builds `finalIndexByUrl`, so these letters are\n * byte-identical to that canonical map for every character URL.\n *\n * Role: the mention's role/usage-mode 3rd segment — `face`/`pose`/`style` parse\n * as usage modes, `person`/`clothes`/`hair`/`expression` parse as variant slugs\n * but are curated roles. Either way it's reused when present in\n * `REFERENCE_ROLE_PRESETS[\"wired-character\"]`, else falls back to the source\n * default (`\"person\"`). `identical`/`face-pose`/`emotion`/`name`/`none` (and a\n * real variant slug like `smile`) are not curated roles → `\"person\"`.\n *\n * Matching: variant-first, canonical-fallback — so a role-word 3rd segment that\n * parsed as a variant slug (e.g. `@kira:1:person`) still attaches the canonical\n * reference instead of being dropped (the legacy resolver skips variant misses).\n */\n\nfunction resolveCharacterMentionsHybrid(\n prompt: string,\n tokens: readonly CharacterMentionTokenInfo[],\n refs: readonly ConnectedReference[],\n existingUrls: readonly string[],\n): ResolveCharacterMentionsHybridResult {\n const bySlug = new Map<string, ConnectedReference>()\n const byVariant = new Map<string, ConnectedReference>()\n for (const r of refs) {\n if (!r.characterSlug) continue\n if (!r.variantSlug) bySlug.set(r.characterSlug, r)\n else byVariant.set(`${r.characterSlug}:${r.variantSlug}`, r)\n }\n\n const presets = REFERENCE_ROLE_PRESETS[\"wired-character\"]\n\n const additionalUrls: string[] = []\n const mentionedCharacterSlugs = new Set<string>()\n const refByUrl = new Map<string, ConnectedReference>()\n // Per-mention `~lock` / `~nolock` (Task 4 + F4): the tri-state lock OVERRIDE\n // per attached URL — `true` (force on) / `false` (force off) / absent\n // (inherit the ref default). The lock loop below feeds this to\n // `withForcedIdentityLock` before `buildIdentityLockLine`. Only tokens that\n // carried a sentinel write here (last sentinel wins); a sentinel-less mention\n // never overwrites, so a `~lock` upstream survives a later plain mention.\n const lockOverrideByUrl = new Map<string, boolean>()\n const matched: Array<{ token: string; offset: number; url: string; role: string }> = []\n\n for (const t of tokens) {\n // Variant-first, canonical-fallback. `variantMatch` (a REAL matched variant\n // URL) doubles as the signal that the 3rd segment SELECTED a variant rather\n // than acting as a role — see the role derivation below.\n const variantMatch = t.variantSlug\n ? byVariant.get(`${t.characterSlug}:${t.variantSlug}`)\n : undefined\n const match = variantMatch ?? bySlug.get(t.characterSlug)\n if (!match || !match.url) continue\n additionalUrls.push(match.url)\n mentionedCharacterSlugs.add(t.characterSlug)\n refByUrl.set(match.url, match)\n if (t.lock !== undefined) lockOverrideByUrl.set(match.url, t.lock)\n // Variant + Role Separation: an explicit 4th-segment ROLE\n // (`@kira:1:walking:clothes`) wins outright and coexists with the variant —\n // the variant picked the image (variantMatch above), the role picks the\n // phrase. Used VERBATIM (curated or custom), mirroring the seg3 custom-role\n // relaxation below.\n const explicitRole = (t.role ?? \"\").trim()\n const segment = (t.usageMode ?? t.variantSlug ?? \"\").trim()\n // Custom roles survive VERBATIM (Unified Reference Roles, Phase D). A\n // non-empty segment is the role when it is a curated preset (face/pose/style\n // modes, person/clothes/… role-slugs) OR a free-form value typed in the\n // variant/role slot that did NOT resolve to a real matched variant URL (e.g.\n // `earrings`) — i.e. it's acting as a role, not selecting a variant. A real\n // variant slug (`smile`) and the directive-only usage modes (identical/\n // face-pose/emotion/name/none) fall back to the NODE default: the character\n // node's `defaultRole` (hybrid dropdown pick, verbatim) → its\n // `defaultUsageMode`-derived role → the source default (\"person\") — via\n // `resolveDefaultRole` (Character Node Role+Lock). Precedence: seg4 role →\n // seg3 token role → node defaultRole → defaultUsageMode-derived → source default.\n const role = explicitRole\n ? explicitRole\n : segment && (presets.includes(segment) || (t.usageMode == null && !variantMatch))\n ? segment\n : resolveDefaultRole(match.defaultRole, match.defaultUsageMode, \"wired-character\")\n matched.push({ token: t.token, offset: t.offset, url: match.url, role })\n }\n\n // Slot letters from the deduped [existing, mention] URL list — the prefix of\n // the caller's `finalIndexByUrl`, so the letters agree.\n const slotByUrl = new Map<string, number>()\n for (const u of [...existingUrls, ...additionalUrls]) {\n if (!slotByUrl.has(u)) slotByUrl.set(u, slotByUrl.size + 1)\n }\n const bindingFor = (url: string): string => {\n const slot = slotByUrl.get(url)\n return slot ? `reference image ${slotToLetter(slot)}` : \"the reference image\"\n }\n\n // Replace mention tokens right-to-left so earlier offsets stay valid;\n // `spliceMentionPhrase` also tidies the horizontal whitespace at each seam.\n let resolvedPrompt = prompt\n for (const m of [...matched].sort((a, b) => b.offset - a.offset)) {\n const phrase = roleToPhrase(m.role, bindingFor(m.url))\n resolvedPrompt = spliceMentionPhrase(resolvedPrompt, m.offset, m.token.length, phrase)\n }\n\n // One identity-lock + one element directive per UNIQUE attached URL (a\n // character mentioned N times attaches one URL → one lock / element line).\n const lockLines: string[] = []\n const elementDirectives: string[] = []\n const seenUrls = new Set<string>()\n for (const m of matched) {\n if (seenUrls.has(m.url)) continue\n seenUrls.add(m.url)\n const ref = refByUrl.get(m.url)\n if (!ref) continue\n const binding = bindingFor(m.url)\n const lock = buildIdentityLockLine(withForcedIdentityLock(ref, lockOverrideByUrl.get(m.url)), binding)\n if (lock) lockLines.push(lock)\n pushOverrideDirective(elementDirectives, ref, binding)\n const inject = ref.elementInjection?.trim()\n if (inject) elementDirectives.push(inject)\n }\n\n return { prompt: resolvedPrompt, additionalUrls, mentionedCharacterSlugs, lockLines, elementDirectives }\n}\n\nexport interface ResolveLocationMentionsResult {\n /** Prompt with `@location:N` tokens replaced by display names + a\n * \"Use these locations:\" directive prepended when at least one bullet\n * fires. */\n prompt: string\n /** Resolved URLs from matched mention tokens, in mention order. Caller\n * is responsible for deduping against the existing URL list (the same\n * contract as `resolveCharacterMentions.additionalUrls`). */\n additionalUrls: string[]\n /** Set of location slugs that had at least one resolved mention. Callers\n * use this to gate \"no mention → canonical fallback\" behavior (mirrors\n * the character flow — Phase 2 #1 attached the canonical URL via\n * `expandWiredLocationRefs` directly, but a future fallback path may\n * use this set to suppress the canonical URL once the user has explicitly\n * pinned a variant via @-mention). */\n mentionedLocationSlugs: Set<string>\n}\n\n/**\n * Per-mode directive text for a location bullet. Mirrors `usageModeDirective`\n * for characters but with the 4-mode location enum:\n * - identical: lock the scene to this exact image (used as background)\n * - style: borrow the look/mood/color palette\n * - layout: borrow the compositional layout / camera framing\n * - none: no bullet emitted (caller handles)\n */\nfunction locationModeDirective(mode: LocationUsageMode): string | null {\n switch (mode) {\n case \"identical\":\n return \"use as the background/setting — match the location exactly.\"\n case \"style\":\n return \"use as a style / mood reference — borrow color, lighting, and atmosphere.\"\n case \"layout\":\n return \"use as a compositional layout / camera framing reference.\"\n case \"none\":\n return null\n }\n}\n\n/**\n * Map a location usage-mode to its HYBRID reference role — the vocabulary\n * `roleToPhrase` renders into \"the {role} from reference image {LETTER}\". The\n * location analog of the character mention's role segment, for the 4-mode\n * location enum:\n * - identical → the source default (`\"location\"`) — lock the scene to this image\n * - style → \"style\" (borrow look / mood / palette)\n * - layout → \"layout\" (borrow compositional framing)\n * - none / undefined / anything else → the source default (`\"location\"`).\n *\n * A PLACE, NOT A BACKDROP — `identical` used to map to `\"background\"`, which is\n * the exact word `DEFAULT_LABEL_BY_SOURCE[\"wired-location\"]` stopped emitting on\n * 2026-08-05 after it was measured harmful: `roleToPhrase` renders it as \"the\n * background from reference image B\", and image models read that as *paste this\n * behind the subject* — on gpt-image-2 (character + location, 4 draws per arm,\n * only the role word varying) every `background` draw came back a cut-out\n * composite with no shared light and no ground contact, while `location` put the\n * subject inside the scene. That fix changed the SOURCE default but missed this\n * branch, so `identical` — the DEFAULT location usage mode\n * (`DEFAULT_LOCATION_USAGE_MODE`) — kept handing every un-roled location mention\n * the harmful word. Both defaults now read from `defaultRoleForSource`, so the\n * source default is the single source of truth and the two cannot drift again.\n * `\"background\"` stays a curated pick in `REFERENCE_ROLE_PRESETS` for the genuine\n * backdrop case — an explicit `@lib:1:background` token is untouched.\n *\n * Accepts a loose `string` so a `ConnectedReference.defaultUsageMode` (typed as\n * the CHARACTER `UsageMode`, which can't express `\"layout\"`) flows in without a\n * cast — unknown / non-location modes fall through to the safe source default\n * instead of throwing. The two mode-specific roles are members of\n * `REFERENCE_ROLE_PRESETS[\"wired-location\"]`, so the phrasing stays curated.\n */\nfunction locationModeToRole(mode: string | null | undefined): string {\n return roleBearingLocationMode(mode) ?? defaultRoleForSource(\"wired-location\")\n}\n\n/**\n * The ROLE a location usage mode expresses, or `null` when the mode expresses no\n * role opinion at all. Splits the 4-mode enum the way the character chain splits\n * `USAGE_MODES`: `style` / `layout` SAY what the reference is, while `identical`\n * (which IS `DEFAULT_LOCATION_USAGE_MODE`) and `none` are directive-only — they\n * say how the LEGACY bullet reads, not what the model should take from the\n * image. Only a role-bearing mode may outrank a ref-level `defaultRole`; see\n * `resolveLocationRole`.\n *\n * Data-driven rather than a hardcoded pair: a mode is role-bearing exactly when\n * it is itself a member of `REFERENCE_ROLE_PRESETS[\"wired-location\"]` — the same\n * test the location pill runs (`LOCATION_ROLE_PRESETS.includes(attrs.usageMode)`)\n * to decide whether a mode-slot value should surface as the pill's hybrid role,\n * and the same shape as the character resolver's `presets.includes(segment)`. A\n * mode added to both lists later is role-bearing on its own, with no list here\n * to remember to update.\n */\nfunction roleBearingLocationMode(mode: string | null | undefined): string | null {\n const m = mode?.trim()\n if (!m) return null\n return REFERENCE_ROLE_PRESETS[\"wired-location\"].includes(m) ? m : null\n}\n\n/**\n * The effective HYBRID role for a wired LOCATION reference — the location analog\n * of `resolveDefaultRole`, and the single source of truth for the location role\n * chain (read by the mention resolver AND the canonical-fallback renderer, so a\n * location cannot phrase itself one way mentioned and another way unmentioned).\n *\n * Precedence:\n * 1. the per-mention token ROLE (`@lib:1:atmosphere`, `@lib:1:x/y:lighting`) —\n * verbatim, slug-normalized so the non-noun specials still hit\n * (`empty-background` → `empty background`).\n * 2. the per-mention token MODE, but ONLY when it is ROLE-BEARING\n * (`@lib:1:style`, `@lib:1:layout` — `roleBearingLocationMode`).\n * 3. the ref's own `defaultRole` — the node/caller's hybrid role pick, same\n * slug normalization as (1).\n * 4. the ref's legacy `defaultUsageMode` → `locationModeToRole`.\n * 5. the source default (`locationModeToRole`'s fallback — `\"location\"`).\n *\n * Step 2 is GATED for the same reason the character chain gates its segment on\n * `presets.includes(segment)`: `identical` and `none` express no role opinion —\n * `identical` IS `DEFAULT_LOCATION_USAGE_MODE`, the un-roled state, and the\n * location pill's `renderText` emits a mode segment whenever the attr is set, so\n * an ungated step 2 would let a round-tripped `@lib:1:identical` suppress the\n * very `defaultRole` this chain exists to honor — on the majority of real\n * tokens. A directive-only mode therefore falls THROUGH to the ref's role, the\n * same way a character's `identical` / `name` / `none` segment falls through to\n * `resolveDefaultRole`. With no `defaultRole` the outcome is unchanged\n * (`identical` → step 4 → the source default, `\"location\"`).\n *\n * Step 3 is what this exists for. `ConnectedReference.defaultRole` is on the\n * wire schema for EVERY source, and the character and named-image mention paths\n * have always consulted it via `resolveDefaultRole` — but the location paths\n * read only the usage mode, so a ref-level default role was silently dropped.\n * It is the ONLY channel a location has for a custom default role: a location\n * mention's 3rd segment is a bucket/variant or a role, so a caller cannot pin a\n * per-mention role AND keep the canonical image, and the character trick of a\n * 4th segment needs a variant to sit in the third. An explicit token role or\n * role-bearing mode still wins (steps 1–2); with no `defaultRole` the chain\n * collapses to exactly the old `t.usageMode ?? defaultUsageMode ?? DEFAULT`\n * derivation.\n */\nfunction resolveLocationRole(\n tokenRole: string | null | undefined,\n tokenUsageMode: string | null | undefined,\n ref: Pick<ConnectedReference, \"defaultRole\" | \"defaultUsageMode\">,\n): string {\n const explicitRole = tokenRole?.trim()\n if (explicitRole) return normalizeRoleSlug(explicitRole)\n const modeRole = roleBearingLocationMode(tokenUsageMode)\n if (modeRole) return modeRole\n const nodeRole = ref.defaultRole?.trim()\n if (nodeRole) return normalizeRoleSlug(nodeRole)\n return locationModeToRole(ref.defaultUsageMode ?? DEFAULT_LOCATION_USAGE_MODE)\n}\n\n/**\n * Resolve `@oldlibrary:1:weather/rain` mentions in the prompt against the\n * pre-expanded `wired-location` ConnectedReferences (from\n * `expandWiredLocationRefs` / `expandLocationNodeIntoRefs`). Mirrors\n * `resolveCharacterMentions` shape:\n *\n * 1. Look up the matching ref by `(locationSlug, bucket, variantSlug)`.\n * 2. Append its URL to `additionalUrls`.\n * 3. Substitute the inline token with the location's display name (or\n * `Image N` for \"none\" mode — image attached without textual bias).\n * 4. Emit a directive bullet under \"Use these locations:\" header, with\n * mode-specific verb. \"none\" mode suppresses the bullet (just like\n * character \"none\").\n *\n * Per-location single-bullet rule: each location emits AT MOST ONE bullet\n * (the first non-none mention \"claims\" the slot). Subsequent mentions of the\n * same location still produce inline substitution + URL but no additional\n * bullet, mirroring `resolveCharacterMentions.firstBulletEmittedFor`.\n *\n * Returns `additionalUrls` deduplication is the caller's responsibility,\n * matching the character contract.\n */\nexport function resolveLocationMentions(\n prompt: string,\n tokens: readonly LocationMentionTokenInfo[],\n refs: readonly ConnectedReference[],\n): ResolveLocationMentionsResult {\n // Build lookup maps: canonical (no variant) and per-(bucket/variant).\n const bySlug = new Map<string, ConnectedReference>()\n const byVariant = new Map<string, ConnectedReference>()\n for (const r of refs) {\n if (!r.locationSlug) continue\n if (!r.locationVariantBucket || !r.locationVariantSlug) {\n bySlug.set(r.locationSlug, r)\n } else {\n byVariant.set(\n `${r.locationSlug}:${r.locationVariantBucket}/${r.locationVariantSlug}`,\n r,\n )\n }\n }\n\n const additionalUrls: string[] = []\n const mentionedLocationSlugs = new Set<string>()\n const firstBulletEmittedFor = new Set<string>()\n const directiveLines: string[] = []\n const replacements: Array<{ token: string; offset: number; replacement: string }> = []\n\n for (const t of tokens) {\n // Bare-slug ROLE tokens (Unified Reference Roles, Phase D — e.g.\n // `@old-library:1:background` / `:atmosphere` / `:as-is` /\n // `:empty-background` / `:lighting`) are a HYBRID-only construct. The\n // additive parser now PARSES them (with `t.role` set, no bucket/variant),\n // but in the LEGACY path they must stay literal text exactly as they did\n // pre-Phase-D, when the parser returned null and the token fell through\n // untouched. Skipping here guarantees byte-identical legacy output: NO\n // inline replacement, NO bullet, NO attached URL, and crucially the slug is\n // NOT added to `mentionedLocationSlugs` — so a wired location still\n // auto-attaches via the unchanged non-character canonical path, just as\n // before. Role resolution lives in `resolveLocationMentionsHybrid`, which is\n // untouched. (`layout`/`style` set `usageMode`, not `role`, so they were\n // always modes and are unaffected.)\n if (t.role) continue\n\n const match = t.bucket && t.variant\n ? byVariant.get(`${t.locationSlug}:${t.bucket}/${t.variant}`)\n : bySlug.get(t.locationSlug)\n if (!match) continue\n\n additionalUrls.push(match.url)\n mentionedLocationSlugs.add(t.locationSlug)\n\n // Per-mention effective mode. Resolution order: per-mention slug override\n // → location node default (not yet plumbed; reserved for future) → global\n // DEFAULT_LOCATION_USAGE_MODE.\n const effectiveMode: LocationUsageMode =\n t.usageMode ?? DEFAULT_LOCATION_USAGE_MODE\n\n // Inline replacement of `@oldlibrary:1:weather/rain` in the user's\n // prompt. For \"none\" we substitute the bare positional reference so the\n // user's sentence reads \"set in Image 1\" — the image is attached, the\n // model sees the position label, but no name biases the textual prompt.\n // Every other mode keeps the location display name for natural prose.\n const displayName = bySlug.get(t.locationSlug)?.defaultName ?? t.locationSlug\n const replacement = effectiveMode === \"none\" ? `Image ${t.imageIndex}` : displayName\n replacements.push({ token: t.token, offset: t.offset, replacement })\n\n // Bullet emission. \"none\" skips entirely; other modes emit one bullet\n // per location on the first non-none mention.\n if (effectiveMode === \"none\") {\n continue\n }\n const isFirstBullet = !firstBulletEmittedFor.has(t.locationSlug)\n if (!isFirstBullet) continue\n firstBulletEmittedFor.add(t.locationSlug)\n\n const directive = locationModeDirective(effectiveMode)\n const subject = `Image ${t.imageIndex} (${displayName})`\n // Canonical-description injection. Mirrors the Phase 2 #1 behavior in\n // `buildIdentityDirective` — only emit for the \"identical\" mode where\n // the description (env, materials, mood) is on-task; \"style\" / \"layout\"\n // modes are about the look/composition and don't need the full\n // description noise.\n const includeCanonicalDesc = effectiveMode === \"identical\"\n const canonicalDesc = match.locationCanonicalDescription?.trim()\n // A per-use `descriptionOverride` IS the caller describing this place for\n // this run, so it fills the identity slot ahead of the location's stored\n // canonical description — and rides every mode that emits a bullet at all,\n // the same rule the character resolvers apply.\n const shownDesc = match.descriptionOverride?.trim()\n || (includeCanonicalDesc ? canonicalDesc : undefined)\n const descPart = shownDesc ? `${subject} — ${shownDesc}` : subject\n directiveLines.push(`- ${descPart}.${directive ? ` ${directive}` : \"\"}`)\n\n // Variant display-name sub-line: only when the user pinned a specific\n // variant. Distinct from `description` (the user-typed text on the\n // location node) — locationVariantDisplayName is the raw bucket name\n // like \"rain\" or \"neon\".\n if (\n t.bucket\n && t.variant\n && match.locationVariantDisplayName\n && match.locationVariantDisplayName !== \"canonical\"\n ) {\n directiveLines.push(` (in this image: ${match.locationVariantDisplayName})`)\n }\n }\n\n // Apply replacements right-to-left so offsets stay valid.\n let resolvedPrompt = prompt\n for (const r of [...replacements].sort((a, b) => b.offset - a.offset)) {\n resolvedPrompt = resolvedPrompt.slice(0, r.offset)\n + r.replacement\n + resolvedPrompt.slice(r.offset + r.token.length)\n }\n\n if (directiveLines.length > 0) {\n resolvedPrompt = `Use these locations:\\n${directiveLines.join(\"\\n\")}\\n\\n${resolvedPrompt}`\n }\n\n return { prompt: resolvedPrompt, additionalUrls, mentionedLocationSlugs }\n}\n\ninterface ResolveLocationMentionsHybridResult {\n /** Body with each `@location` mention replaced INLINE by its role phrase\n * (\"the {role} from reference image {LETTER}\"). No directive block. */\n prompt: string\n /** Matched location URLs in mention order (deduped by the caller). */\n additionalUrls: string[]\n /** Slugs that had at least one resolved mention. */\n mentionedLocationSlugs: Set<string>\n /** Per-reference opt-in identity-lock lines (deduped per URL). Locks are OFF\n * for locations by default — `buildIdentityLockLine` returns null unless the\n * ref sets `identityLock.enabled === true` with custom text (there is no\n * built-in wired-location lock wording). Caller prepends them as ONE block. */\n lockLines: string[]\n /** Non-empty `elementInjection` fragments (deduped per URL). Caller appends\n * them as trailing scene directives. */\n elementDirectives: string[]\n}\n\n/**\n * HYBRID-mode location mention convergence (Unified Reference Roles, Phase C).\n *\n * The location analog of `resolveCharacterMentionsHybrid`. Where the LEGACY\n * `resolveLocationMentions` (above) prepends a `\"Use these locations:\"` bullet\n * block + replaces `@location` tokens with display names, this renders each\n * mention as the inline role phrase `\"the {role} from reference image {LETTER}\"`\n * and surfaces the optional opt-in identity-lock + wired `elementInjection`\n * SEPARATELY (caller prepends one lock block, appends element directives). No\n * directive block is produced.\n *\n * MATCHING is byte-identical to the legacy resolver (variant-first, NO canonical\n * fallback on a variant miss) so the set of attached URLs / matched tokens never\n * diverges between formats — only the rendered phrasing differs.\n *\n * ROLE is `resolveLocationRole(t.role, t.usageMode, ref)` — per-mention role →\n * per-mention ROLE-BEARING mode (`style` / `layout`; the directive-only\n * `identical` / `none` fall through) → the ref's own `defaultRole` → its\n * `defaultUsageMode` → the source default. So a node whose default mode is\n * \"style\" renders \"the style from …\" for a bare `@old-library:1`, and one\n * carrying `defaultRole: \"atmosphere\"` renders \"the atmosphere from …\".\n *\n * SLOT/LETTER: a URL's 1-based position in `dedup([...existingUrls,\n * ...mentionUrls])`. The caller passes `existingUrls = [base refs, resolved\n * character mentions]` (location mentions are merged AFTER character mentions and\n * BEFORE the character canonical/extra URLs), so these letters are a prefix of —\n * and byte-identical to — the caller's final `finalIndexByUrl` for every location\n * URL.\n */\nfunction resolveLocationMentionsHybrid(\n prompt: string,\n tokens: readonly LocationMentionTokenInfo[],\n refs: readonly ConnectedReference[],\n existingUrls: readonly string[],\n): ResolveLocationMentionsHybridResult {\n const bySlug = new Map<string, ConnectedReference>()\n const byVariant = new Map<string, ConnectedReference>()\n for (const r of refs) {\n if (!r.locationSlug) continue\n if (!r.locationVariantBucket || !r.locationVariantSlug) {\n bySlug.set(r.locationSlug, r)\n } else {\n byVariant.set(`${r.locationSlug}:${r.locationVariantBucket}/${r.locationVariantSlug}`, r)\n }\n }\n\n const additionalUrls: string[] = []\n const mentionedLocationSlugs = new Set<string>()\n const refByUrl = new Map<string, ConnectedReference>()\n // Per-mention `~lock` / `~nolock` (Task 4 + F4): the tri-state lock OVERRIDE\n // per attached URL — `true` (force on, so a location lock line appears even\n // though location locks default OFF) / `false` (force off, suppressing a\n // ref-level enabled lock) / absent (inherit). Fed to `withForcedIdentityLock`\n // below. Only sentinel-bearing mentions write here (last sentinel wins).\n const lockOverrideByUrl = new Map<string, boolean>()\n const matched: Array<{ token: string; offset: number; url: string; role: string }> = []\n\n for (const t of tokens) {\n // Variant-first, canonical-fallback-FREE (ternary, NOT `??`) — identical to\n // the legacy resolver so the matched URL set never diverges between formats.\n const match = t.bucket && t.variant\n ? byVariant.get(`${t.locationSlug}:${t.bucket}/${t.variant}`)\n : bySlug.get(t.locationSlug)\n if (!match || !match.url) continue\n additionalUrls.push(match.url)\n mentionedLocationSlugs.add(t.locationSlug)\n refByUrl.set(match.url, match)\n if (t.lock !== undefined) lockOverrideByUrl.set(match.url, t.lock)\n // A bare-slug ROLE (Unified Reference Roles, Phase D — e.g. `background`,\n // `empty-background`, `as-is`, or a curated custom role) is used VERBATIM:\n // it's acting as a role, not selecting a bucket/variant. With no role\n // segment, the chain falls through the token's ROLE-BEARING mode, then the\n // REF's own `defaultRole`, then its usage mode — see `resolveLocationRole`.\n const role = resolveLocationRole(t.role, t.usageMode, match)\n matched.push({ token: t.token, offset: t.offset, url: match.url, role })\n }\n\n // Slot letters from the deduped [existing, mention] URL list — the prefix of\n // the caller's `finalIndexByUrl`, so the letters agree.\n const slotByUrl = new Map<string, number>()\n for (const u of [...existingUrls, ...additionalUrls]) {\n if (!slotByUrl.has(u)) slotByUrl.set(u, slotByUrl.size + 1)\n }\n const bindingFor = (url: string): string => {\n const slot = slotByUrl.get(url)\n return slot ? `reference image ${slotToLetter(slot)}` : \"the reference image\"\n }\n\n // Replace mention tokens right-to-left so earlier offsets stay valid;\n // `spliceMentionPhrase` also tidies the horizontal whitespace at each seam.\n let resolvedPrompt = prompt\n for (const m of [...matched].sort((a, b) => b.offset - a.offset)) {\n const phrase = roleToPhrase(m.role, bindingFor(m.url))\n resolvedPrompt = spliceMentionPhrase(resolvedPrompt, m.offset, m.token.length, phrase)\n }\n\n // One opt-in lock + one element directive per UNIQUE attached URL.\n const lockLines: string[] = []\n const elementDirectives: string[] = []\n const seenUrls = new Set<string>()\n for (const m of matched) {\n if (seenUrls.has(m.url)) continue\n seenUrls.add(m.url)\n const ref = refByUrl.get(m.url)\n if (!ref) continue\n const binding = bindingFor(m.url)\n const lock = buildIdentityLockLine(withForcedIdentityLock(ref, lockOverrideByUrl.get(m.url)), binding)\n if (lock) lockLines.push(lock)\n pushOverrideDirective(elementDirectives, ref, binding)\n const inject = ref.elementInjection?.trim()\n if (inject) elementDirectives.push(inject)\n }\n\n return { prompt: resolvedPrompt, additionalUrls, mentionedLocationSlugs, lockLines, elementDirectives }\n}\n\ninterface ResolveImageMentionsHybridResult {\n /** Body with each `@<image-name>` mention replaced INLINE by its role phrase\n * (\"the {role} from reference image {LETTER}\", or the bare binding when the\n * role resolves to the media default `\"\"`). No directive block. */\n prompt: string\n /** Matched image URLs in mention order (deduped by the caller). */\n additionalUrls: string[]\n /** NO `mentionedImageSlugs` — the location result's analog exists to FILTER\n * mentioned refs out of `connectedReferences`, and this pass deliberately\n * does no such filtering (see the caller's NOTE). Carrying the set anyway\n * would advertise a filter that does not exist. */\n /**\n * The URLs a mention BOUND (deduped). This pass already surfaced each bound\n * ref's per-use `descriptionOverride` as its own trailing line, so the\n * caller's untold-override sweep skips them — the same by-URL suppression\n * contract `resolveEntityMentionsHybrid` carries, for the same reason: told\n * once, never twice.\n */\n mentionedUrls: Set<string>\n /** Per-reference identity-lock lines (deduped per URL). Caller prepends them\n * as ONE block, merged with the character/location lock lines. */\n lockLines: string[]\n /** Non-empty `elementInjection` fragments (deduped per URL). Caller appends\n * them as trailing scene directives. */\n elementDirectives: string[]\n}\n\n/**\n * HYBRID named-image mention convergence (P3). The media analog of\n * `resolveLocationMentionsHybrid`, for `wired-image` / `manual` references\n * addressed by the slug of their `defaultName` (an upload node's label on the\n * canvas, or the name a thin client puts on the reference).\n *\n * ASYMMETRY vs. characters and locations: a media ref AUTO-ATTACHES its URL\n * through the New path whether or not it is mentioned, and carries NO canonical\n * prose. So a mention here is BINDING + RE-SEATING, never attach-gating — which\n * is why the caller does NOT filter mentioned refs out of `connectedReferences`\n * the way the location pass does.\n *\n * NO LEGACY COUNTERPART. The Phase-0 arm that reaches this is hybrid-gated, so\n * an `@name:N` token under the legacy reference format stays literal text and\n * the ref attaches exactly as it does today (the `resolveLocationMentions`\n * role-token precedent, where `if (t.role) continue` leaves the token alone).\n *\n * DUPLICATE SLUGS: FIRST WINS (`if (!bySlug.has(...))`), matching\n * `buildTileIdForUrl`. Every unrenamed upload node shares its default label, so\n * ties are the common case, not an edge.\n *\n * ROLE precedence: the per-mention 3rd segment (VERBATIM — media role presets\n * are all single-word, so `normalizeRoleSlug` is location-only and must NOT be\n * called here) → the node default via `resolveDefaultRole` → `\"\"`, which\n * `roleToPhrase` renders as the BARE binding (\"reference image C\"), i.e. today's\n * ref-only default with a name attached to it.\n *\n * CAPPED REFS: `imageReferenceLimit(provider)` truncates `connectedReferences`\n * BEFORE Phase 0, so a mention whose ref was capped out silently falls through\n * as literal text — matching how a capped character mention behaves today.\n */\nfunction resolveImageMentionsHybrid(\n prompt: string,\n tokens: readonly ImageMentionTokenInfo[],\n refs: readonly ConnectedReference[],\n existingUrls: readonly string[],\n): ResolveImageMentionsHybridResult {\n const bySlug = new Map<string, ConnectedReference>()\n for (const r of refs) {\n // `imageMentionSlugForRef` is the SAME predicate `knownImageSlugsFromRefs`\n // applies to build the finder's known-slug set — one gate, so this map and\n // that set can never admit different refs. (It also drops extras, which\n // render through `renderExtraRefsHybrid` with their own body lines, and\n // grammar-invalid slugs, where emptiness is NOT the gate.)\n const slug = imageMentionSlugForRef(r)\n if (!slug) continue\n if (!bySlug.has(slug)) bySlug.set(slug, r)\n }\n\n const additionalUrls: string[] = []\n const refByUrl = new Map<string, ConnectedReference>()\n // Per-mention `~lock` / `~nolock`: the tri-state lock OVERRIDE per attached\n // URL, fed to `withForcedIdentityLock` below. Only sentinel-bearing mentions\n // write here (last sentinel wins), mirroring the location resolver.\n const lockOverrideByUrl = new Map<string, boolean>()\n const matched: Array<{ token: string; offset: number; url: string; role: string }> = []\n\n for (const t of tokens) {\n const match = bySlug.get(t.imageSlug)\n if (!match || !match.url) continue\n additionalUrls.push(match.url)\n refByUrl.set(match.url, match)\n if (t.lock !== undefined) lockOverrideByUrl.set(match.url, t.lock)\n const role = (t.role ?? \"\").trim()\n || resolveDefaultRole(match.defaultRole, match.defaultUsageMode, match.source)\n matched.push({ token: t.token, offset: t.offset, url: match.url, role })\n }\n\n // Slot letters from the deduped [existing, mention] URL list — the prefix of\n // the caller's `finalIndexByUrl`, so the letters agree.\n const slotByUrl = new Map<string, number>()\n for (const u of [...existingUrls, ...additionalUrls]) {\n if (!slotByUrl.has(u)) slotByUrl.set(u, slotByUrl.size + 1)\n }\n const bindingFor = (url: string): string => {\n const slot = slotByUrl.get(url)\n return slot ? `reference image ${slotToLetter(slot)}` : \"the reference image\"\n }\n\n // Replace mention tokens right-to-left so earlier offsets stay valid;\n // `spliceMentionPhrase` also tidies the horizontal whitespace at each seam.\n let resolvedPrompt = prompt\n for (const m of [...matched].sort((a, b) => b.offset - a.offset)) {\n const phrase = roleToPhrase(m.role, bindingFor(m.url))\n resolvedPrompt = spliceMentionPhrase(resolvedPrompt, m.offset, m.token.length, phrase)\n }\n\n // One lock + one element directive per UNIQUE attached URL.\n const lockLines: string[] = []\n const elementDirectives: string[] = []\n const seenUrls = new Set<string>()\n for (const m of matched) {\n if (seenUrls.has(m.url)) continue\n seenUrls.add(m.url)\n const ref = refByUrl.get(m.url)\n if (!ref) continue\n const binding = bindingFor(m.url)\n const lock = buildIdentityLockLine(withForcedIdentityLock(ref, lockOverrideByUrl.get(m.url)), binding)\n if (lock) lockLines.push(lock)\n pushOverrideDirective(elementDirectives, ref, binding)\n const inject = ref.elementInjection?.trim()\n if (inject) elementDirectives.push(inject)\n }\n\n return { prompt: resolvedPrompt, additionalUrls, mentionedUrls: seenUrls, lockLines, elementDirectives }\n}\n\ninterface ResolveEntityMentionsHybridResult {\n /** Body with each `@<entity-name>` mention replaced INLINE by its role phrase\n * (\"the creature from reference image D\", \"the material from reference image\n * B\", …). No directive block. */\n prompt: string\n /** Matched entity URLs in mention order (deduped by the caller). */\n additionalUrls: string[]\n /**\n * The URLs a mention BOUND — fed into `renderObjectCreatureCanonicalHybrid`'s\n * `coveredUrls` so the ref's trailing canonical phrase is SUPPRESSED. This is\n * the whole point of the pass: without it the same reference would render\n * twice, once inline and once as the dangling trailing line the mention exists\n * to replace. Distinct from `additionalUrls` only in being a set — kept as its\n * own field so the suppression contract is explicit at both ends.\n */\n mentionedUrls: Set<string>\n /** Per-reference identity-lock lines (deduped per URL). Caller prepends them\n * as ONE block, merged with the character/location/image lock lines. */\n lockLines: string[]\n /** Non-empty `elementInjection` fragments (deduped per URL). Caller appends\n * them as trailing scene directives. */\n elementDirectives: string[]\n}\n\n/**\n * HYBRID wired-entity mention convergence — the `wired-creature` /\n * `wired-object` analog of `resolveImageMentionsHybrid`, for entities addressed\n * by the slug of their `defaultName`.\n *\n * THE BUG THIS KILLS. An unmentioned creature renders through\n * `renderObjectCreatureCanonicalHybrid` as a TRAILING phrase — \"the creature\n * from reference image D\" — appended after the scene and the style hints, while\n * the creature's name sits in the prose as plain text the model has no reason to\n * connect to a reference. A mention binds the two: the phrase renders INLINE at\n * the typed position, and this pass's `mentionedUrls` suppresses the trailing\n * fallback for that ref.\n *\n * ASYMMETRY vs. images, and why suppression is needed here but not there: a\n * media ref carries NO canonical prose, so the image pass has nothing to\n * suppress. A creature/object DOES, so this pass must hand its bound URLs to the\n * canonical renderer's `coveredUrls` — exactly the mechanism that already stops\n * an `{image:N}`-token-referenced entity from double-rendering.\n *\n * NOT a `connectedReferences` FILTER, matching the image pass and unlike the\n * location pass: the ref stays in the list so `nonCharacterRefs[N-1]` positional\n * indexing for `{image:N}` tokens is unperturbed and the New-path URL merge keeps\n * the ref's earlier Phase-0 slot (the merge dedups by URL). Suppression is\n * coveredUrls-only.\n *\n * PRECEDENCE. The caller runs this AFTER the character, location and image\n * passes, each of which has already spliced its own tokens out — so a name shared\n * with an earlier kind never reaches this pass (character → location → image →\n * creature → object). The creature-before-object tail is settled HERE, in the\n * slug → ref map: creature refs are inserted first, so a name claimed by both a\n * creature and an object binds the CREATURE.\n *\n * DUPLICATE SLUGS within a kind: FIRST WINS, matching the image pass.\n *\n * ROLE precedence: the per-mention 3rd segment (VERBATIM — both entity preset\n * lists are single-word, so `normalizeRoleSlug` stays location-only and must NOT\n * be called here) → the ref's own `defaultRole`, then its `defaultUsageMode`, via\n * the SHARED `resolveDefaultRole` helper → the SOURCE default (`\"creature\"` /\n * `\"object\"`).\n *\n * ONE HELPER, NOT A COPY. `resolveDefaultRole` is the same chain the character\n * and named-image resolvers run, and `ConnectedReference.defaultRole` is a wire\n * field on EVERY source (see its doc in `types.ts`), so an entity ref's role pick\n * is honored here for free. The LOCATION paths need their own `resolveLocationRole`\n * only because a location token carries a MODE segment whose role-bearing members\n * (`style` / `layout`) sit between the token role and the ref's `defaultRole`, and\n * because location roles are slug-normalized; an entity token has no mode segment\n * (`EntityMentionTokenInfo` is role + lock only) and no multi-word roles, so there\n * is no gate to replicate and an entity analog of that helper would be two copies\n * of one chain.\n *\n * That LAST step is the one `renderObjectCreatureCanonicalHybrid` would also have\n * used for the trailing line — but only that one: the canonical renderer reads\n * `defaultRoleForSource(r.source)` and ignores `defaultRole` / `defaultUsageMode`\n * entirely. So a bare `@nessie:4` relocates the IDENTICAL phrase only when the ref\n * carries neither node field; with a node default the mention honors it and the\n * phrase CHANGES (\"the anatomy from …\" rather than \"the creature from …\"). That is\n * deliberate — it is what `resolveCharacterMentionsHybrid` and\n * `resolveImageMentionsHybrid` do, and it is pinned by\n * `entity-convergence-image.test.ts`. Suppression is\n * unaffected either way: the mention pass covers the same URL and emits the same\n * lock line (modulo a `~lock`/`~nolock` sentinel) and the same `elementInjection`.\n *\n * NO LEGACY COUNTERPART — the image-grammar precedent. The Phase-0 arm that\n * reaches this is hybrid-gated, so under the legacy reference format an\n * `@name:N` token stays literal text and the entity attaches with its numbered\n * directive exactly as it does today.\n *\n * CAPPED REFS: `imageReferenceLimit(provider)` truncates `connectedReferences`\n * BEFORE Phase 0, so a mention whose ref was capped out silently falls through as\n * literal text — matching how a capped character or image mention behaves today.\n */\nfunction resolveEntityMentionsHybrid(\n prompt: string,\n tokens: readonly EntityMentionTokenInfo[],\n refs: readonly ConnectedReference[],\n existingUrls: readonly string[],\n): ResolveEntityMentionsHybridResult {\n const bySlug = new Map<string, ConnectedReference>()\n // Creature-first insertion IS the creature → object half of the precedence\n // chain (the other four steps are the caller's pass order). `entityMentionSlug\n // ForRef` is the SAME predicate `knownEntitySlugsFromRefs` applies to build the\n // finder's known-slug set — one gate, so this map and that set can never admit\n // different refs.\n for (const source of [\"wired-creature\", \"wired-object\"] as const) {\n for (const r of refs) {\n if (r.source !== source) continue\n const slug = entityMentionSlugForRef(r)\n if (!slug) continue\n if (!bySlug.has(slug)) bySlug.set(slug, r)\n }\n }\n\n const additionalUrls: string[] = []\n const mentionedUrls = new Set<string>()\n const refByUrl = new Map<string, ConnectedReference>()\n // Per-mention `~lock` / `~nolock`: the tri-state lock OVERRIDE per attached\n // URL, fed to `withForcedIdentityLock` below. Only sentinel-bearing mentions\n // write here (last sentinel wins), mirroring the image/location resolvers.\n const lockOverrideByUrl = new Map<string, boolean>()\n const matched: Array<{ token: string; offset: number; url: string; role: string }> = []\n\n for (const t of tokens) {\n const match = bySlug.get(t.entitySlug)\n if (!match || !match.url) continue\n additionalUrls.push(match.url)\n mentionedUrls.add(match.url)\n refByUrl.set(match.url, match)\n if (t.lock !== undefined) lockOverrideByUrl.set(match.url, t.lock)\n const role = (t.role ?? \"\").trim()\n || resolveDefaultRole(match.defaultRole, match.defaultUsageMode, match.source)\n matched.push({ token: t.token, offset: t.offset, url: match.url, role })\n }\n\n // Slot letters from the deduped [existing, mention] URL list — the prefix of\n // the caller's `finalIndexByUrl`, so the letters agree.\n const slotByUrl = new Map<string, number>()\n for (const u of [...existingUrls, ...additionalUrls]) {\n if (!slotByUrl.has(u)) slotByUrl.set(u, slotByUrl.size + 1)\n }\n const bindingFor = (url: string): string => {\n const slot = slotByUrl.get(url)\n return slot ? `reference image ${slotToLetter(slot)}` : \"the reference image\"\n }\n\n // Replace mention tokens right-to-left so earlier offsets stay valid;\n // `spliceMentionPhrase` also tidies the horizontal whitespace at each seam —\n // an entity chip serializes with its own trailing space exactly like every\n // other mention chip, so its seams get the same collapse as the character,\n // location and named-image ones.\n let resolvedPrompt = prompt\n for (const m of [...matched].sort((a, b) => b.offset - a.offset)) {\n const phrase = roleToPhrase(m.role, bindingFor(m.url))\n resolvedPrompt = spliceMentionPhrase(resolvedPrompt, m.offset, m.token.length, phrase)\n }\n\n // One lock + one element directive per UNIQUE attached URL. These are the\n // SAME lines `renderObjectCreatureCanonicalHybrid` would have emitted for the\n // ref, moved here — which is why suppressing its canonical entry does not lose\n // an opt-in lock or a wired `elementInjection`.\n const lockLines: string[] = []\n const elementDirectives: string[] = []\n const seenUrls = new Set<string>()\n for (const m of matched) {\n if (seenUrls.has(m.url)) continue\n seenUrls.add(m.url)\n const ref = refByUrl.get(m.url)\n if (!ref) continue\n const binding = bindingFor(m.url)\n const lock = buildIdentityLockLine(withForcedIdentityLock(ref, lockOverrideByUrl.get(m.url)), binding)\n if (lock) lockLines.push(lock)\n pushOverrideDirective(elementDirectives, ref, binding)\n const inject = ref.elementInjection?.trim()\n if (inject) elementDirectives.push(inject)\n }\n\n return { prompt: resolvedPrompt, additionalUrls, mentionedUrls, lockLines, elementDirectives }\n}\n\n/**\n * Build the canonical-fallback directive lines + URLs for wired characters\n * that were NOT @-mentioned in the prompt. Matches the pre-mention behavior:\n * a character wired to a generator without any `@-mention` still contributes\n * its default URL + a strong identity directive, so users who wire a single\n * character without typing anything get the same result they did before the\n * `@-mention` feature shipped.\n *\n * Returns directive lines (matching `resolveCharacterMentions`'s format) and\n * canonical URLs (variantSlug === undefined entries only) keyed by\n * `characterSlug`, deduped. Callers prepend the directives + merge the URLs.\n *\n * Numbering: each emitted line is prefixed with `Image N (Name) — …` where\n * N is the position of this canonical URL in the final `referenceImageUrls`\n * list. The caller passes `startIndex` (1-based) for the first canonical\n * URL; subsequent canonical URLs get `startIndex + 1`, `+ 2`, etc.\n *\n * Without the numeric prefix the model has no way to link \"Image 1\" in its\n * input array to the directive bullet \"shira — young woman…\" — which led\n * users to see uncorrelated directives and ungrouped reference images.\n */\nfunction buildCanonicalFallback(\n refs: readonly ConnectedReference[],\n mentionedSlugs: ReadonlySet<string>,\n startIndex: number,\n): { directiveLines: string[]; urls: string[] } {\n const directiveLines: string[] = []\n const urls: string[] = []\n const seenSlugs = new Set<string>()\n let cursor = startIndex\n for (const r of refs) {\n if (r.source !== \"wired-character\") continue\n if (!r.characterSlug) continue\n if (mentionedSlugs.has(r.characterSlug)) continue\n if (seenSlugs.has(r.characterSlug)) continue\n // Canonical entry only — never auto-attach a variant for an unmentioned\n // character. Multiple wired characters each contribute one canonical\n // URL + one directive, mirroring the legacy auto-attach behavior.\n if (r.variantSlug) continue\n if (!r.url) continue\n seenSlugs.add(r.characterSlug)\n urls.push(r.url)\n const displayName = r.defaultName || r.characterSlug\n // Mode source: character node's `defaultUsageMode` (if set), else the\n // global `DEFAULT_USAGE_MODE` (\"identical\"). Without a slug-level\n // override available here (the user hasn't @-mentioned this character),\n // the node's default is the only signal — preserves the legacy \"match\n // exactly\" behavior when no default is configured.\n const effectiveMode: UsageMode = r.defaultUsageMode ?? DEFAULT_USAGE_MODE\n // Minimal-intervention modes:\n // - \"none\": URL is attached but NO bullet is emitted — the visual\n // speaks for itself, no textual bias.\n // - \"name\": one bullet with the name, no trailing directive — lets the\n // model correlate the position with a named entity without\n // prescribing usage.\n if (effectiveMode === \"none\") {\n // Bare URL attachment, no bullet — `cursor` still advances so any\n // downstream extras that pair-back via \"same subject as Image N\" see\n // the correct positional slot for this character.\n cursor += 1\n continue\n }\n if (effectiveMode === \"name\") {\n directiveLines.push(`- Image ${cursor} (${displayName})`)\n cursor += 1\n continue\n }\n const directive = usageModeDirective(effectiveMode)\n const includeCanonicalDesc =\n effectiveMode === \"identical\" || effectiveMode === \"face-pose\"\n // Subject line includes the numeric position so the model can correlate\n // \"Image N in the input array\" with the named character in the directive.\n const subject = `Image ${cursor} (${displayName})`\n // Wired elements (held-prop / styling / text) ride this bullet alongside\n // the (mode-gated) canonical description. This is the reported path — a\n // character wired with no @-mention — so a composed character surfaces its\n // elements wherever it's used downstream.\n // Per-use override ahead of the stored canonical description, mode-gate\n // included — same rule as the mention path above.\n const descPart = composeIdentityDescPart(\n subject,\n r.descriptionOverride?.trim()\n || (includeCanonicalDesc ? r.characterCanonicalDescription : undefined),\n r.elementInjection,\n )\n // `directive` is non-null here (\"none\"/\"name\" already short-circuited).\n directiveLines.push(`- ${descPart}.${directive ? ` ${directive}` : \"\"}`)\n cursor += 1\n }\n return { directiveLines, urls }\n}\n\n/**\n * Build directive lines + URLs for user-attached \"extra reference images\"\n * (entries with `isExtraRef === true`). Runs alongside `buildCanonicalFallback`\n * — both feed into the same \"Use these characters:\\n...\" block prepended to\n * the prompt.\n *\n * Numbering rule: starts at `nextImageIndex` (passed in by the caller — equal\n * to the count of already-emitted canonical fallback URLs + the count of\n * mention URLs) and increments by 1 per extra ref. The caller's URL merge\n * order must match this counter so \"Image N\" in the directive resolves to\n * the N-th URL in the final `referenceImageUrls` array.\n *\n * Per-extra directive shape:\n * - manual extra (source === \"manual\" + description set)\n * → `Image N (reference): <description>.`\n * - character extra (source === \"wired-character\" + characterSlug set\n * + description set) where the SAME `characterSlug` was already emitted\n * as a mention or canonical entry\n * → `Image N is the same subject as Image M, <description>.`\n * where M is the position of the earlier same-character image.\n * - character extra of a previously-unseen character (no canonical, no\n * mention) → emit a canonical-style directive (display name + mode\n * directive). Acts as the \"first sight\" attachment for that character.\n *\n * The caller is responsible for:\n * 1. Merging `urls` into `referenceImageUrls` in the same order as the\n * directive lines (so positions align).\n * 2. Concatenating `directiveLines` onto the existing \"Use these characters:\"\n * block (or creating a new one).\n *\n * `emittedCharacterPositions` is a map from characterSlug → position (1-based)\n * of the FIRST emitted image for that character. The caller pre-populates it\n * with positions from mentions + canonical fallback so that \"Image B is the\n * same subject as Image A\" can reference an earlier slot correctly.\n */\nfunction buildExtraRefDirectives(\n refs: readonly ConnectedReference[],\n emittedCharacterPositions: ReadonlyMap<string, number>,\n startIndex: number,\n): { directiveLines: string[]; urls: string[] } {\n const directiveLines: string[] = []\n const urls: string[] = []\n // Local copy of the position map so first-sight extras can be referenced by\n // later extras of the same character (e.g. two extras of Kira where the\n // first becomes \"Image M\" and the second pairs back to \"M\").\n const positionsByChar = new Map(emittedCharacterPositions)\n let cursor = startIndex\n for (const r of refs) {\n if (!r.isExtraRef) continue\n if (!r.url) continue\n // A per-use `descriptionOverride` fills THIS extra's description slot —\n // every branch below reads one `description`, so the override lands in the\n // pair-back tail, the name-mode bullet and the first-sight descriptor alike\n // (and, being the caller's own words, outranks the stored canonical too).\n const description = (r.descriptionOverride ?? \"\").trim()\n || (r.description ?? r.variantDescription ?? \"\").trim()\n // Character extra\n if (r.source === \"wired-character\" && r.characterSlug) {\n const effectiveMode: UsageMode = r.defaultUsageMode ?? DEFAULT_USAGE_MODE\n const earlierPos = positionsByChar.get(r.characterSlug)\n if (earlierPos !== undefined) {\n // Pair-back form. `Image N is the same subject as Image M, <desc>.`\n // Description is optional — when absent we still emit the pairing.\n // Minimal-intervention modes suppress even the pair-back bullet so\n // the user's \"don't bias with text\" intent extends to extras.\n if (effectiveMode !== \"none\") {\n const tail = description ? `, ${description}` : \"\"\n directiveLines.push(`- Image ${cursor} is the same subject as Image ${earlierPos}${tail}.`)\n }\n } else if (effectiveMode === \"none\") {\n // First sight of this character via an extra ref, but mode is \"none\".\n // Attach the URL, emit no bullet, record the position so any later\n // extras of the same character that pair-back land on the right slot.\n positionsByChar.set(r.characterSlug, cursor)\n } else if (effectiveMode === \"name\") {\n // \"Name only\" — labeled subject + the per-ref description (when\n // present), no trailing directive.\n const displayName = r.defaultName || r.characterSlug\n const subject = `Image ${cursor} (${displayName})`\n const descPart = description ? `${subject} — ${description}` : subject\n directiveLines.push(`- ${descPart}.`)\n positionsByChar.set(r.characterSlug, cursor)\n } else {\n // First sight of this character via an extra ref. Emit a canonical-style\n // directive — the description (or the character's canonical desc) is\n // the descriptive part, and the usage mode is whatever the caller\n // resolved onto `defaultUsageMode` (per-ref override → node default →\n // identical, applied when the ExtraRef was mapped to a ConnectedReference).\n const directive = usageModeDirective(effectiveMode)\n const displayName = r.defaultName || r.characterSlug\n const subject = `Image ${cursor} (${displayName})`\n const includeCanonicalDesc =\n effectiveMode === \"identical\" || effectiveMode === \"face-pose\"\n const canonicalDesc = r.characterCanonicalDescription?.trim()\n // Description preference: per-ref description > canonical (when mode\n // allows it) > nothing. The per-ref description is what the user\n // typed in the extra-ref row, so it always wins. The character's wired\n // elements (held-prop / styling) ride alongside whichever wins.\n const chosenDesc = description\n ? description\n : (includeCanonicalDesc ? canonicalDesc : undefined)\n const descPart = composeIdentityDescPart(subject, chosenDesc, r.elementInjection)\n directiveLines.push(`- ${descPart}.${directive ? ` ${directive}` : \"\"}`)\n positionsByChar.set(r.characterSlug, cursor)\n }\n } else {\n // Manual / generic extra. Description (when present) goes in the\n // parenthetical; absent description still emits a positional marker so\n // the URL position is unambiguous in the prompt.\n if (description) {\n directiveLines.push(`- Image ${cursor} (reference): ${description}.`)\n } else {\n directiveLines.push(`- Image ${cursor} (reference).`)\n }\n }\n urls.push(r.url)\n cursor += 1\n }\n return { directiveLines, urls }\n}\n\n// ---------------------------------------------------------------------------\n// HYBRID variants of the canonical-fallback + extra-ref directives (Unified\n// Reference Roles, Phase A — Task 4). Where the LEGACY builders above prepend a\n// \"Use these characters:\" bullet block with numeric \"Image N\" addressing, these\n// attach the SAME reference URLs but render each entry as an inline, lowercase\n// role phrase / pair-back directive bound to a lettered slot (\"reference image\n// A\"). Letters come from the caller's unified slot map (the same\n// `finalIndexByUrl` order as the rest of the hybrid path), so the numbering\n// agrees byte-for-byte. The legacy builders stay untouched.\n// ---------------------------------------------------------------------------\n\n/**\n * Select the unmentioned wired-character refs that contribute a canonical\n * fallback URL in hybrid mode. SELECTION ONLY — identical filtering to\n * `buildCanonicalFallback` (canonical entry only, deduped per `characterSlug`,\n * skipping @-mentioned slugs) so the two paths never disagree on WHICH\n * characters auto-attach; rendering happens in `renderCanonicalFallbackHybrid`\n * once the slot letters are known. Keep this filter in sync with\n * `buildCanonicalFallback`.\n */\nfunction selectCanonicalFallbackRefs(\n refs: readonly ConnectedReference[],\n mentionedSlugs: ReadonlySet<string>,\n): ConnectedReference[] {\n const out: ConnectedReference[] = []\n const seenSlugs = new Set<string>()\n for (const r of refs) {\n if (r.source !== \"wired-character\") continue\n if (!r.characterSlug) continue\n if (mentionedSlugs.has(r.characterSlug)) continue\n if (seenSlugs.has(r.characterSlug)) continue\n if (r.variantSlug) continue // never auto-attach a variant for an unmentioned char\n if (!r.url) continue\n seenSlugs.add(r.characterSlug)\n out.push(r)\n }\n return out\n}\n\n/**\n * Render the hybrid canonical fallback: each unmentioned wired character →\n * the inline role phrase `roleToPhrase(defaultRoleForSource(source), binding)`\n * (the caller appends these to the body as trailing scene directives) + its\n * opt-in identity-lock line (null by default — emitted only when the ref sets\n * `identityLock.enabled === true`) + its wired `elementInjection` (held-prop /\n * styling / text) as a trailing scene directive. `letterForUrl` maps the ref's\n * already-attached URL to its slot letter.\n *\n * `elementInjection` must NOT be silently dropped for an unmentioned character:\n * the legacy `buildCanonicalFallback` folds it into the bullet via\n * `composeIdentityDescPart`, and the hybrid MENTION path surfaces it via\n * `resolveCharacterMentionsHybrid`'s `elementDirectives`. We mirror the latter's\n * shape exactly (raw trimmed injection string, surfaced as its own trailing\n * line) so mentioned and unmentioned characters stay consistent in hybrid mode.\n */\nfunction renderCanonicalFallbackHybrid(\n refs: readonly ConnectedReference[],\n letterForUrl: (url: string) => string,\n): { phrases: string[]; lockLines: string[]; elementDirectives: string[] } {\n const phrases: string[] = []\n const lockLines: string[] = []\n const elementDirectives: string[] = []\n for (const r of refs) {\n const binding = `reference image ${letterForUrl(r.url)}`\n // Node-default role chain (Character Node Role+Lock): the character node's\n // `defaultRole` (hybrid dropdown pick, verbatim — Custom survives) → its\n // `defaultUsageMode`-derived role → the source default (\"person\"). This is\n // the MOST COMMON wiring (wired, not @-mentioned), which previously\n // hardcoded the source default and ignored the node entirely.\n phrases.push(roleToPhrase(resolveDefaultRole(r.defaultRole, r.defaultUsageMode, r.source), binding))\n const lock = buildIdentityLockLine(r, binding)\n if (lock) lockLines.push(lock)\n pushOverrideDirective(elementDirectives, r, binding)\n const inject = r.elementInjection?.trim()\n if (inject) elementDirectives.push(inject)\n }\n return { phrases, lockLines, elementDirectives }\n}\n\n/**\n * Render the hybrid extra-ref directives. Mirrors `buildExtraRefDirectives`'s\n * manual-vs-pair-back SHAPES, but with lettered bindings + lowercase phrasing\n * instead of \"Image N\":\n * - manual extra (with description) → \"<description> (reference image L).\"\n * - character extra, earlier sibling → \"reference image L is the same subject\n * as reference image M[, <desc>].\"\n * - character extra, first sight → role phrase [+ \", <desc>\"] + opt-in lock\n * + wired `elementInjection` (surfaced as\n * a SEPARATE trailing directive, mirroring\n * `renderCanonicalFallbackHybrid`).\n * `seedLetterByChar` carries each character's FIRST emitted letter from the\n * mention / canonical-fallback pass, so a picked-variant extra pairs back to the\n * earlier reference; first-sight extras record their own letter for any later\n * same-character extras. A description-less manual extra attaches its URL with\n * no directive (nothing to surface).\n *\n * `elementInjection` must NOT be silently dropped for a first-sight extra-ref\n * character: the legacy `buildExtraRefDirectives` folds it into the first-sight\n * bullet via `composeIdentityDescPart`, so the hybrid path surfaces the trimmed\n * injection as its own trailing line (same shape as the canonical / mention\n * paths). Only the FIRST-SIGHT branch attaches it — a pair-back extra references\n * an earlier image whose element directive was already emitted there.\n */\nfunction renderExtraRefsHybrid(\n extraRefs: readonly ConnectedReference[],\n letterForUrl: (url: string) => string,\n seedLetterByChar: ReadonlyMap<string, string>,\n): { bodyLines: string[]; lockLines: string[]; elementDirectives: string[] } {\n const bodyLines: string[] = []\n const lockLines: string[] = []\n const elementDirectives: string[] = []\n const firstLetterByChar = new Map(seedLetterByChar)\n for (const r of extraRefs) {\n if (!r.url) continue\n const letter = letterForUrl(r.url)\n const binding = `reference image ${letter}`\n // Per-use override fills the extras' own `, <desc>` clause — the one\n // description slot the hybrid format has (see `described-references.ts`).\n const description = (r.descriptionOverride ?? \"\").trim()\n || (r.description ?? r.variantDescription ?? \"\").trim()\n if (r.source === \"wired-character\" && r.characterSlug) {\n const earlier = firstLetterByChar.get(r.characterSlug)\n if (earlier !== undefined && earlier !== letter) {\n const tail = description ? `, ${description}` : \"\"\n bodyLines.push(`${binding} is the same subject as reference image ${earlier}${tail}.`)\n } else {\n // Role chain (Character Node Role+Lock): the node's `defaultRole`\n // (hybrid dropdown pick, VERBATIM — Custom survives; the expander only\n // stamps it when the extra carries no per-ref usageMode override) → the\n // COALESCED `defaultUsageMode`-derived role → the source default — via\n // the shared `resolveDefaultRole` helper.\n //\n // `defaultUsageMode` here is COALESCED (`expandExtraRefsToConnected-\n // References` folds per-ref `usageMode` → char-node default →\n // \"identical\"), so a character extra always carries a defined mode.\n // The VIDEO extras path (`video-reference-resolver.ts`) feeds the same\n // helper its own coalesced `effectiveMode` + `meta.defaultRole` — image\n // and video are fully converged (same helper, same precedence); pinned\n // by `character-convergence-image.test.ts`.\n const role = resolveDefaultRole(r.defaultRole, r.defaultUsageMode, r.source)\n const phrase = roleToPhrase(role, binding)\n bodyLines.push(description ? `${phrase}, ${description}.` : `${phrase}.`)\n const lock = buildIdentityLockLine(r, binding)\n if (lock) lockLines.push(lock)\n const inject = r.elementInjection?.trim()\n if (inject) elementDirectives.push(inject)\n firstLetterByChar.set(r.characterSlug, letter)\n }\n } else if (description) {\n bodyLines.push(`${description} (${binding}).`)\n }\n }\n return { bodyLines, lockLines, elementDirectives }\n}\n\n/**\n * Render the hybrid canonical convergence for UNMENTIONED wired locations (the\n * location analog of `renderCanonicalFallbackHybrid`). Each unmentioned\n * `wired-location` ref → the inline role phrase\n * `roleToPhrase(resolveLocationRole(null, null, ref), binding)` — the SAME role\n * chain the mention path runs, minus the token steps (the caller appends these as\n * trailing scene directives) + its opt-in identity-lock line\n * (null unless the ref enables one — locations have no built-in lock wording) +\n * its wired `elementInjection` as a trailing directive.\n *\n * Unlike characters — whose canonical URLs are merged in Phase 0 — unmentioned\n * locations flow through the New path's `nonCharacterRefs` / `finalIndexByUrl`,\n * so the slot letter is read straight from `finalIndexByUrl` (the single source\n * of truth for the assembled URL order). MENTIONED locations were already\n * converged inline in Phase 0 and filtered out of `nonCharacterRefs`, so they\n * never reach here. Deduped per URL to mirror `buildNonCharacterDirectives`'s\n * per-URL `coveredUrls` guard (a location wired twice → one phrase).\n *\n * `coveredUrls` is the set of URLs ALREADY expanded inline by an `{image:N}`\n * token in this hybrid scene (derived exactly as the legacy builder does — see\n * the call site). A location that is BOTH unmentioned AND `{image:N}`-token-\n * referenced is rendered ONCE (inline, via the scene); we `continue` here so it\n * is not ALSO emitted as a trailing canonical phrase (the C1 review Minor).\n *\n * `renderedUrls` reports the URLs that DID render here — and therefore already\n * carry their per-use `descriptionOverride` line — so the caller's untold-\n * override sweep skips them instead of re-deriving this loop's predicate.\n */\nfunction renderLocationCanonicalHybrid(\n nonCharacterRefs: readonly ConnectedReference[],\n finalIndexByUrl: ReadonlyMap<string, number>,\n coveredUrls: ReadonlySet<string>,\n): { phrases: string[]; lockLines: string[]; elementDirectives: string[]; renderedUrls: Set<string> } {\n const phrases: string[] = []\n const lockLines: string[] = []\n const elementDirectives: string[] = []\n const seenUrls = new Set<string>()\n for (const r of nonCharacterRefs) {\n if (r.source !== \"wired-location\") continue\n if (!r.url || seenUrls.has(r.url) || coveredUrls.has(r.url)) continue\n const slot = finalIndexByUrl.get(r.url)\n if (!slot) continue\n seenUrls.add(r.url)\n const binding = `reference image ${slotToLetter(slot)}`\n // Same role chain as the mention path (there is no token here, so it starts\n // at the ref's own `defaultRole`) — one helper, so a location cannot phrase\n // itself one way mentioned and another way unmentioned.\n phrases.push(roleToPhrase(resolveLocationRole(null, null, r), binding))\n const lock = buildIdentityLockLine(r, binding)\n if (lock) lockLines.push(lock)\n pushOverrideDirective(elementDirectives, r, binding)\n const inject = r.elementInjection?.trim()\n if (inject) elementDirectives.push(inject)\n }\n return { phrases, lockLines, elementDirectives, renderedUrls: seenUrls }\n}\n\n/**\n * Render the hybrid canonical convergence for UNMENTIONED wired objects /\n * creatures (the object/creature analog of `renderLocationCanonicalHybrid`).\n * Each unmentioned `wired-object` ref → \"the object from reference image\n * {LETTER}\"; each `wired-creature` → \"the creature from reference image\n * {LETTER}\" — via `roleToPhrase(defaultRoleForSource(source), binding)` (the\n * source-default role, mirroring `renderCanonicalFallbackHybrid` for characters,\n * not the location's mode-aware role) + its opt-in identity-lock line (null by\n * default — `wired-object` has no built-in lock wording at all; `wired-creature`\n * has wording but it is OFF unless `identityLock.enabled === true`, per Plan A's\n * default-off flip) + its wired `elementInjection` as a trailing directive.\n *\n * `coveredUrls` is every URL that ALREADY rendered inline in this scene, and it\n * carries TWO contributions the caller unions together: the URLs expanded by an\n * `{image:N}` token, and — since the creature/object mention leg — the URLs bound\n * by a Phase-0 `@creature` / `@object` mention. Either way the ref renders ONCE,\n * inline, never also as a trailing canonical phrase.\n *\n * The mention half is why this loop is NOT reached via a `connectedReferences`\n * filter the way mentioned locations are: an entity ref stays in the list to keep\n * `nonCharacterRefs[N-1]` positional `{image:N}` indexing stable, so suppression\n * has to happen HERE, per URL. The mention pass emits the same lock line and\n * `elementInjection` this loop would have, so nothing is lost by skipping it.\n *\n * Deduped per URL (an object wired twice → one phrase). `renderedUrls` reports\n * the URLs that DID render — already carrying their per-use\n * `descriptionOverride` line — for the caller's untold-override sweep.\n */\nfunction renderObjectCreatureCanonicalHybrid(\n nonCharacterRefs: readonly ConnectedReference[],\n finalIndexByUrl: ReadonlyMap<string, number>,\n coveredUrls: ReadonlySet<string>,\n): { phrases: string[]; lockLines: string[]; elementDirectives: string[]; renderedUrls: Set<string> } {\n const phrases: string[] = []\n const lockLines: string[] = []\n const elementDirectives: string[] = []\n const seenUrls = new Set<string>()\n for (const r of nonCharacterRefs) {\n if (r.source !== \"wired-object\" && r.source !== \"wired-creature\") continue\n if (!r.url || seenUrls.has(r.url) || coveredUrls.has(r.url)) continue\n const slot = finalIndexByUrl.get(r.url)\n if (!slot) continue\n seenUrls.add(r.url)\n const binding = `reference image ${slotToLetter(slot)}`\n phrases.push(roleToPhrase(defaultRoleForSource(r.source), binding))\n const lock = buildIdentityLockLine(r, binding)\n if (lock) lockLines.push(lock)\n pushOverrideDirective(elementDirectives, r, binding)\n const inject = r.elementInjection?.trim()\n if (inject) elementDirectives.push(inject)\n }\n return { phrases, lockLines, elementDirectives, renderedUrls: seenUrls }\n}\n\n/**\n * The per-use `descriptionOverride` of every non-character reference the hybrid\n * format renders NO role phrase for — the last leg of \"the override is honoured\n * wherever the reference ships\".\n *\n * Three kinds land here: a ref a `{image:N:label}` token expanded INLINE (the\n * expansion carries no description slot, and the covered set suppresses both\n * canonical renders), an unmentioned `wired-image` / `manual` / `wired-face` ref\n * (no canonical render exists for those sources at all), and any other seated\n * ref the passes above left unspoken. Each gets ONE\n * `reference image <LETTER> — <override>.` line, from the same helper every\n * other site uses, numbered against `finalIndexByUrl`.\n *\n * `toldUrls` is every URL a pass above ALREADY gave an override line — the two\n * canonical renders' `renderedUrls` plus the image / entity mention passes'\n * bound URLs — so a reference that is both @-mentioned and token-covered is told\n * once, never twice. A URL is marked swept only when it actually emitted a line,\n * so two refs sharing one URL where only the later carries an override still\n * speak.\n */\nfunction renderUntoldOverridesHybrid(\n nonCharacterRefs: readonly ConnectedReference[],\n finalIndexByUrl: ReadonlyMap<string, number>,\n toldUrls: ReadonlySet<string>,\n): string[] {\n const lines: string[] = []\n const sweptUrls = new Set<string>()\n for (const r of nonCharacterRefs) {\n if (!r.url || toldUrls.has(r.url) || sweptUrls.has(r.url)) continue\n const slot = finalIndexByUrl.get(r.url)\n if (!slot) continue\n const before = lines.length\n pushOverrideDirective(lines, r, `reference image ${slotToLetter(slot)}`)\n if (lines.length > before) sweptUrls.add(r.url)\n }\n return lines\n}\n\n/**\n * Per-character extra refs need to know which numbered slot the EARLIER\n * emitted image of the same character lives in. This helper walks the\n * URL-merge order built up by `buildImagePrompt` and returns the\n * `characterSlug → first-position` map used by `buildExtraRefDirectives`.\n *\n * The merge order matches `mergedUrls` in `buildImagePrompt`:\n * [pre-existing referenceImageUrls] + [resolved mentions] + [canonical fallback]\n * (followed by extras when this helper is consulted).\n *\n * For each URL in the merged list, we look up the originating\n * `ConnectedReference` to learn its `characterSlug`. The first time we see\n * a slug, we record its position; later same-slug images don't overwrite.\n */\n/**\n * Build a stable-tile-ID-per-URL mapping for the FINAL URL list emitted by\n * `buildImagePrompt`. Mirrors the scheme in `compute-injected-refs.ts` so the\n * frontend reorder UI and the backend `referenceOrder` sort agree.\n *\n * Used internally by `applyReferenceOrder` below. Kept as a separate helper\n * so the test in `prompt-builder.test.ts` can pin the ID scheme contract.\n *\n * Resolution order (first wins per URL):\n * 1. URL is a wired character variant whose @-mention is in `prompt` →\n * `mention:<slug>:<variant|canonical>`. Variant slug derived from the\n * mention token, NOT the ref's `variantSlug` — the same URL can match\n * multiple variants in edge cases, but the mention token is the\n * authoritative user-typed source.\n * 2. URL belongs to an `isExtraRef` entry → `wired:<id>` (the extra ref's\n * stable id, which the consumer panel keeps in sync with the row's id).\n * 3. URL is a non-character wired ref → `wired:<sourceNodeId>` via the\n * provided `sourceNodeIdById` map, falling back to `ref.id`.\n * 4. URL is a wired character canonical (no mention) → `char-canonical:<slug>`.\n *\n * URLs not matched by any of the above keep a null entry; they're sorted\n * stable after the matched URLs and don't participate in reorder.\n */\nfunction buildTileIdForUrl(\n urls: readonly string[],\n refs: readonly ConnectedReference[],\n prompt: string,\n sourceNodeIdById?: ReadonlyMap<string, string>,\n): Array<string | null> {\n // Build slug → mention's variant decision (the first time the mention\n // resolved per slug+variant): used to key mention URLs.\n const knownSlugs = Array.from(\n new Set(\n refs.map((r) => r.characterSlug).filter((s): s is string => Boolean(s)),\n ),\n )\n const mentionTokens = knownSlugs.length > 0\n ? findCharacterMentionTokens(prompt, knownSlugs)\n : []\n // url → tile id, populated only for mentioned variants.\n const mentionUrlToId = new Map<string, string>()\n const bySlug = new Map<string, ConnectedReference>()\n const byVariant = new Map<string, ConnectedReference>()\n for (const r of refs) {\n if (!r.characterSlug) continue\n if (!r.variantSlug) {\n if (!bySlug.has(r.characterSlug)) bySlug.set(r.characterSlug, r)\n } else {\n byVariant.set(`${r.characterSlug}:${r.variantSlug}`, r)\n }\n }\n for (const t of mentionTokens) {\n const match = t.variantSlug\n ? byVariant.get(`${t.characterSlug}:${t.variantSlug}`)\n : bySlug.get(t.characterSlug)\n if (!match?.url) continue\n if (!mentionUrlToId.has(match.url)) {\n mentionUrlToId.set(match.url, `mention:${t.characterSlug}:${t.variantSlug || \"canonical\"}`)\n }\n }\n\n // url → first matching ref (used for both canonical and wired-raw paths).\n const firstRefByUrl = new Map<string, ConnectedReference>()\n for (const r of refs) {\n if (!r.url) continue\n if (!firstRefByUrl.has(r.url)) firstRefByUrl.set(r.url, r)\n }\n\n return urls.map((url) => {\n const mentionId = mentionUrlToId.get(url)\n if (mentionId) return mentionId\n const ref = firstRefByUrl.get(url)\n if (!ref) return null\n // Extra refs use their stable id (set by the consumer panel).\n if (ref.isExtraRef) {\n return `wired:${sourceNodeIdById?.get(ref.id) ?? ref.id}`\n }\n if (ref.source === \"wired-character\" && ref.characterSlug) {\n // Canonical entry (no variant slug) when reached via the fallback path.\n // Variant entries are handled by the mention path above.\n if (!ref.variantSlug) {\n return `char-canonical:${ref.characterSlug}`\n }\n // A wired-character VARIANT URL with no mention shouldn't appear in the\n // final URL list under normal flow, but handle it defensively.\n return `mention:${ref.characterSlug}:${ref.variantSlug}`\n }\n // Non-character wired or manual entry.\n return `wired:${sourceNodeIdById?.get(ref.id) ?? ref.id}`\n })\n}\n\n/**\n * Reorder URLs by `referenceOrder` AND renumber `Image N` tokens in the\n * prompt to match. Returns the new URL list + the rewritten prompt. When\n * `referenceOrder` is empty / null / all-stale, the original URLs + prompt\n * are returned unchanged (no-op contract).\n *\n * Renumbering rule: build an `original-pos → new-pos` map from the URL move\n * indices, then regex-replace `Image N` substrings (word-boundary-anchored\n * so we don't touch \"Image 12\" while remapping \"Image 1\"). Done in one pass\n * via a callback that looks up each match in the map; unknown positions are\n * left as-is.\n *\n * NB: `findCharacterMentionTokens` is already applied BEFORE this step, so\n * any `@kira:1:smile` literals in the prompt have been replaced with display\n * names — only positional `Image N` markers remain to be remapped.\n *\n * Exposed (non-export internal) — also called by video branches in\n * payload-builder / execute-node via `applyReferenceOrderToVideo` so video\n * prompts honor the same reorder semantics as image prompts.\n */\nexport function applyReferenceOrderToVideo(\n urls: readonly string[],\n prompt: string | undefined,\n refs: readonly ConnectedReference[],\n referenceOrder: readonly string[] | undefined,\n sourceNodeIdById?: ReadonlyMap<string, string>,\n /**\n * Number of LEADING reference images (e.g. plain image-refs that precede the\n * asset URLs in the unified `@image_N` numbering — see\n * `resolveVideoReferenceCore`'s `leadingRefUrls`). `urls` here are the ASSET\n * URLs only; their prompt ordinals are `ordinalOffset + 1 …`, so the renumber\n * remap is keyed by the offset ordinal and leading ordinals (`1 … offset`)\n * pass through untouched. Defaults to 0 → behaviour unchanged.\n */\n ordinalOffset = 0,\n): { urls: string[]; prompt: string | undefined } {\n if (!referenceOrder || !referenceOrder.length || urls.length < 2) {\n return { urls: [...urls], prompt }\n }\n const reordered = applyReferenceOrder(\n urls,\n prompt ?? \"\",\n refs,\n referenceOrder,\n sourceNodeIdById,\n ordinalOffset,\n )\n return {\n urls: reordered.urls,\n prompt: prompt === undefined ? undefined : reordered.prompt,\n }\n}\n\nfunction applyReferenceOrder(\n urls: readonly string[],\n prompt: string,\n refs: readonly ConnectedReference[],\n referenceOrder: readonly string[],\n sourceNodeIdById?: ReadonlyMap<string, string>,\n ordinalOffset = 0,\n): { urls: string[]; prompt: string } {\n if (!referenceOrder.length) return { urls: [...urls], prompt }\n const tileIds = buildTileIdForUrl(urls, refs, prompt, sourceNodeIdById)\n // Map: tile id → original index in URLs array. Keeps first occurrence per\n // tile id (URLs are already deduped by `buildImagePrompt`'s merge step).\n const byTileId = new Map<string, number>()\n for (let i = 0; i < tileIds.length; i++) {\n const id = tileIds[i]\n if (id && !byTileId.has(id)) byTileId.set(id, i)\n }\n const newOrderIndices: number[] = []\n const seenIndices = new Set<number>()\n for (const id of referenceOrder) {\n const idx = byTileId.get(id)\n if (idx === undefined) continue\n if (seenIndices.has(idx)) continue\n newOrderIndices.push(idx)\n seenIndices.add(idx)\n }\n // Append URLs not in `referenceOrder` in their original order.\n for (let i = 0; i < urls.length; i++) {\n if (!seenIndices.has(i)) {\n newOrderIndices.push(i)\n seenIndices.add(i)\n }\n }\n // No-op check: if `newOrderIndices` is `[0, 1, 2, …]` we'd rebuild the same\n // arrays. Cheap to detect, lets us avoid the regex when the user hasn't\n // actually changed anything.\n let isNoop = newOrderIndices.length === urls.length\n for (let i = 0; isNoop && i < newOrderIndices.length; i++) {\n if (newOrderIndices[i] !== i) isNoop = false\n }\n if (isNoop) return { urls: [...urls], prompt }\n const newUrls = newOrderIndices.map((i) => urls[i])\n // Build orig-1based-pos → new-1based-pos map for prompt renumbering. Offset by\n // `ordinalOffset` so when `urls` are the ASSET tail of a unified list (leading\n // image-refs occupy `1 … ordinalOffset`), the asset ordinals `ordinalOffset+1 …`\n // remap among themselves and the leading ordinals are never matched (their keys\n // aren't in `remap`, so the regex leaves them untouched).\n const remap = new Map<number, number>()\n for (let newPos = 0; newPos < newOrderIndices.length; newPos++) {\n remap.set(ordinalOffset + newOrderIndices[newPos] + 1, ordinalOffset + newPos + 1)\n }\n // Replace every positional ordinal (1-3 digit, word-boundary) substring,\n // preserving its prefix: image prompts use `Image N`, video prompts use the\n // `@image_N` binding form (REF_BINDING.ordinal). The alternation is\n // case-exact (no `i` flag) so each form re-emits with the SAME prefix.\n // Negative lookahead on digits guards against `Image 12` → `Image 32` when\n // remapping 1 → 3. The lookbehind prevents catching `XImage 1` / `foo@image_1`.\n const renumbered = prompt.replace(/(?<![A-Za-z])(@image_|Image )(\\d{1,3})(?!\\d)/g, (whole, prefix, n) => {\n const orig = parseInt(n, 10)\n const next = remap.get(orig)\n if (next === undefined || next === orig) return whole\n return `${prefix}${next}`\n })\n return { urls: newUrls, prompt: renumbered }\n}\n\nfunction buildCharacterPositionMap(\n mergedUrls: readonly string[],\n refs: readonly ConnectedReference[],\n): Map<string, number> {\n const byUrl = new Map<string, ConnectedReference>()\n for (const r of refs) {\n if (!r.url) continue\n if (!byUrl.has(r.url)) byUrl.set(r.url, r)\n }\n const positions = new Map<string, number>()\n for (let i = 0; i < mergedUrls.length; i++) {\n const ref = byUrl.get(mergedUrls[i])\n const slug = ref?.characterSlug\n if (slug && !positions.has(slug)) {\n positions.set(slug, i + 1)\n }\n }\n return positions\n}\n\nexport interface BuildImagePromptConfig {\n /** Raw user prompt text */\n prompt: string\n /** Image provider key (e.g. \"nano-banana\", \"gpt-image\") */\n provider: string\n /** Style text to append (e.g. \"cinematic\") */\n style?: string\n /** Negative prompt text */\n negativePrompt?: string\n /** Character definitions selected for this node */\n characterDefs?: CharacterDef[]\n /** User-level prompt template overrides */\n userTemplates?: Record<string, string>\n /** Flow-level prompt template overrides */\n flowTemplates?: Record<string, string>\n /** Reference image URLs from direct connections, extracted refs, and character refs */\n referenceImageUrls?: string[]\n /** Ancestor reference image URLs (fallback when no direct refs exist) */\n ancestorRefs?: string[]\n /**\n * Rich connected-reference data. When provided, supersedes `characterDefs`\n * and `referenceImageUrls`: per-identity directives come from this list +\n * any `{image:N:label}` mentions in the prompt, URLs come from this list\n * in order, and tokens expand to \"the {label} from image {N}\".\n */\n connectedReferences?: ConnectedReference[]\n /**\n * References the caller can NAME and DESCRIBE but has no media for (an\n * un-bound cast role, an analysis slot). They attach no URL and claim no\n * `Image N` / lettered slot — they reach the model as prose, rendered once by\n * `renderDescribedReferenceLines` and joined the way the active format joins\n * its trailing directives. Present with NO `connectedReferences` is the normal\n * case (a story landing before any entity exists), so they enter the\n * connected-reference path on their own.\n */\n describedReferences?: readonly DescribedReference[]\n /** Per-identity (imageIndex+label) user overrides for fidelity / custom text. */\n identityMeta?: readonly IdentityMeta[]\n /**\n * Reference-prompt assembly format for the `{image:N:label}` connected-\n * reference (non-character) path. Additive + opt-in:\n * - \"legacy\" (default): the \"Use these references:/Compose them naturally:\"\n * wrap with numeric `Image N` directives — unchanged behavior.\n * - \"hybrid\": token expansion only — every `{image:N:label}` token → \"the\n * <label> from reference image <LETTER>\". NO lock snippet is auto-injected\n * (authors prepend their own). Images-only for now; characters/objects/\n * locations still render legacy. v1 skips `referenceOrder` renumbering.\n */\n referenceFormat?: \"legacy\" | \"hybrid\"\n /**\n * OPTIONAL reference-lock snippet to prepend ahead of the hybrid scene. Only\n * used when `referenceFormat === \"hybrid\"`. Nothing is prepended by default —\n * authors include their own lock snippet in the prompt text. Provide this only\n * if a caller wants to auto-prepend a lock.\n */\n referenceLockSnippet?: string\n /**\n * User-defined reorder of the injected reference list. Each entry is a\n * stable tile ID using the scheme from `compute-injected-refs.ts`:\n * - `wired:<sourceNodeId>` (a wired upstream — manual / wired-image /\n * wired-face / wired-object / wired-location / extra-ref)\n * - `mention:<characterSlug>:<variantSlug|canonical>` (an `@-mention`\n * resolved to a character variant URL)\n * - `char-canonical:<characterSlug>` (the auto-attached canonical\n * fallback for a wired character that the user did NOT `@-mention`)\n *\n * Behavior: after the existing assembly produces a URL list + a prompt\n * with `Image N` directives, the URLs are re-ordered to match this list\n * AND every `Image N` token in the prompt is renumbered consistently\n * (so directive bullets, the user's typed `Image N` references, and the\n * worker `referenceImageUrls` index all agree).\n *\n * IDs in this array that don't match any tile are silently dropped. Tiles\n * whose ID is NOT in this array fall to the end in their natural order.\n * Identical fixtures on frontend + backend MUST produce identical URL\n * lists — the helper is shared via `compute-injected-refs.ts`.\n *\n * Stable-ID-per-URL mapping for the post-assembly re-order is computed\n * from `connectedReferences` + the user's prompt; passing `referenceOrder`\n * is a no-op when `connectedReferences` is missing (legacy path).\n *\n * Optional, omit to keep the existing natural order.\n */\n referenceOrder?: readonly string[]\n /**\n * Map of `connectedReferences[i].id → sourceNodeId` so wired-raw tile IDs\n * match the upstream node IDs the consumer panel exposes. When omitted, the\n * builder falls back to `connectedReferences[i].id` (which equals the\n * upstream node ID for wired entries built by the existing image-configs +\n * payload-builder flow).\n */\n sourceNodeIdById?: ReadonlyMap<string, string>\n /**\n * Character slugs whose canonical-fallback the user has explicitly hidden\n * via the × button. Mention URLs for the same character still attach.\n */\n suppressedCanonicalCharacterIds?: readonly string[]\n /**\n * Location slugs (or DB ids) whose canonical-fallback the user has hidden\n * via the × button. Mirrors `suppressedCanonicalCharacterIds`: the upstream\n * `wired-location` ref still attaches, but the canonical establishing-shot\n * URL is dropped from the injected reference list.\n *\n * NOTE (Phase 1A): the location canonical-fallback path is wired up in a\n * follow-up PR (`injected-reference-helpers.ts`). Until then, this\n * parameter is accepted but inert — callers can pass it through without\n * any behavior change. Once the canonical-fallback logic lands, the\n * builder will filter `connectedReferences` with `source === \"wired-location\"`\n * and a matching slug, exactly like the character path does.\n */\n suppressedCanonicalLocationIds?: readonly string[]\n /**\n * When true, skip the entire mention-resolution block (character identity\n * directives, `Image N (Kira)` bullets, additional ref URLs from\n * `connectedReferences`) AND strip raw `@slug[:V[:variant]]` tokens from\n * the prompt. Used by the LoRA inference path\n * (`flux-lora-character`) — the trigger word + LoRA carries identity, so\n * the directive bullets are redundant and the wired-character refs\n * shouldn't be injected as `Image N`.\n *\n * The strip regex is grammar-agnostic — it eats LOCATION and named-IMAGE\n * mentions (`@town:3:background`) as well as character ones. That is\n * INTENDED, not an oversight: this path drops `connectedReferences` outright,\n * so there is no reference left for any mention to bind to and a surviving\n * token would reach the model as literal noise. Do not narrow it.\n */\n skipCharacterMentions?: boolean\n}\n\nexport interface BuildImagePromptResult {\n /** Final assembled prompt */\n prompt: string\n /** Native negative prompt (only for models that support it), undefined otherwise */\n nativeNegativePrompt: string | undefined\n /** Filtered reference image URLs (only for models that support them) */\n referenceImageUrls: string[] | undefined\n}\n\nexport type PromptSegmentOrigin =\n | \"user\" // typed by the user\n | \"variable\" // resolved {Node Label} value\n | \"picker\" // parameter-picker / cinematography fragment\n | \"mention\" // identity/reference directive block\n | \"style\" // auto-appended Style suffix\n | \"negative\" // auto-appended Avoid suffix\n\nexport interface PromptSegment {\n readonly text: string\n readonly origin: PromptSegmentOrigin\n}\n\nexport interface BuildImagePromptSegmentsResult extends BuildImagePromptResult {\n /** Origin-tagged decomposition of `prompt`. INVARIANT (tested):\n * segments.map(s => s.text).join(\"\") === prompt. */\n segments: PromptSegment[]\n}\n\n/**\n * Internal capture surface for `buildImagePromptSegments`. `buildImagePrompt`\n * itself never passes this — its output is byte-identical with or without it.\n * Each field records a span produced during final assembly so the segment\n * decomposition can be reconstructed without re-deriving the string:\n * - `directivesPrefix`: the directive block PREPENDED ahead of the user body\n * (connectedReferences path, \"Use these references…/Compose them…\" wrap).\n * Empty when the directive block was spliced mid-string into a Phase-0\n * \"Use these characters:\" block (documented degradation → body collapses).\n * - `bodyBeforeSuffixes`: the prompt string captured immediately BEFORE the\n * style/avoid suffixes were appended (covers the common no-truncation case).\n * - `styleSuffix` / `avoidSuffix`: the `\\nStyle: …` / `\\nAvoid: …` strings.\n * - `overflowChars`: how many characters the provider cap forced OFF the tail\n * (0 when the assembled prompt fit). Accumulated across every clamp site in\n * both assembly paths. Read by {@link buildImagePromptWithOverflow} so a\n * cap-aware caller can shed its own lowest-value text and re-assemble\n * instead of letting the order-blind tail cut decide.\n */\ninterface AssemblyMarks {\n directivesPrefix: string\n bodyBeforeSuffixes: string\n styleSuffix: string\n avoidSuffix: string\n overflowChars: number\n}\n\n/** Keep `bodySegments` when the assembled body still equals their join;\n * otherwise collapse to one `user` segment (assembly rewrote the body —\n * mention replacement, {image:N} expansion, truncation, or reorder). */\nfunction reconcileBodySegments(body: string, bodySegments: readonly PromptSegment[] | undefined): PromptSegment[] {\n if (!body) return []\n if (bodySegments && bodySegments.map((s) => s.text).join(\"\") === body) {\n return [...bodySegments]\n }\n return [{ text: body, origin: \"user\" }]\n}\n\n/**\n * The `Style:` / `Avoid:` control lines with the separator each one needs.\n *\n * They are self-labeling and stay at the very END of the prompt, which makes\n * them the only text that can still land under an open `[style]` header — the\n * section has no terminator, so a blank line is what closes its scope. `Avoid:`\n * reads the body WITH `Style:` already on it, so once the first control line has\n * closed the section the second rejoins on a single newline, exactly as before.\n *\n * Derived from the body they are appended to, because the cap's tail cut moves\n * that boundary. The cut can only NARROW the separator — the section is the last\n * block, so a cut either drops it entirely or lands inside it — which is what\n * lets the caller reserve on the pre-cut body and re-derive afterwards.\n */\nfunction controlSuffixes(\n body: string,\n styleLine: string,\n avoidLine: string,\n): { styleSuffix: string; avoidSuffix: string } {\n const separator = (text: string): string =>\n endsInsideStyleSection(text) ? STYLE_SECTION_GAP : \"\\n\"\n const styleSuffix = styleLine ? `${separator(body)}${styleLine}` : \"\"\n const avoidSuffix = avoidLine ? `${separator(body + styleSuffix)}${avoidLine}` : \"\"\n return { styleSuffix, avoidSuffix }\n}\n\n/**\n * Build the final image generation prompt from config.\n * Handles character description wrapping, style appending, negative prompt routing,\n * truncation, and reference image filtering.\n *\n * Thin passthrough over `buildImagePromptInternal` — byte-identical behavior,\n * no marks captured. Use `buildImagePromptSegments` when you also need the\n * origin-tagged decomposition.\n */\nexport function buildImagePrompt(config: BuildImagePromptConfig): BuildImagePromptResult {\n return buildImagePromptInternal(config)\n}\n\n/** {@link buildImagePrompt} plus `overflowChars`. */\nexport interface BuildImagePromptOverflowResult extends BuildImagePromptResult {\n /**\n * Characters the provider's prompt cap forced off the tail — `0` when the\n * assembled prompt fit. This is the amount of text that must LEAVE the body\n * for the prompt to fit without a tail cut, so a caller can shed exactly\n * enough of its own droppable text and re-assemble.\n */\n overflowChars: number\n}\n\n/**\n * `buildImagePrompt` plus the size of the cap overflow it had to clamp away.\n *\n * The prompt (and every other field) is BYTE-IDENTICAL to `buildImagePrompt` —\n * the marks channel only observes. Exists because the tail clamp is ORDER-BLIND:\n * it cuts whatever happens to be last, which on a low-cap provider can sever a\n * reference directive or the user's own prose while a decorative hint clause\n * survives. `assembleImageInput` uses this to drop its lowest-value text\n * (direction-folded hint clauses) FIRST and re-assemble; the clamp then stays\n * the last-resort fallback for a body that overflows on prose alone.\n */\nexport function buildImagePromptWithOverflow(\n config: BuildImagePromptConfig,\n): BuildImagePromptOverflowResult {\n const marks = newAssemblyMarks()\n const result = buildImagePromptInternal(config, marks)\n return { ...result, overflowChars: marks.overflowChars }\n}\n\n/** Fresh zeroed marks — one construction site so a new field can't be forgotten. */\nfunction newAssemblyMarks(): AssemblyMarks {\n return {\n directivesPrefix: \"\",\n bodyBeforeSuffixes: \"\",\n styleSuffix: \"\",\n avoidSuffix: \"\",\n overflowChars: 0,\n }\n}\n\n/**\n * Shared assembly body for `buildImagePrompt` + `buildImagePromptSegments`.\n * When `marks` is provided, records the directive-prefix / body / suffix spans\n * (guarded by `if (marks)`) so callers can reconstruct an origin-tagged\n * decomposition. The string output is identical regardless of `marks`.\n */\nfunction buildImagePromptInternal(config: BuildImagePromptConfig, marks?: AssemblyMarks): BuildImagePromptResult {\n let {\n provider,\n style,\n negativePrompt,\n characterDefs = [],\n userTemplates,\n flowTemplates,\n referenceImageUrls = [],\n ancestorRefs = [],\n connectedReferences,\n identityMeta = [],\n } = config\n const referenceOrder = config.referenceOrder ?? []\n const sourceNodeIdById = config.sourceNodeIdById\n const suppressedCanonicalCharacterIds = new Set(\n config.suppressedCanonicalCharacterIds ?? [],\n )\n const suppressedCanonicalLocationIds = config.suppressedCanonicalLocationIds ?? []\n // `referenceFormat` is preserved across the Phase-0 `config = {...config}`\n // reassignment, so computing this once up front is stable. Gates the hybrid\n // character convergence (Phase 0) and the non-capitalizing scene render below.\n const isHybrid = config.referenceFormat === \"hybrid\"\n // Described references (name + description, no media) — rendered ONCE, up\n // front, so the reassignments below can't lose them. They attach no URL, so\n // they take no part in numbering; they are joined onto the assembled prompt at\n // the single site in the connected-reference path below, ahead of the provider\n // cap so a shed sees them like any other body text. Empty for every caller\n // that doesn't send them → nothing downstream changes.\n const describedLines = renderDescribedReferenceLines(config.describedReferences)\n // Set when Phase 0 converged character OR location @-mentions into inline\n // hybrid role phrases (+ identity-lock + element directives). Tells the hybrid\n // scene render to expand any remaining {image:N} tokens WITHOUT capitalizing\n // line-initials (which would corrupt \"the face from reference image A\" → \"The\n // face …\" / \"the style from reference image A\" → \"The style …\").\n let hybridBodyConverged = false\n // URLs bound by a Phase-0 wired-entity (`@creature` / `@object`) mention.\n // Declared at function scope because it must BRIDGE the two blocks below:\n // Phase 0 populates it, and the New path unions it into\n // `renderObjectCreatureCanonicalHybrid`'s `coveredUrls` so a mentioned\n // creature/object does NOT also emit its trailing canonical phrase. Empty for\n // every prompt without an entity mention, which is what keeps those outputs\n // byte-identical.\n const mentionedEntityUrls = new Set<string>()\n // URLs bound by a Phase-0 named-image (`@<image-name>`) mention. Bridges the\n // same two blocks for the OTHER suppression the New path owes: that pass\n // already emitted each bound ref's per-use `descriptionOverride` line, so the\n // untold-override sweep must not say it a second time. Empty for every prompt\n // without an image mention.\n const mentionedImageUrls = new Set<string>()\n\n // Character LoRA inference path: trigger word + LoRA model carry identity,\n // so we strip raw `@slug[:V[:variant]]` tokens from the prompt AND drop the\n // connected-reference machinery entirely (no Image N bullets, no\n // ref URLs). The LoRA model gets a clean prompt + the trigger word\n // injected by the Replicate buildInput (see providers/replicate/image.ts).\n if (config.skipCharacterMentions) {\n config = {\n ...config,\n prompt: config.prompt.replace(\n /@[a-z0-9_-]+(?::\\d+(?::[a-z0-9_-]+)?)?\\s?/gi,\n \"\",\n ).trim(),\n }\n connectedReferences = undefined\n referenceImageUrls = []\n }\n\n // Apply canonical suppression UP FRONT so `buildCanonicalFallback` never\n // sees the suppressed slugs. This is the only way to drop both the URL\n // and the directive line; filtering after the fact would leave the\n // directive numbering misaligned.\n if (\n connectedReferences\n && suppressedCanonicalCharacterIds.size > 0\n ) {\n connectedReferences = connectedReferences.filter((r) => {\n if (r.source !== \"wired-character\") return true\n if (!r.characterSlug) return true\n // Only drop the CANONICAL entry — `@-mentioned` variants are explicit\n // and should stay even when canonical is suppressed.\n if (r.variantSlug) return true\n if (r.isExtraRef) return true\n return !suppressedCanonicalCharacterIds.has(r.characterSlug)\n })\n }\n\n // Cap structured references to the provider's image-reference limit — the SAME\n // cap the canvas enforces via handle-limits. Applied UP FRONT (like the\n // suppression filter above) so the direct API / MCP / SDK path can't send more\n // references than the provider accepts and leave an `Image N` directive\n // pointing at a slot the provider silently drops. Flat `referenceImageUrls` are\n // numbered first, so they consume the budget. Only ref-capable providers\n // (refCap > 0) cap here; non-ref providers drop all URLs via `supportsRefs`.\n if (connectedReferences && connectedReferences.length > 0) {\n const refCap = imageReferenceLimit(provider)\n if (refCap > 0) {\n const structuredBudget = Math.max(0, refCap - referenceImageUrls.length)\n if (connectedReferences.length > structuredBudget) {\n // ATTACH-PRIORITY slice, not raw order. The raw list interleaves each\n // wired character's canonical with its whole variant array, and an\n // unmentioned VARIANT never attaches — yet a raw slice let one\n // variant-rich character fill the budget and evict every character\n // wired after it ENTIRELY, canonical included (the \"two characters\n // wired, one sent\" incident: 1 canonical + 7 variants consumed\n // nano-banana-pro's cap of 8, and the second character vanished\n // while the provider received TWO urls total). Non-variant entries\n // (canonicals, manual refs, extra-refs) take the budget first;\n // variants fill what remains as mention candidates. Survivors keep\n // their original relative order, so slot numbering is unchanged for\n // every graph that fit the budget before.\n const nonVariants = connectedReferences.filter((r) => !r.variantSlug || r.isExtraRef === true)\n const variants = connectedReferences.filter((r) => r.variantSlug && r.isExtraRef !== true)\n const kept = new Set([...nonVariants, ...variants].slice(0, structuredBudget))\n connectedReferences = connectedReferences.filter((r) => kept.has(r))\n }\n }\n }\n\n // -------------------------------------------------------------------------\n // Phase 0: resolve `@<character-slug>:<index>(:<variant-slug>)?` tokens\n // AND apply the per-character canonical fallback for unmentioned wired\n // characters. Runs BEFORE the existing `{image:N}` resolution path. Both\n // coexist: Phase 0 handles slug-based character mentions / fallbacks;\n // the existing path below handles `{image:N:label}` tokens for\n // non-character refs.\n //\n // Per-character contract:\n // - wired-character WITHOUT any `@-mention` → contribute canonical URL\n // + a strong identity directive (pre-mention-feature behavior).\n // - wired-character WITH at least one `@-mention` → contribute ONLY\n // mentioned variant URLs (no canonical auto-attach).\n // -------------------------------------------------------------------------\n if (connectedReferences && connectedReferences.length > 0) {\n const knownCharacterSlugs = Array.from(\n new Set(\n connectedReferences\n .map((r) => r.characterSlug)\n .filter((s): s is string => typeof s === \"string\" && s.length > 0)\n )\n )\n const hasExtraRefs = connectedReferences.some((r) => r.isExtraRef === true)\n // We only need to run the directive-emission machinery if either\n // (a) there's at least one character ref (mention / canonical fallback\n // could fire), or (b) there's at least one user-attached extra ref\n // (manual uploads with descriptions, or character-variant extras).\n // The empty-extras-empty-characters case falls through to the standard\n // non-character ref path unchanged.\n // Known location slugs (Phase 2 #2) — separate from character slugs.\n // Each location row contributes a canonical entry + per-variant entries,\n // all sharing the same `locationSlug`; we want the unique set for finder.\n const knownLocationSlugs = Array.from(\n new Set(\n connectedReferences\n .map((r) => r.locationSlug)\n .filter((s): s is string => typeof s === \"string\" && s.length > 0)\n )\n )\n // Named-image mentions (P3). Slugs derive from each media ref's\n // `defaultName` — there is no `imageSlug` wire field; the derivation is\n // shared with the backend orchestrator's structured-branch gate via\n // `knownImageSlugsFromRefs`, so the two can never disagree about whether a\n // prompt carries a resolvable image mention.\n const knownImageSlugs = knownImageSlugsFromRefs(connectedReferences)\n // EXISTENCE-ONLY precheck, gating the Phase-0 arm below. Unlike characters\n // (whose canonical fallback must run even with ZERO mentions), images have\n // NO canonical fallback, so an image-only graph with no mention has no\n // reason to enter Phase 0 — gating on TOKEN presence keeps today's control\n // flow and byte output for every unmentioned graph BY CONSTRUCTION.\n // HYBRID-only: under the legacy format an `@name:N` token stays literal text.\n const hasImageMentionTokens = isHybrid\n && knownImageSlugs.length > 0\n && findImageMentionTokens(config.prompt, knownImageSlugs).length > 0\n // Wired-entity mentions (`wired-creature` / `wired-object`). Slugs derive\n // from each entity ref's `defaultName` — no `entitySlug` wire field, matching\n // the image grammar — and the derivation is shared with the backend\n // orchestrator's structured-branch gate via `knownEntitySlugsFromRefs`.\n const knownEntitySlugs = knownEntitySlugsFromRefs(connectedReferences)\n // EXISTENCE-ONLY precheck, gating the Phase-0 arm below — the image\n // precedent. An unmentioned creature/object already renders correctly\n // through `renderObjectCreatureCanonicalHybrid`, so a graph with no entity\n // mention has no reason to enter Phase 0: gating on TOKEN presence keeps\n // today's control flow and byte output for every such graph BY\n // CONSTRUCTION. HYBRID-only — under the legacy format an `@name:N` token\n // stays literal text.\n const hasEntityMentionTokens = isHybrid\n && knownEntitySlugs.length > 0\n && findEntityMentionTokens(config.prompt, knownEntitySlugs).length > 0\n if (knownCharacterSlugs.length > 0 || hasExtraRefs || knownLocationSlugs.length > 0 || hasImageMentionTokens || hasEntityMentionTokens) {\n const mentionTokens = knownCharacterSlugs.length > 0\n ? findCharacterMentionTokens(config.prompt, knownCharacterSlugs)\n : []\n // Character @-mention resolution. HYBRID (Unified Reference Roles,\n // Phase A): each mention becomes the inline role phrase \"the {role} from\n // reference image {LETTER}\" with the optional identity-lock + wired\n // elementInjection surfaced SEPARATELY, and NO \"Use these characters:\"\n // block. LEGACY keeps the bullet block (and is shared verbatim with the\n // video resolver — untouched here).\n let hybridLockLines: string[] = []\n let hybridElementDirectives: string[] = []\n let resolved: ResolveCharacterMentionsResult\n if (isHybrid && mentionTokens.length > 0) {\n const h = resolveCharacterMentionsHybrid(\n config.prompt,\n mentionTokens,\n connectedReferences,\n referenceImageUrls,\n )\n resolved = {\n prompt: h.prompt,\n additionalUrls: h.additionalUrls,\n mentionedCharacterSlugs: h.mentionedCharacterSlugs,\n }\n hybridLockLines = h.lockLines\n hybridElementDirectives = h.elementDirectives\n hybridBodyConverged = true\n } else {\n resolved = mentionTokens.length > 0\n ? resolveCharacterMentions(config.prompt, mentionTokens, connectedReferences)\n : { prompt: config.prompt, additionalUrls: [], mentionedCharacterSlugs: new Set<string>() }\n }\n\n // Phase 2 #2: resolve `@oldlibrary:1:weather/rain` location mentions on\n // the post-character-resolution prompt. Character resolution may have\n // already swapped its own @-tokens for display names; location tokens\n // (different slug namespace) remain intact for this pass.\n const locationTokens = knownLocationSlugs.length > 0\n ? findLocationMentionTokens(resolved.prompt, knownLocationSlugs)\n : []\n // Location mention convergence. HYBRID (Unified Reference Roles, Phase C):\n // each `@location` mention becomes the inline role phrase \"the {role} from\n // reference image {LETTER}\" (role from the location node's usage mode) with\n // the opt-in lock + wired elementInjection surfaced SEPARATELY, and NO \"Use\n // these locations:\" block. LEGACY keeps the bullet block. `existingUrls` =\n // [base refs, resolved CHARACTER mentions] so location slot letters are a\n // prefix of the final `finalIndexByUrl` (location URLs merge after character\n // mentions, before the character canonical/extra URLs).\n let hybridLocationLockLines: string[] = []\n let hybridLocationElementDirectives: string[] = []\n let locationResolved: ResolveLocationMentionsResult\n if (isHybrid && locationTokens.length > 0) {\n const hl = resolveLocationMentionsHybrid(\n resolved.prompt,\n locationTokens,\n connectedReferences,\n [...(referenceImageUrls || []), ...resolved.additionalUrls],\n )\n locationResolved = {\n prompt: hl.prompt,\n additionalUrls: hl.additionalUrls,\n mentionedLocationSlugs: hl.mentionedLocationSlugs,\n }\n hybridLocationLockLines = hl.lockLines\n hybridLocationElementDirectives = hl.elementDirectives\n // Inline role phrases now live in the body → skip line-initial\n // capitalization. Only when a mention actually matched + was replaced.\n if (hl.additionalUrls.length > 0) hybridBodyConverged = true\n } else {\n locationResolved = locationTokens.length > 0\n ? resolveLocationMentions(resolved.prompt, locationTokens, connectedReferences)\n : { prompt: resolved.prompt, additionalUrls: [] as string[], mentionedLocationSlugs: new Set<string>() }\n }\n // Merge location's resolved prompt + URLs back into `resolved` so the\n // rest of the pipeline (fallback, extras, urlsByOrder) doesn't need\n // separate plumbing.\n resolved.prompt = locationResolved.prompt\n resolved.additionalUrls = [...resolved.additionalUrls, ...locationResolved.additionalUrls]\n // Per-variant location refs are mention-only — they were already\n // attached via `additionalUrls` when matched, and should NEVER\n // auto-attach via the non-character ref path below (line 1112).\n // Canonical refs whose slug was mentioned are also handled by the\n // resolver — drop to avoid double-attaching the canonical URL when the\n // user explicitly pinned a variant via `@-mention`.\n const mentionedLocationSlugs = locationResolved.mentionedLocationSlugs\n connectedReferences = connectedReferences.filter((r) => {\n if (r.source !== \"wired-location\") return true\n if (!r.locationSlug) return true\n if (r.locationVariantBucket) return false\n return !mentionedLocationSlugs.has(r.locationSlug)\n })\n // Pass 3 (P3): named-image mentions, resolved on the POST-character,\n // POST-location prompt. The finder MUST re-run here — the earlier passes\n // spliced their own tokens out, so any offset computed before them is\n // stale. PRECEDENCE character → location → image falls out of this pass\n // order: a name shared by a character and an image resolves as the\n // character, and the image token never fires.\n //\n // `existingUrls` is already location-inclusive because `additionalUrls`\n // absorbed the location URLs just above, so the mention slot letters stay\n // a prefix of the final `finalIndexByUrl`.\n let hybridImageLockLines: string[] = []\n let hybridImageElementDirectives: string[] = []\n if (hasImageMentionTokens) {\n const imageTokens = findImageMentionTokens(resolved.prompt, knownImageSlugs)\n if (imageTokens.length > 0) {\n const hi = resolveImageMentionsHybrid(\n resolved.prompt,\n imageTokens,\n connectedReferences,\n [...(referenceImageUrls || []), ...resolved.additionalUrls],\n )\n resolved.prompt = hi.prompt\n resolved.additionalUrls = [...resolved.additionalUrls, ...hi.additionalUrls]\n hybridImageLockLines = hi.lockLines\n hybridImageElementDirectives = hi.elementDirectives\n // The override handoff to the New path: a bound URL was already told\n // its per-use description here, inline with the mention, so the\n // untold-override sweep below skips it.\n for (const u of hi.mentionedUrls) mentionedImageUrls.add(u)\n // Inline role phrases now live in the body → skip line-initial\n // capitalization, which would otherwise corrupt a mid-sentence\n // \"the background from reference image C\".\n if (hi.additionalUrls.length > 0) hybridBodyConverged = true\n }\n }\n // NOTE — deliberately NO `connectedReferences` filter for mentioned image\n // refs (the location pass filters, just above). The New-path URL merge\n // dedups by URL so the ref keeps its earlier Phase-0 slot; wired-image /\n // manual refs have no canonical-fallback prose to double-emit (that loop\n // is gated to wired-location/object/creature); and leaving the ref in\n // place keeps `nonCharacterRefs[N-1]` positional indexing stable for\n // `{image:N}` tokens.\n //\n // Pass 4: wired-entity (`@creature` / `@object`) mentions, resolved on the\n // POST-character, POST-location, POST-image prompt. The finder MUST re-run\n // here — every earlier pass spliced its own tokens out, so an offset\n // computed before them is stale. PRECEDENCE character → location → image →\n // creature → object falls out of this pass order plus the creature-first\n // map inside the resolver: a name shared with an earlier kind resolves as\n // that kind, and the entity token never fires.\n //\n // `existingUrls` is already location- AND image-inclusive because\n // `additionalUrls` absorbed both above, so the mention slot letters stay a\n // prefix of the final `finalIndexByUrl`.\n let hybridEntityLockLines: string[] = []\n let hybridEntityElementDirectives: string[] = []\n if (hasEntityMentionTokens) {\n const entityTokens = findEntityMentionTokens(resolved.prompt, knownEntitySlugs)\n if (entityTokens.length > 0) {\n const he = resolveEntityMentionsHybrid(\n resolved.prompt,\n entityTokens,\n connectedReferences,\n [...(referenceImageUrls || []), ...resolved.additionalUrls],\n )\n resolved.prompt = he.prompt\n resolved.additionalUrls = [...resolved.additionalUrls, ...he.additionalUrls]\n hybridEntityLockLines = he.lockLines\n hybridEntityElementDirectives = he.elementDirectives\n // The suppression handoff to the New path: every bound URL is skipped\n // by `renderObjectCreatureCanonicalHybrid`, so the phrase renders ONCE\n // — inline, where the user typed it — instead of also dangling as a\n // trailing \"the creature from reference image D\" line. Like the image\n // pass, the ref itself is NOT filtered out of `connectedReferences`\n // (positional `{image:N}` stability); coveredUrls is the whole\n // mechanism.\n for (const u of he.mentionedUrls) mentionedEntityUrls.add(u)\n // Inline role phrases now live in the body → skip line-initial\n // capitalization, which would otherwise corrupt a mid-sentence\n // \"the creature from reference image D\".\n if (he.additionalUrls.length > 0) hybridBodyConverged = true\n }\n }\n // Default-fallback canonical URLs + directives for any wired character\n // that has zero mentions in the prompt. Mirrors the legacy behavior the\n // mention feature replaced — wire a character with no typing required.\n //\n // `startIndex` = position (1-based) of the first canonical fallback\n // URL in the final merged list. Computed by deduping the prefix\n // (pre-existing refs + mention URLs) so that if a mention URL\n // coincidentally equals an upstream ref, the canonical lines still\n // point at the correct position.\n const prefixDedupedLength = ([\n ...(referenceImageUrls || []),\n ...resolved.additionalUrls,\n ].filter((u, i, a) => a.indexOf(u) === i)).length\n // Canonical fallback (unmentioned wired character → auto-attached URL).\n // LEGACY emits the \"Use these characters:\" bullet block; HYBRID (Task 4)\n // attaches the SAME canonical URLs but renders each as an inline role\n // phrase + opt-in lock below (once the slot letters are known). Selection\n // is shared so both paths auto-attach the same characters.\n const canonicalFallbackRefs = isHybrid\n ? selectCanonicalFallbackRefs(connectedReferences, resolved.mentionedCharacterSlugs)\n : []\n const fallback = isHybrid\n ? { directiveLines: [] as string[], urls: canonicalFallbackRefs.map((r) => r.url) }\n : buildCanonicalFallback(\n connectedReferences,\n resolved.mentionedCharacterSlugs,\n prefixDedupedLength + 1,\n )\n let promptForNext = resolved.prompt\n if (fallback.directiveLines.length > 0) {\n // Mirror `resolveCharacterMentions`'s \"Use these characters:\\n…\" block\n // structure. When both blocks exist, append fallback bullets to the\n // same block so the model sees one consolidated header.\n if (promptForNext.startsWith(\"Use these characters:\\n\")) {\n const splitIdx = promptForNext.indexOf(\"\\n\\n\")\n if (splitIdx !== -1) {\n const header = promptForNext.slice(0, splitIdx)\n const rest = promptForNext.slice(splitIdx)\n promptForNext = `${header}\\n${fallback.directiveLines.join(\"\\n\")}${rest}`\n } else {\n promptForNext = `${promptForNext}\\n${fallback.directiveLines.join(\"\\n\")}`\n }\n } else {\n promptForNext = `Use these characters:\\n${fallback.directiveLines.join(\"\\n\")}\\n\\n${promptForNext}`\n }\n }\n const mergedUrls = [\n ...(referenceImageUrls || []),\n ...resolved.additionalUrls,\n ...fallback.urls,\n ].filter((u, i, a) => a.indexOf(u) === i)\n\n // Extra-ref directives: user-attached refs (manual uploads + picked\n // character variants). Emitted AFTER mentions + canonical fallback so\n // they get the next positional slots. Numbering = position in the final\n // ref URL list (mergedUrls.length + 1, +2, …).\n const characterPositions = buildCharacterPositionMap(mergedUrls, connectedReferences)\n // Extra-refs (manual uploads + picked character variants). LEGACY emits\n // \"Image N\" bullets in the \"Use these characters:\" block; HYBRID (Task 4)\n // attaches the SAME URLs but renders manual / pair-back directives with\n // lettered bindings below. Filter shared so both paths attach the same URLs.\n const extraRefsHybrid = isHybrid\n ? connectedReferences.filter((r) => r.isExtraRef === true && Boolean(r.url))\n : []\n const extras = isHybrid\n ? { directiveLines: [] as string[], urls: extraRefsHybrid.map((r) => r.url) }\n : buildExtraRefDirectives(\n connectedReferences,\n characterPositions,\n mergedUrls.length + 1,\n )\n // Always merge extras' URLs — minimal-intervention modes (\"none\" /\n // \"name\") may emit zero or one bullet while still attaching the image.\n // Gating the URL merge on `directiveLines.length > 0` would silently\n // drop the URL for a `none`-mode extra.\n const finalMergedUrls = [...mergedUrls, ...extras.urls]\n .filter((u, i, a) => a.indexOf(u) === i)\n if (extras.directiveLines.length > 0) {\n if (promptForNext.startsWith(\"Use these characters:\\n\")) {\n const splitIdx = promptForNext.indexOf(\"\\n\\n\")\n if (splitIdx !== -1) {\n const header = promptForNext.slice(0, splitIdx)\n const rest = promptForNext.slice(splitIdx)\n promptForNext = `${header}\\n${extras.directiveLines.join(\"\\n\")}${rest}`\n } else {\n promptForNext = `${promptForNext}\\n${extras.directiveLines.join(\"\\n\")}`\n }\n } else {\n promptForNext = `Use these characters:\\n${extras.directiveLines.join(\"\\n\")}\\n\\n${promptForNext}`\n }\n }\n\n // Hybrid assembly. Prepend ONE identity-lock block (mention + canonical\n // fallback + first-sight extra locks) and append the trailing scene\n // directives (mention element injections + canonical role phrases +\n // canonical element injections + extra-ref directives + extra-ref element\n // injections) — never the legacy \"Use these characters:\" block.\n if (isHybrid) {\n // Unified slot map over the final hybrid URL order\n // [base, mentions, canonical, extras] — the exact prefix of the \"New\n // path\" `finalIndexByUrl`, so every lettered binding agrees byte-for-byte.\n const slotByUrl = new Map<string, number>()\n finalMergedUrls.forEach((u, i) => {\n if (!slotByUrl.has(u)) slotByUrl.set(u, i + 1)\n })\n const letterForUrl = (url: string): string => slotToLetter(slotByUrl.get(url) ?? 0)\n\n // (A) canonical fallback → role phrases + opt-in locks.\n const canonical = renderCanonicalFallbackHybrid(canonicalFallbackRefs, letterForUrl)\n // (B) extra-refs → manual / pair-back directives + first-sight locks.\n // Seed the pair-back lookup with each character's FIRST emitted letter\n // (mention / canonical fallback), converted from its mergedUrls position.\n const seedLetterByChar = new Map<string, string>()\n for (const [slug, pos] of characterPositions) {\n seedLetterByChar.set(slug, slotToLetter(pos))\n }\n const extrasRendered = renderExtraRefsHybrid(extraRefsHybrid, letterForUrl, seedLetterByChar)\n\n // Role phrases are intentionally lowercase (\"the person from reference\n // image A\"); flag the converged state so the scene render below skips\n // line-initial capitalization (which would corrupt them).\n if (canonical.phrases.length > 0 || extrasRendered.bodyLines.length > 0) {\n hybridBodyConverged = true\n }\n\n // Location MENTION locks/elements (the role phrases themselves are\n // already inline in `promptForNext`). Mentioned-location URLs sit\n // between the character mentions and the character canonical/extras in\n // `finalMergedUrls`, so their letters were computed against the matching\n // prefix in `resolveLocationMentionsHybrid` and need no re-derivation here.\n // Set-dedup: a reference can be locked via more than one path (e.g. an\n // extra whose URL equals the wired canonical is routed to first-sight\n // by the pair-back letter gate) — identical lock lines say nothing new\n // to the model, so emit each exact line once. Line texts are\n // {ref}-bound, so distinct references never collapse.\n const allLockLines = [...new Set([\n ...hybridLockLines,\n ...hybridLocationLockLines,\n ...hybridImageLockLines,\n ...hybridEntityLockLines,\n ...canonical.lockLines,\n ...extrasRendered.lockLines,\n ])]\n const trailingLines = [\n ...hybridElementDirectives,\n ...hybridLocationElementDirectives,\n ...hybridImageElementDirectives,\n ...hybridEntityElementDirectives,\n ...canonical.phrases,\n ...canonical.elementDirectives,\n ...extrasRendered.bodyLines,\n ...extrasRendered.elementDirectives,\n ]\n const lockBlock = allLockLines.length > 0 ? `${allLockLines.join(\"\\n\")}\\n\\n` : \"\"\n // Scene content, so it extends the BODY: appended flat it would land\n // under a `[style]` header the composer left open.\n promptForNext = `${lockBlock}${insertBeforeStyleSection(promptForNext, trailingLines)}`\n }\n\n // Mutate the config locals (NOT the original passed config).\n config = {\n ...config,\n prompt: promptForNext,\n referenceImageUrls: finalMergedUrls,\n }\n referenceImageUrls = config.referenceImageUrls || []\n }\n }\n\n // -------------------------------------------------------------------------\n // New path: rich `connectedReferences` provided. Per-identity directives\n // are emitted at the top, `{image:N:label}` tokens expand to natural-\n // language phrases, and URLs are sent in connectedReferences order.\n //\n // Character refs (source === \"wired-character\") are AUTOCOMPLETE-ONLY by\n // default — they ONLY contribute URLs + directives via Phase 0 mention\n // resolution above (`referenceImageUrls` and a \"Use these characters…\"\n // prefix). A wired character with no @-mention in the prompt contributes\n // zero URLs and zero directives here. Non-character refs (manual, wired-creature,\n // wired-image, wired-face, wired-object, wired-location) still auto-\n // attach so unchanged behavior for them.\n // -------------------------------------------------------------------------\n // Entered by `connectedReferences` OR by described references alone: a story\n // landing whose cast has no entities yet sends only names + descriptions, and\n // the legacy path below has no directive seam to join them onto.\n // An EMPTY connected list with ancestor images takes the flat path below, the\n // one that sends them: the editor always passes `connectedReferences` (empty\n // when nothing is wired directly), and this path never reads `ancestorRefs`,\n // so a photo reaching the node only through a passthrough node was dropped\n // and its `{image:N}` rendered as a label (#2010). The workflow run builds\n // that graph on the flat path (no connected list), so both now agree.\n const ancestorsOnly =\n connectedReferences !== undefined &&\n connectedReferences.length === 0 &&\n referenceImageUrls.length === 0 &&\n ancestorRefs.length > 0\n if ((connectedReferences && !ancestorsOnly) || describedLines.length > 0) {\n const structuredRefs = connectedReferences ?? []\n let prompt = config.prompt\n\n // Described references, LEGACY half — joined BEFORE the directive assembly\n // below, because the block it creates is the block that assembly consolidates\n // into. Joined AFTER instead, a request whose references produce the\n // \"Use these references for the output image:\" wrap (any non-character ref,\n // no wired character) would get a SECOND \"Use these characters:\" header\n // prepended above it. Prepending here also keeps `marks.directivesPrefix`\n // honest: the prepend branch that records it is only reachable when the\n // prompt does NOT already open with the character block.\n if (!isHybrid && describedLines.length > 0) {\n prompt = appendReferenceLines(prompt, describedLines, \"legacy\")\n }\n\n // Non-character refs are still emitted as per-identity directives + URLs.\n // Character refs are filtered out here — Phase 0 has already added their\n // URLs to `referenceImageUrls` (via mention resolution) and prepended the\n // \"Use these characters…\" directive block. User-attached extras\n // (isExtraRef === true) are also filtered out: Phase 0 already emitted\n // their per-ref directive (\"Image N (reference): <description>.\" / \"same\n // subject as Image M, …\") and merged their URLs into `referenceImageUrls`.\n // Letting them through here would double-emit the URLs (and append a\n // second positional directive via the {image:N:label} path).\n const nonCharacterRefs = structuredRefs.filter(\n (r) => r.source !== \"wired-character\" && r.isExtraRef !== true,\n )\n\n // -----------------------------------------------------------------------\n // Single source of truth for positional numbering.\n //\n // Phase 0 already numbered the character / extra directives against the\n // order [referenceImageUrls, mentions, canonical-fallback, extras] and\n // wrote both the bullets and the URLs into `referenceImageUrls`. We APPEND\n // the non-character URLs after that list (never prepend) so those Phase-0\n // numbers stay valid, then derive EVERY non-character directive's `Image N`\n // from this one final ordered list via a `url → index` map.\n //\n // The old code prepended `nonCharacterUrls` ahead of the Phase-0 list,\n // which shifted every character/extra `Image N` by `nonCharacterUrls.length`\n // while their directive text was already baked — the root cause of the\n // off-by-(non-char-count) desync. Appending is byte-identical to the old\n // prepend whenever a non-char URL already lives in `referenceImageUrls`\n // (dedup keeps its existing slot); it only differs for the genuinely-new\n // location/object URLs that the prepend mis-slotted.\n // -----------------------------------------------------------------------\n const nonCharacterUrls = nonCharacterRefs\n .map((r) => r.url)\n .filter((u): u is string => Boolean(u))\n const assembledUrls = [...referenceImageUrls, ...nonCharacterUrls]\n .filter((u, i, a) => a.indexOf(u) === i)\n const finalIndexByUrl = new Map<string, number>()\n assembledUrls.forEach((u, i) => {\n if (!finalIndexByUrl.has(u)) finalIndexByUrl.set(u, i + 1)\n })\n\n // The list an `{image:N}` token is numbered against: normally the\n // non-character connected refs. With NO connected references at all (the\n // path was entered through described references, or with an explicitly\n // empty list) there is nothing else to address, so N counts the flat URLs,\n // as on the flat path. Otherwise the photo is sent at slot 1 while\n // `{image:1:person}` renders as `person` (#2010). Only token binding reads\n // this; directives, canonical renders and covered-URL sets keep\n // `nonCharacterRefs`. No token can bind against an empty list, so no output\n // that binds a token today changes.\n const tokenRefs: readonly ConnectedReference[] = structuredRefs.length === 0\n ? referenceImageUrls.map((url, i) => ({\n id: `flat-${i + 1}`,\n defaultName: `Image ${i + 1}`,\n source: \"wired-image\" as const,\n url,\n }))\n : nonCharacterRefs\n\n // Non-character directives — `{image:N}` identities (renumbered to their\n // final slot) + the location/object canonical fallback — all numbered\n // against the unified `finalIndexByUrl`.\n const directives = buildNonCharacterDirectives(\n prompt,\n nonCharacterRefs,\n identityMeta,\n finalIndexByUrl,\n suppressedCanonicalLocationIds,\n )\n if (isHybrid) {\n // Hybrid reference format (images-only, flag-gated): TOKEN EXPANSION ONLY.\n // Every {image:N:label} token becomes \"the <label> from reference image\n // <LETTER>\". NO reference-lock snippet is auto-injected — authors prepend\n // their own lock (default-deny / likeness / compose / extract / ghost-\n // mannequin, per goal) in the prompt text, and it passes through here\n // untouched. A caller MAY still opt to prepend one via\n // `config.referenceLockSnippet`, but nothing is added by default.\n // Replaces the legacy \"Use these references:/Compose:\" wrap + numeric\n // token expansion. Objects stay legacy; CHARACTERS were already converged\n // in Phase 0 (role phrases + identity-lock + element directives), and\n // LOCATIONS converge here too — mentioned ones inline in Phase 0, the\n // unmentioned canonical ones as the trailing role phrases appended below.\n //\n // When Phase 0 converged a character OR location mention, the body is final\n // and intentionally lowercase (\"the face from reference image A\") — expand\n // any remaining {image:N} tokens but DON'T capitalize line-initials (which\n // would corrupt those phrases). Otherwise render the user scene as before\n // (capitalized line-initials); appended canonical phrases stay lowercase\n // because they're added AFTER this capitalizing pass.\n const scene = hybridBodyConverged\n ? prompt\n .split(\"\\n\")\n .map((line) => expandImageRefTokensHybrid(line, tokenRefs, finalIndexByUrl))\n .join(\"\\n\")\n : buildHybridScene(prompt, tokenRefs, finalIndexByUrl)\n // URLs already expanded inline by an `{image:N}` token in this scene.\n // Derived EXACTLY as the legacy `buildNonCharacterDirectives` derives its\n // `coveredUrls` — via `collectIdentities` (labeled `{image:N:label}`\n // tokens present in the prompt, indexing `nonCharacterRefs[N-1]`) — so the\n // hybrid and legacy notions of \"token-covered\" share one source of truth\n // and never drift. Threaded into both canonical renders so an unmentioned\n // wired object / creature / location that is ALSO `{image:N}`-referenced\n // renders ONCE (inline), never also as a trailing canonical phrase.\n const tokenCoveredUrls = new Set<string>()\n for (const id of collectIdentities(prompt, nonCharacterRefs, identityMeta)) {\n const coveredUrl = nonCharacterRefs[id.imageIndex - 1]?.url\n if (coveredUrl) tokenCoveredUrls.add(coveredUrl)\n }\n // Unmentioned wired-location / -object / -creature canonical convergence\n // (Phase C): each → the trailing role phrase \"the {role} from reference\n // image {LETTER}\" + opt-in lock + wired elementInjection, numbered against\n // `finalIndexByUrl`. Mentioned locations were converged inline in Phase 0\n // and filtered out of `nonCharacterRefs`; mentioned objects/creatures were\n // converged inline too but stay in the list, so they are suppressed by URL\n // via the covered set below.\n const locCanon = renderLocationCanonicalHybrid(nonCharacterRefs, finalIndexByUrl, tokenCoveredUrls)\n // Objects/creatures now have a mention path too, so their covered set is\n // the union of the `{image:N}`-token URLs and the URLs a Phase-0\n // `@creature` / `@object` mention bound. That union is the SUPPRESSION —\n // a mentioned entity already rendered its role phrase inline, and without\n // this it would ALSO emit the trailing \"the creature from reference image\n // D\" line, which is the exact double-render this leg removes. Locations\n // keep `tokenCoveredUrls` alone: their mentioned refs are FILTERED out of\n // `nonCharacterRefs` upstream, so they never reach the loop at all.\n const objCoveredUrls = mentionedEntityUrls.size > 0\n ? new Set([...tokenCoveredUrls, ...mentionedEntityUrls])\n : tokenCoveredUrls\n const objCanon = renderObjectCreatureCanonicalHybrid(nonCharacterRefs, finalIndexByUrl, objCoveredUrls)\n const canonLockLines = [...locCanon.lockLines, ...objCanon.lockLines]\n const canonLockBlock = canonLockLines.length > 0 ? `${canonLockLines.join(\"\\n\")}\\n\\n` : \"\"\n // Per-use descriptions nothing above spoke for: a `{image:N}`-covered ref\n // (expanded inline, suppressed from both canonical renders) and a seated\n // `wired-image` / `manual` ref (which has no canonical render at all)\n // would otherwise drop their `descriptionOverride` silently — the one\n // place the hybrid format renders neither a description slot nor a role\n // phrase. Deduped against every URL a pass above already told.\n const toldOverrideUrls = new Set<string>([\n ...locCanon.renderedUrls,\n ...objCanon.renderedUrls,\n ...mentionedEntityUrls,\n ...mentionedImageUrls,\n ])\n const untoldOverrides = renderUntoldOverridesHybrid(\n nonCharacterRefs,\n finalIndexByUrl,\n toldOverrideUrls,\n )\n const canonTrailingLines = [\n ...locCanon.phrases, ...objCanon.phrases,\n ...locCanon.elementDirectives, ...objCanon.elementDirectives,\n ...untoldOverrides,\n ]\n // Role phrases and element injections are scene content → they extend the\n // BODY, ahead of the `[style]` section (which has no terminator, so a flat\n // append would read as one more look clause).\n const composedScene = `${canonLockBlock}${insertBeforeStyleSection(scene, canonTrailingLines)}`\n prompt = config.referenceLockSnippet\n ? `${config.referenceLockSnippet}\\n${composedScene}`\n : composedScene\n // The hybrid token rewrite can't be modeled by the segment marks → the\n // join-mismatch fallback in buildImagePromptSegments collapses to a single\n // segment (documented degradation, same as the Phase-0 splice branch).\n if (marks) marks.directivesPrefix = \"\"\n } else if (directives) {\n // Capture the prompt state across the splice so the segment builder can\n // isolate what the directive block contributed as a PREFIX. Only the\n // prepend branch yields a clean prefix; the Phase-0 consolidation branch\n // splices mid-string (no prefix) → marks.directivesPrefix stays \"\" and\n // the body collapses via the join fallback (documented degradation).\n const beforeDirectives = prompt\n if (prompt.startsWith(\"Use these characters:\\n\")) {\n // Consolidate into the existing Phase-0 directive block (the same splice\n // pattern Phase 0 uses for fallback / extras) instead of wrapping it in\n // a second \"Use these references…/Compose them naturally\" layer.\n const splitIdx = prompt.indexOf(\"\\n\\n\")\n if (splitIdx !== -1) {\n prompt = prompt.slice(0, splitIdx) + \"\\n\" + directives + prompt.slice(splitIdx)\n } else {\n prompt = `${prompt}\\n${directives}`\n }\n } else {\n // \"Use these references…\" header + bulleted directives + the\n // \"Compose them naturally…\" prefix proved most reliable in user\n // testing. Numeric indices (\"Image 1\") match the user-typed\n // `@character:N` slug format so the literal prompt and the final\n // identity directive are visually linked.\n prompt = prompt\n ? `Use these references for the output image:\\n${directives}\\n\\nCompose them naturally into a single image: ${prompt}`\n : `Use these references for the output image:\\n${directives}`\n // Prepend case: the new string ends with `beforeDirectives` (or is the\n // whole prefix when the body was empty). Everything before that tail is\n // the directive prefix.\n if (marks) {\n marks.directivesPrefix = prompt.slice(0, prompt.length - beforeDirectives.length)\n }\n }\n }\n\n // Described references, HYBRID half: trailing scene directives, so they land\n // behind the reference role phrases the branch above appended (the legacy\n // half ran before it — see the comment at that call). Still ahead of the\n // provider cap below, so the lines are body text like any other.\n if (isHybrid && describedLines.length > 0) {\n prompt = appendReferenceLines(prompt, describedLines, \"hybrid\")\n }\n\n const styleText = style?.trim()\n const styleLine = styleText && !isDeniedStyleId(styleText) ? `Style: ${getStylePromptHint(styleText) || styleText}` : \"\"\n\n const negPrompt = negativePrompt?.trim()\n let nativeNegativePrompt: string | undefined\n let avoidLine = \"\"\n if (negPrompt) {\n if (NATIVE_NEGATIVE_PROMPT_MODELS.has(provider)) {\n // Clamp native negatives to the provider's verified cap (e.g. ideogram /\n // qwen = 500) so an over-long negative can't trigger a provider reject.\n nativeNegativePrompt = negPrompt.slice(0, getMaxNegativePromptChars(provider))\n } else {\n avoidLine = `Avoid: ${negPrompt}`\n }\n }\n\n // Cap the assembled prompt at the PROVIDER's max (default IMAGE_PROMPT_MAX =\n // 5000, what the image routes already accept) — never the old hardcoded\n // 2000, which silently severed the appended cinematography/picker hints +\n // the `Avoid:` negative whenever the body was long. The style/avoid suffixes\n // are RESERVED first so a long body can never drop them (the control text is\n // the most important to keep). Truncate the BODY, THEN append the suffixes.\n // The cut is ORDER-BLIND — record how much it removed so a cap-aware caller\n // (`assembleImageInput`) can shed its own lowest-value text and re-assemble.\n const maxLen = getMaxImagePromptChars(provider)\n // Reserved on the PRE-cut body; the cut can only NARROW the separator (see\n // `controlSuffixes`), so the re-derived suffixes always fit the reservation.\n const preCut = controlSuffixes(prompt, styleLine, avoidLine)\n const reserved = preCut.styleSuffix.length + preCut.avoidSuffix.length\n if (prompt.length + reserved > maxLen) {\n if (marks) marks.overflowChars += prompt.length + reserved - maxLen\n prompt = prompt.slice(0, Math.max(0, maxLen - reserved - 3)) + \"...\"\n }\n const { styleSuffix, avoidSuffix } = controlSuffixes(prompt, styleLine, avoidLine)\n if (marks) {\n marks.styleSuffix = styleSuffix\n marks.avoidSuffix = avoidSuffix\n }\n // Body span = everything after the captured directive prefix, taken from the\n // possibly-truncated body so the segment join still reconstructs (empty in the\n // Phase-0 consolidation branch → collapses via the fallback, the documented\n // degradation).\n if (marks) marks.bodyBeforeSuffixes = prompt.slice(marks.directivesPrefix.length)\n prompt = prompt + styleSuffix + avoidSuffix\n // Safety clamp for a pathological native-less negative that alone overflows.\n if (prompt.length > maxLen) {\n if (marks) marks.overflowChars += prompt.length - maxLen\n prompt = prompt.slice(0, maxLen - 3) + \"...\"\n }\n\n // Resolve `{image:N:label}` → \"Image <finalSlot> (label)\". The token's N\n // indexes `nonCharacterRefs`; we rewrite it to the ref's FINAL slot so the\n // body text agrees with the directive numbering above. (The hybrid format\n // already expanded tokens to lettered role phrases in buildHybridScene.)\n if (!isHybrid) {\n prompt = expandImageRefTokensForRefs(prompt, tokenRefs, finalIndexByUrl)\n }\n\n const supportsRefs = MODELS_WITH_REFERENCE_IMAGE_SUPPORT.has(provider)\n\n // Apply user-defined `referenceOrder` to the final URL list, with a\n // matching renumber of every `Image N` token in the prompt. Skipped when\n // the model doesn't support refs (refs will be dropped anyway) or when no\n // order was supplied (no-op contract).\n let finalUrls = assembledUrls\n let finalPrompt = prompt\n // v1: the hybrid format skips referenceOrder renumbering (its tokens are\n // already expanded to fixed letters). Reorder support is a follow-up.\n if (!isHybrid && supportsRefs && referenceOrder.length > 0 && assembledUrls.length > 1) {\n const reordered = applyReferenceOrder(\n assembledUrls,\n prompt,\n structuredRefs,\n referenceOrder,\n sourceNodeIdById,\n )\n finalUrls = reordered.urls\n finalPrompt = reordered.prompt\n }\n\n const refsToSend = supportsRefs && finalUrls.length > 0 ? finalUrls : undefined\n\n // LAST, after the reorder (as the video core runs `resolveReferenceTokens`\n // last): an `{image:N}` with no image at N becomes its label, or nothing.\n // The binding test is the one both expanders above use, so a token that\n // binds is never touched here and every wired output is unchanged.\n const assembledPrompt = dropUnwiredImageTokens(\n finalPrompt,\n (n) => Boolean(tokenFinalSlot(n, tokenRefs, finalIndexByUrl)),\n )\n\n return { prompt: assembledPrompt, nativeNegativePrompt, referenceImageUrls: refsToSend }\n }\n\n // -------------------------------------------------------------------------\n // Legacy path — kept for callers that haven't migrated to connectedReferences.\n // -------------------------------------------------------------------------\n\n // Build character description lines\n const charDescs = characterDefs\n .filter((c) => c.type === \"description\" && c.description)\n .map((c) => {\n let templateKey: string\n switch (c.category) {\n case \"face\": templateKey = \"face-description\"; break\n case \"location\": templateKey = \"location-description\"; break\n case \"object\": templateKey = \"object-description\"; break\n default: templateKey = \"character-description\"; break\n }\n const template = resolveTemplate(templateKey, userTemplates, flowTemplates)\n return applyTemplate(template, {\n name: c.name,\n description: c.description || \"\",\n })\n })\n\n // Assemble prompt. The wrapper template composes the BODY only — a `[style]`\n // section is lifted off first and re-attached after, so a description can\n // never land under its header (and a user-overridden template, which may put\n // the descriptions anywhere, still only ever rearranges the body).\n let prompt = config.prompt\n if (charDescs.length > 0) {\n const wrapperTemplate = resolveTemplate(\"generate-image-wrapper\", userTemplates, flowTemplates)\n const { body, section } = splitStyleSection(prompt)\n const wrapped = applyTemplate(wrapperTemplate, {\n userPrompt: body,\n assetDescriptions: charDescs.join(\" \"),\n })\n prompt = section.length > 0 ? `${wrapped}${STYLE_SECTION_GAP}${section}` : wrapped\n }\n\n // Append style — if the inline `style` is a known STYLES catalog id, inject\n // the richer promptHint; otherwise fall back to the raw text (covers custom\n // free-text styles that don't match a preset).\n const styleText = style?.trim()\n const styleLine = styleText && !isDeniedStyleId(styleText) ? `Style: ${getStylePromptHint(styleText) || styleText}` : \"\"\n\n // Handle negative prompt: native support vs prompt-appended\n const negPrompt = negativePrompt?.trim()\n let nativeNegativePrompt: string | undefined\n let avoidLine = \"\"\n if (negPrompt) {\n if (NATIVE_NEGATIVE_PROMPT_MODELS.has(provider)) {\n nativeNegativePrompt = negPrompt.slice(0, getMaxNegativePromptChars(provider))\n } else {\n avoidLine = `Avoid: ${negPrompt}`\n }\n }\n\n // Cap at the provider max (default IMAGE_PROMPT_MAX = 5000), reserving the\n // style/avoid suffixes so a long body never severs the appended control text\n // (was a hardcoded 2000 tail-cut that dropped the negative). Truncate the\n // BODY, THEN append the suffixes. Same order-blind cut as the\n // connectedReferences path above → same `overflowChars` bookkeeping.\n const maxLen = getMaxImagePromptChars(provider)\n const preCut = controlSuffixes(prompt, styleLine, avoidLine)\n const reserved = preCut.styleSuffix.length + preCut.avoidSuffix.length\n if (prompt.length + reserved > maxLen) {\n if (marks) marks.overflowChars += prompt.length + reserved - maxLen\n prompt = prompt.slice(0, Math.max(0, maxLen - reserved - 3)) + \"...\"\n }\n const { styleSuffix, avoidSuffix } = controlSuffixes(prompt, styleLine, avoidLine)\n if (marks) {\n marks.styleSuffix = styleSuffix\n marks.avoidSuffix = avoidSuffix\n }\n // Legacy path has no directive prefix; the body is the char-desc-wrapped\n // (possibly-truncated) prompt right before the style/avoid suffixes.\n if (marks) marks.bodyBeforeSuffixes = prompt\n prompt = prompt + styleSuffix + avoidSuffix\n // Safety clamp for a pathological native-less negative that alone overflows.\n if (prompt.length > maxLen) {\n if (marks) marks.overflowChars += prompt.length - maxLen\n prompt = prompt.slice(0, maxLen - 3) + \"...\"\n }\n\n // Merge reference images: direct refs first, then ancestor fallback\n const allRefs = referenceImageUrls.length > 0 ? referenceImageUrls : ancestorRefs\n const supportsRefs = MODELS_WITH_REFERENCE_IMAGE_SUPPORT.has(provider)\n const refsToSend = supportsRefs && allRefs.length > 0 ? allRefs : undefined\n\n // Expand {image:N} position references in prompt (legacy: → \"[reference image N]\")\n prompt = expandImagePositionRefs(prompt, allRefs.length)\n // Then the unwired rule for a token past the last image — same pass, same\n // binding test, as the connected-reference return above.\n prompt = dropUnwiredImageTokens(prompt, (n) => hasImageAt(n, allRefs.length))\n\n return { prompt, nativeNegativePrompt, referenceImageUrls: refsToSend }\n}\n\n/**\n * `buildImagePrompt` plus an origin-tagged decomposition of the assembled\n * `prompt`. The string output (and all other fields) is byte-identical to\n * `buildImagePrompt` — the segments are derived from assembly marks recorded\n * during the same pass.\n *\n * ABSOLUTE INVARIANT (tested): `segments.map(s => s.text).join(\"\") === prompt`.\n * Anything the marks can't model — `{image:N}` token expansion, `referenceOrder`\n * renumbering, mid-string Phase-0 directive splicing, truncation — breaks the\n * join, and we collapse to a single `user` segment rather than ship a wrong\n * decomposition. Callers pass `bodySegments` (origins user/variable/picker/…)\n * for the body text; they survive only when the assembly didn't rewrite the\n * body string.\n */\nexport function buildImagePromptSegments(\n config: BuildImagePromptConfig,\n bodySegments?: readonly PromptSegment[],\n): BuildImagePromptSegmentsResult {\n const marks = newAssemblyMarks()\n\n const result = buildImagePromptInternal(config, marks)\n\n let segments: PromptSegment[] = [\n ...(marks.directivesPrefix ? [{ text: marks.directivesPrefix, origin: \"mention\" as const }] : []),\n ...reconcileBodySegments(marks.bodyBeforeSuffixes, bodySegments),\n ...(marks.styleSuffix ? [{ text: marks.styleSuffix, origin: \"style\" as const }] : []),\n ...(marks.avoidSuffix ? [{ text: marks.avoidSuffix, origin: \"negative\" as const }] : []),\n ]\n // Absolute invariant: join === prompt. Any assembly step we didn't model\n // (truncation, token expansion, reorder renumbering, Phase-0 mid-string\n // splice) breaks the join — detect against the FINAL returned prompt and\n // fall back rather than ship a wrong decomposition.\n if (segments.map((s) => s.text).join(\"\") !== result.prompt) {\n segments = result.prompt ? [{ text: result.prompt, origin: \"user\" }] : []\n }\n return { ...result, segments }\n}\n\n// ---------------------------------------------------------------------------\n// Identity helpers (new system)\n// ---------------------------------------------------------------------------\n\n/** Sources whose default fidelity is \"strict\" — they carry strong identity. */\nconst STRICT_DEFAULT_SOURCES: ReadonlySet<ReferenceSource> = new Set([\n \"wired-character\",\n \"wired-face\",\n \"wired-object\",\n \"wired-creature\",\n \"wired-location\",\n])\n\n// `IMAGE_TOKEN_PATTERN` (`{image:N}` / `{image:N:label}`) lives in\n// image-token-pattern.ts, shared with the preset metadata that reads which\n// references a template names.\n\n/**\n * The final 1-based slot an `{image:N}` token binds to on the connected-reference\n * path — the slot of `refs[N - 1]`'s URL — or `undefined` when no image sits at\n * N (no such reference, or one without a URL). The ONE binding test shared by\n * both token expanders and the unwired-token pass, so \"this token is wired\"\n * means the same thing to all three.\n */\nfunction tokenFinalSlot(\n n: number,\n refs: readonly ConnectedReference[],\n finalIndexByUrl: ReadonlyMap<string, number>,\n): number | undefined {\n const ref = refs[n - 1]\n return ref?.url ? finalIndexByUrl.get(ref.url) : undefined\n}\n\n/** Whether position N has an image among `count` flat references (the\n * no-`connectedReferences` path). Shared by its expander and the unwired pass. */\nfunction hasImageAt(n: number, count: number): boolean {\n return n >= 1 && n <= count\n}\n\n/**\n * The last step of image prompt assembly. Every `{image:N}` token still in the\n * prompt whose N has no image follows the unwired rule SHARED with the video\n * resolver (`resolveReferenceTokens`): a labelled token becomes its label, an\n * unlabelled one is dropped, and the horizontal gap left behind is collapsed\n * and the prompt trimmed.\n *\n * WIRED OUTPUT IS UNCHANGED BY CONSTRUCTION, on two counts:\n * - a token whose N binds (`isWired`) is returned verbatim — the expanders\n * already rendered every such token they own;\n * - the tidy runs only when at least one token was dropped, so a prompt whose\n * tokens all bind keeps every doubled space and indent its author typed.\n * (The video resolver tidies unconditionally; the image path never did, and\n * a wired image prompt stays byte-identical.)\n *\n * TWO PLACES KEEP A TOKEN AS TYPED, on purpose:\n * - a WIRED token the hybrid format never expands — its expansion covers the\n * scene only, so one typed into the negative prompt keeps its text in the\n * `Avoid:` line (rewriting it would move a wired output);\n * - the native negative prompt (`nativeNegativePrompt`, the models in\n * `NATIVE_NEGATIVE_PROMPT_MODELS` such as ideogram-v3) is never read by this\n * pass — it goes to the provider's own negative field as typed, wired or not.\n */\nfunction dropUnwiredImageTokens(prompt: string, isWired: (n: number) => boolean): string {\n let dropped = false\n const out = prompt.replace(IMAGE_TOKEN_PATTERN, (match: string, num: string, label?: string) => {\n if (isWired(parseInt(num, 10))) return match\n dropped = true\n return unboundReferenceTokenText(label)\n })\n return dropped ? tidyReferenceTokenGaps(out) : prompt\n}\n\ninterface ResolvedIdentity {\n imageIndex: number\n label: string // empty string = bare positional ref (no role)\n fidelity: IdentityFidelity\n customText?: string\n description?: string // from upstream connected reference\n /** `source` from the upstream ConnectedReference — used to opt the directive\n * builder into source-aware behavior (e.g. appending location canonical\n * description to wired-location bullets). Mirrors the character pattern\n * where `characterCanonicalDescription` is used by the Phase 0 mention\n * resolver, but for locations the consumer is the directive builder. */\n source?: ReferenceSource\n /** Location's canonical description, propagated from the wired-location\n * ConnectedReference. The directive builder appends this to the bullet\n * when source === \"wired-location\" AND the location's slug is NOT in\n * `suppressedCanonicalLocationIds`. */\n locationCanonicalDescription?: string | null\n /** Slug for the location source, used by `suppressedCanonicalLocationIds`\n * filtering. */\n locationSlug?: string\n /** Mirrors ConnectedReference.locationReferencePhotoKind — propagated so\n * `buildIdentityDirective` can annotate the subject line. */\n locationReferencePhotoKind?: string\n}\n\nfunction defaultFidelityForSource(source: ReferenceSource | undefined): IdentityFidelity {\n if (!source) return \"balanced\"\n return STRICT_DEFAULT_SOURCES.has(source) ? \"strict\" : \"balanced\"\n}\n\n/**\n * Return the unique set of identities to emit directives for: only the\n * `{image:N:label}` mentions actually present in the prompt.\n *\n * Connected references that the user hasn't mentioned still get sent to the\n * provider (via `referenceImageUrls`), but they get no auto-generated\n * directive — the user controls what's in the prompt by mentioning.\n */\nfunction collectIdentities(\n prompt: string,\n refs: readonly ConnectedReference[],\n meta: readonly IdentityMeta[],\n): ResolvedIdentity[] {\n const seen = new Set<string>()\n const mentions: Array<{ imageIndex: number; label: string }> = []\n for (const m of prompt.matchAll(IMAGE_TOKEN_PATTERN)) {\n const n = parseInt(m[1], 10)\n if (n < 1 || n > refs.length) continue\n const label = (m[2] ?? \"\").trim()\n if (!label) continue // bare {image:N} → no identity directive, just position\n const key = `${n}:${label}`\n if (seen.has(key)) continue\n seen.add(key)\n mentions.push({ imageIndex: n, label })\n }\n\n return mentions.map(({ imageIndex, label }) => {\n const ref = refs[imageIndex - 1]\n const m = meta.find((x) => x.imageIndex === imageIndex && x.label === label)\n return {\n imageIndex,\n label,\n fidelity: m?.fidelity ?? defaultFidelityForSource(ref?.source),\n customText: m?.customText?.trim() || undefined,\n // Per-use override ahead of the ref's own description; the directive\n // builder's location-canonical fallback only fires when BOTH are absent,\n // so an override outranks the stored location wording too.\n description: ref?.descriptionOverride?.trim() || ref?.description,\n source: ref?.source,\n locationCanonicalDescription: ref?.locationCanonicalDescription,\n locationSlug: ref?.locationSlug,\n locationReferencePhotoKind: ref?.locationReferencePhotoKind,\n }\n })\n}\n\n/** Labels that mean \"use as scene/setting\" — verb shifts away from \"match\". */\nconst BACKGROUND_LABELS: ReadonlySet<string> = new Set([\n \"background\", \"setting\", \"scene\", \"environment\", \"location\",\n])\n/** Labels that mean \"apply this look/material\" rather than \"include this thing\". */\nconst TEXTURE_LABELS: ReadonlySet<string> = new Set([\n \"texture\", \"style\", \"pattern\", \"look\", \"material\",\n])\n\n/**\n * Subject form for directive bullets: parenthetical label after the image\n * index so the model sees both the position binding and the role descriptor\n * in one tight phrase. Numeric indices (\"Image 1\") match the typed token\n * (e.g. `@kira:1:smile`) so users can trace the slug through to the final\n * assembled directive.\n *\n * \"dragon\" + 1 → \"Image 1 (dragon)\"\n * \"Danny\" + 2 → \"Image 2 (Danny)\"\n * \"dragon\" + 1 + desc \"red scales\" → \"Image 1 (dragon — red scales)\"\n * no label + 3 → \"Image 3\"\n */\nfunction formatDirectiveSubject(label: string, imageIndex: number, description?: string): string {\n if (!label && !description) return `Image ${imageIndex}`\n const inner = label && description\n ? `${label} — ${description}`\n : (label || description)!\n return `Image ${imageIndex} (${inner})`\n}\n\n/** Labels that mean \"a person / character\" — strengthen the directive so the\n * model holds the face + body + distinctive features. Folds the\n * identity-preservation language (previously appended as a trailing\n * global clause via `collectIdentityLockClause`) directly into the per-image\n * bullet so the model sees the identifier and the rule together. */\nconst PERSON_LABELS: ReadonlySet<string> = new Set([\n \"person\", \"character\", \"face\", \"subject\", \"people\",\n])\n\n/** Labels that mean \"a creature / animal subject\" — the animal analog of\n * PERSON_LABELS. A bound creature is a LIVING subject with its own identity\n * (a specific cat, dragon, beast), so the directive locks anatomy, markings,\n * coloration, and distinctive features instead of the person face/body\n * phrasing — and instead of the generic prop \"match exactly\" verb a\n * `wired-object` gets. */\nconst CREATURE_LABELS: ReadonlySet<string> = new Set([\n \"creature\", \"animal\", \"pet\", \"beast\", \"monster\",\n])\n\nfunction buildIdentityDirective(\n id: ResolvedIdentity,\n suppressedCanonicalLocationIds?: readonly string[],\n): string {\n if (id.fidelity === \"custom\" && id.customText) {\n return `- ${id.customText}`\n }\n\n // Location canonical-description injection (Phase 2 #1). Mirrors the\n // character canonical-description pattern (see `characterCanonicalDescription`\n // in the Phase 0 mention resolver above). When a wired-location ref has\n // canonical text AND the user hasn't suppressed it via the × button on the\n // Injected References list, the canonical description gets folded into the\n // directive subject so the model sees \"Image N (location — <canonical\n // description>)\" without the user typing it. Per-ref description (from the\n // user-typed Description field on the location node) still wins when present.\n let effectiveDescription = id.description\n if (\n !effectiveDescription\n && id.source === \"wired-location\"\n && id.locationCanonicalDescription\n && !(id.locationSlug && suppressedCanonicalLocationIds?.includes(id.locationSlug))\n ) {\n effectiveDescription = id.locationCanonicalDescription.trim() || undefined\n }\n\n // Phase 2 #3: kind-tagged reference-photo annotation. When the ref carries\n // a `locationReferencePhotoKind`, fold its human-friendly label into the\n // subject's parenthetical so the model sees the photo's role inline with\n // the location name (e.g. \"Image 1 (Old Library — wide-angle reference)\").\n // The annotation rides on the LABEL (not the description) so it survives\n // the description-overrides-canonical precedence above.\n let effectiveLabel = id.label\n if (id.locationReferencePhotoKind && effectiveLabel) {\n effectiveLabel = `${effectiveLabel} — ${locationReferencePhotoKindLabel(id.locationReferencePhotoKind as LocationReferencePhotoKind)}`\n }\n\n const subject = formatDirectiveSubject(effectiveLabel, id.imageIndex, effectiveDescription)\n const lower = id.label.toLowerCase()\n\n // Role-aware verbs — these read more naturally than \"match exactly\" for\n // background scenes or texture/style references.\n if (BACKGROUND_LABELS.has(lower)) {\n return `- ${subject} — use as the background/setting.`\n }\n if (TEXTURE_LABELS.has(lower)) {\n return `- ${subject} — apply this ${id.label}.`\n }\n\n // Person/character labels: strengthen the directive (regardless of fidelity)\n // so the global trailing identity-lock clause becomes redundant.\n // \"loose\" still gets the inspiration form so users can opt out.\n if (PERSON_LABELS.has(lower) && id.fidelity !== \"loose\") {\n return `- ${subject} — match exactly. Maintain perfect likeness (face, body proportions, distinctive features).`\n }\n\n // Creature/animal labels: the same identity-lock strength as a person, with\n // animal-subject phrasing — anatomy/markings/coloration are what make THIS\n // cat this cat. \"loose\" still opts out to the inspiration form below.\n if (CREATURE_LABELS.has(lower) && id.fidelity !== \"loose\") {\n return `- ${subject} — this is a creature/animal subject: match it exactly. Maintain perfect likeness (anatomy, markings, coloration, distinctive features).`\n }\n\n switch (id.fidelity) {\n case \"strict\":\n return `- ${subject} — match exactly. Maintain perfect likeness.`\n case \"loose\":\n return `- ${subject} — use loosely as inspiration.`\n case \"custom\": // custom without text falls through to balanced\n case \"balanced\":\n default:\n return `- ${subject} — match exactly.`\n }\n}\n\n/**\n * Build the non-character directive block for `buildImagePrompt`'s\n * connectedReferences path:\n * 1. `{image:N:label}` identity directives (legacy positional mentions), in\n * prompt-mention order, renumbered from their `nonCharacterRefs` index to\n * the ref's FINAL slot.\n * 2. Canonical-style fallback directives for `wired-location` / `wired-object`\n * / `wired-creature` refs that are present but neither `{image:N}`-referenced\n * nor @-mentioned (@-mentioned locations were already filtered out of\n * connectedReferences in Phase 0). Mirrors the character canonical fallback\n * so a wired setting / object / creature gets a directive with zero typing\n * required. Scoped to those three sources — opaque `manual` / `wired-image`\n * uploads carry no metadata to describe and keep their (intentional)\n * directive-free behavior.\n *\n * Every directive's `Image N` is numbered against `finalIndexByUrl` (the single\n * source of truth for the assembled URL order), so the index always matches the\n * URL slot. `coveredUrls` prevents a URL emitted via a token from being\n * re-emitted by the fallback AND dedupes a location/object wired twice.\n */\nfunction buildNonCharacterDirectives(\n prompt: string,\n nonCharacterRefs: readonly ConnectedReference[],\n identityMeta: readonly IdentityMeta[],\n finalIndexByUrl: ReadonlyMap<string, number>,\n suppressedCanonicalLocationIds: readonly string[],\n): string {\n const lines: string[] = []\n const coveredUrls = new Set<string>()\n\n for (const id of collectIdentities(prompt, nonCharacterRefs, identityMeta)) {\n const ref = nonCharacterRefs[id.imageIndex - 1]\n const finalIdx = ref?.url ? finalIndexByUrl.get(ref.url) : undefined\n const line = buildIdentityDirective(\n finalIdx ? { ...id, imageIndex: finalIdx } : id,\n suppressedCanonicalLocationIds,\n )\n if (line.length > 0) lines.push(line)\n if (ref?.url) coveredUrls.add(ref.url)\n }\n\n for (const ref of nonCharacterRefs) {\n if (ref.source !== \"wired-location\" && ref.source !== \"wired-object\" && ref.source !== \"wired-creature\") continue\n if (!ref.url || coveredUrls.has(ref.url)) continue\n const finalIdx = finalIndexByUrl.get(ref.url)\n if (!finalIdx) continue\n coveredUrls.add(ref.url)\n const line = buildIdentityDirective(\n {\n imageIndex: finalIdx,\n // A background label routes wired-location through the\n // \"use as the background/setting\" verb (and folds\n // locationCanonicalDescription); wired-creature routes through the\n // creature/animal-subject identity lock (CREATURE_LABELS);\n // wired-object falls through to the strict \"match exactly\" verb.\n label: ref.source === \"wired-location\"\n ? \"location\"\n : ref.source === \"wired-creature\"\n ? \"creature\"\n : \"object\",\n fidelity: defaultFidelityForSource(ref.source),\n description: ref.descriptionOverride?.trim() || ref.description?.trim() || undefined,\n source: ref.source,\n locationCanonicalDescription: ref.locationCanonicalDescription,\n locationSlug: ref.locationSlug,\n locationReferencePhotoKind: ref.locationReferencePhotoKind,\n },\n suppressedCanonicalLocationIds,\n )\n if (line.length > 0) lines.push(line)\n }\n\n return lines.join(\"\\n\")\n}\n\n/**\n * Replace `{image:N:label}` and `{image:N}` tokens with natural-language\n * phrases bound to a numbered image (Image 1 / 2 / 3 …).\n *\n * - `{image:N:label}` → `Image {N} ({label})`\n * - `{image:N}` → `Image {N}` (no role specified)\n *\n * Same parenthetical form as the directive subject so the model sees a\n * consistent identifier in both the bulleted list and the scene description.\n * Numeric indices match the user-typed slug format (`@kira:1:smile`).\n *\n * Out-of-range indices are left untouched by this helper. `buildImagePrompt`\n * then renders any such token by the unwired rule (`dropUnwiredImageTokens`):\n * its label, or nothing — never the raw token.\n */\nexport function expandImageRefTokens(prompt: string, imageCount: number): string {\n return prompt.replace(IMAGE_TOKEN_PATTERN, (match, num, label) => {\n const n = parseInt(num, 10)\n if (n < 1 || n > imageCount) return match\n return label ? `Image ${n} (${label})` : `Image ${n}`\n })\n}\n\n/**\n * Like `expandImageRefTokens`, but remaps each `{image:N}` token from its index\n * in `refs` (the non-character ref list the token was authored against) to the\n * ref's FINAL 1-based slot in the assembled URL list. Used by\n * `buildImagePrompt`'s connectedReferences path so body-text `Image N` markers\n * agree with the directive numbering after non-character URLs are appended.\n *\n * When the final slot equals the token index (no Phase-0 prefix shifting the\n * positions), the output is byte-identical to `expandImageRefTokens`.\n * Out-of-range tokens (or refs without a URL) are left untouched here; the\n * assembly's last step, `dropUnwiredImageTokens`, renders them by the unwired\n * rule with the same `tokenFinalSlot` binding test.\n */\nfunction expandImageRefTokensForRefs(\n prompt: string,\n refs: readonly ConnectedReference[],\n finalIndexByUrl: ReadonlyMap<string, number>,\n): string {\n return prompt.replace(IMAGE_TOKEN_PATTERN, (match, num, label) => {\n const finalIdx = tokenFinalSlot(parseInt(num, 10), refs, finalIndexByUrl)\n if (!finalIdx) return match\n return label ? `Image ${finalIdx} (${label})` : `Image ${finalIdx}`\n })\n}\n\n// ---------------------------------------------------------------------------\n// Hybrid reference format (images-only, flag-gated via\n// `BuildImagePromptConfig.referenceFormat === \"hybrid\"`). TOKEN EXPANSION ONLY:\n// every {image:N:label} token → \"the <label> from reference image <LETTER>\"\n// (letters map the FINAL 1-based slot, 1→A). NO reference-lock snippet is\n// auto-injected — authors prepend their own lock in the prompt text (it passes\n// through untouched); a caller may optionally prepend one via\n// `config.referenceLockSnippet`. Scope is the `{image:N:label}` non-character\n// path — characters/objects/locations still use the legacy wrap.\n// ---------------------------------------------------------------------------\n\n/** Map a 1-based reference slot to a letter (1→A, 2→B …). Slots beyond 26 fall\n * back to the numeric slot so we never emit a non-letter control character. */\nfunction slotToLetter(slot: number): string {\n return slot >= 1 && slot <= 26 ? String.fromCharCode(64 + slot) : String(slot)\n}\n\n/** Hybrid inline phrase for a `{image:N:label}` token bound to a lettered slot.\n * Uniform: \"the <label> from reference image <letter>\" — the label is used\n * verbatim (the global identity directive handles subject preservation, so no\n * per-role branching is needed). A label-less token → \"reference image <letter>\". */\nfunction hybridRolePhrase(label: string, letter: string): string {\n if (!label) return `reference image ${letter}`\n return `the ${label} from reference image ${letter}`\n}\n\n/**\n * Like `expandImageRefTokensForRefs`, but emits the hybrid lettered phrase\n * (\"the subject from reference image A\") instead of the legacy \"Image N\n * (label)\". Out-of-range tokens / URL-less refs are left untouched here and\n * rendered by the unwired rule at the end of assembly (`dropUnwiredImageTokens`).\n *\n * A `{image:N:label}` pill is a mention chip like any other: `buildRefPillNodes`\n * appends its own trailing space to EVERY pill it builds, the positional\n * `imageRef` node included, so `a man wearing {image:1:hat} in the park` is the\n * ordinary shape and it expanded to \"…the hat from reference image A in the\n * park\". Splice through `spliceMentionPhrase` for the same seam tidy the three\n * `@`-mention resolvers use, right-to-left over offsets taken against the\n * pre-splice string (its OFFSET SAFETY note covers exactly this loop). The\n * legacy `expandImageRefTokensForRefs` keeps its raw `.replace` — legacy output\n * is pinned byte-identical.\n */\nfunction expandImageRefTokensHybrid(\n prompt: string,\n refs: readonly ConnectedReference[],\n finalIndexByUrl: ReadonlyMap<string, number>,\n): string {\n const splices: Array<{ offset: number; length: number; phrase: string }> = []\n for (const m of prompt.matchAll(IMAGE_TOKEN_PATTERN)) {\n const finalIdx = tokenFinalSlot(parseInt(m[1], 10), refs, finalIndexByUrl)\n if (!finalIdx) continue\n splices.push({\n offset: m.index ?? 0,\n length: m[0].length,\n phrase: hybridRolePhrase((m[2] ?? \"\").trim(), slotToLetter(finalIdx)),\n })\n }\n\n // `matchAll` yields ascending offsets; splice back-to-front so the\n // not-yet-applied (smaller) offsets stay valid.\n let resolved = prompt\n for (let i = splices.length - 1; i >= 0; i--) {\n const s = splices[i]\n resolved = spliceMentionPhrase(resolved, s.offset, s.length, s.phrase)\n }\n return resolved\n}\n\n/** Capitalize the first alphabetic character of a string (line-initial). */\nfunction capitalizeLineInitial(line: string): string {\n return line.replace(/[a-zA-Z]/, (c) => c.toUpperCase())\n}\n\n/** Render the user prompt as the hybrid scene: each `{image:N:label}` token\n * expanded to its uniform lettered phrase, each line's first letter\n * capitalized. No per-role special-casing — the label drives the phrase.\n *\n * The capitalizer STOPS at the `[style]` section and everything after it: the\n * header would become `[Style]:`, and every catalog clause under it would gain\n * a capital it was not written with. The header line is matched EXACTLY — the\n * composer never indents it, and the whitespace collapses on this path are\n * horizontal-only (`[^\\S\\r\\n]`), so nothing can pad it before this runs. */\nfunction buildHybridScene(\n prompt: string,\n refs: readonly ConnectedReference[],\n finalIndexByUrl: ReadonlyMap<string, number>,\n): string {\n const lines = prompt.split(\"\\n\")\n const sectionAt = lines.indexOf(STYLE_SECTION_HEADER)\n return lines\n .map((line, i) => {\n const expanded = expandImageRefTokensHybrid(line, refs, finalIndexByUrl)\n return sectionAt >= 0 && i >= sectionAt ? expanded : capitalizeLineInitial(expanded)\n })\n .join(\"\\n\")\n}\n\n/** Build the combined per-identity directive intro for previews.\n * Each directive is emitted on its own line so the model (and the human\n * reading the FinalPromptPreview) can see the structure clearly. */\nexport function buildIdentityDirectives(\n prompt: string,\n refs: readonly ConnectedReference[],\n meta: readonly IdentityMeta[] = [],\n suppressedCanonicalLocationIds?: readonly string[],\n): string {\n return collectIdentities(prompt, refs, meta)\n .map((id) => buildIdentityDirective(id, suppressedCanonicalLocationIds))\n .filter((s) => s.length > 0)\n .join(\"\\n\")\n}\n\n// ---------------------------------------------------------------------------\n// Backward-compat shims — preview/test helpers used elsewhere still reference\n// the old names. Keep thin wrappers so we don't break callers in this round.\n// ---------------------------------------------------------------------------\n\n/** @deprecated Use `expandImageRefTokens` (label-aware). */\nexport function expandImagePositionRefs(\n prompt: string,\n imageCount: number,\n names?: readonly string[],\n): string {\n return prompt.replace(IMAGE_TOKEN_PATTERN, (match, num, label) => {\n const n = parseInt(num, 10)\n if (!hasImageAt(n, imageCount)) return match\n if (label) return `Image ${n} (${label})`\n if (names && names[n - 1]) return names[n - 1]\n return `Image ${n}`\n })\n}\n\n/** @deprecated Use `buildIdentityDirectives(prompt, refs, meta)`. */\nexport function buildReferenceBlocks(\n refs: readonly ConnectedReference[],\n _meta: readonly IdentityMeta[] = [],\n): string {\n // Legacy callers don't have prompt context — emit a default-label block per ref.\n const synthPrompt = \"\"\n return buildIdentityDirectives(synthPrompt, refs, _meta)\n}\n\n// ---------------------------------------------------------------------------\n// Scene prompt builder — shared between frontend DAG executor and backend\n// orchestrator. Builds a rich image-generation prompt from SceneNodeData.\n// ---------------------------------------------------------------------------\n\nexport const SCENE_PROMPT_MAX_LENGTH = 2000\nconst SCENE_PROMPT_SAFE_LENGTH = 1800\n\nexport const SHOT_LABELS: Record<string, string> = {\n \"extreme-wide\": \"EXTREME WIDE SHOT\",\n \"wide\": \"WIDE SHOT\",\n \"medium-wide\": \"MEDIUM WIDE SHOT\",\n \"medium\": \"MEDIUM SHOT\",\n \"medium-close\": \"MEDIUM CLOSE-UP\",\n \"close-up\": \"CLOSE-UP\",\n \"extreme-close-up\": \"EXTREME CLOSE-UP\",\n}\n\nexport const ANGLE_LABELS: Record<string, string> = {\n \"eye-level\": \"eye level\",\n \"low-angle\": \"low angle\",\n \"high-angle\": \"high angle\",\n \"birds-eye\": \"bird's eye view\",\n \"worms-eye\": \"worm's eye view\",\n \"dutch\": \"dutch angle\",\n}\n\nexport const ASPECT_RATIO_LABELS: Record<string, string> = {\n \"16:9\": \"wide landscape composition\",\n \"9:16\": \"vertical portrait composition\",\n \"1:1\": \"square composition\",\n \"4:3\": \"classic frame composition\",\n \"21:9\": \"ultrawide cinematic composition\",\n \"4:5\": \"tall portrait composition\",\n}\n\nexport const MOVEMENT_LABELS: Record<string, string> = {\n static: \"static camera\",\n pan: \"camera panning\",\n tilt: \"camera tilting\",\n dolly: \"dolly shot\",\n tracking: \"tracking shot\",\n crane: \"crane shot\",\n handheld: \"handheld camera\",\n zoom: \"zoom\",\n}\n\nexport function truncateText(text: string, maxLen: number): string {\n if (text.length <= maxLen) return text\n return text.slice(0, maxLen - 3) + \"...\"\n}\n\n/**\n * Build a rich image-generation prompt from scene node data + character\n * definitions. Used by both the frontend DAG executor and the backend\n * orchestrator so that scene prompts are identical regardless of\n * execution path.\n */\nexport function buildScenePrompt(\n data: SceneData,\n assets: readonly CharacterDef[],\n options?: { forDisplay?: boolean },\n): string {\n const noTruncate = options?.forDisplay === true\n const t = noTruncate ? (text: string, _max: number) => text : truncateText\n const highParts: string[] = []\n const medParts: string[] = []\n const lowParts: string[] = []\n\n // Shot type and angle (high)\n const shot = SHOT_LABELS[data.shotType] ?? \"MEDIUM SHOT\"\n const angle = ANGLE_LABELS[data.cameraAngle] ?? \"eye level\"\n highParts.push(`${shot}, ${angle}`)\n\n // Aspect ratio composition hint (medium)\n if (data.aspectRatio && data.aspectRatio !== \"16:9\") {\n const ratioLabel = ASPECT_RATIO_LABELS[data.aspectRatio]\n if (ratioLabel) medParts.push(ratioLabel)\n }\n\n // Characters with mood and action (high, but truncate descriptions)\n if (data.characters.length > 0) {\n const maxDescLen = data.characters.length > 2 ? 80 : 150\n const charDescs = data.characters.map((entry) => {\n const asset = assets.find((a) => a.id === entry.assetId)\n const name = asset?.name ?? \"a figure\"\n const desc = asset?.description ? `, ${t(asset.description, maxDescLen)}` : \"\"\n const mood = entry.mood ? `, ${entry.mood}` : \"\"\n const action = entry.action ? ` ${entry.action}` : \"\"\n const pos = entry.positionInFrame ? ` (${entry.positionInFrame})` : \"\"\n return `${name}${desc}${mood}${action}${pos}`\n })\n highParts.push(`of ${charDescs.join(\" and \")}`)\n }\n\n // Locations (high, but truncate names)\n if (data.locations && data.locations.length > 0) {\n const locDescs = data.locations.map((loc) => {\n const asset = assets.find((a) => a.id === loc.assetId)\n const rawName = loc.name ?? asset?.description ?? asset?.name ?? \"location\"\n const name = t(rawName, 120)\n const envParts: string[] = []\n const tod = loc.timeOfDay ?? data.timeOfDay\n const wth = loc.weather ?? data.weather\n const lit = loc.lighting ?? data.lighting\n if (tod !== \"noon\") envParts.push(`${tod} light`)\n if (wth !== \"clear\") envParts.push(wth)\n if (lit !== \"natural\") envParts.push(`${lit} lighting`)\n return envParts.length > 0 ? `${name} (${envParts.join(\", \")})` : name\n })\n highParts.push(`in ${locDescs.join(\" and \")}`)\n } else {\n const envParts: string[] = []\n if (data.timeOfDay !== \"noon\") envParts.push(`${data.timeOfDay} light`)\n if (data.weather !== \"clear\") envParts.push(data.weather)\n if (data.lighting !== \"natural\") envParts.push(`${data.lighting} lighting`)\n if (envParts.length > 0) highParts.push(envParts.join(\", \"))\n }\n\n // Objects (medium)\n if (data.objects.length > 0) {\n const objDescs = data.objects.map((o) => {\n const asset = assets.find((a) => a.id === o.assetId)\n return o.description ?? asset?.name ?? \"object\"\n })\n medParts.push(`with ${objDescs.join(\", \")}`)\n }\n\n // Mood (medium)\n if (data.mood.length > 0) {\n medParts.push(`${data.mood.join(\", \")} atmosphere`)\n }\n\n // Visual style (medium)\n if (data.visualStyle) {\n medParts.push(`${data.visualStyle} style`)\n }\n\n // Depth of field (low)\n if (data.depthOfField !== \"medium\") {\n lowParts.push(`${data.depthOfField} depth of field`)\n }\n\n // Lens (low)\n if (data.lensType !== \"normal\") {\n lowParts.push(`${data.lensType} lens`)\n }\n\n // Camera movement (medium)\n if (data.cameraMovement !== \"static\") {\n medParts.push(MOVEMENT_LABELS[data.cameraMovement] ?? data.cameraMovement)\n }\n\n // Color palette (low)\n if (data.colorPalette.length > 0) {\n lowParts.push(`${data.colorPalette.join(\", \")} color palette`)\n }\n\n // Summary as additional context (medium, truncated)\n if (data.summary.trim()) {\n medParts.push(t(data.summary.trim(), 300))\n }\n\n // Dialogue context (low, truncated)\n if (data.dialogue && data.dialogue.length > 0) {\n const dialogueDesc = data.dialogue\n .filter((d) => d.text.trim())\n .map((d) => `${d.characterName}${d.emotion ? ` (${d.emotion})` : \"\"}: \"${t(d.text.trim(), 80)}\"`)\n .join(\"; \")\n if (dialogueDesc) lowParts.push(`dialogue: ${t(dialogueDesc, 250)}`)\n }\n\n // Director notes (low, truncated)\n if (data.directorNotes?.trim()) {\n lowParts.push(t(data.directorNotes.trim(), 200))\n }\n\n // Assemble with progressive dropping\n let result = [...highParts, ...medParts, ...lowParts].join(\", \")\n\n if (!noTruncate) {\n if (result.length > SCENE_PROMPT_SAFE_LENGTH) {\n let dropCount = 0\n while (dropCount < lowParts.length && result.length > SCENE_PROMPT_SAFE_LENGTH) {\n dropCount++\n result = [...highParts, ...medParts, ...lowParts.slice(0, lowParts.length - dropCount)].join(\", \")\n }\n }\n if (result.length > SCENE_PROMPT_SAFE_LENGTH) {\n const medRemaining = [...medParts]\n while (medRemaining.length > 0 && result.length > SCENE_PROMPT_SAFE_LENGTH) {\n medRemaining.pop()\n result = [...highParts, ...medRemaining].join(\", \")\n }\n }\n if (result.length > SCENE_PROMPT_MAX_LENGTH) {\n result = result.slice(0, SCENE_PROMPT_MAX_LENGTH - 3) + \"...\"\n }\n }\n\n return result\n}\n\n","/**\n * Path-1 structured prompt fields → composed prompt fragment.\n *\n * Used by:\n * - Nodaro's MCP server (Phase 6 v1.1) — generate_image / generate_video verbs\n * accept these structured fields and run them through this helper before\n * passing the composite prompt to the underlying route.\n * - (Optional) Frontend editor — same logic so the editor and MCP produce\n * identical prompts for the same inputs.\n *\n * NOTE: this is a parallel utility to `prompt-builder.ts`. The latter does\n * image-specific composition (character/template/reference handling), while\n * this module handles the Path-1 structured-field shape that MCP verbs accept\n * (free-form strings under person/styling/setting/camera/lens/mood). Existing\n * frontend `buildPersonHints` / `buildStylingHints` helpers operate on catalog\n * IDs and are not interchangeable with this renderer.\n */\n\nexport interface StructuredPromptFields {\n person?: {\n age?: number\n gender?: \"man\" | \"woman\" | \"child\" | \"non-binary\"\n hair?: string\n eyes?: string\n expression?: string\n profession?: string\n warriorType?: string\n }\n styling?: {\n mood?: string\n lighting?: string\n aesthetic?: string\n colorLook?: string\n }\n setting?: {\n era?: string\n atmosphere?: string\n backdrop?: string\n }\n camera?: {\n framing?: string\n motion?: string\n format?: string\n }\n lens?: {\n focalLength?: string\n aperture?: string\n }\n /** Standalone shorthand mood (overrides styling.mood if both are set). */\n mood?: string\n}\n\n/**\n * Render structured fields → composite prompt fragment to be appended to the\n * user's free-text prompt. Returns \"\" if no fields populated.\n */\nexport function renderStructuredFields(fields: StructuredPromptFields): string {\n const parts: string[] = []\n if (fields.person) parts.push(renderPerson(fields.person))\n if (fields.styling) {\n // The standalone `mood` shorthand overrides styling.mood (per the type\n // doc) — drop styling.mood when the shorthand is set so the two don't both\n // render conflicting \"mood …\" / \"Mood: …\" directives.\n const styling = fields.mood ? { ...fields.styling, mood: undefined } : fields.styling\n parts.push(renderStyling(styling))\n }\n if (fields.setting) parts.push(renderSetting(fields.setting))\n if (fields.camera) parts.push(renderCamera(fields.camera))\n if (fields.lens) parts.push(renderLens(fields.lens))\n if (fields.mood) parts.push(`Mood: ${fields.mood}.`)\n return parts.filter((s) => s.length > 0).join(\" \")\n}\n\nfunction renderPerson(p: NonNullable<StructuredPromptFields[\"person\"]>): string {\n const bits: string[] = []\n if (p.age) bits.push(`${p.age} years old`)\n if (p.gender) bits.push(p.gender)\n if (p.profession) bits.push(p.profession)\n if (p.warriorType) bits.push(`(${p.warriorType})`)\n if (p.hair) bits.push(`with ${p.hair} hair`)\n if (p.eyes) bits.push(`${p.eyes} eyes`)\n if (p.expression) bits.push(`${p.expression} expression`)\n return bits.length > 0 ? `Subject: ${bits.join(\", \")}.` : \"\"\n}\n\nfunction renderStyling(s: NonNullable<StructuredPromptFields[\"styling\"]>): string {\n const bits: string[] = []\n if (s.mood) bits.push(`mood ${s.mood}`)\n if (s.lighting) bits.push(`${s.lighting} lighting`)\n if (s.aesthetic) bits.push(`${s.aesthetic} aesthetic`)\n if (s.colorLook) bits.push(`${s.colorLook} color`)\n return bits.length > 0 ? `Style: ${bits.join(\", \")}.` : \"\"\n}\n\nfunction renderSetting(s: NonNullable<StructuredPromptFields[\"setting\"]>): string {\n const bits: string[] = []\n if (s.era) bits.push(`${s.era} era`)\n if (s.atmosphere) bits.push(`${s.atmosphere} atmosphere`)\n if (s.backdrop) bits.push(`set in ${s.backdrop}`)\n return bits.length > 0 ? `Setting: ${bits.join(\", \")}.` : \"\"\n}\n\nfunction renderCamera(c: NonNullable<StructuredPromptFields[\"camera\"]>): string {\n const bits: string[] = []\n if (c.framing) bits.push(`${c.framing} framing`)\n if (c.motion) bits.push(c.motion)\n if (c.format) bits.push(`${c.format} format`)\n return bits.length > 0 ? `Camera: ${bits.join(\", \")}.` : \"\"\n}\n\nfunction renderLens(l: NonNullable<StructuredPromptFields[\"lens\"]>): string {\n const bits: string[] = []\n if (l.focalLength) bits.push(l.focalLength)\n if (l.aperture) bits.push(`f/${l.aperture}`)\n return bits.length > 0 ? `Lens: ${bits.join(\", \")}.` : \"\"\n}\n","/**\n * THE SUBJECT REGISTRY — the ordered table of every SUBJECT dimension the flat\n * `subject` channel carries (who is in the shot: Person, Styling, and the three\n * prop catalogs), plus the one renderer that folds it into prompt text.\n *\n * WHY A SECOND CHANNEL, NOT `StructuredPromptFields`: that type is FREE TEXT\n * (`person.hair?: string` → \"with {hair} hair\"), its reader is a hand-authored\n * field table whose totality is compile-time enforced by mapped types, its\n * values are bounded as prose (200 chars), and it renders as headed sentences\n * (\"Subject: …. Style: ….\"). None of those survive contact with ~50 CATALOG IDS\n * plus deployment-registered pack dimensions unknown at compile time, whose\n * hints are authored as comma-joinable compound clauses. `direction-registry.ts`\n * already has the four properties this channel needs — a platform-owned fold\n * order exported for client preview parity, a DERIVED wire schema and node\n * reader, unknown-key/unknown-id inertness, and shared bounds across both doors\n * — so this module mirrors it. `direction-registry.ts` hands this scope off by\n * name in its own header.\n *\n * WIRE VOCABULARY: the keys are the platform's OWN node-data field names — the\n * ones `PERSON_FIELD_BY_DIMENSION` / `STYLING_FIELD_BY_DIMENSION` and the prop\n * pickers' `valueField` already use (`hairBase`, `lipState`, `wardrobeState`,\n * `heldProp`, `material`, `animal`, …). A canvas person/styling node stores\n * exactly these, and every `build*Hints` already consumes them.\n *\n * THE WIRE IS A FLAT BAG, AND THE FLATNESS IS LOAD-BEARING (not a shortcut):\n * `collectStylingFragments` reads `data.lipState` — a PERSON field — to skip\n * `makeup-bold-lips` when `lip-state-bold-red` is already selected. That dedupe\n * only fires for a consumer folding both pickers off ONE shared value map,\n * which is precisely what this channel is. Nesting `person` / `styling` as\n * sub-records would hand the styling builder a bag with no `lipState` in it and\n * the lipstick clause would silently double. Hence: flat wire, and the group\n * rows below receive the WHOLE normalized bag rather than a slice of it.\n *\n * PRE/POST FREE TEXT IS DELIBERATELY OFF THE WIRE (v1): `PersonValue` and\n * `StylingValue` BOTH declare `preText`/`postText` and both `collect*Fragments`\n * read them, so a shared flat bag would emit the same prose twice. They are the\n * only genuine key collision in the set and are simply not `SUBJECT_KEYS`, so\n * the normalizer drops them. Per-subject free text is the one future need that\n * would force either nesting or suffixed keys (`personPreText` / …).\n *\n * IMPORT RULE (hard, inherited from the direction registry): this module\n * imports only `get*PromptHint` / `get*Term` / `build*Hints` FUNCTIONS and the\n * `*_FIELD_BY_DIMENSION` / `*_DIMENSION_ORDER` maps — never a raw UPPERCASE\n * catalog array (`PEOPLE`, `STYLINGS`, `ANIMALS`). `catalog-funnel-ratchet.test.ts`\n * derives its watch set from `picker-catalogs.ts`'s uppercase value imports and\n * can only SHRINK, so a raw array import here would be a new offender — which\n * is exactly why the animal getters live in `@nodaro/shared`. Nothing here\n * reads an environment variable either (`content-free-contract.test.ts`):\n * verbosity and surface are threaded parameters, never deployment state.\n *\n * DISJOINT FROM `direction` BY CONTRACT: `SUBJECT_KEYS ∩ DIRECTION_KEYS = ∅`,\n * pinned by a test. `pose` rides `direction` even though the picker wiring files\n * it under \"Subject / Object\"; keeping the two key sets disjoint is what stops\n * one selection emitting two clauses.\n */\nimport type { PickerHintMode } from \"./term.js\"\nimport {\n DIRECTION_ARRAY_CEILING,\n DIRECTION_ID_MAX_CHARS,\n} from \"./direction-registry.js\"\nimport {\n buildPersonHints,\n getPersonDimensionLimit,\n PERSON_DIMENSION_ORDER,\n PERSON_FIELD_BY_DIMENSION,\n type PersonDimension,\n type PersonValue,\n} from \"./person.js\"\nimport {\n getRegisteredPersonDimensionOrder,\n getRegisteredPersonFieldByDimension,\n} from \"./person-packs.js\"\nimport {\n buildStylingHints,\n getStylingDimensionLimit,\n STYLING_DIMENSION_ORDER,\n STYLING_FIELD_BY_DIMENSION,\n type StylingDimension,\n type StylingValue,\n} from \"./styling.js\"\nimport { buildHeldPropHints } from \"./held-prop.js\"\nimport { buildMaterialHints } from \"./materials.js\"\nimport { curatedAnimalPromptHint, curatedAnimalTerm } from \"./shared-catalog-overlay.js\"\n\n/** Which generation stages fold a dimension (mirrors `DirectionSurface`). */\nexport type SubjectSurface = \"image\" | \"video\" | \"both\"\n\n/**\n * Flat subject ids — the wire shape and the canvas node-data shape.\n *\n * Keys are the platform's own field names; a value is one id, a list of ids, or\n * (for `customAge` alone) a number. Absent ≠ empty: a missing key means \"no\n * hint\", never a default.\n */\nexport type SubjectFields = Readonly<Record<string, string | readonly string[] | number>>\n\n/**\n * A fold row whose render consumes the WHOLE normalized bag and returns ONE\n * already-joined clause.\n *\n * Two reasons this kind exists rather than one row per person/styling field:\n * 1. the cross-catalog dedupe described in the module header needs the whole\n * bag in one call;\n * 2. these builders emit FRAGMENTS, not clauses — 30 person fragments handed\n * to the `\". \"` prompt-hint join read as \"a beautiful woman. in her 30s.\n * East Asian.\" The catalogs' own grammar is a comma-joined compound clause,\n * so the row joins with \", \" and hands back a single piece.\n */\nexport interface SubjectGroupFieldSpec {\n /** Fold-row id. NOT a wire key — a group row reads many of them. */\n readonly key: string\n readonly kind: \"group\"\n readonly surface: SubjectSurface\n /** The whole normalized bag in, one joined clause out (`[]` when empty). */\n readonly render: (subject: SubjectFields, mode: PickerHintMode) => string[]\n}\n\n/** A fold row that reads ONE wire key holding catalog ids (the prop catalogs). */\nexport interface SubjectIdsFieldSpec {\n /** Wire key AND fold-row id — these rows are one key each. */\n readonly key: string\n readonly kind: \"ids\"\n readonly surface: SubjectSurface\n /** Ids honored. Extras are SLICED by the normalizer, never a 400. */\n readonly maxPicks: number\n readonly render: (ids: readonly string[], mode: PickerHintMode) => string[]\n}\n\nexport type SubjectFieldSpec = SubjectGroupFieldSpec | SubjectIdsFieldSpec\n\n// ── Render adapters (module-private) ────────────────────────────────────────\n\n/**\n * The shape both group builders accept. Their declared parameters are\n * `Record<string, unknown> & PersonValue` and `… & StylingValue`; the\n * intersection is assignable to both, so ONE adapter serves both rows without\n * erasing the argument type — a builder signature change fails to typecheck\n * here rather than silently passing the wrong bag.\n */\ntype SubjectBuilderData = Record<string, unknown> & PersonValue & StylingValue\n\n/** A `build*Hints` that returns FRAGMENTS → one comma-joined clause. */\nconst viaFragmentBuilder =\n (build: (data: SubjectBuilderData, mode: PickerHintMode) => string[]) =>\n (subject: SubjectFields, mode: PickerHintMode): string[] => {\n const clause = build(subject as unknown as SubjectBuilderData, mode)\n .filter((s) => s.length > 0)\n .join(\", \")\n return clause.length > 0 ? [clause] : []\n }\n\n/** A catalog whose own builder already returns a clause LIST (held props). */\nconst viaListBuilder =\n (build: (v: unknown, mode: PickerHintMode) => string[]) =>\n (ids: readonly string[], mode: PickerHintMode): string[] =>\n build(ids.length === 1 ? ids[0] : [...ids], mode).filter((s) => s.length > 0)\n\n/** A catalog whose own builder returns ONE blended clause (materials). */\nconst viaStringBuilder =\n (build: (v: unknown, mode: PickerHintMode) => string) =>\n (ids: readonly string[], mode: PickerHintMode): string[] => {\n const s = build(ids.length === 1 ? ids[0] : [...ids], mode)\n return s.length > 0 ? [s] : []\n }\n\n/**\n * Independent per-id emission — the same doctrine as the direction registry's\n * `perId`. Only ever receives NON-EMPTY ids (the normalizer drops empties).\n */\nconst perId =\n (full: (id: string) => string, compact: (id: string) => string) =>\n (ids: readonly string[], mode: PickerHintMode): string[] => {\n const out: string[] = []\n for (const id of ids) {\n const frag = mode === \"compact\" ? compact(id) : full(id)\n if (frag.length > 0) out.push(frag)\n }\n return out\n }\n\n/**\n * THE TABLE. Declaration order IS fold order (`SUBJECT_FOLD_KEYS`), pinned by\n * `__tests__/subject-registry.test.ts`.\n *\n * Person leads (who), then how they are styled, then what they hold, what it is\n * made of, and finally the animal in frame. Both group rows run over the SAME\n * normalized bag, in this order, which is what keeps the styling builder's\n * `lipState` dedupe alive.\n *\n * SECOND MEANING OF POSITION (same as `DIRECTION_FIELDS`): both cap-aware\n * assemblers fold this table AHEAD of the direction table into ONE sheddable\n * list and shed it TAIL-FIRST through `hint-shedding.ts`, so a row's position\n * here is also its survival order under a provider's prompt cap — subject\n * clauses outlive every direction clause, and within this block `animal` leaves\n * before `person`. A compatibility order, not a ranking; anything needing a\n * real ranking adds an explicit priority column rather than reordering rows.\n */\nexport const SUBJECT_FIELDS = [\n { key: \"person\", kind: \"group\", surface: \"both\", render: viaFragmentBuilder(buildPersonHints) },\n { key: \"styling\", kind: \"group\", surface: \"both\", render: viaFragmentBuilder(buildStylingHints) },\n { key: \"heldProp\", kind: \"ids\", surface: \"both\", maxPicks: 2, render: viaListBuilder(buildHeldPropHints) },\n { key: \"material\", kind: \"ids\", surface: \"both\", maxPicks: 2, render: viaStringBuilder(buildMaterialHints) },\n { key: \"animal\", kind: \"ids\", surface: \"both\", maxPicks: 1, render: perId(curatedAnimalPromptHint, curatedAnimalTerm) },\n] as const satisfies ReadonlyArray<SubjectFieldSpec>\n\nexport type SubjectFieldRow = (typeof SUBJECT_FIELDS)[number]\n\n/**\n * Table order — THE canonical fold order, over ROWS (not wire keys). Exported\n * so a client's \"will inject into prompt\" preview folds in the exact order the\n * server does, the way `DIRECTION_KEYS` does for direction.\n */\nexport const SUBJECT_FOLD_KEYS: ReadonlyArray<string> = SUBJECT_FIELDS.map((f) => f.key)\n\n/** The prop rows — the wire keys a fold row owns one-to-one. */\nconst IDS_ROWS: ReadonlyArray<SubjectIdsFieldSpec> = (\n SUBJECT_FIELDS as ReadonlyArray<SubjectFieldSpec>\n).filter((f): f is SubjectIdsFieldSpec => f.kind === \"ids\")\n\n/**\n * The one person field that is a NUMBER, not ids: the literal age in years,\n * consulted only when `age === \"age-custom\"` (`buildAgeFragment`). It has no\n * styling twin, so it rides the flat bag without collision.\n */\nexport const SUBJECT_CUSTOM_AGE_KEY = \"customAge\"\n\n/** `customAge` bounds, mirroring `buildAgeFragment`'s own clamp. */\nconst CUSTOM_AGE_MIN = 0\nconst CUSTOM_AGE_MAX = 120\n\n/**\n * THE WIRE KEY SET, derived — every person field, `customAge`, every styling\n * field, then the prop rows, in fold order. Never hand-listed: a dimension\n * added to either catalog joins the channel by construction.\n *\n * BASE ONLY, deliberately: a deployment-registered person pack adds dimensions\n * at RUNTIME, so the pack-aware set is computed per call inside\n * `normalizeSubjectFields` (and inside `readSubjectFields`). This constant is\n * what a client enumerates to build its projection; a pack dimension it cannot\n * know about still rides the wire and still folds.\n *\n * ONE CONSEQUENCE, noted rather than fixed: the person builder's legacy `lips`\n * fallback field is not a dimension and so is not here, making it unreachable\n * through this channel. Intended — the wire speaks the current vocabulary; the\n * fallback stays for node blobs written before the split.\n */\nexport const SUBJECT_KEYS: ReadonlyArray<string> = [\n ...PERSON_DIMENSION_ORDER.map((d) => PERSON_FIELD_BY_DIMENSION[d]),\n SUBJECT_CUSTOM_AGE_KEY,\n ...STYLING_DIMENSION_ORDER.map((d) => STYLING_FIELD_BY_DIMENSION[d]),\n ...IDS_ROWS.map((f) => f.key),\n]\n\n/**\n * `SUBJECT_KEYS` plus whatever a deployment-registered person pack added — the\n * set the DOORS accept (`readSubjectFields`, and any route-side normalize).\n *\n * Rebuilt per call because pack registration happens at boot, after this module\n * is imported. With no packs registered it is `SUBJECT_KEYS` exactly, pinned by\n * a test.\n */\nexport function getRegisteredSubjectKeys(): ReadonlyArray<string> {\n const fieldByDimension = getRegisteredPersonFieldByDimension()\n const personFields: string[] = []\n for (const dimension of getRegisteredPersonDimensionOrder()) {\n const field = fieldByDimension[dimension]\n if (field) personFields.push(field)\n }\n return [\n ...personFields,\n SUBJECT_CUSTOM_AGE_KEY,\n ...STYLING_DIMENSION_ORDER.map((d) => STYLING_FIELD_BY_DIMENSION[d]),\n ...IDS_ROWS.map((f) => f.key),\n ]\n}\n\n/** Verbosity for a whole subject fold. No family split — subject is one family. */\nexport type SubjectHintMode = PickerHintMode\n\n/** Image policy: the full mechanism clause for every dimension. */\nexport const SUBJECT_IMAGE_HINT_MODE_DEFAULT: SubjectHintMode = \"full\"\n\n/**\n * Video policy: the compact professional term.\n *\n * A fully specified person at `\"full\"` is ~30 paragraph clauses, and on the\n * video stage the start frame already carries the subject's identity — the\n * clip's prompt needs the subject NAMED, not re-described. (The image stage,\n * which is where the subject is actually being built, keeps `\"full\"`.)\n */\nexport const SUBJECT_VIDEO_HINT_MODE_DEFAULT: SubjectHintMode = \"compact\"\n\n/**\n * Wire tolerance ceiling for an array-valued subject key, and the ceiling for\n * one id's length. DEFINED AS the direction constants rather than re-typed, so\n * ONE literal governs both channels and both doors (the route schema and the\n * persisted-node reader) — the wire and the canvas cannot start disagreeing\n * about which strings are ids at all.\n */\nexport const SUBJECT_ARRAY_CEILING = DIRECTION_ARRAY_CEILING\nexport const SUBJECT_ID_MAX_CHARS = DIRECTION_ID_MAX_CHARS\n\n/**\n * Bound on the NUMBER of keys in a subject bag. `SUBJECT_KEYS` is 54 today;\n * this leaves generous headroom for deployment-registered pack dimensions while\n * still closing an otherwise unbounded record that lands verbatim in\n * `jobs.input_data`. Unknown keys are inert (the renderer never reads them), so\n * this is storage hygiene, not validation.\n */\nexport const MAX_SUBJECT_KEYS = 128\n\n/** Bound on the LENGTH of one wire key. Field names are short identifiers. */\nexport const SUBJECT_KEY_MAX_CHARS = 64\n\n/**\n * `string | string[]` → deduped, non-empty, capped id list.\n *\n * Byte-for-byte the direction registry's `normalizeDirectionIds`, including the\n * `ids.length >= maxPicks` bail — load-bearing, not an optimization: the dedupe\n * is an `includes` scan, so without it the cost is quadratic in the CALLER's\n * array length, and one caller reads untrusted persisted JSONB. Bailing is\n * semantics-preserving: once `maxPicks` unique ids exist, no later entry can\n * change the sliced result.\n */\nfunction normalizeIds(value: unknown, maxPicks: number): string[] {\n const ids: string[] = []\n if (typeof value === \"string\") {\n if (value) ids.push(value)\n } else if (Array.isArray(value)) {\n for (const v of value) {\n if (ids.length >= maxPicks) break\n if (typeof v === \"string\" && v && !ids.includes(v)) ids.push(v)\n }\n }\n return ids.slice(0, maxPicks)\n}\n\n/**\n * Pack-aware field → per-dimension pick limit, rebuilt per call.\n *\n * Person's dimension→field map is pack-composed at runtime\n * (`getRegisteredPersonFieldByDimension`), so this cannot be a module constant;\n * a pack dimension is single-select today (`getPersonDimensionLimit` knows only\n * the base union and resolves a pack key to 1 — see `PersonPack.dimensions`).\n * Styling has no pack seam and reads its static map.\n */\nfunction limitByField(): Map<string, number> {\n const out = new Map<string, number>()\n const personFieldByDimension = getRegisteredPersonFieldByDimension()\n for (const dimension of getRegisteredPersonDimensionOrder()) {\n const field = personFieldByDimension[dimension]\n if (field) out.set(field, getPersonDimensionLimit(dimension as PersonDimension))\n }\n for (const dimension of STYLING_DIMENSION_ORDER) {\n out.set(\n STYLING_FIELD_BY_DIMENSION[dimension],\n getStylingDimensionLimit(dimension as StylingDimension),\n )\n }\n for (const row of IDS_ROWS) out.set(row.key, row.maxPicks)\n return out\n}\n\n/**\n * THE NORMALIZER — a known-key, per-dimension-capped copy of a subject bag.\n *\n * WHY IT EXISTS (and why the fold is unusable without it): the subject builders\n * do NOT cap. `collectPersonFragments` / `collectStylingFragments` /\n * `emitIndependentFragments` emit EVERY id they are handed; `normalizePickIds`\n * and `pickHeldPropIds` dedupe but never slice; only `buildMaterialHints` caps,\n * and only structurally at 2. `MAX_SELECTED_BY_DIMENSION`'s own doc names its\n * consumers as the picker UI, the analyzer schema and the Zod validator — NOT\n * the builders. Straight off the wire, then, a bag is a clause amplifier: 8 ids\n * (the array ceiling) on each of ~50 dimensions. This is where the per-dimension\n * cap actually gets enforced.\n *\n * It also:\n * - DROPS UNKNOWN KEYS, so `jobs.input_data` stays the platform's vocabulary\n * (unknown IDS stay inert instead — every getter resolves a miss to `\"\"`);\n * - UNWRAPS a single-id array to a bare string. Load-bearing:\n * `collectPersonFragments` reads a single-pick dimension with\n * `typeof raw === \"string\"`, so a legitimate `[\"hair-base-long\"]` from a\n * client's array-shaped store would otherwise contribute NOTHING;\n * - clamps `customAge` to a whole `0..120`, mirroring `buildAgeFragment`.\n *\n * Copy-on-write: the caller's object is never mutated. Idempotent, so calling it\n * at a door AND inside the renderer is free.\n */\nexport function normalizeSubjectFields(\n subject: SubjectFields | undefined,\n): SubjectFields | undefined {\n if (!subject || typeof subject !== \"object\" || Array.isArray(subject)) return undefined\n const src = subject as Record<string, unknown>\n const limits = limitByField()\n const out: Record<string, string | string[] | number> = {}\n\n const rawAge = src[SUBJECT_CUSTOM_AGE_KEY]\n if (typeof rawAge === \"number\" && Number.isFinite(rawAge)) {\n out[SUBJECT_CUSTOM_AGE_KEY] = Math.max(\n CUSTOM_AGE_MIN,\n Math.min(CUSTOM_AGE_MAX, Math.round(rawAge)),\n )\n }\n\n for (const [field, limit] of limits) {\n const ids = normalizeIds(src[field], limit)\n if (ids.length === 0) continue\n out[field] = ids.length === 1 ? ids[0]! : ids\n }\n\n return Object.keys(out).length > 0 ? out : undefined\n}\n\n/** The rows a given generation stage folds, in table order. */\nexport function subjectFieldsForSurface(\n surface: \"image\" | \"video\",\n): ReadonlyArray<SubjectFieldSpec> {\n return SUBJECT_FIELDS.filter((f) => f.surface === \"both\" || f.surface === surface)\n}\n\n/**\n * Every clause the `subject` channel injects, in canonical table order.\n *\n * NORMALIZES ONCE, at the top, and hands THE SAME bag to both group rows — that\n * single shared bag is the mechanism behind the styling builder's cross-catalog\n * `lipState` dedupe, and it must not depend on a door having normalized first\n * (the normalizer is idempotent, so a door may do it too).\n *\n * Iterates the TABLE, never the caller's object: unknown wire keys contribute\n * nothing, the order is platform-owned, and an off-surface row is inert.\n * Unknown IDS are skipped too — every `get*PromptHint` returns `\"\"` on a miss,\n * so a retired or pack-only id costs no clause rather than a 400.\n *\n * DEDUPE by exact clause string, FIRST OCCURRENCE WINS (order-preserving),\n * matching `renderDirectionHints`.\n *\n * Exported so a client's \"will inject into prompt\" preview renders the exact\n * server output — called on the very object the client sends — instead of\n * re-implementing the fold.\n */\nexport function renderSubjectHints(\n subject: SubjectFields | undefined,\n opts: { surface: \"image\" | \"video\"; mode?: SubjectHintMode },\n): string[] {\n const bag = normalizeSubjectFields(subject)\n if (!bag) return []\n const mode = opts.mode ?? \"full\"\n const out: string[] = []\n const seen = new Set<string>()\n for (const spec of SUBJECT_FIELDS) {\n if (spec.surface !== \"both\" && spec.surface !== opts.surface) continue\n const hints =\n spec.kind === \"group\"\n ? spec.render(bag, mode)\n : spec.render(normalizeIds((bag as Record<string, unknown>)[spec.key], spec.maxPicks), mode)\n for (const hint of hints) {\n if (hint.length > 0 && !seen.has(hint)) {\n seen.add(hint)\n out.push(hint)\n }\n }\n }\n return out\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/prompt-style-section.ts","../src/described-references.ts","../src/unbound-reference-tokens.ts","../src/prompt-builder.ts","../src/prompt-builder-structured-fields.ts","../src/subject-registry.ts"],"names":["renderDirectionHintClauses","joinSentences","joinPromptHints","DEFAULT_USAGE_MODE","usageModeDirective","REFERENCE_ROLE_PRESETS","resolveDefaultRole","roleToPhrase","buildIdentityLockLine","withForcedIdentityLock","defaultRoleForSource","normalizeRoleSlug","DEFAULT_LOCATION_USAGE_MODE","imageMentionSlugForRef","entityMentionSlugForRef","findCharacterMentionTokens","imageReferenceLimit","knownImageSlugsFromRefs","findImageMentionTokens","knownEntitySlugsFromRefs","findEntityMentionTokens","findLocationMentionTokens","prompt","styleText","styleLine","isDeniedStyleId","getStylePromptHint","negPrompt","nativeNegativePrompt","avoidLine","NATIVE_NEGATIVE_PROMPT_MODELS","getMaxNegativePromptChars","maxLen","getMaxImagePromptChars","preCut","reserved","styleSuffix","avoidSuffix","supportsRefs","MODELS_WITH_REFERENCE_IMAGE_SUPPORT","refsToSend","resolveTemplate","applyTemplate","IMAGE_TOKEN_PATTERN","locationReferencePhotoKindLabel","buildPersonHints","buildStylingHints","buildHeldPropHints","buildMaterialHints","curatedAnimalPromptHint","curatedAnimalTerm","PERSON_DIMENSION_ORDER","PERSON_FIELD_BY_DIMENSION","STYLING_DIMENSION_ORDER","STYLING_FIELD_BY_DIMENSION","getRegisteredPersonFieldByDimension","getRegisteredPersonDimensionOrder","DIRECTION_ARRAY_CEILING","DIRECTION_ID_MAX_CHARS","getPersonDimensionLimit","getStylingDimensionLimit"],"mappings":"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","file":"chunk-ZLRB5BVT.cjs","sourcesContent":["/**\n * THE `[style]` SECTION — the trailing block an assembled prompt carries when a\n * run selects any LOOK dimension, shared by the image (`assembleImageInput`)\n * and video (`composeVideoPromptText`) composers so the two surfaces render one\n * shape.\n *\n * <body>\n *\n * [style]:\n * <film line>\n * <scene line>\n *\n * WHY THE LOOK CLAUSES MOVED: folded inline, a broad direction buried the shot\n * — a dozen grade/lighting/era sentences between the user's prose and the\n * structured fields, all in the same register, with nothing telling the model\n * which sentences describe the ACTION and which describe the LOOK. The section\n * says it structurally instead.\n *\n * WHAT STAYS IN THE BODY: the user's prose, the subject fold, the whole MOTION\n * family, and the structured fragment last. Camera motion is part of the shot\n * prose, not the look — so the body/section boundary IS the registry's `family`\n * column, the same column the video verbosity policy splits on. Coupling them\n * is deliberate: one row cannot be shot-prose for the verbosity policy and look\n * for the section.\n *\n * THE SECTION HAS NO TERMINATOR, so \"after the section\" is not a shape a caller\n * can reach by appending: every assembler downstream of the composer (both\n * reference resolvers, the legacy character-description wrapper, `Style:` /\n * `Avoid:`) joins its text with a single `\\n`, which lands it UNDER the header.\n * Two helpers below are how they stay out — `insertBeforeStyleSection` for body\n * content, `endsInsideStyleSection` for the self-labeling control lines that\n * must stay last. A terminator instead would dangle whenever nothing follows,\n * and would break the byte parity below.\n *\n * THE ZERO-CLAUSE CONTRACT (load-bearing): with no look clause — none selected,\n * all shed, or all deduped away — there is NO header and NO extra newline, and\n * the output is byte-identical to the plain hint join. That keeps the\n * verbatim-and-untrimmed no-op alive (zero hints AND zero section → the user's\n * prompt back byte-for-byte, `undefined` included), which is what the routes'\n * `composed !== prompt` guard reads to decide whether to pin\n * `input_data.userPrompt`.\n *\n * NO INDENTATION ANYWHERE: the video reference resolver collapses 2+ horizontal\n * spaces unanchored, so an indented section line would come back flattened. The\n * section is written flush-left rather than relying on that collapse to be\n * harmless.\n */\nimport { joinPromptHints } from \"./prompt-hint-join.js\"\nimport { joinSentences } from \"./hint-join.js\"\nimport {\n renderDirectionHintClauses,\n type DirectionFamily,\n type DirectionFields,\n type DirectionRenderOptions,\n type DirectionStyleGroup,\n} from \"./direction-registry.js\"\n\n/**\n * The section header, verbatim. Lowercase and bracketed so it reads as\n * structure rather than as a sentence — and so it can be found again by\n * `buildImagePrompt`'s hybrid line-capitalizer, which must stop here\n * (`[Style]:` would be a different token, and capitalized clause lines would\n * corrupt the lowercase catalog wording).\n */\nexport const STYLE_SECTION_HEADER = \"[style]:\"\n\n/** The blank line between the body and the section. Omitted for an empty body. */\nexport const STYLE_SECTION_GAP = \"\\n\\n\"\n\n/** The section's opening bytes — the gap, the header and the newline before its\n * first clause line (the section is never emitted without one). */\nconst STYLE_SECTION_OPENING = `${STYLE_SECTION_GAP}${STYLE_SECTION_HEADER}\\n`\n\n/**\n * Split a composed prompt into the BODY and the `[style]` section it ends with\n * (`section: \"\"` when it carries none, the body then being the whole string;\n * the section comes back WITHOUT the gap).\n *\n * Matched from the RIGHT: the composer always emits the section last, and a\n * user's own prose is free to contain the same characters. A blank body drops\n * the gap with it, so the section-only form is matched on its own.\n */\nexport function splitStyleSection(prompt: string): { body: string; section: string } {\n const at = prompt.lastIndexOf(STYLE_SECTION_OPENING)\n if (at >= 0) {\n return { body: prompt.slice(0, at), section: prompt.slice(at + STYLE_SECTION_GAP.length) }\n }\n return prompt.startsWith(`${STYLE_SECTION_HEADER}\\n`)\n ? { body: \"\", section: prompt }\n : { body: prompt, section: \"\" }\n}\n\n/**\n * Extend a composed prompt's BODY with more lines, AHEAD of the `[style]`\n * section — what every assembler downstream of the composer needs, because the\n * section has no terminator: a plain append lands under the header and reads as\n * one more look clause. Reference bindings, element directives and character\n * descriptions are scene content that belongs with the prose, and leaving the\n * look clauses last is where a look tail was measured to cost nothing.\n *\n * With no section this IS the plain `\"\\n\"` join every caller emitted before —\n * the byte-parity path, down to the leading newline an empty prompt produces.\n */\nexport function insertBeforeStyleSection(prompt: string, lines: readonly string[]): string {\n if (lines.length === 0) return prompt\n const block = lines.join(\"\\n\")\n const { body, section } = splitStyleSection(prompt)\n if (section.length === 0) return `${prompt}\\n${block}`\n return `${body.length > 0 ? `${body}\\n${block}` : block}${STYLE_SECTION_GAP}${section}`\n}\n\n/**\n * True when `prompt` ends INSIDE the section — its last `\\n\\n`-delimited block\n * opens with the header. What the self-labeling control lines (`Style:`,\n * `Avoid:`) read: they stay at the END of the prompt by design, so a blank line\n * of their own is the only thing that can close the header's scope ahead of\n * them.\n */\nexport function endsInsideStyleSection(prompt: string): boolean {\n const at = prompt.lastIndexOf(STYLE_SECTION_GAP)\n const lastBlock = at >= 0 ? prompt.slice(at + STYLE_SECTION_GAP.length) : prompt\n return lastBlock.startsWith(`${STYLE_SECTION_HEADER}\\n`)\n}\n\n/** Where a rendered clause reads in the assembled prompt. */\nexport type PromptClauseSlot = \"body\" | \"film\" | \"scene\"\n\n/** A rendered clause plus the line it belongs on. */\nexport interface SlottedPromptClause {\n readonly text: string\n readonly slot: PromptClauseSlot\n}\n\n/**\n * The slot a direction row's clause takes: motion stays in the body, the five\n * `styleGroup: \"film\"` rows lead the section, every other look row follows on\n * the scene line.\n */\nexport function styleSlotFor(\n row: { readonly family: DirectionFamily; readonly styleGroup?: DirectionStyleGroup },\n): PromptClauseSlot {\n if (row.family === \"motion\") return \"body\"\n return row.styleGroup === \"film\" ? \"film\" : \"scene\"\n}\n\n/**\n * The SUBJECT channel's clauses: always body. Who is in the shot is the noun\n * phrase the look modifies, not part of the look.\n */\nexport function asBodyClauses(texts: readonly string[]): SlottedPromptClause[] {\n return texts.map((text) => ({ text, slot: \"body\" as const }))\n}\n\n/**\n * Fold a direction bag and tag each clause with its slot, in registry table\n * order. The ORDER is the fold/survival order, not the string order — the\n * composers slice this list from the tail when a cap forces a shed, and only\n * then hand the surviving prefix to `composeSectionedPrompt`.\n */\nexport function partitionStyleClauses(\n direction: DirectionFields | undefined,\n opts: DirectionRenderOptions,\n): SlottedPromptClause[] {\n return renderDirectionHintClauses(direction, opts).map((clause) => ({\n text: clause.text,\n slot: styleSlotFor(clause),\n }))\n}\n\n/**\n * The section block for a set of clauses — `\"\"` when none of them is a look\n * clause. Each line is omitted entirely when its half of the split is empty, so\n * a scene-only fold never emits a blank film line.\n */\nexport function styleSectionFromClauses(clauses: readonly SlottedPromptClause[]): string {\n const line = (slot: PromptClauseSlot) =>\n joinSentences(clauses.filter((c) => c.slot === slot).map((c) => c.text))\n const lines = [line(\"film\"), line(\"scene\")].filter((l) => l.length > 0)\n return lines.length === 0 ? \"\" : `${STYLE_SECTION_HEADER}\\n${lines.join(\"\\n\")}`\n}\n\n/**\n * The section for a raw direction bag — the entry point a client renders its\n * preview through, so the preview and the server emit the same bytes.\n */\nexport function renderStyleSection(\n direction: DirectionFields | undefined,\n opts: DirectionRenderOptions,\n): string {\n return styleSectionFromClauses(partitionStyleClauses(direction, opts))\n}\n\n/**\n * The assembled prompt for a set of clauses: body clauses `\". \"`-joined onto the\n * user's prompt, the structured fragment last in the body, then the section.\n *\n * TRIMMING follows `joinPromptHints`: the prompt is trimmed whenever ANYTHING\n * folded — a section counts, so a look-only fold trims too, or the blank line\n * would inherit the prompt's trailing whitespace. With nothing folded at all the\n * prompt is returned VERBATIM AND UNTRIMMED (`undefined` passes straight\n * through), which is the byte-parity contract every existing caller rests on.\n *\n * A blank body drops the gap with it, so the result never opens on a newline —\n * the same reason `joinPromptHints` filters a blank prompt out of its join.\n */\nexport function composeSectionedPrompt<T extends string | undefined>(\n userPrompt: T,\n clauses: readonly SlottedPromptClause[],\n structuredFragment: string,\n): string | T {\n const bodyHints = [\n ...clauses.filter((c) => c.slot === \"body\").map((c) => c.text),\n structuredFragment,\n ].filter((p) => p.length > 0)\n const section = styleSectionFromClauses(clauses)\n if (section.length === 0) {\n return bodyHints.length === 0 ? userPrompt : joinPromptHints(userPrompt ?? \"\", bodyHints)\n }\n const body =\n bodyHints.length > 0 ? joinPromptHints(userPrompt ?? \"\", bodyHints) : (userPrompt ?? \"\").trim()\n return body.length > 0 ? `${body}${STYLE_SECTION_GAP}${section}` : section\n}\n\n/**\n * What each clause costs the assembled prompt, as the EXACT composed-length\n * delta of adding it to the prefix below it. Feeds `keepableDirectionHints`,\n * which walks the list tail-first.\n *\n * Exact deltas rather than \"clause + separator\" because the section's own bytes\n * are not evenly distributed: the FIRST look clause carries the whole\n * `\"\\n\\n[style]:\\n\"` header (11 characters that only come back when the section\n * disappears), the second look clause of a line carries a `\". \"`, the first of\n * the scene line carries a `\"\\n\"`. Flat costs would under-price the header, so\n * the walk would cover a deficit with more clauses than it needs and over-shed\n * — visible as a fold that drops two clauses where one would have fit. The\n * deltas do not change between shed iterations (the walk only ever shortens the\n * prefix), so they are computed once, before the loop.\n */\nexport function sectionedClauseCosts(\n userPrompt: string | undefined,\n clauses: readonly SlottedPromptClause[],\n structuredFragment: string,\n): number[] {\n const lengthAt = (kept: number) =>\n composeSectionedPrompt(userPrompt, clauses.slice(0, kept), structuredFragment)?.length ?? 0\n const costs: number[] = []\n let below = lengthAt(0)\n for (let i = 0; i < clauses.length; i++) {\n const at = lengthAt(i + 1)\n costs.push(at - below)\n below = at\n }\n return costs\n}\n","/**\n * Described references + per-reference description overrides + rail captions —\n * the ONE place either lane phrases \"what this reference IS\".\n *\n * Three shapes, one grammar (`<subject> — <description>.`) plus the caption's\n * `<binding>: <caption>.`:\n *\n * - a DESCRIBED reference (`DescribedReference`, no media) → `Natalie — a\n * tall woman in a red coat.` The subject is the NAME, because a described\n * reference has no seat to bind to: correlation with the prose is by name,\n * which is why the caller leaves the name in the prompt rather than an\n * indexed `@slug:N` mention (that grammar is url-gated).\n * - a per-use `descriptionOverride` on a reference the HYBRID format gives no\n * description slot (a mention / canonical-fallback / location / object role\n * phrase carries none) → `reference image A — a tall woman in a red coat.`\n * Same grammar, the BINDING as the subject. Where a description slot DOES\n * exist (every legacy bullet, and the hybrid extras' `, <desc>` clause) the\n * override fills THAT slot instead, so the model is never told twice.\n * - a rail CAPTION for a video / audio reference → `@video_1: the establishing\n * drone shot.` Index-aligned with the caller's url array.\n *\n * Rendering is separate from JOINING on purpose: the lines are format-agnostic\n * text, and each lane already owns where a trailing directive goes (the image\n * hybrid's `trailingLines`, the video core's `trailingLines` /\n * `allFallbackLines`). `appendReferenceLines` is the joiner for the call sites\n * that have no such array to push into — it bullets the lines into the legacy\n * \"Use these characters:\" block or lands them ahead of the `[style]` section in\n * hybrid, matching what each lane's own assembly does.\n */\n\nimport type { DescribedReference } from \"@nodaro/shared/types\"\nimport { insertBeforeStyleSection } from \"./prompt-style-section.js\"\n\n/** Which reference-prompt format the lines are being rendered for. */\nexport type ReferenceLineFormat = \"legacy\" | \"hybrid\"\n\n/** The legacy directive block every lane consolidates its bullets into. */\nconst CHARACTER_BLOCK_HEADER = \"Use these characters:\"\n\n/**\n * The ONE phrasing for \"this subject is described as …\":\n * `<subject> — <description>.`\n *\n * `subject` is the name for a described reference and the reference's binding\n * (`reference image A` / `@image_2`) for a per-use description override. Both\n * halves are trimmed; an empty half yields `\"\"` (the caller drops the line).\n */\nexport function referenceDescriptionLine(\n subject: string,\n description: string | null | undefined,\n): string {\n const s = subject.trim()\n const d = description?.trim()\n if (!s || !d) return \"\"\n return `${s} — ${d}.`\n}\n\n/**\n * Render the described references (name + description, no media) as trailing\n * lines. Entries missing either half contribute nothing; entries repeating a\n * name (case-insensitively) render once — a description a caller sent twice\n * says nothing new to the model, and every sibling renderer in both lanes\n * dedups the same way.\n */\nexport function renderDescribedReferenceLines(\n refs: readonly DescribedReference[] | undefined,\n): string[] {\n if (!refs || refs.length === 0) return []\n const lines: string[] = []\n const seen = new Set<string>()\n for (const r of refs) {\n const key = r.name?.trim().toLowerCase()\n if (!key || seen.has(key)) continue\n const line = referenceDescriptionLine(r.name, r.description)\n if (!line) continue\n seen.add(key)\n lines.push(line)\n }\n return lines\n}\n\n/**\n * Render the video / audio rail captions as `@video_N: <caption>.` /\n * `@audio_N: <caption>.` lines, index-aligned with the caller's url arrays.\n *\n * Each list is bounded by the count of references of that kind that actually\n * ship, so a caption for a url the provider cap dropped never binds a phantom\n * `@video_N`. Blank captions are holes in an aligned array, not lines.\n */\nexport function renderReferenceCaptionLines(\n videoCaptions: readonly string[] | undefined,\n audioCaptions: readonly string[] | undefined,\n counts: { readonly video: number; readonly audio: number },\n): string[] {\n const lines: string[] = []\n const render = (captions: readonly string[] | undefined, kind: \"video\" | \"audio\", cap: number) => {\n if (!captions) return\n for (let i = 0; i < captions.length && i < cap; i++) {\n const text = captions[i]?.trim()\n if (!text) continue\n lines.push(`@${kind}_${i + 1}: ${text}.`)\n }\n }\n render(videoCaptions, \"video\", counts.video)\n render(audioCaptions, \"audio\", counts.audio)\n return lines\n}\n\n/**\n * Append reference lines to an assembled prompt the way the surrounding lane\n * would have.\n *\n * - hybrid → trailing scene directives ahead of the `[style]` section (the\n * section has no terminator, so a flat append would read as one more look\n * clause).\n * - legacy → `- ` bullets consolidated into the existing\n * \"Use these characters:\" block, or a new block prepended ahead of the\n * body — the same splice-or-create both lanes already do for their\n * canonical-fallback and extra-ref bullets.\n *\n * No lines → the prompt is returned unchanged, byte-for-byte.\n */\nexport function appendReferenceLines(\n prompt: string,\n lines: readonly string[],\n format: ReferenceLineFormat,\n): string {\n if (lines.length === 0) return prompt\n if (format === \"hybrid\") return insertBeforeStyleSection(prompt, lines)\n const bullets = lines.map((l) => `- ${l}`).join(\"\\n\")\n if (prompt.startsWith(`${CHARACTER_BLOCK_HEADER}\\n`)) {\n const splitIdx = prompt.indexOf(\"\\n\\n\")\n if (splitIdx === -1) return `${prompt}\\n${bullets}`\n return `${prompt.slice(0, splitIdx)}\\n${bullets}${prompt.slice(splitIdx)}`\n }\n const block = `${CHARACTER_BLOCK_HEADER}\\n${bullets}`\n return prompt ? `${block}\\n\\n${prompt}` : block\n}\n","/**\n * The unwired half of the editor reference-token contract — what a\n * `{image:N:label}` / `{video:N:label}` / `{audio:N:label}` token becomes when\n * no reference of its kind sits at its position. ONE rule for every surface:\n * the video resolver (`resolveReferenceTokens`) and the image prompt builder\n * (`buildImagePrompt`) both render an unwired token through these two\n * functions, so the image and video paths cannot drift apart on it.\n *\n * Each caller keeps its own token grammar and its own WIRED rendering (video:\n * `the person from @image_1`; image: `Image 1 (person)` /\n * `the person from reference image A`); only the unwired outcome is shared.\n */\n\n/**\n * The text an unwired token renders to: its label as written, or nothing for a\n * label-less token. Text a resolver does not rewrite keeps its tokens as typed\n * — on image prompts a wired token in a hybrid `Avoid:` line and the native\n * negative prompt, both on purpose (see `dropUnwiredImageTokens`).\n */\nexport function unboundReferenceTokenText(label: string | undefined): string {\n return label ?? \"\"\n}\n\n/**\n * Tidy the gap a dropped token leaves: collapse every run of 2+ HORIZONTAL\n * whitespace to one space, then trim. The class is `[^\\S\\r\\n]` (NOT `\\s`) so\n * the `\\n` / `\\n\\n` separators between assembled blocks survive — a `\\s{2,}`\n * collapse would merge paragraphs.\n */\nexport function tidyReferenceTokenGaps(prompt: string): string {\n return prompt.replace(/[^\\S\\r\\n]{2,}/g, \" \").trim()\n}\n","/**\n * Image prompt assembly logic shared between frontend and backend.\n * Handles character description expansion, style appending, negative prompt routing,\n * provider-aware prompt truncation (default 5000 chars), and reference image filtering by model support.\n */\n\nimport { joinSentences } from \"./hint-join.js\"\nimport { IMAGE_TOKEN_PATTERN } from \"./image-token-pattern.js\"\nimport { resolveTemplate, applyTemplate } from \"./prompt-templates.js\"\nimport { NATIVE_NEGATIVE_PROMPT_MODELS, MODELS_WITH_REFERENCE_IMAGE_SUPPORT, imageReferenceLimit, getMaxImagePromptChars, getMaxNegativePromptChars } from \"@nodaro/shared/models\"\nimport { getStylePromptHint, isDeniedStyleId } from \"./style.js\"\nimport {\n STYLE_SECTION_GAP,\n STYLE_SECTION_HEADER,\n endsInsideStyleSection,\n insertBeforeStyleSection,\n splitStyleSection,\n} from \"./prompt-style-section.js\"\nimport {\n findCharacterMentionTokens,\n type CharacterMentionTokenInfo,\n usageModeDirective,\n DEFAULT_USAGE_MODE,\n type UsageMode,\n roleToPhrase,\n defaultRoleForSource,\n REFERENCE_ROLE_PRESETS,\n normalizeRoleSlug,\n resolveDefaultRole,\n findLocationMentionTokens,\n DEFAULT_LOCATION_USAGE_MODE,\n type LocationMentionTokenInfo,\n type LocationUsageMode,\n findImageMentionTokens,\n imageMentionSlugForRef,\n knownImageSlugsFromRefs,\n type ImageMentionTokenInfo,\n findEntityMentionTokens,\n entityMentionSlugForRef,\n knownEntitySlugsFromRefs,\n type EntityMentionTokenInfo,\n locationReferencePhotoKindLabel,\n type LocationReferencePhotoKind\n} from \"@nodaro/shared/entities\"\nimport { buildIdentityLockLine, withForcedIdentityLock } from \"./identity-lock.js\"\nimport type { CharacterDef, ConnectedReference, DescribedReference, IdentityFidelity, IdentityMeta, ReferenceSource, SceneData } from \"@nodaro/shared/types\"\nimport { appendReferenceLines, referenceDescriptionLine, renderDescribedReferenceLines } from \"./described-references.js\"\nimport { tidyReferenceTokenGaps, unboundReferenceTokenText } from \"./unbound-reference-tokens.js\"\n\nexport interface ResolveCharacterMentionsResult {\n /** Prompt with @-tokens replaced by display names + \"Use these characters:\" directive prepended. */\n prompt: string\n /** Resolved URLs from matched mention tokens, in mention order, deduped via caller responsibility. */\n additionalUrls: string[]\n /**\n * Set of character slugs that had at least one resolved mention token.\n * Callers use this to gate the per-character \"no mention → canonical\n * fallback\" behavior so a wired character with no `@-mention` still gets\n * its canonical URL attached (existing pre-mention-feature behavior).\n */\n mentionedCharacterSlugs: Set<string>\n}\n\n/**\n * Compose the descriptive body of a character identity bullet:\n * `${subject} — ${canonicalDesc?}. ${elementInjection?}` (parts joined by \". \")\n *\n * Either part may be absent. `canonicalDesc` is mode-gated by the caller (pass\n * `undefined` to omit it for non-identity modes); `elementInjection` is the\n * mode-INDEPENDENT scene-composition fragment wired into the character node's\n * Assets/Prompt handle (held-prop / styling / text). When BOTH are absent the\n * bullet collapses to the bare `subject` — byte-identical to the\n * pre-elementInjection output, which the parity tests pin.\n */\nfunction composeIdentityDescPart(\n subject: string,\n canonicalDesc: string | null | undefined,\n elementInjection: string | null | undefined,\n): string {\n const parts: string[] = []\n const c = canonicalDesc?.trim()\n if (c) parts.push(c)\n const e = elementInjection?.trim()\n if (e) parts.push(e)\n return parts.length > 0 ? `${subject} — ${joinSentences(parts)}` : subject\n}\n\n/**\n * The trailing line a per-use `descriptionOverride` contributes in HYBRID\n * format. The hybrid role phrase (\"the person from reference image A\") carries\n * no description slot, so the override is surfaced as its own binding-subject\n * line via the ONE phrasing helper in `described-references.ts`. It is pushed\n * onto the reference's `elementDirectives` — the array every hybrid renderer\n * already uses for \"the trailing scene directives this reference contributes\" —\n * so it lands with that reference's other lines instead of threading a ninth\n * channel through eight call sites.\n *\n * The hybrid EXTRAS path does not call this: it has a real `, <desc>` clause,\n * which the override fills instead (so the model is never told twice). Nothing\n * is pushed without an override, which is what keeps every existing hybrid\n * output byte-identical.\n */\nfunction pushOverrideDirective(\n out: string[],\n ref: Pick<ConnectedReference, \"descriptionOverride\">,\n binding: string,\n): void {\n const line = referenceDescriptionLine(binding, ref.descriptionOverride)\n if (line) out.push(line)\n}\n\n/**\n * Resolve @-mention tokens in a prompt against connected references.\n * Returns: augmented prompt (with directives prepended + tokens replaced\n * by character display names) and the set of asset URLs to include as refs.\n *\n * Behavior:\n * - Build two lookup Maps: `bySlug` for canonical entries, `byVariant` for variant entries.\n * - Iterate tokens left-to-right so directives are emitted in mention order.\n * - For each token, prefer the variant match when variantSlug present; fall back to canonical.\n * - `charactersSeen` Set guards the long canonical description to appear AT MOST ONCE\n * per character even when the character is mentioned in several tokens.\n * - Build a `replacements` array (token + offset + replacement display name) and\n * apply right-to-left so earlier replacements do not shift later offsets.\n * - Prepend a \"Use these characters:\\n…\" directive section when any directives were emitted.\n * - Each directive bullet leads with the user-visible `Image N (Name)` index pulled\n * directly from the typed token (e.g. `@kira:1:smile` → `Image 1 (Kira)`).\n * This lets the user trace a literal slug in the prompt to its appearance in\n * the final assembled identity-directive block.\n */\nexport function resolveCharacterMentions(\n prompt: string,\n tokens: readonly CharacterMentionTokenInfo[],\n refs: readonly ConnectedReference[],\n): ResolveCharacterMentionsResult {\n const bySlug = new Map<string, ConnectedReference>()\n const byVariant = new Map<string, ConnectedReference>()\n for (const r of refs) {\n if (!r.characterSlug) continue\n if (!r.variantSlug) {\n bySlug.set(r.characterSlug, r)\n } else {\n byVariant.set(`${r.characterSlug}:${r.variantSlug}`, r)\n }\n }\n\n const additionalUrls: string[] = []\n // `firstBulletEmittedFor` tracks the slug of characters that have already\n // produced a non-\"none\" bullet. Each character emits AT MOST ONE primary\n // bullet (the rich identity / name-only line). \"none\" mentions don't claim\n // this slot — they emit no bullet AT ALL — so a later \"face\" mention of the\n // same character still emits its directive bullet on first sight. Without\n // this split, a `[none, face]` mention pair would suppress both bullets\n // because the first iteration would silently consume the \"first mention\"\n // slot without emitting anything.\n const firstBulletEmittedFor = new Set<string>()\n const mentionedCharacterSlugs = new Set<string>()\n const directiveLines: string[] = []\n\n const replacements: Array<{ token: string; offset: number; replacement: string }> = []\n for (const t of tokens) {\n const match = t.variantSlug\n ? byVariant.get(`${t.characterSlug}:${t.variantSlug}`)\n : bySlug.get(t.characterSlug)\n if (!match) continue\n\n additionalUrls.push(match.url)\n mentionedCharacterSlugs.add(t.characterSlug)\n\n // Per-mention effective mode. Resolution order: per-mention slug override\n // → character node default → global DEFAULT_USAGE_MODE. Used both to\n // shape the inline replacement and to decide whether (and how) to emit a\n // bullet for this mention.\n const effectiveMode: UsageMode =\n t.usageMode ?? match.defaultUsageMode ?? DEFAULT_USAGE_MODE\n\n const displayName = bySlug.get(t.characterSlug)?.defaultName ?? t.characterSlug\n // Inline replacement of `@kira:1:smile` in the user's prompt. For \"none\"\n // mode we substitute the bare positional reference (`Image 1`) so the\n // user's sentence reads \"show Image 1 dancing\" — the image is attached,\n // the model sees the position label, but no character name biases the\n // textual prompt. Every other mode (including \"name\") keeps the legacy\n // `Kira` substitution so prose flows naturally.\n const replacement = effectiveMode === \"none\"\n ? `Image ${t.imageIndex}`\n : displayName\n replacements.push({ token: t.token, offset: t.offset, replacement })\n\n // Bullet emission rules per mode:\n // - \"none\": NO bullet (zero textual intervention; only the image is\n // attached). Doesn't consume the per-character \"first bullet\" slot —\n // a later non-none mention can still emit its primary directive.\n // If EVERY mention of a character is \"none\", that character\n // contributes no bullets at all, so it won't appear under the\n // \"Use these characters:\" header.\n // - \"name\": ONE bullet on first non-none mention only —\n // `- Image N (Name)` with no trailing directive. Tells the model who\n // the character is so it can correlate, without prescribing how to\n // use the image.\n // - other modes: ONE bullet on first non-none mention only,\n // `- Image N (Name) — <canonical?>. <directive>`.\n if (effectiveMode === \"none\") {\n // Suppress everything — the inline replacement above is the only signal.\n continue\n }\n const isFirstBullet = !firstBulletEmittedFor.has(t.characterSlug)\n if (effectiveMode === \"name\") {\n if (isFirstBullet) {\n directiveLines.push(`- Image ${t.imageIndex} (${displayName})`)\n firstBulletEmittedFor.add(t.characterSlug)\n }\n } else if (isFirstBullet) {\n const directive = usageModeDirective(effectiveMode)\n const subject = `Image ${t.imageIndex} (${displayName})`\n // Canonical description is identity-context — only useful when the model\n // is being asked to lock to that identity (\"identical\" / \"face-pose\").\n // For \"emotion\" / \"style\" modes the canonical description (face/body/\n // features) is noise relative to the directive's intent, so we omit it\n // and keep the bullet focused on the mode-specific instruction.\n const includeCanonicalDesc =\n effectiveMode === \"identical\" || effectiveMode === \"face-pose\"\n // Canonical desc is mode-gated; the character's wired elements\n // (held-prop / styling / text) ride the bullet in every mode that emits\n // one. Byte-identical to the old `${subject} — ${canonical}` form when no\n // injection is present.\n // A per-use `descriptionOverride` IS the caller describing this subject\n // for this run, so it fills the identity slot ahead of the entity's stored\n // canonical description — and rides every mode that emits a bullet at all\n // (the mode gate exists to suppress STORED identity noise, not the\n // caller's own words). \"none\" still emits nothing: it returned above.\n const descPart = composeIdentityDescPart(\n subject,\n match.descriptionOverride?.trim()\n || (includeCanonicalDesc ? match.characterCanonicalDescription : undefined),\n match.elementInjection,\n )\n // `directive` is non-null here because usageModeDirective only returns\n // null for \"none\"/\"name\", both of which are already handled above.\n directiveLines.push(`- ${descPart}.${directive ? ` ${directive}` : \"\"}`)\n firstBulletEmittedFor.add(t.characterSlug)\n }\n // Variant-description sub-line only makes sense alongside an emitted\n // bullet — for \"none\"/\"name\" modes it's dropped (those modes are\n // intentionally minimal).\n if (\n t.variantSlug\n && match.variantDescription\n && effectiveMode !== \"name\"\n && isFirstBullet\n ) {\n directiveLines.push(` (in this image: ${match.variantDescription.trim()})`)\n }\n }\n\n // Apply replacements right-to-left so offsets remain valid.\n let resolvedPrompt = prompt\n for (const r of [...replacements].sort((a, b) => b.offset - a.offset)) {\n resolvedPrompt = resolvedPrompt.slice(0, r.offset)\n + r.replacement\n + resolvedPrompt.slice(r.offset + r.token.length)\n }\n\n if (directiveLines.length > 0) {\n resolvedPrompt = `Use these characters:\\n${directiveLines.join(\"\\n\")}\\n\\n${resolvedPrompt}`\n }\n\n return { prompt: resolvedPrompt, additionalUrls, mentionedCharacterSlugs }\n}\n\n/**\n * Splice one resolved mention phrase in for its token, collapsing the horizontal\n * whitespace ON EITHER SIDE OF THE SEAM to a single space. The single splice\n * primitive for every HYBRID image mention splice — the four `@`-mention\n * resolvers (character, location, named image, wired entity) and the\n * `{image:N:label}` positional-pill expansion (`expandImageRefTokensHybrid`).\n *\n * WHY: an editor serializes a mention chip as its token plus its own trailing\n * space, and the prose that follows the chip carries the space the author typed\n * — so a perfectly ordinary sentence arrives as `@panda:1 and @panda2:2 …` and\n * assembles to \"the person from reference image A and reference image C …\",\n * with the doubled space sitting exactly where the model is being told what the\n * reference IS. The VIDEO core never shows this because `resolveReferenceTokens`\n * runs a `[^\\S\\r\\n]{2,}` collapse over its fully-assembled prompt on every\n * return; the image path has no such tidy. This is that collapse, SCOPED to the\n * seam: a doubled space the author put elsewhere in their prose is theirs to\n * keep, and a prompt whose seams are already single-spaced is byte-identical\n * (the run must be 2+ to match).\n *\n * The class is `[^\\S\\r\\n]` (NOT `\\s`) for the same reason the video tidy uses\n * it: `\\n` / `\\n\\n` separate the assembled blocks, and a `\\s`-based collapse\n * would silently merge paragraphs.\n *\n * INDENTATION is structure, not a seam. The leading collapse is anchored with a\n * `(?<=\\S)` lookbehind so it only fires on a run that FOLLOWS prose on the same\n * line. A mention that opens an indented line (`\"Scene:\\n @panda:1 stands\"` —\n * a shot list, a numbered beat sheet) keeps its indent verbatim; without the\n * anchor that run IS the left seam and a 4-space indent flattened to one space,\n * which is the same class of damage as merging paragraphs and would have made\n * the \"already-single-spaced prompts are byte-identical\" claim false for every\n * multi-line prompt. The trailing collapse stays unconditional: a run AFTER a\n * chip is the reported bug itself and can never be indentation.\n *\n * OFFSET SAFETY: callers splice right-to-left over offsets taken against the\n * pre-splice string. The left-hand collapse only ever removes characters from\n * the whitespace run immediately preceding THIS token — positions at or after\n * the end of any earlier token (tokens are non-whitespace and never overlap) —\n * so every not-yet-applied (smaller) offset stays valid.\n */\nfunction spliceMentionPhrase(\n prompt: string,\n offset: number,\n tokenLength: number,\n phrase: string,\n): string {\n const before = prompt.slice(0, offset).replace(/(?<=\\S)[^\\S\\r\\n]{2,}$/, \" \")\n const after = prompt.slice(offset + tokenLength).replace(/^[^\\S\\r\\n]{2,}/, \" \")\n return before + phrase + after\n}\n\ninterface ResolveCharacterMentionsHybridResult {\n /** Body with each `@`-mention replaced INLINE by its role phrase\n * (\"the {role} from reference image {LETTER}\"). No directive block. */\n prompt: string\n /** Matched character URLs in mention order (deduped by the caller). */\n additionalUrls: string[]\n /** Slugs that had at least one resolved mention. */\n mentionedCharacterSlugs: Set<string>\n /** Per-reference identity-lock lines (non-null, deduped per URL). Caller\n * prepends them as ONE block. */\n lockLines: string[]\n /** Non-empty `elementInjection` fragments (deduped per URL). Caller appends\n * them as trailing scene directives. */\n elementDirectives: string[]\n}\n\n/**\n * HYBRID-mode character mention convergence (Unified Reference Roles, Phase A).\n *\n * Where `resolveCharacterMentions` (above) prepends the legacy\n * `\"Use these characters:\"` bullet block + replaces tokens with bare display\n * names — and is shared VERBATIM with the video resolver, so its contract must\n * NOT change — this renders each `@`-mention as the inline role phrase\n * `\"the {role} from reference image {LETTER}\"` and surfaces the optional\n * identity-lock + wired `elementInjection` SEPARATELY (the caller prepends one\n * lock block and appends element directives). No directive block is produced.\n *\n * Slot/letter: a character URL's 1-based position in\n * `dedup([...existingUrls, ...mentionUrls])`. The caller appends non-character\n * URLs AFTER this list when it builds `finalIndexByUrl`, so these letters are\n * byte-identical to that canonical map for every character URL.\n *\n * Role: the mention's role/usage-mode 3rd segment — `face`/`pose`/`style` parse\n * as usage modes, `person`/`clothes`/`hair`/`expression` parse as variant slugs\n * but are curated roles. Either way it's reused when present in\n * `REFERENCE_ROLE_PRESETS[\"wired-character\"]`, else falls back to the source\n * default (`\"person\"`). `identical`/`face-pose`/`emotion`/`name`/`none` (and a\n * real variant slug like `smile`) are not curated roles → `\"person\"`.\n *\n * Matching: variant-first, canonical-fallback — so a role-word 3rd segment that\n * parsed as a variant slug (e.g. `@kira:1:person`) still attaches the canonical\n * reference instead of being dropped (the legacy resolver skips variant misses).\n */\n\nfunction resolveCharacterMentionsHybrid(\n prompt: string,\n tokens: readonly CharacterMentionTokenInfo[],\n refs: readonly ConnectedReference[],\n existingUrls: readonly string[],\n): ResolveCharacterMentionsHybridResult {\n const bySlug = new Map<string, ConnectedReference>()\n const byVariant = new Map<string, ConnectedReference>()\n for (const r of refs) {\n if (!r.characterSlug) continue\n if (!r.variantSlug) bySlug.set(r.characterSlug, r)\n else byVariant.set(`${r.characterSlug}:${r.variantSlug}`, r)\n }\n\n const presets = REFERENCE_ROLE_PRESETS[\"wired-character\"]\n\n const additionalUrls: string[] = []\n const mentionedCharacterSlugs = new Set<string>()\n const refByUrl = new Map<string, ConnectedReference>()\n // Per-mention `~lock` / `~nolock` (Task 4 + F4): the tri-state lock OVERRIDE\n // per attached URL — `true` (force on) / `false` (force off) / absent\n // (inherit the ref default). The lock loop below feeds this to\n // `withForcedIdentityLock` before `buildIdentityLockLine`. Only tokens that\n // carried a sentinel write here (last sentinel wins); a sentinel-less mention\n // never overwrites, so a `~lock` upstream survives a later plain mention.\n const lockOverrideByUrl = new Map<string, boolean>()\n const matched: Array<{ token: string; offset: number; url: string; role: string }> = []\n\n for (const t of tokens) {\n // Variant-first, canonical-fallback. `variantMatch` (a REAL matched variant\n // URL) doubles as the signal that the 3rd segment SELECTED a variant rather\n // than acting as a role — see the role derivation below.\n const variantMatch = t.variantSlug\n ? byVariant.get(`${t.characterSlug}:${t.variantSlug}`)\n : undefined\n const match = variantMatch ?? bySlug.get(t.characterSlug)\n if (!match || !match.url) continue\n additionalUrls.push(match.url)\n mentionedCharacterSlugs.add(t.characterSlug)\n refByUrl.set(match.url, match)\n if (t.lock !== undefined) lockOverrideByUrl.set(match.url, t.lock)\n // Variant + Role Separation: an explicit 4th-segment ROLE\n // (`@kira:1:walking:clothes`) wins outright and coexists with the variant —\n // the variant picked the image (variantMatch above), the role picks the\n // phrase. Used VERBATIM (curated or custom), mirroring the seg3 custom-role\n // relaxation below.\n const explicitRole = (t.role ?? \"\").trim()\n const segment = (t.usageMode ?? t.variantSlug ?? \"\").trim()\n // Custom roles survive VERBATIM (Unified Reference Roles, Phase D). A\n // non-empty segment is the role when it is a curated preset (face/pose/style\n // modes, person/clothes/… role-slugs) OR a free-form value typed in the\n // variant/role slot that did NOT resolve to a real matched variant URL (e.g.\n // `earrings`) — i.e. it's acting as a role, not selecting a variant. A real\n // variant slug (`smile`) and the directive-only usage modes (identical/\n // face-pose/emotion/name/none) fall back to the NODE default: the character\n // node's `defaultRole` (hybrid dropdown pick, verbatim) → its\n // `defaultUsageMode`-derived role → the source default (\"person\") — via\n // `resolveDefaultRole` (Character Node Role+Lock). Precedence: seg4 role →\n // seg3 token role → node defaultRole → defaultUsageMode-derived → source default.\n const role = explicitRole\n ? explicitRole\n : segment && (presets.includes(segment) || (t.usageMode == null && !variantMatch))\n ? segment\n : resolveDefaultRole(match.defaultRole, match.defaultUsageMode, \"wired-character\")\n matched.push({ token: t.token, offset: t.offset, url: match.url, role })\n }\n\n // Slot letters from the deduped [existing, mention] URL list — the prefix of\n // the caller's `finalIndexByUrl`, so the letters agree.\n const slotByUrl = new Map<string, number>()\n for (const u of [...existingUrls, ...additionalUrls]) {\n if (!slotByUrl.has(u)) slotByUrl.set(u, slotByUrl.size + 1)\n }\n const bindingFor = (url: string): string => {\n const slot = slotByUrl.get(url)\n return slot ? `reference image ${slotToLetter(slot)}` : \"the reference image\"\n }\n\n // Replace mention tokens right-to-left so earlier offsets stay valid;\n // `spliceMentionPhrase` also tidies the horizontal whitespace at each seam.\n let resolvedPrompt = prompt\n for (const m of [...matched].sort((a, b) => b.offset - a.offset)) {\n const phrase = roleToPhrase(m.role, bindingFor(m.url))\n resolvedPrompt = spliceMentionPhrase(resolvedPrompt, m.offset, m.token.length, phrase)\n }\n\n // One identity-lock + one element directive per UNIQUE attached URL (a\n // character mentioned N times attaches one URL → one lock / element line).\n const lockLines: string[] = []\n const elementDirectives: string[] = []\n const seenUrls = new Set<string>()\n for (const m of matched) {\n if (seenUrls.has(m.url)) continue\n seenUrls.add(m.url)\n const ref = refByUrl.get(m.url)\n if (!ref) continue\n const binding = bindingFor(m.url)\n const lock = buildIdentityLockLine(withForcedIdentityLock(ref, lockOverrideByUrl.get(m.url)), binding)\n if (lock) lockLines.push(lock)\n pushOverrideDirective(elementDirectives, ref, binding)\n const inject = ref.elementInjection?.trim()\n if (inject) elementDirectives.push(inject)\n }\n\n return { prompt: resolvedPrompt, additionalUrls, mentionedCharacterSlugs, lockLines, elementDirectives }\n}\n\nexport interface ResolveLocationMentionsResult {\n /** Prompt with `@location:N` tokens replaced by display names + a\n * \"Use these locations:\" directive prepended when at least one bullet\n * fires. */\n prompt: string\n /** Resolved URLs from matched mention tokens, in mention order. Caller\n * is responsible for deduping against the existing URL list (the same\n * contract as `resolveCharacterMentions.additionalUrls`). */\n additionalUrls: string[]\n /** Set of location slugs that had at least one resolved mention. Callers\n * use this to gate \"no mention → canonical fallback\" behavior (mirrors\n * the character flow — Phase 2 #1 attached the canonical URL via\n * `expandWiredLocationRefs` directly, but a future fallback path may\n * use this set to suppress the canonical URL once the user has explicitly\n * pinned a variant via @-mention). */\n mentionedLocationSlugs: Set<string>\n}\n\n/**\n * Per-mode directive text for a location bullet. Mirrors `usageModeDirective`\n * for characters but with the 4-mode location enum:\n * - identical: lock the scene to this exact image (used as background)\n * - style: borrow the look/mood/color palette\n * - layout: borrow the compositional layout / camera framing\n * - none: no bullet emitted (caller handles)\n */\nfunction locationModeDirective(mode: LocationUsageMode): string | null {\n switch (mode) {\n case \"identical\":\n return \"use as the background/setting — match the location exactly.\"\n case \"style\":\n return \"use as a style / mood reference — borrow color, lighting, and atmosphere.\"\n case \"layout\":\n return \"use as a compositional layout / camera framing reference.\"\n case \"none\":\n return null\n }\n}\n\n/**\n * Map a location usage-mode to its HYBRID reference role — the vocabulary\n * `roleToPhrase` renders into \"the {role} from reference image {LETTER}\". The\n * location analog of the character mention's role segment, for the 4-mode\n * location enum:\n * - identical → the source default (`\"location\"`) — lock the scene to this image\n * - style → \"style\" (borrow look / mood / palette)\n * - layout → \"layout\" (borrow compositional framing)\n * - none / undefined / anything else → the source default (`\"location\"`).\n *\n * A PLACE, NOT A BACKDROP — `identical` used to map to `\"background\"`, which is\n * the exact word `DEFAULT_LABEL_BY_SOURCE[\"wired-location\"]` stopped emitting on\n * 2026-08-05 after it was measured harmful: `roleToPhrase` renders it as \"the\n * background from reference image B\", and image models read that as *paste this\n * behind the subject* — on gpt-image-2 (character + location, 4 draws per arm,\n * only the role word varying) every `background` draw came back a cut-out\n * composite with no shared light and no ground contact, while `location` put the\n * subject inside the scene. That fix changed the SOURCE default but missed this\n * branch, so `identical` — the DEFAULT location usage mode\n * (`DEFAULT_LOCATION_USAGE_MODE`) — kept handing every un-roled location mention\n * the harmful word. Both defaults now read from `defaultRoleForSource`, so the\n * source default is the single source of truth and the two cannot drift again.\n * `\"background\"` stays a curated pick in `REFERENCE_ROLE_PRESETS` for the genuine\n * backdrop case — an explicit `@lib:1:background` token is untouched.\n *\n * Accepts a loose `string` so a `ConnectedReference.defaultUsageMode` (typed as\n * the CHARACTER `UsageMode`, which can't express `\"layout\"`) flows in without a\n * cast — unknown / non-location modes fall through to the safe source default\n * instead of throwing. The two mode-specific roles are members of\n * `REFERENCE_ROLE_PRESETS[\"wired-location\"]`, so the phrasing stays curated.\n */\nfunction locationModeToRole(mode: string | null | undefined): string {\n return roleBearingLocationMode(mode) ?? defaultRoleForSource(\"wired-location\")\n}\n\n/**\n * The ROLE a location usage mode expresses, or `null` when the mode expresses no\n * role opinion at all. Splits the 4-mode enum the way the character chain splits\n * `USAGE_MODES`: `style` / `layout` SAY what the reference is, while `identical`\n * (which IS `DEFAULT_LOCATION_USAGE_MODE`) and `none` are directive-only — they\n * say how the LEGACY bullet reads, not what the model should take from the\n * image. Only a role-bearing mode may outrank a ref-level `defaultRole`; see\n * `resolveLocationRole`.\n *\n * Data-driven rather than a hardcoded pair: a mode is role-bearing exactly when\n * it is itself a member of `REFERENCE_ROLE_PRESETS[\"wired-location\"]` — the same\n * test the location pill runs (`LOCATION_ROLE_PRESETS.includes(attrs.usageMode)`)\n * to decide whether a mode-slot value should surface as the pill's hybrid role,\n * and the same shape as the character resolver's `presets.includes(segment)`. A\n * mode added to both lists later is role-bearing on its own, with no list here\n * to remember to update.\n */\nfunction roleBearingLocationMode(mode: string | null | undefined): string | null {\n const m = mode?.trim()\n if (!m) return null\n return REFERENCE_ROLE_PRESETS[\"wired-location\"].includes(m) ? m : null\n}\n\n/**\n * The effective HYBRID role for a wired LOCATION reference — the location analog\n * of `resolveDefaultRole`, and the single source of truth for the location role\n * chain (read by the mention resolver AND the canonical-fallback renderer, so a\n * location cannot phrase itself one way mentioned and another way unmentioned).\n *\n * Precedence:\n * 1. the per-mention token ROLE (`@lib:1:atmosphere`, `@lib:1:x/y:lighting`) —\n * verbatim, slug-normalized so the non-noun specials still hit\n * (`empty-background` → `empty background`).\n * 2. the per-mention token MODE, but ONLY when it is ROLE-BEARING\n * (`@lib:1:style`, `@lib:1:layout` — `roleBearingLocationMode`).\n * 3. the ref's own `defaultRole` — the node/caller's hybrid role pick, same\n * slug normalization as (1).\n * 4. the ref's legacy `defaultUsageMode` → `locationModeToRole`.\n * 5. the source default (`locationModeToRole`'s fallback — `\"location\"`).\n *\n * Step 2 is GATED for the same reason the character chain gates its segment on\n * `presets.includes(segment)`: `identical` and `none` express no role opinion —\n * `identical` IS `DEFAULT_LOCATION_USAGE_MODE`, the un-roled state, and the\n * location pill's `renderText` emits a mode segment whenever the attr is set, so\n * an ungated step 2 would let a round-tripped `@lib:1:identical` suppress the\n * very `defaultRole` this chain exists to honor — on the majority of real\n * tokens. A directive-only mode therefore falls THROUGH to the ref's role, the\n * same way a character's `identical` / `name` / `none` segment falls through to\n * `resolveDefaultRole`. With no `defaultRole` the outcome is unchanged\n * (`identical` → step 4 → the source default, `\"location\"`).\n *\n * Step 3 is what this exists for. `ConnectedReference.defaultRole` is on the\n * wire schema for EVERY source, and the character and named-image mention paths\n * have always consulted it via `resolveDefaultRole` — but the location paths\n * read only the usage mode, so a ref-level default role was silently dropped.\n * It is the ONLY channel a location has for a custom default role: a location\n * mention's 3rd segment is a bucket/variant or a role, so a caller cannot pin a\n * per-mention role AND keep the canonical image, and the character trick of a\n * 4th segment needs a variant to sit in the third. An explicit token role or\n * role-bearing mode still wins (steps 1–2); with no `defaultRole` the chain\n * collapses to exactly the old `t.usageMode ?? defaultUsageMode ?? DEFAULT`\n * derivation.\n */\nfunction resolveLocationRole(\n tokenRole: string | null | undefined,\n tokenUsageMode: string | null | undefined,\n ref: Pick<ConnectedReference, \"defaultRole\" | \"defaultUsageMode\">,\n): string {\n const explicitRole = tokenRole?.trim()\n if (explicitRole) return normalizeRoleSlug(explicitRole)\n const modeRole = roleBearingLocationMode(tokenUsageMode)\n if (modeRole) return modeRole\n const nodeRole = ref.defaultRole?.trim()\n if (nodeRole) return normalizeRoleSlug(nodeRole)\n return locationModeToRole(ref.defaultUsageMode ?? DEFAULT_LOCATION_USAGE_MODE)\n}\n\n/**\n * Resolve `@oldlibrary:1:weather/rain` mentions in the prompt against the\n * pre-expanded `wired-location` ConnectedReferences (from\n * `expandWiredLocationRefs` / `expandLocationNodeIntoRefs`). Mirrors\n * `resolveCharacterMentions` shape:\n *\n * 1. Look up the matching ref by `(locationSlug, bucket, variantSlug)`.\n * 2. Append its URL to `additionalUrls`.\n * 3. Substitute the inline token with the location's display name (or\n * `Image N` for \"none\" mode — image attached without textual bias).\n * 4. Emit a directive bullet under \"Use these locations:\" header, with\n * mode-specific verb. \"none\" mode suppresses the bullet (just like\n * character \"none\").\n *\n * Per-location single-bullet rule: each location emits AT MOST ONE bullet\n * (the first non-none mention \"claims\" the slot). Subsequent mentions of the\n * same location still produce inline substitution + URL but no additional\n * bullet, mirroring `resolveCharacterMentions.firstBulletEmittedFor`.\n *\n * Returns `additionalUrls` deduplication is the caller's responsibility,\n * matching the character contract.\n */\nexport function resolveLocationMentions(\n prompt: string,\n tokens: readonly LocationMentionTokenInfo[],\n refs: readonly ConnectedReference[],\n): ResolveLocationMentionsResult {\n // Build lookup maps: canonical (no variant) and per-(bucket/variant).\n const bySlug = new Map<string, ConnectedReference>()\n const byVariant = new Map<string, ConnectedReference>()\n for (const r of refs) {\n if (!r.locationSlug) continue\n if (!r.locationVariantBucket || !r.locationVariantSlug) {\n bySlug.set(r.locationSlug, r)\n } else {\n byVariant.set(\n `${r.locationSlug}:${r.locationVariantBucket}/${r.locationVariantSlug}`,\n r,\n )\n }\n }\n\n const additionalUrls: string[] = []\n const mentionedLocationSlugs = new Set<string>()\n const firstBulletEmittedFor = new Set<string>()\n const directiveLines: string[] = []\n const replacements: Array<{ token: string; offset: number; replacement: string }> = []\n\n for (const t of tokens) {\n // Bare-slug ROLE tokens (Unified Reference Roles, Phase D — e.g.\n // `@old-library:1:background` / `:atmosphere` / `:as-is` /\n // `:empty-background` / `:lighting`) are a HYBRID-only construct. The\n // additive parser now PARSES them (with `t.role` set, no bucket/variant),\n // but in the LEGACY path they must stay literal text exactly as they did\n // pre-Phase-D, when the parser returned null and the token fell through\n // untouched. Skipping here guarantees byte-identical legacy output: NO\n // inline replacement, NO bullet, NO attached URL, and crucially the slug is\n // NOT added to `mentionedLocationSlugs` — so a wired location still\n // auto-attaches via the unchanged non-character canonical path, just as\n // before. Role resolution lives in `resolveLocationMentionsHybrid`, which is\n // untouched. (`layout`/`style` set `usageMode`, not `role`, so they were\n // always modes and are unaffected.)\n if (t.role) continue\n\n const match = t.bucket && t.variant\n ? byVariant.get(`${t.locationSlug}:${t.bucket}/${t.variant}`)\n : bySlug.get(t.locationSlug)\n if (!match) continue\n\n additionalUrls.push(match.url)\n mentionedLocationSlugs.add(t.locationSlug)\n\n // Per-mention effective mode. Resolution order: per-mention slug override\n // → location node default (not yet plumbed; reserved for future) → global\n // DEFAULT_LOCATION_USAGE_MODE.\n const effectiveMode: LocationUsageMode =\n t.usageMode ?? DEFAULT_LOCATION_USAGE_MODE\n\n // Inline replacement of `@oldlibrary:1:weather/rain` in the user's\n // prompt. For \"none\" we substitute the bare positional reference so the\n // user's sentence reads \"set in Image 1\" — the image is attached, the\n // model sees the position label, but no name biases the textual prompt.\n // Every other mode keeps the location display name for natural prose.\n const displayName = bySlug.get(t.locationSlug)?.defaultName ?? t.locationSlug\n const replacement = effectiveMode === \"none\" ? `Image ${t.imageIndex}` : displayName\n replacements.push({ token: t.token, offset: t.offset, replacement })\n\n // Bullet emission. \"none\" skips entirely; other modes emit one bullet\n // per location on the first non-none mention.\n if (effectiveMode === \"none\") {\n continue\n }\n const isFirstBullet = !firstBulletEmittedFor.has(t.locationSlug)\n if (!isFirstBullet) continue\n firstBulletEmittedFor.add(t.locationSlug)\n\n const directive = locationModeDirective(effectiveMode)\n const subject = `Image ${t.imageIndex} (${displayName})`\n // Canonical-description injection. Mirrors the Phase 2 #1 behavior in\n // `buildIdentityDirective` — only emit for the \"identical\" mode where\n // the description (env, materials, mood) is on-task; \"style\" / \"layout\"\n // modes are about the look/composition and don't need the full\n // description noise.\n const includeCanonicalDesc = effectiveMode === \"identical\"\n const canonicalDesc = match.locationCanonicalDescription?.trim()\n // A per-use `descriptionOverride` IS the caller describing this place for\n // this run, so it fills the identity slot ahead of the location's stored\n // canonical description — and rides every mode that emits a bullet at all,\n // the same rule the character resolvers apply.\n const shownDesc = match.descriptionOverride?.trim()\n || (includeCanonicalDesc ? canonicalDesc : undefined)\n const descPart = shownDesc ? `${subject} — ${shownDesc}` : subject\n directiveLines.push(`- ${descPart}.${directive ? ` ${directive}` : \"\"}`)\n\n // Variant display-name sub-line: only when the user pinned a specific\n // variant. Distinct from `description` (the user-typed text on the\n // location node) — locationVariantDisplayName is the raw bucket name\n // like \"rain\" or \"neon\".\n if (\n t.bucket\n && t.variant\n && match.locationVariantDisplayName\n && match.locationVariantDisplayName !== \"canonical\"\n ) {\n directiveLines.push(` (in this image: ${match.locationVariantDisplayName})`)\n }\n }\n\n // Apply replacements right-to-left so offsets stay valid.\n let resolvedPrompt = prompt\n for (const r of [...replacements].sort((a, b) => b.offset - a.offset)) {\n resolvedPrompt = resolvedPrompt.slice(0, r.offset)\n + r.replacement\n + resolvedPrompt.slice(r.offset + r.token.length)\n }\n\n if (directiveLines.length > 0) {\n resolvedPrompt = `Use these locations:\\n${directiveLines.join(\"\\n\")}\\n\\n${resolvedPrompt}`\n }\n\n return { prompt: resolvedPrompt, additionalUrls, mentionedLocationSlugs }\n}\n\ninterface ResolveLocationMentionsHybridResult {\n /** Body with each `@location` mention replaced INLINE by its role phrase\n * (\"the {role} from reference image {LETTER}\"). No directive block. */\n prompt: string\n /** Matched location URLs in mention order (deduped by the caller). */\n additionalUrls: string[]\n /** Slugs that had at least one resolved mention. */\n mentionedLocationSlugs: Set<string>\n /** Per-reference opt-in identity-lock lines (deduped per URL). Locks are OFF\n * for locations by default — `buildIdentityLockLine` returns null unless the\n * ref sets `identityLock.enabled === true` with custom text (there is no\n * built-in wired-location lock wording). Caller prepends them as ONE block. */\n lockLines: string[]\n /** Non-empty `elementInjection` fragments (deduped per URL). Caller appends\n * them as trailing scene directives. */\n elementDirectives: string[]\n}\n\n/**\n * HYBRID-mode location mention convergence (Unified Reference Roles, Phase C).\n *\n * The location analog of `resolveCharacterMentionsHybrid`. Where the LEGACY\n * `resolveLocationMentions` (above) prepends a `\"Use these locations:\"` bullet\n * block + replaces `@location` tokens with display names, this renders each\n * mention as the inline role phrase `\"the {role} from reference image {LETTER}\"`\n * and surfaces the optional opt-in identity-lock + wired `elementInjection`\n * SEPARATELY (caller prepends one lock block, appends element directives). No\n * directive block is produced.\n *\n * MATCHING is byte-identical to the legacy resolver (variant-first, NO canonical\n * fallback on a variant miss) so the set of attached URLs / matched tokens never\n * diverges between formats — only the rendered phrasing differs.\n *\n * ROLE is `resolveLocationRole(t.role, t.usageMode, ref)` — per-mention role →\n * per-mention ROLE-BEARING mode (`style` / `layout`; the directive-only\n * `identical` / `none` fall through) → the ref's own `defaultRole` → its\n * `defaultUsageMode` → the source default. So a node whose default mode is\n * \"style\" renders \"the style from …\" for a bare `@old-library:1`, and one\n * carrying `defaultRole: \"atmosphere\"` renders \"the atmosphere from …\".\n *\n * SLOT/LETTER: a URL's 1-based position in `dedup([...existingUrls,\n * ...mentionUrls])`. The caller passes `existingUrls = [base refs, resolved\n * character mentions]` (location mentions are merged AFTER character mentions and\n * BEFORE the character canonical/extra URLs), so these letters are a prefix of —\n * and byte-identical to — the caller's final `finalIndexByUrl` for every location\n * URL.\n */\nfunction resolveLocationMentionsHybrid(\n prompt: string,\n tokens: readonly LocationMentionTokenInfo[],\n refs: readonly ConnectedReference[],\n existingUrls: readonly string[],\n): ResolveLocationMentionsHybridResult {\n const bySlug = new Map<string, ConnectedReference>()\n const byVariant = new Map<string, ConnectedReference>()\n for (const r of refs) {\n if (!r.locationSlug) continue\n if (!r.locationVariantBucket || !r.locationVariantSlug) {\n bySlug.set(r.locationSlug, r)\n } else {\n byVariant.set(`${r.locationSlug}:${r.locationVariantBucket}/${r.locationVariantSlug}`, r)\n }\n }\n\n const additionalUrls: string[] = []\n const mentionedLocationSlugs = new Set<string>()\n const refByUrl = new Map<string, ConnectedReference>()\n // Per-mention `~lock` / `~nolock` (Task 4 + F4): the tri-state lock OVERRIDE\n // per attached URL — `true` (force on, so a location lock line appears even\n // though location locks default OFF) / `false` (force off, suppressing a\n // ref-level enabled lock) / absent (inherit). Fed to `withForcedIdentityLock`\n // below. Only sentinel-bearing mentions write here (last sentinel wins).\n const lockOverrideByUrl = new Map<string, boolean>()\n const matched: Array<{ token: string; offset: number; url: string; role: string }> = []\n\n for (const t of tokens) {\n // Variant-first, canonical-fallback-FREE (ternary, NOT `??`) — identical to\n // the legacy resolver so the matched URL set never diverges between formats.\n const match = t.bucket && t.variant\n ? byVariant.get(`${t.locationSlug}:${t.bucket}/${t.variant}`)\n : bySlug.get(t.locationSlug)\n if (!match || !match.url) continue\n additionalUrls.push(match.url)\n mentionedLocationSlugs.add(t.locationSlug)\n refByUrl.set(match.url, match)\n if (t.lock !== undefined) lockOverrideByUrl.set(match.url, t.lock)\n // A bare-slug ROLE (Unified Reference Roles, Phase D — e.g. `background`,\n // `empty-background`, `as-is`, or a curated custom role) is used VERBATIM:\n // it's acting as a role, not selecting a bucket/variant. With no role\n // segment, the chain falls through the token's ROLE-BEARING mode, then the\n // REF's own `defaultRole`, then its usage mode — see `resolveLocationRole`.\n const role = resolveLocationRole(t.role, t.usageMode, match)\n matched.push({ token: t.token, offset: t.offset, url: match.url, role })\n }\n\n // Slot letters from the deduped [existing, mention] URL list — the prefix of\n // the caller's `finalIndexByUrl`, so the letters agree.\n const slotByUrl = new Map<string, number>()\n for (const u of [...existingUrls, ...additionalUrls]) {\n if (!slotByUrl.has(u)) slotByUrl.set(u, slotByUrl.size + 1)\n }\n const bindingFor = (url: string): string => {\n const slot = slotByUrl.get(url)\n return slot ? `reference image ${slotToLetter(slot)}` : \"the reference image\"\n }\n\n // Replace mention tokens right-to-left so earlier offsets stay valid;\n // `spliceMentionPhrase` also tidies the horizontal whitespace at each seam.\n let resolvedPrompt = prompt\n for (const m of [...matched].sort((a, b) => b.offset - a.offset)) {\n const phrase = roleToPhrase(m.role, bindingFor(m.url))\n resolvedPrompt = spliceMentionPhrase(resolvedPrompt, m.offset, m.token.length, phrase)\n }\n\n // One opt-in lock + one element directive per UNIQUE attached URL.\n const lockLines: string[] = []\n const elementDirectives: string[] = []\n const seenUrls = new Set<string>()\n for (const m of matched) {\n if (seenUrls.has(m.url)) continue\n seenUrls.add(m.url)\n const ref = refByUrl.get(m.url)\n if (!ref) continue\n const binding = bindingFor(m.url)\n const lock = buildIdentityLockLine(withForcedIdentityLock(ref, lockOverrideByUrl.get(m.url)), binding)\n if (lock) lockLines.push(lock)\n pushOverrideDirective(elementDirectives, ref, binding)\n const inject = ref.elementInjection?.trim()\n if (inject) elementDirectives.push(inject)\n }\n\n return { prompt: resolvedPrompt, additionalUrls, mentionedLocationSlugs, lockLines, elementDirectives }\n}\n\ninterface ResolveImageMentionsHybridResult {\n /** Body with each `@<image-name>` mention replaced INLINE by its role phrase\n * (\"the {role} from reference image {LETTER}\", or the bare binding when the\n * role resolves to the media default `\"\"`). No directive block. */\n prompt: string\n /** Matched image URLs in mention order (deduped by the caller). */\n additionalUrls: string[]\n /** NO `mentionedImageSlugs` — the location result's analog exists to FILTER\n * mentioned refs out of `connectedReferences`, and this pass deliberately\n * does no such filtering (see the caller's NOTE). Carrying the set anyway\n * would advertise a filter that does not exist. */\n /**\n * The URLs a mention BOUND (deduped). This pass already surfaced each bound\n * ref's per-use `descriptionOverride` as its own trailing line, so the\n * caller's untold-override sweep skips them — the same by-URL suppression\n * contract `resolveEntityMentionsHybrid` carries, for the same reason: told\n * once, never twice.\n */\n mentionedUrls: Set<string>\n /** Per-reference identity-lock lines (deduped per URL). Caller prepends them\n * as ONE block, merged with the character/location lock lines. */\n lockLines: string[]\n /** Non-empty `elementInjection` fragments (deduped per URL). Caller appends\n * them as trailing scene directives. */\n elementDirectives: string[]\n}\n\n/**\n * HYBRID named-image mention convergence (P3). The media analog of\n * `resolveLocationMentionsHybrid`, for `wired-image` / `manual` references\n * addressed by the slug of their `defaultName` (an upload node's label on the\n * canvas, or the name a thin client puts on the reference).\n *\n * ASYMMETRY vs. characters and locations: a media ref AUTO-ATTACHES its URL\n * through the New path whether or not it is mentioned, and carries NO canonical\n * prose. So a mention here is BINDING + RE-SEATING, never attach-gating — which\n * is why the caller does NOT filter mentioned refs out of `connectedReferences`\n * the way the location pass does.\n *\n * NO LEGACY COUNTERPART. The Phase-0 arm that reaches this is hybrid-gated, so\n * an `@name:N` token under the legacy reference format stays literal text and\n * the ref attaches exactly as it does today (the `resolveLocationMentions`\n * role-token precedent, where `if (t.role) continue` leaves the token alone).\n *\n * DUPLICATE SLUGS: FIRST WINS (`if (!bySlug.has(...))`), matching\n * `buildTileIdForUrl`. Every unrenamed upload node shares its default label, so\n * ties are the common case, not an edge.\n *\n * ROLE precedence: the per-mention 3rd segment (VERBATIM — media role presets\n * are all single-word, so `normalizeRoleSlug` is location-only and must NOT be\n * called here) → the node default via `resolveDefaultRole` → `\"\"`, which\n * `roleToPhrase` renders as the BARE binding (\"reference image C\"), i.e. today's\n * ref-only default with a name attached to it.\n *\n * CAPPED REFS: `imageReferenceLimit(provider)` truncates `connectedReferences`\n * BEFORE Phase 0, so a mention whose ref was capped out silently falls through\n * as literal text — matching how a capped character mention behaves today.\n */\nfunction resolveImageMentionsHybrid(\n prompt: string,\n tokens: readonly ImageMentionTokenInfo[],\n refs: readonly ConnectedReference[],\n existingUrls: readonly string[],\n): ResolveImageMentionsHybridResult {\n const bySlug = new Map<string, ConnectedReference>()\n for (const r of refs) {\n // `imageMentionSlugForRef` is the SAME predicate `knownImageSlugsFromRefs`\n // applies to build the finder's known-slug set — one gate, so this map and\n // that set can never admit different refs. (It also drops extras, which\n // render through `renderExtraRefsHybrid` with their own body lines, and\n // grammar-invalid slugs, where emptiness is NOT the gate.)\n const slug = imageMentionSlugForRef(r)\n if (!slug) continue\n if (!bySlug.has(slug)) bySlug.set(slug, r)\n }\n\n const additionalUrls: string[] = []\n const refByUrl = new Map<string, ConnectedReference>()\n // Per-mention `~lock` / `~nolock`: the tri-state lock OVERRIDE per attached\n // URL, fed to `withForcedIdentityLock` below. Only sentinel-bearing mentions\n // write here (last sentinel wins), mirroring the location resolver.\n const lockOverrideByUrl = new Map<string, boolean>()\n const matched: Array<{ token: string; offset: number; url: string; role: string }> = []\n\n for (const t of tokens) {\n const match = bySlug.get(t.imageSlug)\n if (!match || !match.url) continue\n additionalUrls.push(match.url)\n refByUrl.set(match.url, match)\n if (t.lock !== undefined) lockOverrideByUrl.set(match.url, t.lock)\n const role = (t.role ?? \"\").trim()\n || resolveDefaultRole(match.defaultRole, match.defaultUsageMode, match.source)\n matched.push({ token: t.token, offset: t.offset, url: match.url, role })\n }\n\n // Slot letters from the deduped [existing, mention] URL list — the prefix of\n // the caller's `finalIndexByUrl`, so the letters agree.\n const slotByUrl = new Map<string, number>()\n for (const u of [...existingUrls, ...additionalUrls]) {\n if (!slotByUrl.has(u)) slotByUrl.set(u, slotByUrl.size + 1)\n }\n const bindingFor = (url: string): string => {\n const slot = slotByUrl.get(url)\n return slot ? `reference image ${slotToLetter(slot)}` : \"the reference image\"\n }\n\n // Replace mention tokens right-to-left so earlier offsets stay valid;\n // `spliceMentionPhrase` also tidies the horizontal whitespace at each seam.\n let resolvedPrompt = prompt\n for (const m of [...matched].sort((a, b) => b.offset - a.offset)) {\n const phrase = roleToPhrase(m.role, bindingFor(m.url))\n resolvedPrompt = spliceMentionPhrase(resolvedPrompt, m.offset, m.token.length, phrase)\n }\n\n // One lock + one element directive per UNIQUE attached URL.\n const lockLines: string[] = []\n const elementDirectives: string[] = []\n const seenUrls = new Set<string>()\n for (const m of matched) {\n if (seenUrls.has(m.url)) continue\n seenUrls.add(m.url)\n const ref = refByUrl.get(m.url)\n if (!ref) continue\n const binding = bindingFor(m.url)\n const lock = buildIdentityLockLine(withForcedIdentityLock(ref, lockOverrideByUrl.get(m.url)), binding)\n if (lock) lockLines.push(lock)\n pushOverrideDirective(elementDirectives, ref, binding)\n const inject = ref.elementInjection?.trim()\n if (inject) elementDirectives.push(inject)\n }\n\n return { prompt: resolvedPrompt, additionalUrls, mentionedUrls: seenUrls, lockLines, elementDirectives }\n}\n\ninterface ResolveEntityMentionsHybridResult {\n /** Body with each `@<entity-name>` mention replaced INLINE by its role phrase\n * (\"the creature from reference image D\", \"the material from reference image\n * B\", …). No directive block. */\n prompt: string\n /** Matched entity URLs in mention order (deduped by the caller). */\n additionalUrls: string[]\n /**\n * The URLs a mention BOUND — fed into `renderObjectCreatureCanonicalHybrid`'s\n * `coveredUrls` so the ref's trailing canonical phrase is SUPPRESSED. This is\n * the whole point of the pass: without it the same reference would render\n * twice, once inline and once as the dangling trailing line the mention exists\n * to replace. Distinct from `additionalUrls` only in being a set — kept as its\n * own field so the suppression contract is explicit at both ends.\n */\n mentionedUrls: Set<string>\n /** Per-reference identity-lock lines (deduped per URL). Caller prepends them\n * as ONE block, merged with the character/location/image lock lines. */\n lockLines: string[]\n /** Non-empty `elementInjection` fragments (deduped per URL). Caller appends\n * them as trailing scene directives. */\n elementDirectives: string[]\n}\n\n/**\n * HYBRID wired-entity mention convergence — the `wired-creature` /\n * `wired-object` analog of `resolveImageMentionsHybrid`, for entities addressed\n * by the slug of their `defaultName`.\n *\n * THE BUG THIS KILLS. An unmentioned creature renders through\n * `renderObjectCreatureCanonicalHybrid` as a TRAILING phrase — \"the creature\n * from reference image D\" — appended after the scene and the style hints, while\n * the creature's name sits in the prose as plain text the model has no reason to\n * connect to a reference. A mention binds the two: the phrase renders INLINE at\n * the typed position, and this pass's `mentionedUrls` suppresses the trailing\n * fallback for that ref.\n *\n * ASYMMETRY vs. images, and why suppression is needed here but not there: a\n * media ref carries NO canonical prose, so the image pass has nothing to\n * suppress. A creature/object DOES, so this pass must hand its bound URLs to the\n * canonical renderer's `coveredUrls` — exactly the mechanism that already stops\n * an `{image:N}`-token-referenced entity from double-rendering.\n *\n * NOT a `connectedReferences` FILTER, matching the image pass and unlike the\n * location pass: the ref stays in the list so `nonCharacterRefs[N-1]` positional\n * indexing for `{image:N}` tokens is unperturbed and the New-path URL merge keeps\n * the ref's earlier Phase-0 slot (the merge dedups by URL). Suppression is\n * coveredUrls-only.\n *\n * PRECEDENCE. The caller runs this AFTER the character, location and image\n * passes, each of which has already spliced its own tokens out — so a name shared\n * with an earlier kind never reaches this pass (character → location → image →\n * creature → object). The creature-before-object tail is settled HERE, in the\n * slug → ref map: creature refs are inserted first, so a name claimed by both a\n * creature and an object binds the CREATURE.\n *\n * DUPLICATE SLUGS within a kind: FIRST WINS, matching the image pass.\n *\n * ROLE precedence: the per-mention 3rd segment (VERBATIM — both entity preset\n * lists are single-word, so `normalizeRoleSlug` stays location-only and must NOT\n * be called here) → the ref's own `defaultRole`, then its `defaultUsageMode`, via\n * the SHARED `resolveDefaultRole` helper → the SOURCE default (`\"creature\"` /\n * `\"object\"`).\n *\n * ONE HELPER, NOT A COPY. `resolveDefaultRole` is the same chain the character\n * and named-image resolvers run, and `ConnectedReference.defaultRole` is a wire\n * field on EVERY source (see its doc in `types.ts`), so an entity ref's role pick\n * is honored here for free. The LOCATION paths need their own `resolveLocationRole`\n * only because a location token carries a MODE segment whose role-bearing members\n * (`style` / `layout`) sit between the token role and the ref's `defaultRole`, and\n * because location roles are slug-normalized; an entity token has no mode segment\n * (`EntityMentionTokenInfo` is role + lock only) and no multi-word roles, so there\n * is no gate to replicate and an entity analog of that helper would be two copies\n * of one chain.\n *\n * That LAST step is the one `renderObjectCreatureCanonicalHybrid` would also have\n * used for the trailing line — but only that one: the canonical renderer reads\n * `defaultRoleForSource(r.source)` and ignores `defaultRole` / `defaultUsageMode`\n * entirely. So a bare `@nessie:4` relocates the IDENTICAL phrase only when the ref\n * carries neither node field; with a node default the mention honors it and the\n * phrase CHANGES (\"the anatomy from …\" rather than \"the creature from …\"). That is\n * deliberate — it is what `resolveCharacterMentionsHybrid` and\n * `resolveImageMentionsHybrid` do, and it is pinned by\n * `entity-convergence-image.test.ts`. Suppression is\n * unaffected either way: the mention pass covers the same URL and emits the same\n * lock line (modulo a `~lock`/`~nolock` sentinel) and the same `elementInjection`.\n *\n * NO LEGACY COUNTERPART — the image-grammar precedent. The Phase-0 arm that\n * reaches this is hybrid-gated, so under the legacy reference format an\n * `@name:N` token stays literal text and the entity attaches with its numbered\n * directive exactly as it does today.\n *\n * CAPPED REFS: `imageReferenceLimit(provider)` truncates `connectedReferences`\n * BEFORE Phase 0, so a mention whose ref was capped out silently falls through as\n * literal text — matching how a capped character or image mention behaves today.\n */\nfunction resolveEntityMentionsHybrid(\n prompt: string,\n tokens: readonly EntityMentionTokenInfo[],\n refs: readonly ConnectedReference[],\n existingUrls: readonly string[],\n): ResolveEntityMentionsHybridResult {\n const bySlug = new Map<string, ConnectedReference>()\n // Creature-first insertion IS the creature → object half of the precedence\n // chain (the other four steps are the caller's pass order). `entityMentionSlug\n // ForRef` is the SAME predicate `knownEntitySlugsFromRefs` applies to build the\n // finder's known-slug set — one gate, so this map and that set can never admit\n // different refs.\n for (const source of [\"wired-creature\", \"wired-object\"] as const) {\n for (const r of refs) {\n if (r.source !== source) continue\n const slug = entityMentionSlugForRef(r)\n if (!slug) continue\n if (!bySlug.has(slug)) bySlug.set(slug, r)\n }\n }\n\n const additionalUrls: string[] = []\n const mentionedUrls = new Set<string>()\n const refByUrl = new Map<string, ConnectedReference>()\n // Per-mention `~lock` / `~nolock`: the tri-state lock OVERRIDE per attached\n // URL, fed to `withForcedIdentityLock` below. Only sentinel-bearing mentions\n // write here (last sentinel wins), mirroring the image/location resolvers.\n const lockOverrideByUrl = new Map<string, boolean>()\n const matched: Array<{ token: string; offset: number; url: string; role: string }> = []\n\n for (const t of tokens) {\n const match = bySlug.get(t.entitySlug)\n if (!match || !match.url) continue\n additionalUrls.push(match.url)\n mentionedUrls.add(match.url)\n refByUrl.set(match.url, match)\n if (t.lock !== undefined) lockOverrideByUrl.set(match.url, t.lock)\n const role = (t.role ?? \"\").trim()\n || resolveDefaultRole(match.defaultRole, match.defaultUsageMode, match.source)\n matched.push({ token: t.token, offset: t.offset, url: match.url, role })\n }\n\n // Slot letters from the deduped [existing, mention] URL list — the prefix of\n // the caller's `finalIndexByUrl`, so the letters agree.\n const slotByUrl = new Map<string, number>()\n for (const u of [...existingUrls, ...additionalUrls]) {\n if (!slotByUrl.has(u)) slotByUrl.set(u, slotByUrl.size + 1)\n }\n const bindingFor = (url: string): string => {\n const slot = slotByUrl.get(url)\n return slot ? `reference image ${slotToLetter(slot)}` : \"the reference image\"\n }\n\n // Replace mention tokens right-to-left so earlier offsets stay valid;\n // `spliceMentionPhrase` also tidies the horizontal whitespace at each seam —\n // an entity chip serializes with its own trailing space exactly like every\n // other mention chip, so its seams get the same collapse as the character,\n // location and named-image ones.\n let resolvedPrompt = prompt\n for (const m of [...matched].sort((a, b) => b.offset - a.offset)) {\n const phrase = roleToPhrase(m.role, bindingFor(m.url))\n resolvedPrompt = spliceMentionPhrase(resolvedPrompt, m.offset, m.token.length, phrase)\n }\n\n // One lock + one element directive per UNIQUE attached URL. These are the\n // SAME lines `renderObjectCreatureCanonicalHybrid` would have emitted for the\n // ref, moved here — which is why suppressing its canonical entry does not lose\n // an opt-in lock or a wired `elementInjection`.\n const lockLines: string[] = []\n const elementDirectives: string[] = []\n const seenUrls = new Set<string>()\n for (const m of matched) {\n if (seenUrls.has(m.url)) continue\n seenUrls.add(m.url)\n const ref = refByUrl.get(m.url)\n if (!ref) continue\n const binding = bindingFor(m.url)\n const lock = buildIdentityLockLine(withForcedIdentityLock(ref, lockOverrideByUrl.get(m.url)), binding)\n if (lock) lockLines.push(lock)\n pushOverrideDirective(elementDirectives, ref, binding)\n const inject = ref.elementInjection?.trim()\n if (inject) elementDirectives.push(inject)\n }\n\n return { prompt: resolvedPrompt, additionalUrls, mentionedUrls, lockLines, elementDirectives }\n}\n\n/**\n * Build the canonical-fallback directive lines + URLs for wired characters\n * that were NOT @-mentioned in the prompt. Matches the pre-mention behavior:\n * a character wired to a generator without any `@-mention` still contributes\n * its default URL + a strong identity directive, so users who wire a single\n * character without typing anything get the same result they did before the\n * `@-mention` feature shipped.\n *\n * Returns directive lines (matching `resolveCharacterMentions`'s format) and\n * canonical URLs (variantSlug === undefined entries only) keyed by\n * `characterSlug`, deduped. Callers prepend the directives + merge the URLs.\n *\n * Numbering: each emitted line is prefixed with `Image N (Name) — …` where\n * N is the position of this canonical URL in the final `referenceImageUrls`\n * list. The caller passes `startIndex` (1-based) for the first canonical\n * URL; subsequent canonical URLs get `startIndex + 1`, `+ 2`, etc.\n *\n * Without the numeric prefix the model has no way to link \"Image 1\" in its\n * input array to the directive bullet \"shira — young woman…\" — which led\n * users to see uncorrelated directives and ungrouped reference images.\n */\nfunction buildCanonicalFallback(\n refs: readonly ConnectedReference[],\n mentionedSlugs: ReadonlySet<string>,\n startIndex: number,\n): { directiveLines: string[]; urls: string[] } {\n const directiveLines: string[] = []\n const urls: string[] = []\n const seenSlugs = new Set<string>()\n let cursor = startIndex\n for (const r of refs) {\n if (r.source !== \"wired-character\") continue\n if (!r.characterSlug) continue\n if (mentionedSlugs.has(r.characterSlug)) continue\n if (seenSlugs.has(r.characterSlug)) continue\n // Canonical entry only — never auto-attach a variant for an unmentioned\n // character. Multiple wired characters each contribute one canonical\n // URL + one directive, mirroring the legacy auto-attach behavior.\n if (r.variantSlug) continue\n if (!r.url) continue\n seenSlugs.add(r.characterSlug)\n urls.push(r.url)\n const displayName = r.defaultName || r.characterSlug\n // Mode source: character node's `defaultUsageMode` (if set), else the\n // global `DEFAULT_USAGE_MODE` (\"identical\"). Without a slug-level\n // override available here (the user hasn't @-mentioned this character),\n // the node's default is the only signal — preserves the legacy \"match\n // exactly\" behavior when no default is configured.\n const effectiveMode: UsageMode = r.defaultUsageMode ?? DEFAULT_USAGE_MODE\n // Minimal-intervention modes:\n // - \"none\": URL is attached but NO bullet is emitted — the visual\n // speaks for itself, no textual bias.\n // - \"name\": one bullet with the name, no trailing directive — lets the\n // model correlate the position with a named entity without\n // prescribing usage.\n if (effectiveMode === \"none\") {\n // Bare URL attachment, no bullet — `cursor` still advances so any\n // downstream extras that pair-back via \"same subject as Image N\" see\n // the correct positional slot for this character.\n cursor += 1\n continue\n }\n if (effectiveMode === \"name\") {\n directiveLines.push(`- Image ${cursor} (${displayName})`)\n cursor += 1\n continue\n }\n const directive = usageModeDirective(effectiveMode)\n const includeCanonicalDesc =\n effectiveMode === \"identical\" || effectiveMode === \"face-pose\"\n // Subject line includes the numeric position so the model can correlate\n // \"Image N in the input array\" with the named character in the directive.\n const subject = `Image ${cursor} (${displayName})`\n // Wired elements (held-prop / styling / text) ride this bullet alongside\n // the (mode-gated) canonical description. This is the reported path — a\n // character wired with no @-mention — so a composed character surfaces its\n // elements wherever it's used downstream.\n // Per-use override ahead of the stored canonical description, mode-gate\n // included — same rule as the mention path above.\n const descPart = composeIdentityDescPart(\n subject,\n r.descriptionOverride?.trim()\n || (includeCanonicalDesc ? r.characterCanonicalDescription : undefined),\n r.elementInjection,\n )\n // `directive` is non-null here (\"none\"/\"name\" already short-circuited).\n directiveLines.push(`- ${descPart}.${directive ? ` ${directive}` : \"\"}`)\n cursor += 1\n }\n return { directiveLines, urls }\n}\n\n/**\n * Build directive lines + URLs for user-attached \"extra reference images\"\n * (entries with `isExtraRef === true`). Runs alongside `buildCanonicalFallback`\n * — both feed into the same \"Use these characters:\\n...\" block prepended to\n * the prompt.\n *\n * Numbering rule: starts at `nextImageIndex` (passed in by the caller — equal\n * to the count of already-emitted canonical fallback URLs + the count of\n * mention URLs) and increments by 1 per extra ref. The caller's URL merge\n * order must match this counter so \"Image N\" in the directive resolves to\n * the N-th URL in the final `referenceImageUrls` array.\n *\n * Per-extra directive shape:\n * - manual extra (source === \"manual\" + description set)\n * → `Image N (reference): <description>.`\n * - character extra (source === \"wired-character\" + characterSlug set\n * + description set) where the SAME `characterSlug` was already emitted\n * as a mention or canonical entry\n * → `Image N is the same subject as Image M, <description>.`\n * where M is the position of the earlier same-character image.\n * - character extra of a previously-unseen character (no canonical, no\n * mention) → emit a canonical-style directive (display name + mode\n * directive). Acts as the \"first sight\" attachment for that character.\n *\n * The caller is responsible for:\n * 1. Merging `urls` into `referenceImageUrls` in the same order as the\n * directive lines (so positions align).\n * 2. Concatenating `directiveLines` onto the existing \"Use these characters:\"\n * block (or creating a new one).\n *\n * `emittedCharacterPositions` is a map from characterSlug → position (1-based)\n * of the FIRST emitted image for that character. The caller pre-populates it\n * with positions from mentions + canonical fallback so that \"Image B is the\n * same subject as Image A\" can reference an earlier slot correctly.\n */\nfunction buildExtraRefDirectives(\n refs: readonly ConnectedReference[],\n emittedCharacterPositions: ReadonlyMap<string, number>,\n startIndex: number,\n): { directiveLines: string[]; urls: string[] } {\n const directiveLines: string[] = []\n const urls: string[] = []\n // Local copy of the position map so first-sight extras can be referenced by\n // later extras of the same character (e.g. two extras of Kira where the\n // first becomes \"Image M\" and the second pairs back to \"M\").\n const positionsByChar = new Map(emittedCharacterPositions)\n let cursor = startIndex\n for (const r of refs) {\n if (!r.isExtraRef) continue\n if (!r.url) continue\n // A per-use `descriptionOverride` fills THIS extra's description slot —\n // every branch below reads one `description`, so the override lands in the\n // pair-back tail, the name-mode bullet and the first-sight descriptor alike\n // (and, being the caller's own words, outranks the stored canonical too).\n const description = (r.descriptionOverride ?? \"\").trim()\n || (r.description ?? r.variantDescription ?? \"\").trim()\n // Character extra\n if (r.source === \"wired-character\" && r.characterSlug) {\n const effectiveMode: UsageMode = r.defaultUsageMode ?? DEFAULT_USAGE_MODE\n const earlierPos = positionsByChar.get(r.characterSlug)\n if (earlierPos !== undefined) {\n // Pair-back form. `Image N is the same subject as Image M, <desc>.`\n // Description is optional — when absent we still emit the pairing.\n // Minimal-intervention modes suppress even the pair-back bullet so\n // the user's \"don't bias with text\" intent extends to extras.\n if (effectiveMode !== \"none\") {\n const tail = description ? `, ${description}` : \"\"\n directiveLines.push(`- Image ${cursor} is the same subject as Image ${earlierPos}${tail}.`)\n }\n } else if (effectiveMode === \"none\") {\n // First sight of this character via an extra ref, but mode is \"none\".\n // Attach the URL, emit no bullet, record the position so any later\n // extras of the same character that pair-back land on the right slot.\n positionsByChar.set(r.characterSlug, cursor)\n } else if (effectiveMode === \"name\") {\n // \"Name only\" — labeled subject + the per-ref description (when\n // present), no trailing directive.\n const displayName = r.defaultName || r.characterSlug\n const subject = `Image ${cursor} (${displayName})`\n const descPart = description ? `${subject} — ${description}` : subject\n directiveLines.push(`- ${descPart}.`)\n positionsByChar.set(r.characterSlug, cursor)\n } else {\n // First sight of this character via an extra ref. Emit a canonical-style\n // directive — the description (or the character's canonical desc) is\n // the descriptive part, and the usage mode is whatever the caller\n // resolved onto `defaultUsageMode` (per-ref override → node default →\n // identical, applied when the ExtraRef was mapped to a ConnectedReference).\n const directive = usageModeDirective(effectiveMode)\n const displayName = r.defaultName || r.characterSlug\n const subject = `Image ${cursor} (${displayName})`\n const includeCanonicalDesc =\n effectiveMode === \"identical\" || effectiveMode === \"face-pose\"\n const canonicalDesc = r.characterCanonicalDescription?.trim()\n // Description preference: per-ref description > canonical (when mode\n // allows it) > nothing. The per-ref description is what the user\n // typed in the extra-ref row, so it always wins. The character's wired\n // elements (held-prop / styling) ride alongside whichever wins.\n const chosenDesc = description\n ? description\n : (includeCanonicalDesc ? canonicalDesc : undefined)\n const descPart = composeIdentityDescPart(subject, chosenDesc, r.elementInjection)\n directiveLines.push(`- ${descPart}.${directive ? ` ${directive}` : \"\"}`)\n positionsByChar.set(r.characterSlug, cursor)\n }\n } else {\n // Manual / generic extra. Description (when present) goes in the\n // parenthetical; absent description still emits a positional marker so\n // the URL position is unambiguous in the prompt.\n if (description) {\n directiveLines.push(`- Image ${cursor} (reference): ${description}.`)\n } else {\n directiveLines.push(`- Image ${cursor} (reference).`)\n }\n }\n urls.push(r.url)\n cursor += 1\n }\n return { directiveLines, urls }\n}\n\n// ---------------------------------------------------------------------------\n// HYBRID variants of the canonical-fallback + extra-ref directives (Unified\n// Reference Roles, Phase A — Task 4). Where the LEGACY builders above prepend a\n// \"Use these characters:\" bullet block with numeric \"Image N\" addressing, these\n// attach the SAME reference URLs but render each entry as an inline, lowercase\n// role phrase / pair-back directive bound to a lettered slot (\"reference image\n// A\"). Letters come from the caller's unified slot map (the same\n// `finalIndexByUrl` order as the rest of the hybrid path), so the numbering\n// agrees byte-for-byte. The legacy builders stay untouched.\n// ---------------------------------------------------------------------------\n\n/**\n * Select the unmentioned wired-character refs that contribute a canonical\n * fallback URL in hybrid mode. SELECTION ONLY — identical filtering to\n * `buildCanonicalFallback` (canonical entry only, deduped per `characterSlug`,\n * skipping @-mentioned slugs) so the two paths never disagree on WHICH\n * characters auto-attach; rendering happens in `renderCanonicalFallbackHybrid`\n * once the slot letters are known. Keep this filter in sync with\n * `buildCanonicalFallback`.\n */\nfunction selectCanonicalFallbackRefs(\n refs: readonly ConnectedReference[],\n mentionedSlugs: ReadonlySet<string>,\n): ConnectedReference[] {\n const out: ConnectedReference[] = []\n const seenSlugs = new Set<string>()\n for (const r of refs) {\n if (r.source !== \"wired-character\") continue\n if (!r.characterSlug) continue\n if (mentionedSlugs.has(r.characterSlug)) continue\n if (seenSlugs.has(r.characterSlug)) continue\n if (r.variantSlug) continue // never auto-attach a variant for an unmentioned char\n if (!r.url) continue\n seenSlugs.add(r.characterSlug)\n out.push(r)\n }\n return out\n}\n\n/**\n * Render the hybrid canonical fallback: each unmentioned wired character →\n * the inline role phrase `roleToPhrase(defaultRoleForSource(source), binding)`\n * (the caller appends these to the body as trailing scene directives) + its\n * opt-in identity-lock line (null by default — emitted only when the ref sets\n * `identityLock.enabled === true`) + its wired `elementInjection` (held-prop /\n * styling / text) as a trailing scene directive. `letterForUrl` maps the ref's\n * already-attached URL to its slot letter.\n *\n * `elementInjection` must NOT be silently dropped for an unmentioned character:\n * the legacy `buildCanonicalFallback` folds it into the bullet via\n * `composeIdentityDescPart`, and the hybrid MENTION path surfaces it via\n * `resolveCharacterMentionsHybrid`'s `elementDirectives`. We mirror the latter's\n * shape exactly (raw trimmed injection string, surfaced as its own trailing\n * line) so mentioned and unmentioned characters stay consistent in hybrid mode.\n */\nfunction renderCanonicalFallbackHybrid(\n refs: readonly ConnectedReference[],\n letterForUrl: (url: string) => string,\n): { phrases: string[]; lockLines: string[]; elementDirectives: string[] } {\n const phrases: string[] = []\n const lockLines: string[] = []\n const elementDirectives: string[] = []\n for (const r of refs) {\n const binding = `reference image ${letterForUrl(r.url)}`\n // Node-default role chain (Character Node Role+Lock): the character node's\n // `defaultRole` (hybrid dropdown pick, verbatim — Custom survives) → its\n // `defaultUsageMode`-derived role → the source default (\"person\"). This is\n // the MOST COMMON wiring (wired, not @-mentioned), which previously\n // hardcoded the source default and ignored the node entirely.\n phrases.push(roleToPhrase(resolveDefaultRole(r.defaultRole, r.defaultUsageMode, r.source), binding))\n const lock = buildIdentityLockLine(r, binding)\n if (lock) lockLines.push(lock)\n pushOverrideDirective(elementDirectives, r, binding)\n const inject = r.elementInjection?.trim()\n if (inject) elementDirectives.push(inject)\n }\n return { phrases, lockLines, elementDirectives }\n}\n\n/**\n * Render the hybrid extra-ref directives. Mirrors `buildExtraRefDirectives`'s\n * manual-vs-pair-back SHAPES, but with lettered bindings + lowercase phrasing\n * instead of \"Image N\":\n * - manual extra (with description) → \"<description> (reference image L).\"\n * - character extra, earlier sibling → \"reference image L is the same subject\n * as reference image M[, <desc>].\"\n * - character extra, first sight → role phrase [+ \", <desc>\"] + opt-in lock\n * + wired `elementInjection` (surfaced as\n * a SEPARATE trailing directive, mirroring\n * `renderCanonicalFallbackHybrid`).\n * `seedLetterByChar` carries each character's FIRST emitted letter from the\n * mention / canonical-fallback pass, so a picked-variant extra pairs back to the\n * earlier reference; first-sight extras record their own letter for any later\n * same-character extras. A description-less manual extra attaches its URL with\n * no directive (nothing to surface).\n *\n * `elementInjection` must NOT be silently dropped for a first-sight extra-ref\n * character: the legacy `buildExtraRefDirectives` folds it into the first-sight\n * bullet via `composeIdentityDescPart`, so the hybrid path surfaces the trimmed\n * injection as its own trailing line (same shape as the canonical / mention\n * paths). Only the FIRST-SIGHT branch attaches it — a pair-back extra references\n * an earlier image whose element directive was already emitted there.\n */\nfunction renderExtraRefsHybrid(\n extraRefs: readonly ConnectedReference[],\n letterForUrl: (url: string) => string,\n seedLetterByChar: ReadonlyMap<string, string>,\n): { bodyLines: string[]; lockLines: string[]; elementDirectives: string[] } {\n const bodyLines: string[] = []\n const lockLines: string[] = []\n const elementDirectives: string[] = []\n const firstLetterByChar = new Map(seedLetterByChar)\n for (const r of extraRefs) {\n if (!r.url) continue\n const letter = letterForUrl(r.url)\n const binding = `reference image ${letter}`\n // Per-use override fills the extras' own `, <desc>` clause — the one\n // description slot the hybrid format has (see `described-references.ts`).\n const description = (r.descriptionOverride ?? \"\").trim()\n || (r.description ?? r.variantDescription ?? \"\").trim()\n if (r.source === \"wired-character\" && r.characterSlug) {\n const earlier = firstLetterByChar.get(r.characterSlug)\n if (earlier !== undefined && earlier !== letter) {\n const tail = description ? `, ${description}` : \"\"\n bodyLines.push(`${binding} is the same subject as reference image ${earlier}${tail}.`)\n } else {\n // Role chain (Character Node Role+Lock): the node's `defaultRole`\n // (hybrid dropdown pick, VERBATIM — Custom survives; the expander only\n // stamps it when the extra carries no per-ref usageMode override) → the\n // COALESCED `defaultUsageMode`-derived role → the source default — via\n // the shared `resolveDefaultRole` helper.\n //\n // `defaultUsageMode` here is COALESCED (`expandExtraRefsToConnected-\n // References` folds per-ref `usageMode` → char-node default →\n // \"identical\"), so a character extra always carries a defined mode.\n // The VIDEO extras path (`video-reference-resolver.ts`) feeds the same\n // helper its own coalesced `effectiveMode` + `meta.defaultRole` — image\n // and video are fully converged (same helper, same precedence); pinned\n // by `character-convergence-image.test.ts`.\n const role = resolveDefaultRole(r.defaultRole, r.defaultUsageMode, r.source)\n const phrase = roleToPhrase(role, binding)\n bodyLines.push(description ? `${phrase}, ${description}.` : `${phrase}.`)\n const lock = buildIdentityLockLine(r, binding)\n if (lock) lockLines.push(lock)\n const inject = r.elementInjection?.trim()\n if (inject) elementDirectives.push(inject)\n firstLetterByChar.set(r.characterSlug, letter)\n }\n } else if (description) {\n bodyLines.push(`${description} (${binding}).`)\n }\n }\n return { bodyLines, lockLines, elementDirectives }\n}\n\n/**\n * Render the hybrid canonical convergence for UNMENTIONED wired locations (the\n * location analog of `renderCanonicalFallbackHybrid`). Each unmentioned\n * `wired-location` ref → the inline role phrase\n * `roleToPhrase(resolveLocationRole(null, null, ref), binding)` — the SAME role\n * chain the mention path runs, minus the token steps (the caller appends these as\n * trailing scene directives) + its opt-in identity-lock line\n * (null unless the ref enables one — locations have no built-in lock wording) +\n * its wired `elementInjection` as a trailing directive.\n *\n * Unlike characters — whose canonical URLs are merged in Phase 0 — unmentioned\n * locations flow through the New path's `nonCharacterRefs` / `finalIndexByUrl`,\n * so the slot letter is read straight from `finalIndexByUrl` (the single source\n * of truth for the assembled URL order). MENTIONED locations were already\n * converged inline in Phase 0 and filtered out of `nonCharacterRefs`, so they\n * never reach here. Deduped per URL to mirror `buildNonCharacterDirectives`'s\n * per-URL `coveredUrls` guard (a location wired twice → one phrase).\n *\n * `coveredUrls` is the set of URLs ALREADY expanded inline by an `{image:N}`\n * token in this hybrid scene (derived exactly as the legacy builder does — see\n * the call site). A location that is BOTH unmentioned AND `{image:N}`-token-\n * referenced is rendered ONCE (inline, via the scene); we `continue` here so it\n * is not ALSO emitted as a trailing canonical phrase (the C1 review Minor).\n *\n * `renderedUrls` reports the URLs that DID render here — and therefore already\n * carry their per-use `descriptionOverride` line — so the caller's untold-\n * override sweep skips them instead of re-deriving this loop's predicate.\n */\nfunction renderLocationCanonicalHybrid(\n nonCharacterRefs: readonly ConnectedReference[],\n finalIndexByUrl: ReadonlyMap<string, number>,\n coveredUrls: ReadonlySet<string>,\n): { phrases: string[]; lockLines: string[]; elementDirectives: string[]; renderedUrls: Set<string> } {\n const phrases: string[] = []\n const lockLines: string[] = []\n const elementDirectives: string[] = []\n const seenUrls = new Set<string>()\n for (const r of nonCharacterRefs) {\n if (r.source !== \"wired-location\") continue\n if (!r.url || seenUrls.has(r.url) || coveredUrls.has(r.url)) continue\n const slot = finalIndexByUrl.get(r.url)\n if (!slot) continue\n seenUrls.add(r.url)\n const binding = `reference image ${slotToLetter(slot)}`\n // Same role chain as the mention path (there is no token here, so it starts\n // at the ref's own `defaultRole`) — one helper, so a location cannot phrase\n // itself one way mentioned and another way unmentioned.\n phrases.push(roleToPhrase(resolveLocationRole(null, null, r), binding))\n const lock = buildIdentityLockLine(r, binding)\n if (lock) lockLines.push(lock)\n pushOverrideDirective(elementDirectives, r, binding)\n const inject = r.elementInjection?.trim()\n if (inject) elementDirectives.push(inject)\n }\n return { phrases, lockLines, elementDirectives, renderedUrls: seenUrls }\n}\n\n/**\n * Render the hybrid canonical convergence for UNMENTIONED wired objects /\n * creatures (the object/creature analog of `renderLocationCanonicalHybrid`).\n * Each unmentioned `wired-object` ref → \"the object from reference image\n * {LETTER}\"; each `wired-creature` → \"the creature from reference image\n * {LETTER}\" — via `roleToPhrase(defaultRoleForSource(source), binding)` (the\n * source-default role, mirroring `renderCanonicalFallbackHybrid` for characters,\n * not the location's mode-aware role) + its opt-in identity-lock line (null by\n * default — `wired-object` has no built-in lock wording at all; `wired-creature`\n * has wording but it is OFF unless `identityLock.enabled === true`, per Plan A's\n * default-off flip) + its wired `elementInjection` as a trailing directive.\n *\n * `coveredUrls` is every URL that ALREADY rendered inline in this scene, and it\n * carries TWO contributions the caller unions together: the URLs expanded by an\n * `{image:N}` token, and — since the creature/object mention leg — the URLs bound\n * by a Phase-0 `@creature` / `@object` mention. Either way the ref renders ONCE,\n * inline, never also as a trailing canonical phrase.\n *\n * The mention half is why this loop is NOT reached via a `connectedReferences`\n * filter the way mentioned locations are: an entity ref stays in the list to keep\n * `nonCharacterRefs[N-1]` positional `{image:N}` indexing stable, so suppression\n * has to happen HERE, per URL. The mention pass emits the same lock line and\n * `elementInjection` this loop would have, so nothing is lost by skipping it.\n *\n * Deduped per URL (an object wired twice → one phrase). `renderedUrls` reports\n * the URLs that DID render — already carrying their per-use\n * `descriptionOverride` line — for the caller's untold-override sweep.\n */\nfunction renderObjectCreatureCanonicalHybrid(\n nonCharacterRefs: readonly ConnectedReference[],\n finalIndexByUrl: ReadonlyMap<string, number>,\n coveredUrls: ReadonlySet<string>,\n): { phrases: string[]; lockLines: string[]; elementDirectives: string[]; renderedUrls: Set<string> } {\n const phrases: string[] = []\n const lockLines: string[] = []\n const elementDirectives: string[] = []\n const seenUrls = new Set<string>()\n for (const r of nonCharacterRefs) {\n if (r.source !== \"wired-object\" && r.source !== \"wired-creature\") continue\n if (!r.url || seenUrls.has(r.url) || coveredUrls.has(r.url)) continue\n const slot = finalIndexByUrl.get(r.url)\n if (!slot) continue\n seenUrls.add(r.url)\n const binding = `reference image ${slotToLetter(slot)}`\n phrases.push(roleToPhrase(defaultRoleForSource(r.source), binding))\n const lock = buildIdentityLockLine(r, binding)\n if (lock) lockLines.push(lock)\n pushOverrideDirective(elementDirectives, r, binding)\n const inject = r.elementInjection?.trim()\n if (inject) elementDirectives.push(inject)\n }\n return { phrases, lockLines, elementDirectives, renderedUrls: seenUrls }\n}\n\n/**\n * The per-use `descriptionOverride` of every non-character reference the hybrid\n * format renders NO role phrase for — the last leg of \"the override is honoured\n * wherever the reference ships\".\n *\n * Three kinds land here: a ref a `{image:N:label}` token expanded INLINE (the\n * expansion carries no description slot, and the covered set suppresses both\n * canonical renders), an unmentioned `wired-image` / `manual` / `wired-face` ref\n * (no canonical render exists for those sources at all), and any other seated\n * ref the passes above left unspoken. Each gets ONE\n * `reference image <LETTER> — <override>.` line, from the same helper every\n * other site uses, numbered against `finalIndexByUrl`.\n *\n * `toldUrls` is every URL a pass above ALREADY gave an override line — the two\n * canonical renders' `renderedUrls` plus the image / entity mention passes'\n * bound URLs — so a reference that is both @-mentioned and token-covered is told\n * once, never twice. A URL is marked swept only when it actually emitted a line,\n * so two refs sharing one URL where only the later carries an override still\n * speak.\n */\nfunction renderUntoldOverridesHybrid(\n nonCharacterRefs: readonly ConnectedReference[],\n finalIndexByUrl: ReadonlyMap<string, number>,\n toldUrls: ReadonlySet<string>,\n): string[] {\n const lines: string[] = []\n const sweptUrls = new Set<string>()\n for (const r of nonCharacterRefs) {\n if (!r.url || toldUrls.has(r.url) || sweptUrls.has(r.url)) continue\n const slot = finalIndexByUrl.get(r.url)\n if (!slot) continue\n const before = lines.length\n pushOverrideDirective(lines, r, `reference image ${slotToLetter(slot)}`)\n if (lines.length > before) sweptUrls.add(r.url)\n }\n return lines\n}\n\n/**\n * Per-character extra refs need to know which numbered slot the EARLIER\n * emitted image of the same character lives in. This helper walks the\n * URL-merge order built up by `buildImagePrompt` and returns the\n * `characterSlug → first-position` map used by `buildExtraRefDirectives`.\n *\n * The merge order matches `mergedUrls` in `buildImagePrompt`:\n * [pre-existing referenceImageUrls] + [resolved mentions] + [canonical fallback]\n * (followed by extras when this helper is consulted).\n *\n * For each URL in the merged list, we look up the originating\n * `ConnectedReference` to learn its `characterSlug`. The first time we see\n * a slug, we record its position; later same-slug images don't overwrite.\n */\n/**\n * Build a stable-tile-ID-per-URL mapping for the FINAL URL list emitted by\n * `buildImagePrompt`. Mirrors the scheme in `compute-injected-refs.ts` so the\n * frontend reorder UI and the backend `referenceOrder` sort agree.\n *\n * Used internally by `applyReferenceOrder` below. Kept as a separate helper\n * so the test in `prompt-builder.test.ts` can pin the ID scheme contract.\n *\n * Resolution order (first wins per URL):\n * 1. URL is a wired character variant whose @-mention is in `prompt` →\n * `mention:<slug>:<variant|canonical>`. Variant slug derived from the\n * mention token, NOT the ref's `variantSlug` — the same URL can match\n * multiple variants in edge cases, but the mention token is the\n * authoritative user-typed source.\n * 2. URL belongs to an `isExtraRef` entry → `wired:<id>` (the extra ref's\n * stable id, which the consumer panel keeps in sync with the row's id).\n * 3. URL is a non-character wired ref → `wired:<sourceNodeId>` via the\n * provided `sourceNodeIdById` map, falling back to `ref.id`.\n * 4. URL is a wired character canonical (no mention) → `char-canonical:<slug>`.\n *\n * URLs not matched by any of the above keep a null entry; they're sorted\n * stable after the matched URLs and don't participate in reorder.\n */\nfunction buildTileIdForUrl(\n urls: readonly string[],\n refs: readonly ConnectedReference[],\n prompt: string,\n sourceNodeIdById?: ReadonlyMap<string, string>,\n): Array<string | null> {\n // Build slug → mention's variant decision (the first time the mention\n // resolved per slug+variant): used to key mention URLs.\n const knownSlugs = Array.from(\n new Set(\n refs.map((r) => r.characterSlug).filter((s): s is string => Boolean(s)),\n ),\n )\n const mentionTokens = knownSlugs.length > 0\n ? findCharacterMentionTokens(prompt, knownSlugs)\n : []\n // url → tile id, populated only for mentioned variants.\n const mentionUrlToId = new Map<string, string>()\n const bySlug = new Map<string, ConnectedReference>()\n const byVariant = new Map<string, ConnectedReference>()\n for (const r of refs) {\n if (!r.characterSlug) continue\n if (!r.variantSlug) {\n if (!bySlug.has(r.characterSlug)) bySlug.set(r.characterSlug, r)\n } else {\n byVariant.set(`${r.characterSlug}:${r.variantSlug}`, r)\n }\n }\n for (const t of mentionTokens) {\n const match = t.variantSlug\n ? byVariant.get(`${t.characterSlug}:${t.variantSlug}`)\n : bySlug.get(t.characterSlug)\n if (!match?.url) continue\n if (!mentionUrlToId.has(match.url)) {\n mentionUrlToId.set(match.url, `mention:${t.characterSlug}:${t.variantSlug || \"canonical\"}`)\n }\n }\n\n // url → first matching ref (used for both canonical and wired-raw paths).\n const firstRefByUrl = new Map<string, ConnectedReference>()\n for (const r of refs) {\n if (!r.url) continue\n if (!firstRefByUrl.has(r.url)) firstRefByUrl.set(r.url, r)\n }\n\n return urls.map((url) => {\n const mentionId = mentionUrlToId.get(url)\n if (mentionId) return mentionId\n const ref = firstRefByUrl.get(url)\n if (!ref) return null\n // Extra refs use their stable id (set by the consumer panel).\n if (ref.isExtraRef) {\n return `wired:${sourceNodeIdById?.get(ref.id) ?? ref.id}`\n }\n if (ref.source === \"wired-character\" && ref.characterSlug) {\n // Canonical entry (no variant slug) when reached via the fallback path.\n // Variant entries are handled by the mention path above.\n if (!ref.variantSlug) {\n return `char-canonical:${ref.characterSlug}`\n }\n // A wired-character VARIANT URL with no mention shouldn't appear in the\n // final URL list under normal flow, but handle it defensively.\n return `mention:${ref.characterSlug}:${ref.variantSlug}`\n }\n // Non-character wired or manual entry.\n return `wired:${sourceNodeIdById?.get(ref.id) ?? ref.id}`\n })\n}\n\n/**\n * Reorder URLs by `referenceOrder` AND renumber `Image N` tokens in the\n * prompt to match. Returns the new URL list + the rewritten prompt. When\n * `referenceOrder` is empty / null / all-stale, the original URLs + prompt\n * are returned unchanged (no-op contract).\n *\n * Renumbering rule: build an `original-pos → new-pos` map from the URL move\n * indices, then regex-replace `Image N` substrings (word-boundary-anchored\n * so we don't touch \"Image 12\" while remapping \"Image 1\"). Done in one pass\n * via a callback that looks up each match in the map; unknown positions are\n * left as-is.\n *\n * NB: `findCharacterMentionTokens` is already applied BEFORE this step, so\n * any `@kira:1:smile` literals in the prompt have been replaced with display\n * names — only positional `Image N` markers remain to be remapped.\n *\n * Exposed (non-export internal) — also called by video branches in\n * payload-builder / execute-node via `applyReferenceOrderToVideo` so video\n * prompts honor the same reorder semantics as image prompts.\n */\nexport function applyReferenceOrderToVideo(\n urls: readonly string[],\n prompt: string | undefined,\n refs: readonly ConnectedReference[],\n referenceOrder: readonly string[] | undefined,\n sourceNodeIdById?: ReadonlyMap<string, string>,\n /**\n * Number of LEADING reference images (e.g. plain image-refs that precede the\n * asset URLs in the unified `@image_N` numbering — see\n * `resolveVideoReferenceCore`'s `leadingRefUrls`). `urls` here are the ASSET\n * URLs only; their prompt ordinals are `ordinalOffset + 1 …`, so the renumber\n * remap is keyed by the offset ordinal and leading ordinals (`1 … offset`)\n * pass through untouched. Defaults to 0 → behaviour unchanged.\n */\n ordinalOffset = 0,\n): { urls: string[]; prompt: string | undefined } {\n if (!referenceOrder || !referenceOrder.length || urls.length < 2) {\n return { urls: [...urls], prompt }\n }\n const reordered = applyReferenceOrder(\n urls,\n prompt ?? \"\",\n refs,\n referenceOrder,\n sourceNodeIdById,\n ordinalOffset,\n )\n return {\n urls: reordered.urls,\n prompt: prompt === undefined ? undefined : reordered.prompt,\n }\n}\n\nfunction applyReferenceOrder(\n urls: readonly string[],\n prompt: string,\n refs: readonly ConnectedReference[],\n referenceOrder: readonly string[],\n sourceNodeIdById?: ReadonlyMap<string, string>,\n ordinalOffset = 0,\n): { urls: string[]; prompt: string } {\n if (!referenceOrder.length) return { urls: [...urls], prompt }\n const tileIds = buildTileIdForUrl(urls, refs, prompt, sourceNodeIdById)\n // Map: tile id → original index in URLs array. Keeps first occurrence per\n // tile id (URLs are already deduped by `buildImagePrompt`'s merge step).\n const byTileId = new Map<string, number>()\n for (let i = 0; i < tileIds.length; i++) {\n const id = tileIds[i]\n if (id && !byTileId.has(id)) byTileId.set(id, i)\n }\n const newOrderIndices: number[] = []\n const seenIndices = new Set<number>()\n for (const id of referenceOrder) {\n const idx = byTileId.get(id)\n if (idx === undefined) continue\n if (seenIndices.has(idx)) continue\n newOrderIndices.push(idx)\n seenIndices.add(idx)\n }\n // Append URLs not in `referenceOrder` in their original order.\n for (let i = 0; i < urls.length; i++) {\n if (!seenIndices.has(i)) {\n newOrderIndices.push(i)\n seenIndices.add(i)\n }\n }\n // No-op check: if `newOrderIndices` is `[0, 1, 2, …]` we'd rebuild the same\n // arrays. Cheap to detect, lets us avoid the regex when the user hasn't\n // actually changed anything.\n let isNoop = newOrderIndices.length === urls.length\n for (let i = 0; isNoop && i < newOrderIndices.length; i++) {\n if (newOrderIndices[i] !== i) isNoop = false\n }\n if (isNoop) return { urls: [...urls], prompt }\n const newUrls = newOrderIndices.map((i) => urls[i])\n // Build orig-1based-pos → new-1based-pos map for prompt renumbering. Offset by\n // `ordinalOffset` so when `urls` are the ASSET tail of a unified list (leading\n // image-refs occupy `1 … ordinalOffset`), the asset ordinals `ordinalOffset+1 …`\n // remap among themselves and the leading ordinals are never matched (their keys\n // aren't in `remap`, so the regex leaves them untouched).\n const remap = new Map<number, number>()\n for (let newPos = 0; newPos < newOrderIndices.length; newPos++) {\n remap.set(ordinalOffset + newOrderIndices[newPos] + 1, ordinalOffset + newPos + 1)\n }\n // Replace every positional ordinal (1-3 digit, word-boundary) substring,\n // preserving its prefix: image prompts use `Image N`, video prompts use the\n // `@image_N` binding form (REF_BINDING.ordinal). The alternation is\n // case-exact (no `i` flag) so each form re-emits with the SAME prefix.\n // Negative lookahead on digits guards against `Image 12` → `Image 32` when\n // remapping 1 → 3. The lookbehind prevents catching `XImage 1` / `foo@image_1`.\n const renumbered = prompt.replace(/(?<![A-Za-z])(@image_|Image )(\\d{1,3})(?!\\d)/g, (whole, prefix, n) => {\n const orig = parseInt(n, 10)\n const next = remap.get(orig)\n if (next === undefined || next === orig) return whole\n return `${prefix}${next}`\n })\n return { urls: newUrls, prompt: renumbered }\n}\n\nfunction buildCharacterPositionMap(\n mergedUrls: readonly string[],\n refs: readonly ConnectedReference[],\n): Map<string, number> {\n const byUrl = new Map<string, ConnectedReference>()\n for (const r of refs) {\n if (!r.url) continue\n if (!byUrl.has(r.url)) byUrl.set(r.url, r)\n }\n const positions = new Map<string, number>()\n for (let i = 0; i < mergedUrls.length; i++) {\n const ref = byUrl.get(mergedUrls[i])\n const slug = ref?.characterSlug\n if (slug && !positions.has(slug)) {\n positions.set(slug, i + 1)\n }\n }\n return positions\n}\n\nexport interface BuildImagePromptConfig {\n /** Raw user prompt text */\n prompt: string\n /** Image provider key (e.g. \"nano-banana\", \"gpt-image\") */\n provider: string\n /** Style text to append (e.g. \"cinematic\") */\n style?: string\n /** Negative prompt text */\n negativePrompt?: string\n /** Character definitions selected for this node */\n characterDefs?: CharacterDef[]\n /** User-level prompt template overrides */\n userTemplates?: Record<string, string>\n /** Flow-level prompt template overrides */\n flowTemplates?: Record<string, string>\n /** Reference image URLs from direct connections, extracted refs, and character refs */\n referenceImageUrls?: string[]\n /** Ancestor reference image URLs (fallback when no direct refs exist) */\n ancestorRefs?: string[]\n /**\n * Rich connected-reference data. When provided, supersedes `characterDefs`\n * and `referenceImageUrls`: per-identity directives come from this list +\n * any `{image:N:label}` mentions in the prompt, URLs come from this list\n * in order, and tokens expand to \"the {label} from image {N}\".\n */\n connectedReferences?: ConnectedReference[]\n /**\n * References the caller can NAME and DESCRIBE but has no media for (an\n * un-bound cast role, an analysis slot). They attach no URL and claim no\n * `Image N` / lettered slot — they reach the model as prose, rendered once by\n * `renderDescribedReferenceLines` and joined the way the active format joins\n * its trailing directives. Present with NO `connectedReferences` is the normal\n * case (a story landing before any entity exists), so they enter the\n * connected-reference path on their own.\n */\n describedReferences?: readonly DescribedReference[]\n /** Per-identity (imageIndex+label) user overrides for fidelity / custom text. */\n identityMeta?: readonly IdentityMeta[]\n /**\n * Reference-prompt assembly format for the `{image:N:label}` connected-\n * reference (non-character) path. Additive + opt-in:\n * - \"legacy\" (default): the \"Use these references:/Compose them naturally:\"\n * wrap with numeric `Image N` directives — unchanged behavior.\n * - \"hybrid\": token expansion only — every `{image:N:label}` token → \"the\n * <label> from reference image <LETTER>\". NO lock snippet is auto-injected\n * (authors prepend their own). Images-only for now; characters/objects/\n * locations still render legacy. v1 skips `referenceOrder` renumbering.\n */\n referenceFormat?: \"legacy\" | \"hybrid\"\n /**\n * OPTIONAL reference-lock snippet to prepend ahead of the hybrid scene. Only\n * used when `referenceFormat === \"hybrid\"`. Nothing is prepended by default —\n * authors include their own lock snippet in the prompt text. Provide this only\n * if a caller wants to auto-prepend a lock.\n */\n referenceLockSnippet?: string\n /**\n * User-defined reorder of the injected reference list. Each entry is a\n * stable tile ID using the scheme from `compute-injected-refs.ts`:\n * - `wired:<sourceNodeId>` (a wired upstream — manual / wired-image /\n * wired-face / wired-object / wired-location / extra-ref)\n * - `mention:<characterSlug>:<variantSlug|canonical>` (an `@-mention`\n * resolved to a character variant URL)\n * - `char-canonical:<characterSlug>` (the auto-attached canonical\n * fallback for a wired character that the user did NOT `@-mention`)\n *\n * Behavior: after the existing assembly produces a URL list + a prompt\n * with `Image N` directives, the URLs are re-ordered to match this list\n * AND every `Image N` token in the prompt is renumbered consistently\n * (so directive bullets, the user's typed `Image N` references, and the\n * worker `referenceImageUrls` index all agree).\n *\n * IDs in this array that don't match any tile are silently dropped. Tiles\n * whose ID is NOT in this array fall to the end in their natural order.\n * Identical fixtures on frontend + backend MUST produce identical URL\n * lists — the helper is shared via `compute-injected-refs.ts`.\n *\n * Stable-ID-per-URL mapping for the post-assembly re-order is computed\n * from `connectedReferences` + the user's prompt; passing `referenceOrder`\n * is a no-op when `connectedReferences` is missing (legacy path).\n *\n * Optional, omit to keep the existing natural order.\n */\n referenceOrder?: readonly string[]\n /**\n * Map of `connectedReferences[i].id → sourceNodeId` so wired-raw tile IDs\n * match the upstream node IDs the consumer panel exposes. When omitted, the\n * builder falls back to `connectedReferences[i].id` (which equals the\n * upstream node ID for wired entries built by the existing image-configs +\n * payload-builder flow).\n */\n sourceNodeIdById?: ReadonlyMap<string, string>\n /**\n * Character slugs whose canonical-fallback the user has explicitly hidden\n * via the × button. Mention URLs for the same character still attach.\n */\n suppressedCanonicalCharacterIds?: readonly string[]\n /**\n * Location slugs (or DB ids) whose canonical-fallback the user has hidden\n * via the × button. Mirrors `suppressedCanonicalCharacterIds`: the upstream\n * `wired-location` ref still attaches, but the canonical establishing-shot\n * URL is dropped from the injected reference list.\n *\n * NOTE (Phase 1A): the location canonical-fallback path is wired up in a\n * follow-up PR (`injected-reference-helpers.ts`). Until then, this\n * parameter is accepted but inert — callers can pass it through without\n * any behavior change. Once the canonical-fallback logic lands, the\n * builder will filter `connectedReferences` with `source === \"wired-location\"`\n * and a matching slug, exactly like the character path does.\n */\n suppressedCanonicalLocationIds?: readonly string[]\n /**\n * When true, skip the entire mention-resolution block (character identity\n * directives, `Image N (Kira)` bullets, additional ref URLs from\n * `connectedReferences`) AND strip raw `@slug[:V[:variant]]` tokens from\n * the prompt. Used by the LoRA inference path\n * (`flux-lora-character`) — the trigger word + LoRA carries identity, so\n * the directive bullets are redundant and the wired-character refs\n * shouldn't be injected as `Image N`.\n *\n * The strip regex is grammar-agnostic — it eats LOCATION and named-IMAGE\n * mentions (`@town:3:background`) as well as character ones. That is\n * INTENDED, not an oversight: this path drops `connectedReferences` outright,\n * so there is no reference left for any mention to bind to and a surviving\n * token would reach the model as literal noise. Do not narrow it.\n */\n skipCharacterMentions?: boolean\n}\n\nexport interface BuildImagePromptResult {\n /** Final assembled prompt */\n prompt: string\n /** Native negative prompt (only for models that support it), undefined otherwise */\n nativeNegativePrompt: string | undefined\n /** Filtered reference image URLs (only for models that support them) */\n referenceImageUrls: string[] | undefined\n}\n\nexport type PromptSegmentOrigin =\n | \"user\" // typed by the user\n | \"variable\" // resolved {Node Label} value\n | \"picker\" // parameter-picker / cinematography fragment\n | \"mention\" // identity/reference directive block\n | \"style\" // auto-appended Style suffix\n | \"negative\" // auto-appended Avoid suffix\n\nexport interface PromptSegment {\n readonly text: string\n readonly origin: PromptSegmentOrigin\n}\n\nexport interface BuildImagePromptSegmentsResult extends BuildImagePromptResult {\n /** Origin-tagged decomposition of `prompt`. INVARIANT (tested):\n * segments.map(s => s.text).join(\"\") === prompt. */\n segments: PromptSegment[]\n}\n\n/**\n * Internal capture surface for `buildImagePromptSegments`. `buildImagePrompt`\n * itself never passes this — its output is byte-identical with or without it.\n * Each field records a span produced during final assembly so the segment\n * decomposition can be reconstructed without re-deriving the string:\n * - `directivesPrefix`: the directive block PREPENDED ahead of the user body\n * (connectedReferences path, \"Use these references…/Compose them…\" wrap).\n * Empty when the directive block was spliced mid-string into a Phase-0\n * \"Use these characters:\" block (documented degradation → body collapses).\n * - `bodyBeforeSuffixes`: the prompt string captured immediately BEFORE the\n * style/avoid suffixes were appended (covers the common no-truncation case).\n * - `styleSuffix` / `avoidSuffix`: the `\\nStyle: …` / `\\nAvoid: …` strings.\n * - `overflowChars`: how many characters the provider cap forced OFF the tail\n * (0 when the assembled prompt fit). Accumulated across every clamp site in\n * both assembly paths. Read by {@link buildImagePromptWithOverflow} so a\n * cap-aware caller can shed its own lowest-value text and re-assemble\n * instead of letting the order-blind tail cut decide.\n */\ninterface AssemblyMarks {\n directivesPrefix: string\n bodyBeforeSuffixes: string\n styleSuffix: string\n avoidSuffix: string\n overflowChars: number\n}\n\n/** Keep `bodySegments` when the assembled body still equals their join;\n * otherwise collapse to one `user` segment (assembly rewrote the body —\n * mention replacement, {image:N} expansion, truncation, or reorder). */\nfunction reconcileBodySegments(body: string, bodySegments: readonly PromptSegment[] | undefined): PromptSegment[] {\n if (!body) return []\n if (bodySegments && bodySegments.map((s) => s.text).join(\"\") === body) {\n return [...bodySegments]\n }\n return [{ text: body, origin: \"user\" }]\n}\n\n/**\n * The `Style:` / `Avoid:` control lines with the separator each one needs.\n *\n * They are self-labeling and stay at the very END of the prompt, which makes\n * them the only text that can still land under an open `[style]` header — the\n * section has no terminator, so a blank line is what closes its scope. `Avoid:`\n * reads the body WITH `Style:` already on it, so once the first control line has\n * closed the section the second rejoins on a single newline, exactly as before.\n *\n * Derived from the body they are appended to, because the cap's tail cut moves\n * that boundary. The cut can only NARROW the separator — the section is the last\n * block, so a cut either drops it entirely or lands inside it — which is what\n * lets the caller reserve on the pre-cut body and re-derive afterwards.\n */\nfunction controlSuffixes(\n body: string,\n styleLine: string,\n avoidLine: string,\n): { styleSuffix: string; avoidSuffix: string } {\n const separator = (text: string): string =>\n endsInsideStyleSection(text) ? STYLE_SECTION_GAP : \"\\n\"\n const styleSuffix = styleLine ? `${separator(body)}${styleLine}` : \"\"\n const avoidSuffix = avoidLine ? `${separator(body + styleSuffix)}${avoidLine}` : \"\"\n return { styleSuffix, avoidSuffix }\n}\n\n/**\n * Build the final image generation prompt from config.\n * Handles character description wrapping, style appending, negative prompt routing,\n * truncation, and reference image filtering.\n *\n * Thin passthrough over `buildImagePromptInternal` — byte-identical behavior,\n * no marks captured. Use `buildImagePromptSegments` when you also need the\n * origin-tagged decomposition.\n */\nexport function buildImagePrompt(config: BuildImagePromptConfig): BuildImagePromptResult {\n return buildImagePromptInternal(config)\n}\n\n/** {@link buildImagePrompt} plus `overflowChars`. */\nexport interface BuildImagePromptOverflowResult extends BuildImagePromptResult {\n /**\n * Characters the provider's prompt cap forced off the tail — `0` when the\n * assembled prompt fit. This is the amount of text that must LEAVE the body\n * for the prompt to fit without a tail cut, so a caller can shed exactly\n * enough of its own droppable text and re-assemble.\n */\n overflowChars: number\n}\n\n/**\n * `buildImagePrompt` plus the size of the cap overflow it had to clamp away.\n *\n * The prompt (and every other field) is BYTE-IDENTICAL to `buildImagePrompt` —\n * the marks channel only observes. Exists because the tail clamp is ORDER-BLIND:\n * it cuts whatever happens to be last, which on a low-cap provider can sever a\n * reference directive or the user's own prose while a decorative hint clause\n * survives. `assembleImageInput` uses this to drop its lowest-value text\n * (direction-folded hint clauses) FIRST and re-assemble; the clamp then stays\n * the last-resort fallback for a body that overflows on prose alone.\n */\nexport function buildImagePromptWithOverflow(\n config: BuildImagePromptConfig,\n): BuildImagePromptOverflowResult {\n const marks = newAssemblyMarks()\n const result = buildImagePromptInternal(config, marks)\n return { ...result, overflowChars: marks.overflowChars }\n}\n\n/** Fresh zeroed marks — one construction site so a new field can't be forgotten. */\nfunction newAssemblyMarks(): AssemblyMarks {\n return {\n directivesPrefix: \"\",\n bodyBeforeSuffixes: \"\",\n styleSuffix: \"\",\n avoidSuffix: \"\",\n overflowChars: 0,\n }\n}\n\n/**\n * Shared assembly body for `buildImagePrompt` + `buildImagePromptSegments`.\n * When `marks` is provided, records the directive-prefix / body / suffix spans\n * (guarded by `if (marks)`) so callers can reconstruct an origin-tagged\n * decomposition. The string output is identical regardless of `marks`.\n */\nfunction buildImagePromptInternal(config: BuildImagePromptConfig, marks?: AssemblyMarks): BuildImagePromptResult {\n let {\n provider,\n style,\n negativePrompt,\n characterDefs = [],\n userTemplates,\n flowTemplates,\n referenceImageUrls = [],\n ancestorRefs = [],\n connectedReferences,\n identityMeta = [],\n } = config\n const referenceOrder = config.referenceOrder ?? []\n const sourceNodeIdById = config.sourceNodeIdById\n const suppressedCanonicalCharacterIds = new Set(\n config.suppressedCanonicalCharacterIds ?? [],\n )\n const suppressedCanonicalLocationIds = config.suppressedCanonicalLocationIds ?? []\n // `referenceFormat` is preserved across the Phase-0 `config = {...config}`\n // reassignment, so computing this once up front is stable. Gates the hybrid\n // character convergence (Phase 0) and the non-capitalizing scene render below.\n const isHybrid = config.referenceFormat === \"hybrid\"\n // Described references (name + description, no media) — rendered ONCE, up\n // front, so the reassignments below can't lose them. They attach no URL, so\n // they take no part in numbering; they are joined onto the assembled prompt at\n // the single site in the connected-reference path below, ahead of the provider\n // cap so a shed sees them like any other body text. Empty for every caller\n // that doesn't send them → nothing downstream changes.\n const describedLines = renderDescribedReferenceLines(config.describedReferences)\n // Set when Phase 0 converged character OR location @-mentions into inline\n // hybrid role phrases (+ identity-lock + element directives). Tells the hybrid\n // scene render to expand any remaining {image:N} tokens WITHOUT capitalizing\n // line-initials (which would corrupt \"the face from reference image A\" → \"The\n // face …\" / \"the style from reference image A\" → \"The style …\").\n let hybridBodyConverged = false\n // URLs bound by a Phase-0 wired-entity (`@creature` / `@object`) mention.\n // Declared at function scope because it must BRIDGE the two blocks below:\n // Phase 0 populates it, and the New path unions it into\n // `renderObjectCreatureCanonicalHybrid`'s `coveredUrls` so a mentioned\n // creature/object does NOT also emit its trailing canonical phrase. Empty for\n // every prompt without an entity mention, which is what keeps those outputs\n // byte-identical.\n const mentionedEntityUrls = new Set<string>()\n // URLs bound by a Phase-0 named-image (`@<image-name>`) mention. Bridges the\n // same two blocks for the OTHER suppression the New path owes: that pass\n // already emitted each bound ref's per-use `descriptionOverride` line, so the\n // untold-override sweep must not say it a second time. Empty for every prompt\n // without an image mention.\n const mentionedImageUrls = new Set<string>()\n\n // Character LoRA inference path: trigger word + LoRA model carry identity,\n // so we strip raw `@slug[:V[:variant]]` tokens from the prompt AND drop the\n // connected-reference machinery entirely (no Image N bullets, no\n // ref URLs). The LoRA model gets a clean prompt + the trigger word\n // injected by the Replicate buildInput (see providers/replicate/image.ts).\n if (config.skipCharacterMentions) {\n config = {\n ...config,\n prompt: config.prompt.replace(\n /@[a-z0-9_-]+(?::\\d+(?::[a-z0-9_-]+)?)?\\s?/gi,\n \"\",\n ).trim(),\n }\n connectedReferences = undefined\n referenceImageUrls = []\n }\n\n // Apply canonical suppression UP FRONT so `buildCanonicalFallback` never\n // sees the suppressed slugs. This is the only way to drop both the URL\n // and the directive line; filtering after the fact would leave the\n // directive numbering misaligned.\n if (\n connectedReferences\n && suppressedCanonicalCharacterIds.size > 0\n ) {\n connectedReferences = connectedReferences.filter((r) => {\n if (r.source !== \"wired-character\") return true\n if (!r.characterSlug) return true\n // Only drop the CANONICAL entry — `@-mentioned` variants are explicit\n // and should stay even when canonical is suppressed.\n if (r.variantSlug) return true\n if (r.isExtraRef) return true\n return !suppressedCanonicalCharacterIds.has(r.characterSlug)\n })\n }\n\n // Cap structured references to the provider's image-reference limit — the SAME\n // cap the canvas enforces via handle-limits. Applied UP FRONT (like the\n // suppression filter above) so the direct API / MCP / SDK path can't send more\n // references than the provider accepts and leave an `Image N` directive\n // pointing at a slot the provider silently drops. Flat `referenceImageUrls` are\n // numbered first, so they consume the budget. Only ref-capable providers\n // (refCap > 0) cap here; non-ref providers drop all URLs via `supportsRefs`.\n if (connectedReferences && connectedReferences.length > 0) {\n const refCap = imageReferenceLimit(provider)\n if (refCap > 0) {\n const structuredBudget = Math.max(0, refCap - referenceImageUrls.length)\n if (connectedReferences.length > structuredBudget) {\n // ATTACH-PRIORITY slice, not raw order. The raw list interleaves each\n // wired character's canonical with its whole variant array, and an\n // unmentioned VARIANT never attaches — yet a raw slice let one\n // variant-rich character fill the budget and evict every character\n // wired after it ENTIRELY, canonical included (the \"two characters\n // wired, one sent\" incident: 1 canonical + 7 variants consumed\n // nano-banana-pro's cap of 8, and the second character vanished\n // while the provider received TWO urls total). Non-variant entries\n // (canonicals, manual refs, extra-refs) take the budget first;\n // variants fill what remains as mention candidates. Survivors keep\n // their original relative order, so slot numbering is unchanged for\n // every graph that fit the budget before.\n const nonVariants = connectedReferences.filter((r) => !r.variantSlug || r.isExtraRef === true)\n const variants = connectedReferences.filter((r) => r.variantSlug && r.isExtraRef !== true)\n const kept = new Set([...nonVariants, ...variants].slice(0, structuredBudget))\n connectedReferences = connectedReferences.filter((r) => kept.has(r))\n }\n }\n }\n\n // -------------------------------------------------------------------------\n // Phase 0: resolve `@<character-slug>:<index>(:<variant-slug>)?` tokens\n // AND apply the per-character canonical fallback for unmentioned wired\n // characters. Runs BEFORE the existing `{image:N}` resolution path. Both\n // coexist: Phase 0 handles slug-based character mentions / fallbacks;\n // the existing path below handles `{image:N:label}` tokens for\n // non-character refs.\n //\n // Per-character contract:\n // - wired-character WITHOUT any `@-mention` → contribute canonical URL\n // + a strong identity directive (pre-mention-feature behavior).\n // - wired-character WITH at least one `@-mention` → contribute ONLY\n // mentioned variant URLs (no canonical auto-attach).\n // -------------------------------------------------------------------------\n if (connectedReferences && connectedReferences.length > 0) {\n const knownCharacterSlugs = Array.from(\n new Set(\n connectedReferences\n .map((r) => r.characterSlug)\n .filter((s): s is string => typeof s === \"string\" && s.length > 0)\n )\n )\n const hasExtraRefs = connectedReferences.some((r) => r.isExtraRef === true)\n // We only need to run the directive-emission machinery if either\n // (a) there's at least one character ref (mention / canonical fallback\n // could fire), or (b) there's at least one user-attached extra ref\n // (manual uploads with descriptions, or character-variant extras).\n // The empty-extras-empty-characters case falls through to the standard\n // non-character ref path unchanged.\n // Known location slugs (Phase 2 #2) — separate from character slugs.\n // Each location row contributes a canonical entry + per-variant entries,\n // all sharing the same `locationSlug`; we want the unique set for finder.\n const knownLocationSlugs = Array.from(\n new Set(\n connectedReferences\n .map((r) => r.locationSlug)\n .filter((s): s is string => typeof s === \"string\" && s.length > 0)\n )\n )\n // Named-image mentions (P3). Slugs derive from each media ref's\n // `defaultName` — there is no `imageSlug` wire field; the derivation is\n // shared with the backend orchestrator's structured-branch gate via\n // `knownImageSlugsFromRefs`, so the two can never disagree about whether a\n // prompt carries a resolvable image mention.\n const knownImageSlugs = knownImageSlugsFromRefs(connectedReferences)\n // EXISTENCE-ONLY precheck, gating the Phase-0 arm below. Unlike characters\n // (whose canonical fallback must run even with ZERO mentions), images have\n // NO canonical fallback, so an image-only graph with no mention has no\n // reason to enter Phase 0 — gating on TOKEN presence keeps today's control\n // flow and byte output for every unmentioned graph BY CONSTRUCTION.\n // HYBRID-only: under the legacy format an `@name:N` token stays literal text.\n const hasImageMentionTokens = isHybrid\n && knownImageSlugs.length > 0\n && findImageMentionTokens(config.prompt, knownImageSlugs).length > 0\n // Wired-entity mentions (`wired-creature` / `wired-object`). Slugs derive\n // from each entity ref's `defaultName` — no `entitySlug` wire field, matching\n // the image grammar — and the derivation is shared with the backend\n // orchestrator's structured-branch gate via `knownEntitySlugsFromRefs`.\n const knownEntitySlugs = knownEntitySlugsFromRefs(connectedReferences)\n // EXISTENCE-ONLY precheck, gating the Phase-0 arm below — the image\n // precedent. An unmentioned creature/object already renders correctly\n // through `renderObjectCreatureCanonicalHybrid`, so a graph with no entity\n // mention has no reason to enter Phase 0: gating on TOKEN presence keeps\n // today's control flow and byte output for every such graph BY\n // CONSTRUCTION. HYBRID-only — under the legacy format an `@name:N` token\n // stays literal text.\n const hasEntityMentionTokens = isHybrid\n && knownEntitySlugs.length > 0\n && findEntityMentionTokens(config.prompt, knownEntitySlugs).length > 0\n if (knownCharacterSlugs.length > 0 || hasExtraRefs || knownLocationSlugs.length > 0 || hasImageMentionTokens || hasEntityMentionTokens) {\n const mentionTokens = knownCharacterSlugs.length > 0\n ? findCharacterMentionTokens(config.prompt, knownCharacterSlugs)\n : []\n // Character @-mention resolution. HYBRID (Unified Reference Roles,\n // Phase A): each mention becomes the inline role phrase \"the {role} from\n // reference image {LETTER}\" with the optional identity-lock + wired\n // elementInjection surfaced SEPARATELY, and NO \"Use these characters:\"\n // block. LEGACY keeps the bullet block (and is shared verbatim with the\n // video resolver — untouched here).\n let hybridLockLines: string[] = []\n let hybridElementDirectives: string[] = []\n let resolved: ResolveCharacterMentionsResult\n if (isHybrid && mentionTokens.length > 0) {\n const h = resolveCharacterMentionsHybrid(\n config.prompt,\n mentionTokens,\n connectedReferences,\n referenceImageUrls,\n )\n resolved = {\n prompt: h.prompt,\n additionalUrls: h.additionalUrls,\n mentionedCharacterSlugs: h.mentionedCharacterSlugs,\n }\n hybridLockLines = h.lockLines\n hybridElementDirectives = h.elementDirectives\n hybridBodyConverged = true\n } else {\n resolved = mentionTokens.length > 0\n ? resolveCharacterMentions(config.prompt, mentionTokens, connectedReferences)\n : { prompt: config.prompt, additionalUrls: [], mentionedCharacterSlugs: new Set<string>() }\n }\n\n // Phase 2 #2: resolve `@oldlibrary:1:weather/rain` location mentions on\n // the post-character-resolution prompt. Character resolution may have\n // already swapped its own @-tokens for display names; location tokens\n // (different slug namespace) remain intact for this pass.\n const locationTokens = knownLocationSlugs.length > 0\n ? findLocationMentionTokens(resolved.prompt, knownLocationSlugs)\n : []\n // Location mention convergence. HYBRID (Unified Reference Roles, Phase C):\n // each `@location` mention becomes the inline role phrase \"the {role} from\n // reference image {LETTER}\" (role from the location node's usage mode) with\n // the opt-in lock + wired elementInjection surfaced SEPARATELY, and NO \"Use\n // these locations:\" block. LEGACY keeps the bullet block. `existingUrls` =\n // [base refs, resolved CHARACTER mentions] so location slot letters are a\n // prefix of the final `finalIndexByUrl` (location URLs merge after character\n // mentions, before the character canonical/extra URLs).\n let hybridLocationLockLines: string[] = []\n let hybridLocationElementDirectives: string[] = []\n let locationResolved: ResolveLocationMentionsResult\n if (isHybrid && locationTokens.length > 0) {\n const hl = resolveLocationMentionsHybrid(\n resolved.prompt,\n locationTokens,\n connectedReferences,\n [...(referenceImageUrls || []), ...resolved.additionalUrls],\n )\n locationResolved = {\n prompt: hl.prompt,\n additionalUrls: hl.additionalUrls,\n mentionedLocationSlugs: hl.mentionedLocationSlugs,\n }\n hybridLocationLockLines = hl.lockLines\n hybridLocationElementDirectives = hl.elementDirectives\n // Inline role phrases now live in the body → skip line-initial\n // capitalization. Only when a mention actually matched + was replaced.\n if (hl.additionalUrls.length > 0) hybridBodyConverged = true\n } else {\n locationResolved = locationTokens.length > 0\n ? resolveLocationMentions(resolved.prompt, locationTokens, connectedReferences)\n : { prompt: resolved.prompt, additionalUrls: [] as string[], mentionedLocationSlugs: new Set<string>() }\n }\n // Merge location's resolved prompt + URLs back into `resolved` so the\n // rest of the pipeline (fallback, extras, urlsByOrder) doesn't need\n // separate plumbing.\n resolved.prompt = locationResolved.prompt\n resolved.additionalUrls = [...resolved.additionalUrls, ...locationResolved.additionalUrls]\n // Per-variant location refs are mention-only — they were already\n // attached via `additionalUrls` when matched, and should NEVER\n // auto-attach via the non-character ref path below (line 1112).\n // Canonical refs whose slug was mentioned are also handled by the\n // resolver — drop to avoid double-attaching the canonical URL when the\n // user explicitly pinned a variant via `@-mention`.\n const mentionedLocationSlugs = locationResolved.mentionedLocationSlugs\n connectedReferences = connectedReferences.filter((r) => {\n if (r.source !== \"wired-location\") return true\n if (!r.locationSlug) return true\n if (r.locationVariantBucket) return false\n return !mentionedLocationSlugs.has(r.locationSlug)\n })\n // Pass 3 (P3): named-image mentions, resolved on the POST-character,\n // POST-location prompt. The finder MUST re-run here — the earlier passes\n // spliced their own tokens out, so any offset computed before them is\n // stale. PRECEDENCE character → location → image falls out of this pass\n // order: a name shared by a character and an image resolves as the\n // character, and the image token never fires.\n //\n // `existingUrls` is already location-inclusive because `additionalUrls`\n // absorbed the location URLs just above, so the mention slot letters stay\n // a prefix of the final `finalIndexByUrl`.\n let hybridImageLockLines: string[] = []\n let hybridImageElementDirectives: string[] = []\n if (hasImageMentionTokens) {\n const imageTokens = findImageMentionTokens(resolved.prompt, knownImageSlugs)\n if (imageTokens.length > 0) {\n const hi = resolveImageMentionsHybrid(\n resolved.prompt,\n imageTokens,\n connectedReferences,\n [...(referenceImageUrls || []), ...resolved.additionalUrls],\n )\n resolved.prompt = hi.prompt\n resolved.additionalUrls = [...resolved.additionalUrls, ...hi.additionalUrls]\n hybridImageLockLines = hi.lockLines\n hybridImageElementDirectives = hi.elementDirectives\n // The override handoff to the New path: a bound URL was already told\n // its per-use description here, inline with the mention, so the\n // untold-override sweep below skips it.\n for (const u of hi.mentionedUrls) mentionedImageUrls.add(u)\n // Inline role phrases now live in the body → skip line-initial\n // capitalization, which would otherwise corrupt a mid-sentence\n // \"the background from reference image C\".\n if (hi.additionalUrls.length > 0) hybridBodyConverged = true\n }\n }\n // NOTE — deliberately NO `connectedReferences` filter for mentioned image\n // refs (the location pass filters, just above). The New-path URL merge\n // dedups by URL so the ref keeps its earlier Phase-0 slot; wired-image /\n // manual refs have no canonical-fallback prose to double-emit (that loop\n // is gated to wired-location/object/creature); and leaving the ref in\n // place keeps `nonCharacterRefs[N-1]` positional indexing stable for\n // `{image:N}` tokens.\n //\n // Pass 4: wired-entity (`@creature` / `@object`) mentions, resolved on the\n // POST-character, POST-location, POST-image prompt. The finder MUST re-run\n // here — every earlier pass spliced its own tokens out, so an offset\n // computed before them is stale. PRECEDENCE character → location → image →\n // creature → object falls out of this pass order plus the creature-first\n // map inside the resolver: a name shared with an earlier kind resolves as\n // that kind, and the entity token never fires.\n //\n // `existingUrls` is already location- AND image-inclusive because\n // `additionalUrls` absorbed both above, so the mention slot letters stay a\n // prefix of the final `finalIndexByUrl`.\n let hybridEntityLockLines: string[] = []\n let hybridEntityElementDirectives: string[] = []\n if (hasEntityMentionTokens) {\n const entityTokens = findEntityMentionTokens(resolved.prompt, knownEntitySlugs)\n if (entityTokens.length > 0) {\n const he = resolveEntityMentionsHybrid(\n resolved.prompt,\n entityTokens,\n connectedReferences,\n [...(referenceImageUrls || []), ...resolved.additionalUrls],\n )\n resolved.prompt = he.prompt\n resolved.additionalUrls = [...resolved.additionalUrls, ...he.additionalUrls]\n hybridEntityLockLines = he.lockLines\n hybridEntityElementDirectives = he.elementDirectives\n // The suppression handoff to the New path: every bound URL is skipped\n // by `renderObjectCreatureCanonicalHybrid`, so the phrase renders ONCE\n // — inline, where the user typed it — instead of also dangling as a\n // trailing \"the creature from reference image D\" line. Like the image\n // pass, the ref itself is NOT filtered out of `connectedReferences`\n // (positional `{image:N}` stability); coveredUrls is the whole\n // mechanism.\n for (const u of he.mentionedUrls) mentionedEntityUrls.add(u)\n // Inline role phrases now live in the body → skip line-initial\n // capitalization, which would otherwise corrupt a mid-sentence\n // \"the creature from reference image D\".\n if (he.additionalUrls.length > 0) hybridBodyConverged = true\n }\n }\n // Default-fallback canonical URLs + directives for any wired character\n // that has zero mentions in the prompt. Mirrors the legacy behavior the\n // mention feature replaced — wire a character with no typing required.\n //\n // `startIndex` = position (1-based) of the first canonical fallback\n // URL in the final merged list. Computed by deduping the prefix\n // (pre-existing refs + mention URLs) so that if a mention URL\n // coincidentally equals an upstream ref, the canonical lines still\n // point at the correct position.\n const prefixDedupedLength = ([\n ...(referenceImageUrls || []),\n ...resolved.additionalUrls,\n ].filter((u, i, a) => a.indexOf(u) === i)).length\n // Canonical fallback (unmentioned wired character → auto-attached URL).\n // LEGACY emits the \"Use these characters:\" bullet block; HYBRID (Task 4)\n // attaches the SAME canonical URLs but renders each as an inline role\n // phrase + opt-in lock below (once the slot letters are known). Selection\n // is shared so both paths auto-attach the same characters.\n const canonicalFallbackRefs = isHybrid\n ? selectCanonicalFallbackRefs(connectedReferences, resolved.mentionedCharacterSlugs)\n : []\n const fallback = isHybrid\n ? { directiveLines: [] as string[], urls: canonicalFallbackRefs.map((r) => r.url) }\n : buildCanonicalFallback(\n connectedReferences,\n resolved.mentionedCharacterSlugs,\n prefixDedupedLength + 1,\n )\n let promptForNext = resolved.prompt\n if (fallback.directiveLines.length > 0) {\n // Mirror `resolveCharacterMentions`'s \"Use these characters:\\n…\" block\n // structure. When both blocks exist, append fallback bullets to the\n // same block so the model sees one consolidated header.\n if (promptForNext.startsWith(\"Use these characters:\\n\")) {\n const splitIdx = promptForNext.indexOf(\"\\n\\n\")\n if (splitIdx !== -1) {\n const header = promptForNext.slice(0, splitIdx)\n const rest = promptForNext.slice(splitIdx)\n promptForNext = `${header}\\n${fallback.directiveLines.join(\"\\n\")}${rest}`\n } else {\n promptForNext = `${promptForNext}\\n${fallback.directiveLines.join(\"\\n\")}`\n }\n } else {\n promptForNext = `Use these characters:\\n${fallback.directiveLines.join(\"\\n\")}\\n\\n${promptForNext}`\n }\n }\n const mergedUrls = [\n ...(referenceImageUrls || []),\n ...resolved.additionalUrls,\n ...fallback.urls,\n ].filter((u, i, a) => a.indexOf(u) === i)\n\n // Extra-ref directives: user-attached refs (manual uploads + picked\n // character variants). Emitted AFTER mentions + canonical fallback so\n // they get the next positional slots. Numbering = position in the final\n // ref URL list (mergedUrls.length + 1, +2, …).\n const characterPositions = buildCharacterPositionMap(mergedUrls, connectedReferences)\n // Extra-refs (manual uploads + picked character variants). LEGACY emits\n // \"Image N\" bullets in the \"Use these characters:\" block; HYBRID (Task 4)\n // attaches the SAME URLs but renders manual / pair-back directives with\n // lettered bindings below. Filter shared so both paths attach the same URLs.\n const extraRefsHybrid = isHybrid\n ? connectedReferences.filter((r) => r.isExtraRef === true && Boolean(r.url))\n : []\n const extras = isHybrid\n ? { directiveLines: [] as string[], urls: extraRefsHybrid.map((r) => r.url) }\n : buildExtraRefDirectives(\n connectedReferences,\n characterPositions,\n mergedUrls.length + 1,\n )\n // Always merge extras' URLs — minimal-intervention modes (\"none\" /\n // \"name\") may emit zero or one bullet while still attaching the image.\n // Gating the URL merge on `directiveLines.length > 0` would silently\n // drop the URL for a `none`-mode extra.\n const finalMergedUrls = [...mergedUrls, ...extras.urls]\n .filter((u, i, a) => a.indexOf(u) === i)\n if (extras.directiveLines.length > 0) {\n if (promptForNext.startsWith(\"Use these characters:\\n\")) {\n const splitIdx = promptForNext.indexOf(\"\\n\\n\")\n if (splitIdx !== -1) {\n const header = promptForNext.slice(0, splitIdx)\n const rest = promptForNext.slice(splitIdx)\n promptForNext = `${header}\\n${extras.directiveLines.join(\"\\n\")}${rest}`\n } else {\n promptForNext = `${promptForNext}\\n${extras.directiveLines.join(\"\\n\")}`\n }\n } else {\n promptForNext = `Use these characters:\\n${extras.directiveLines.join(\"\\n\")}\\n\\n${promptForNext}`\n }\n }\n\n // Hybrid assembly. Prepend ONE identity-lock block (mention + canonical\n // fallback + first-sight extra locks) and append the trailing scene\n // directives (mention element injections + canonical role phrases +\n // canonical element injections + extra-ref directives + extra-ref element\n // injections) — never the legacy \"Use these characters:\" block.\n if (isHybrid) {\n // Unified slot map over the final hybrid URL order\n // [base, mentions, canonical, extras] — the exact prefix of the \"New\n // path\" `finalIndexByUrl`, so every lettered binding agrees byte-for-byte.\n const slotByUrl = new Map<string, number>()\n finalMergedUrls.forEach((u, i) => {\n if (!slotByUrl.has(u)) slotByUrl.set(u, i + 1)\n })\n const letterForUrl = (url: string): string => slotToLetter(slotByUrl.get(url) ?? 0)\n\n // (A) canonical fallback → role phrases + opt-in locks.\n const canonical = renderCanonicalFallbackHybrid(canonicalFallbackRefs, letterForUrl)\n // (B) extra-refs → manual / pair-back directives + first-sight locks.\n // Seed the pair-back lookup with each character's FIRST emitted letter\n // (mention / canonical fallback), converted from its mergedUrls position.\n const seedLetterByChar = new Map<string, string>()\n for (const [slug, pos] of characterPositions) {\n seedLetterByChar.set(slug, slotToLetter(pos))\n }\n const extrasRendered = renderExtraRefsHybrid(extraRefsHybrid, letterForUrl, seedLetterByChar)\n\n // Role phrases are intentionally lowercase (\"the person from reference\n // image A\"); flag the converged state so the scene render below skips\n // line-initial capitalization (which would corrupt them).\n if (canonical.phrases.length > 0 || extrasRendered.bodyLines.length > 0) {\n hybridBodyConverged = true\n }\n\n // Location MENTION locks/elements (the role phrases themselves are\n // already inline in `promptForNext`). Mentioned-location URLs sit\n // between the character mentions and the character canonical/extras in\n // `finalMergedUrls`, so their letters were computed against the matching\n // prefix in `resolveLocationMentionsHybrid` and need no re-derivation here.\n // Set-dedup: a reference can be locked via more than one path (e.g. an\n // extra whose URL equals the wired canonical is routed to first-sight\n // by the pair-back letter gate) — identical lock lines say nothing new\n // to the model, so emit each exact line once. Line texts are\n // {ref}-bound, so distinct references never collapse.\n const allLockLines = [...new Set([\n ...hybridLockLines,\n ...hybridLocationLockLines,\n ...hybridImageLockLines,\n ...hybridEntityLockLines,\n ...canonical.lockLines,\n ...extrasRendered.lockLines,\n ])]\n const trailingLines = [\n ...hybridElementDirectives,\n ...hybridLocationElementDirectives,\n ...hybridImageElementDirectives,\n ...hybridEntityElementDirectives,\n ...canonical.phrases,\n ...canonical.elementDirectives,\n ...extrasRendered.bodyLines,\n ...extrasRendered.elementDirectives,\n ]\n const lockBlock = allLockLines.length > 0 ? `${allLockLines.join(\"\\n\")}\\n\\n` : \"\"\n // Scene content, so it extends the BODY: appended flat it would land\n // under a `[style]` header the composer left open.\n promptForNext = `${lockBlock}${insertBeforeStyleSection(promptForNext, trailingLines)}`\n }\n\n // Mutate the config locals (NOT the original passed config).\n config = {\n ...config,\n prompt: promptForNext,\n referenceImageUrls: finalMergedUrls,\n }\n referenceImageUrls = config.referenceImageUrls || []\n }\n }\n\n // -------------------------------------------------------------------------\n // New path: rich `connectedReferences` provided. Per-identity directives\n // are emitted at the top, `{image:N:label}` tokens expand to natural-\n // language phrases, and URLs are sent in connectedReferences order.\n //\n // Character refs (source === \"wired-character\") are AUTOCOMPLETE-ONLY by\n // default — they ONLY contribute URLs + directives via Phase 0 mention\n // resolution above (`referenceImageUrls` and a \"Use these characters…\"\n // prefix). A wired character with no @-mention in the prompt contributes\n // zero URLs and zero directives here. Non-character refs (manual, wired-creature,\n // wired-image, wired-face, wired-object, wired-location) still auto-\n // attach so unchanged behavior for them.\n // -------------------------------------------------------------------------\n // Entered by `connectedReferences` OR by described references alone: a story\n // landing whose cast has no entities yet sends only names + descriptions, and\n // the legacy path below has no directive seam to join them onto.\n // An EMPTY connected list with ancestor images takes the flat path below, the\n // one that sends them: the editor always passes `connectedReferences` (empty\n // when nothing is wired directly), and this path never reads `ancestorRefs`,\n // so a photo reaching the node only through a passthrough node was dropped\n // and its `{image:N}` rendered as a label (#2010). The workflow run builds\n // that graph on the flat path (no connected list), so both now agree.\n const ancestorsOnly =\n connectedReferences !== undefined &&\n connectedReferences.length === 0 &&\n referenceImageUrls.length === 0 &&\n ancestorRefs.length > 0\n if ((connectedReferences && !ancestorsOnly) || describedLines.length > 0) {\n const structuredRefs = connectedReferences ?? []\n let prompt = config.prompt\n\n // Described references, LEGACY half — joined BEFORE the directive assembly\n // below, because the block it creates is the block that assembly consolidates\n // into. Joined AFTER instead, a request whose references produce the\n // \"Use these references for the output image:\" wrap (any non-character ref,\n // no wired character) would get a SECOND \"Use these characters:\" header\n // prepended above it. Prepending here also keeps `marks.directivesPrefix`\n // honest: the prepend branch that records it is only reachable when the\n // prompt does NOT already open with the character block.\n if (!isHybrid && describedLines.length > 0) {\n prompt = appendReferenceLines(prompt, describedLines, \"legacy\")\n }\n\n // Non-character refs are still emitted as per-identity directives + URLs.\n // Character refs are filtered out here — Phase 0 has already added their\n // URLs to `referenceImageUrls` (via mention resolution) and prepended the\n // \"Use these characters…\" directive block. User-attached extras\n // (isExtraRef === true) are also filtered out: Phase 0 already emitted\n // their per-ref directive (\"Image N (reference): <description>.\" / \"same\n // subject as Image M, …\") and merged their URLs into `referenceImageUrls`.\n // Letting them through here would double-emit the URLs (and append a\n // second positional directive via the {image:N:label} path).\n const nonCharacterRefs = structuredRefs.filter(\n (r) => r.source !== \"wired-character\" && r.isExtraRef !== true,\n )\n\n // -----------------------------------------------------------------------\n // Single source of truth for positional numbering.\n //\n // Phase 0 already numbered the character / extra directives against the\n // order [referenceImageUrls, mentions, canonical-fallback, extras] and\n // wrote both the bullets and the URLs into `referenceImageUrls`. We APPEND\n // the non-character URLs after that list (never prepend) so those Phase-0\n // numbers stay valid, then derive EVERY non-character directive's `Image N`\n // from this one final ordered list via a `url → index` map.\n //\n // The old code prepended `nonCharacterUrls` ahead of the Phase-0 list,\n // which shifted every character/extra `Image N` by `nonCharacterUrls.length`\n // while their directive text was already baked — the root cause of the\n // off-by-(non-char-count) desync. Appending is byte-identical to the old\n // prepend whenever a non-char URL already lives in `referenceImageUrls`\n // (dedup keeps its existing slot); it only differs for the genuinely-new\n // location/object URLs that the prepend mis-slotted.\n // -----------------------------------------------------------------------\n const nonCharacterUrls = nonCharacterRefs\n .map((r) => r.url)\n .filter((u): u is string => Boolean(u))\n const assembledUrls = [...referenceImageUrls, ...nonCharacterUrls]\n .filter((u, i, a) => a.indexOf(u) === i)\n const finalIndexByUrl = new Map<string, number>()\n assembledUrls.forEach((u, i) => {\n if (!finalIndexByUrl.has(u)) finalIndexByUrl.set(u, i + 1)\n })\n\n // The list an `{image:N}` token is numbered against: normally the\n // non-character connected refs. With NO connected references at all (the\n // path was entered through described references, or with an explicitly\n // empty list) there is nothing else to address, so N counts the flat URLs,\n // as on the flat path. Otherwise the photo is sent at slot 1 while\n // `{image:1:person}` renders as `person` (#2010). Only token binding reads\n // this; directives, canonical renders and covered-URL sets keep\n // `nonCharacterRefs`. No token can bind against an empty list, so no output\n // that binds a token today changes.\n const tokenRefs: readonly ConnectedReference[] = structuredRefs.length === 0\n ? referenceImageUrls.map((url, i) => ({\n id: `flat-${i + 1}`,\n defaultName: `Image ${i + 1}`,\n source: \"wired-image\" as const,\n url,\n }))\n : nonCharacterRefs\n\n // Non-character directives — `{image:N}` identities (renumbered to their\n // final slot) + the location/object canonical fallback — all numbered\n // against the unified `finalIndexByUrl`.\n const directives = buildNonCharacterDirectives(\n prompt,\n nonCharacterRefs,\n identityMeta,\n finalIndexByUrl,\n suppressedCanonicalLocationIds,\n )\n if (isHybrid) {\n // Hybrid reference format (images-only, flag-gated): TOKEN EXPANSION ONLY.\n // Every {image:N:label} token becomes \"the <label> from reference image\n // <LETTER>\". NO reference-lock snippet is auto-injected — authors prepend\n // their own lock (default-deny / likeness / compose / extract / ghost-\n // mannequin, per goal) in the prompt text, and it passes through here\n // untouched. A caller MAY still opt to prepend one via\n // `config.referenceLockSnippet`, but nothing is added by default.\n // Replaces the legacy \"Use these references:/Compose:\" wrap + numeric\n // token expansion. Objects stay legacy; CHARACTERS were already converged\n // in Phase 0 (role phrases + identity-lock + element directives), and\n // LOCATIONS converge here too — mentioned ones inline in Phase 0, the\n // unmentioned canonical ones as the trailing role phrases appended below.\n //\n // When Phase 0 converged a character OR location mention, the body is final\n // and intentionally lowercase (\"the face from reference image A\") — expand\n // any remaining {image:N} tokens but DON'T capitalize line-initials (which\n // would corrupt those phrases). Otherwise render the user scene as before\n // (capitalized line-initials); appended canonical phrases stay lowercase\n // because they're added AFTER this capitalizing pass.\n const scene = hybridBodyConverged\n ? prompt\n .split(\"\\n\")\n .map((line) => expandImageRefTokensHybrid(line, tokenRefs, finalIndexByUrl))\n .join(\"\\n\")\n : buildHybridScene(prompt, tokenRefs, finalIndexByUrl)\n // URLs already expanded inline by an `{image:N}` token in this scene.\n // Derived EXACTLY as the legacy `buildNonCharacterDirectives` derives its\n // `coveredUrls` — via `collectIdentities` (labeled `{image:N:label}`\n // tokens present in the prompt, indexing `nonCharacterRefs[N-1]`) — so the\n // hybrid and legacy notions of \"token-covered\" share one source of truth\n // and never drift. Threaded into both canonical renders so an unmentioned\n // wired object / creature / location that is ALSO `{image:N}`-referenced\n // renders ONCE (inline), never also as a trailing canonical phrase.\n const tokenCoveredUrls = new Set<string>()\n for (const id of collectIdentities(prompt, nonCharacterRefs, identityMeta)) {\n const coveredUrl = nonCharacterRefs[id.imageIndex - 1]?.url\n if (coveredUrl) tokenCoveredUrls.add(coveredUrl)\n }\n // Unmentioned wired-location / -object / -creature canonical convergence\n // (Phase C): each → the trailing role phrase \"the {role} from reference\n // image {LETTER}\" + opt-in lock + wired elementInjection, numbered against\n // `finalIndexByUrl`. Mentioned locations were converged inline in Phase 0\n // and filtered out of `nonCharacterRefs`; mentioned objects/creatures were\n // converged inline too but stay in the list, so they are suppressed by URL\n // via the covered set below.\n const locCanon = renderLocationCanonicalHybrid(nonCharacterRefs, finalIndexByUrl, tokenCoveredUrls)\n // Objects/creatures now have a mention path too, so their covered set is\n // the union of the `{image:N}`-token URLs and the URLs a Phase-0\n // `@creature` / `@object` mention bound. That union is the SUPPRESSION —\n // a mentioned entity already rendered its role phrase inline, and without\n // this it would ALSO emit the trailing \"the creature from reference image\n // D\" line, which is the exact double-render this leg removes. Locations\n // keep `tokenCoveredUrls` alone: their mentioned refs are FILTERED out of\n // `nonCharacterRefs` upstream, so they never reach the loop at all.\n const objCoveredUrls = mentionedEntityUrls.size > 0\n ? new Set([...tokenCoveredUrls, ...mentionedEntityUrls])\n : tokenCoveredUrls\n const objCanon = renderObjectCreatureCanonicalHybrid(nonCharacterRefs, finalIndexByUrl, objCoveredUrls)\n const canonLockLines = [...locCanon.lockLines, ...objCanon.lockLines]\n const canonLockBlock = canonLockLines.length > 0 ? `${canonLockLines.join(\"\\n\")}\\n\\n` : \"\"\n // Per-use descriptions nothing above spoke for: a `{image:N}`-covered ref\n // (expanded inline, suppressed from both canonical renders) and a seated\n // `wired-image` / `manual` ref (which has no canonical render at all)\n // would otherwise drop their `descriptionOverride` silently — the one\n // place the hybrid format renders neither a description slot nor a role\n // phrase. Deduped against every URL a pass above already told.\n const toldOverrideUrls = new Set<string>([\n ...locCanon.renderedUrls,\n ...objCanon.renderedUrls,\n ...mentionedEntityUrls,\n ...mentionedImageUrls,\n ])\n const untoldOverrides = renderUntoldOverridesHybrid(\n nonCharacterRefs,\n finalIndexByUrl,\n toldOverrideUrls,\n )\n const canonTrailingLines = [\n ...locCanon.phrases, ...objCanon.phrases,\n ...locCanon.elementDirectives, ...objCanon.elementDirectives,\n ...untoldOverrides,\n ]\n // Role phrases and element injections are scene content → they extend the\n // BODY, ahead of the `[style]` section (which has no terminator, so a flat\n // append would read as one more look clause).\n const composedScene = `${canonLockBlock}${insertBeforeStyleSection(scene, canonTrailingLines)}`\n prompt = config.referenceLockSnippet\n ? `${config.referenceLockSnippet}\\n${composedScene}`\n : composedScene\n // The hybrid token rewrite can't be modeled by the segment marks → the\n // join-mismatch fallback in buildImagePromptSegments collapses to a single\n // segment (documented degradation, same as the Phase-0 splice branch).\n if (marks) marks.directivesPrefix = \"\"\n } else if (directives) {\n // Capture the prompt state across the splice so the segment builder can\n // isolate what the directive block contributed as a PREFIX. Only the\n // prepend branch yields a clean prefix; the Phase-0 consolidation branch\n // splices mid-string (no prefix) → marks.directivesPrefix stays \"\" and\n // the body collapses via the join fallback (documented degradation).\n const beforeDirectives = prompt\n if (prompt.startsWith(\"Use these characters:\\n\")) {\n // Consolidate into the existing Phase-0 directive block (the same splice\n // pattern Phase 0 uses for fallback / extras) instead of wrapping it in\n // a second \"Use these references…/Compose them naturally\" layer.\n const splitIdx = prompt.indexOf(\"\\n\\n\")\n if (splitIdx !== -1) {\n prompt = prompt.slice(0, splitIdx) + \"\\n\" + directives + prompt.slice(splitIdx)\n } else {\n prompt = `${prompt}\\n${directives}`\n }\n } else {\n // \"Use these references…\" header + bulleted directives + the\n // \"Compose them naturally…\" prefix proved most reliable in user\n // testing. Numeric indices (\"Image 1\") match the user-typed\n // `@character:N` slug format so the literal prompt and the final\n // identity directive are visually linked.\n prompt = prompt\n ? `Use these references for the output image:\\n${directives}\\n\\nCompose them naturally into a single image: ${prompt}`\n : `Use these references for the output image:\\n${directives}`\n // Prepend case: the new string ends with `beforeDirectives` (or is the\n // whole prefix when the body was empty). Everything before that tail is\n // the directive prefix.\n if (marks) {\n marks.directivesPrefix = prompt.slice(0, prompt.length - beforeDirectives.length)\n }\n }\n }\n\n // Described references, HYBRID half: trailing scene directives, so they land\n // behind the reference role phrases the branch above appended (the legacy\n // half ran before it — see the comment at that call). Still ahead of the\n // provider cap below, so the lines are body text like any other.\n if (isHybrid && describedLines.length > 0) {\n prompt = appendReferenceLines(prompt, describedLines, \"hybrid\")\n }\n\n const styleText = style?.trim()\n const styleLine = styleText && !isDeniedStyleId(styleText) ? `Style: ${getStylePromptHint(styleText) || styleText}` : \"\"\n\n const negPrompt = negativePrompt?.trim()\n let nativeNegativePrompt: string | undefined\n let avoidLine = \"\"\n if (negPrompt) {\n if (NATIVE_NEGATIVE_PROMPT_MODELS.has(provider)) {\n // Clamp native negatives to the provider's verified cap (e.g. ideogram /\n // qwen = 500) so an over-long negative can't trigger a provider reject.\n nativeNegativePrompt = negPrompt.slice(0, getMaxNegativePromptChars(provider))\n } else {\n avoidLine = `Avoid: ${negPrompt}`\n }\n }\n\n // Cap the assembled prompt at the PROVIDER's max (default IMAGE_PROMPT_MAX =\n // 5000, what the image routes already accept) — never the old hardcoded\n // 2000, which silently severed the appended cinematography/picker hints +\n // the `Avoid:` negative whenever the body was long. The style/avoid suffixes\n // are RESERVED first so a long body can never drop them (the control text is\n // the most important to keep). Truncate the BODY, THEN append the suffixes.\n // The cut is ORDER-BLIND — record how much it removed so a cap-aware caller\n // (`assembleImageInput`) can shed its own lowest-value text and re-assemble.\n const maxLen = getMaxImagePromptChars(provider)\n // Reserved on the PRE-cut body; the cut can only NARROW the separator (see\n // `controlSuffixes`), so the re-derived suffixes always fit the reservation.\n const preCut = controlSuffixes(prompt, styleLine, avoidLine)\n const reserved = preCut.styleSuffix.length + preCut.avoidSuffix.length\n if (prompt.length + reserved > maxLen) {\n if (marks) marks.overflowChars += prompt.length + reserved - maxLen\n prompt = prompt.slice(0, Math.max(0, maxLen - reserved - 3)) + \"...\"\n }\n const { styleSuffix, avoidSuffix } = controlSuffixes(prompt, styleLine, avoidLine)\n if (marks) {\n marks.styleSuffix = styleSuffix\n marks.avoidSuffix = avoidSuffix\n }\n // Body span = everything after the captured directive prefix, taken from the\n // possibly-truncated body so the segment join still reconstructs (empty in the\n // Phase-0 consolidation branch → collapses via the fallback, the documented\n // degradation).\n if (marks) marks.bodyBeforeSuffixes = prompt.slice(marks.directivesPrefix.length)\n prompt = prompt + styleSuffix + avoidSuffix\n // Safety clamp for a pathological native-less negative that alone overflows.\n if (prompt.length > maxLen) {\n if (marks) marks.overflowChars += prompt.length - maxLen\n prompt = prompt.slice(0, maxLen - 3) + \"...\"\n }\n\n // Resolve `{image:N:label}` → \"Image <finalSlot> (label)\". The token's N\n // indexes `nonCharacterRefs`; we rewrite it to the ref's FINAL slot so the\n // body text agrees with the directive numbering above. (The hybrid format\n // already expanded tokens to lettered role phrases in buildHybridScene.)\n if (!isHybrid) {\n prompt = expandImageRefTokensForRefs(prompt, tokenRefs, finalIndexByUrl)\n }\n\n const supportsRefs = MODELS_WITH_REFERENCE_IMAGE_SUPPORT.has(provider)\n\n // Apply user-defined `referenceOrder` to the final URL list, with a\n // matching renumber of every `Image N` token in the prompt. Skipped when\n // the model doesn't support refs (refs will be dropped anyway) or when no\n // order was supplied (no-op contract).\n let finalUrls = assembledUrls\n let finalPrompt = prompt\n // v1: the hybrid format skips referenceOrder renumbering (its tokens are\n // already expanded to fixed letters). Reorder support is a follow-up.\n if (!isHybrid && supportsRefs && referenceOrder.length > 0 && assembledUrls.length > 1) {\n const reordered = applyReferenceOrder(\n assembledUrls,\n prompt,\n structuredRefs,\n referenceOrder,\n sourceNodeIdById,\n )\n finalUrls = reordered.urls\n finalPrompt = reordered.prompt\n }\n\n const refsToSend = supportsRefs && finalUrls.length > 0 ? finalUrls : undefined\n\n // LAST, after the reorder (as the video core runs `resolveReferenceTokens`\n // last): an `{image:N}` with no image at N becomes its label, or nothing.\n // The binding test is the one both expanders above use, so a token that\n // binds is never touched here and every wired output is unchanged.\n const assembledPrompt = dropUnwiredImageTokens(\n finalPrompt,\n (n) => Boolean(tokenFinalSlot(n, tokenRefs, finalIndexByUrl)),\n )\n\n return { prompt: assembledPrompt, nativeNegativePrompt, referenceImageUrls: refsToSend }\n }\n\n // -------------------------------------------------------------------------\n // Legacy path — kept for callers that haven't migrated to connectedReferences.\n // -------------------------------------------------------------------------\n\n // Build character description lines\n const charDescs = characterDefs\n .filter((c) => c.type === \"description\" && c.description)\n .map((c) => {\n let templateKey: string\n switch (c.category) {\n case \"face\": templateKey = \"face-description\"; break\n case \"location\": templateKey = \"location-description\"; break\n case \"object\": templateKey = \"object-description\"; break\n default: templateKey = \"character-description\"; break\n }\n const template = resolveTemplate(templateKey, userTemplates, flowTemplates)\n return applyTemplate(template, {\n name: c.name,\n description: c.description || \"\",\n })\n })\n\n // Assemble prompt. The wrapper template composes the BODY only — a `[style]`\n // section is lifted off first and re-attached after, so a description can\n // never land under its header (and a user-overridden template, which may put\n // the descriptions anywhere, still only ever rearranges the body).\n let prompt = config.prompt\n if (charDescs.length > 0) {\n const wrapperTemplate = resolveTemplate(\"generate-image-wrapper\", userTemplates, flowTemplates)\n const { body, section } = splitStyleSection(prompt)\n const wrapped = applyTemplate(wrapperTemplate, {\n userPrompt: body,\n assetDescriptions: charDescs.join(\" \"),\n })\n prompt = section.length > 0 ? `${wrapped}${STYLE_SECTION_GAP}${section}` : wrapped\n }\n\n // Append style — if the inline `style` is a known STYLES catalog id, inject\n // the richer promptHint; otherwise fall back to the raw text (covers custom\n // free-text styles that don't match a preset).\n const styleText = style?.trim()\n const styleLine = styleText && !isDeniedStyleId(styleText) ? `Style: ${getStylePromptHint(styleText) || styleText}` : \"\"\n\n // Handle negative prompt: native support vs prompt-appended\n const negPrompt = negativePrompt?.trim()\n let nativeNegativePrompt: string | undefined\n let avoidLine = \"\"\n if (negPrompt) {\n if (NATIVE_NEGATIVE_PROMPT_MODELS.has(provider)) {\n nativeNegativePrompt = negPrompt.slice(0, getMaxNegativePromptChars(provider))\n } else {\n avoidLine = `Avoid: ${negPrompt}`\n }\n }\n\n // Cap at the provider max (default IMAGE_PROMPT_MAX = 5000), reserving the\n // style/avoid suffixes so a long body never severs the appended control text\n // (was a hardcoded 2000 tail-cut that dropped the negative). Truncate the\n // BODY, THEN append the suffixes. Same order-blind cut as the\n // connectedReferences path above → same `overflowChars` bookkeeping.\n const maxLen = getMaxImagePromptChars(provider)\n const preCut = controlSuffixes(prompt, styleLine, avoidLine)\n const reserved = preCut.styleSuffix.length + preCut.avoidSuffix.length\n if (prompt.length + reserved > maxLen) {\n if (marks) marks.overflowChars += prompt.length + reserved - maxLen\n prompt = prompt.slice(0, Math.max(0, maxLen - reserved - 3)) + \"...\"\n }\n const { styleSuffix, avoidSuffix } = controlSuffixes(prompt, styleLine, avoidLine)\n if (marks) {\n marks.styleSuffix = styleSuffix\n marks.avoidSuffix = avoidSuffix\n }\n // Legacy path has no directive prefix; the body is the char-desc-wrapped\n // (possibly-truncated) prompt right before the style/avoid suffixes.\n if (marks) marks.bodyBeforeSuffixes = prompt\n prompt = prompt + styleSuffix + avoidSuffix\n // Safety clamp for a pathological native-less negative that alone overflows.\n if (prompt.length > maxLen) {\n if (marks) marks.overflowChars += prompt.length - maxLen\n prompt = prompt.slice(0, maxLen - 3) + \"...\"\n }\n\n // Merge reference images: direct refs first, then ancestor fallback\n const allRefs = referenceImageUrls.length > 0 ? referenceImageUrls : ancestorRefs\n const supportsRefs = MODELS_WITH_REFERENCE_IMAGE_SUPPORT.has(provider)\n const refsToSend = supportsRefs && allRefs.length > 0 ? allRefs : undefined\n\n // Expand {image:N} position references in prompt (legacy: → \"[reference image N]\")\n prompt = expandImagePositionRefs(prompt, allRefs.length)\n // Then the unwired rule for a token past the last image — same pass, same\n // binding test, as the connected-reference return above.\n prompt = dropUnwiredImageTokens(prompt, (n) => hasImageAt(n, allRefs.length))\n\n return { prompt, nativeNegativePrompt, referenceImageUrls: refsToSend }\n}\n\n/**\n * `buildImagePrompt` plus an origin-tagged decomposition of the assembled\n * `prompt`. The string output (and all other fields) is byte-identical to\n * `buildImagePrompt` — the segments are derived from assembly marks recorded\n * during the same pass.\n *\n * ABSOLUTE INVARIANT (tested): `segments.map(s => s.text).join(\"\") === prompt`.\n * Anything the marks can't model — `{image:N}` token expansion, `referenceOrder`\n * renumbering, mid-string Phase-0 directive splicing, truncation — breaks the\n * join, and we collapse to a single `user` segment rather than ship a wrong\n * decomposition. Callers pass `bodySegments` (origins user/variable/picker/…)\n * for the body text; they survive only when the assembly didn't rewrite the\n * body string.\n */\nexport function buildImagePromptSegments(\n config: BuildImagePromptConfig,\n bodySegments?: readonly PromptSegment[],\n): BuildImagePromptSegmentsResult {\n const marks = newAssemblyMarks()\n\n const result = buildImagePromptInternal(config, marks)\n\n let segments: PromptSegment[] = [\n ...(marks.directivesPrefix ? [{ text: marks.directivesPrefix, origin: \"mention\" as const }] : []),\n ...reconcileBodySegments(marks.bodyBeforeSuffixes, bodySegments),\n ...(marks.styleSuffix ? [{ text: marks.styleSuffix, origin: \"style\" as const }] : []),\n ...(marks.avoidSuffix ? [{ text: marks.avoidSuffix, origin: \"negative\" as const }] : []),\n ]\n // Absolute invariant: join === prompt. Any assembly step we didn't model\n // (truncation, token expansion, reorder renumbering, Phase-0 mid-string\n // splice) breaks the join — detect against the FINAL returned prompt and\n // fall back rather than ship a wrong decomposition.\n if (segments.map((s) => s.text).join(\"\") !== result.prompt) {\n segments = result.prompt ? [{ text: result.prompt, origin: \"user\" }] : []\n }\n return { ...result, segments }\n}\n\n// ---------------------------------------------------------------------------\n// Identity helpers (new system)\n// ---------------------------------------------------------------------------\n\n/** Sources whose default fidelity is \"strict\" — they carry strong identity. */\nconst STRICT_DEFAULT_SOURCES: ReadonlySet<ReferenceSource> = new Set([\n \"wired-character\",\n \"wired-face\",\n \"wired-object\",\n \"wired-creature\",\n \"wired-location\",\n])\n\n// `IMAGE_TOKEN_PATTERN` (`{image:N}` / `{image:N:label}`) lives in\n// image-token-pattern.ts, shared with the preset metadata that reads which\n// references a template names.\n\n/**\n * The final 1-based slot an `{image:N}` token binds to on the connected-reference\n * path — the slot of `refs[N - 1]`'s URL — or `undefined` when no image sits at\n * N (no such reference, or one without a URL). The ONE binding test shared by\n * both token expanders and the unwired-token pass, so \"this token is wired\"\n * means the same thing to all three.\n */\nfunction tokenFinalSlot(\n n: number,\n refs: readonly ConnectedReference[],\n finalIndexByUrl: ReadonlyMap<string, number>,\n): number | undefined {\n const ref = refs[n - 1]\n return ref?.url ? finalIndexByUrl.get(ref.url) : undefined\n}\n\n/** Whether position N has an image among `count` flat references (the\n * no-`connectedReferences` path). Shared by its expander and the unwired pass. */\nfunction hasImageAt(n: number, count: number): boolean {\n return n >= 1 && n <= count\n}\n\n/**\n * The last step of image prompt assembly. Every `{image:N}` token still in the\n * prompt whose N has no image follows the unwired rule SHARED with the video\n * resolver (`resolveReferenceTokens`): a labelled token becomes its label, an\n * unlabelled one is dropped, and the horizontal gap left behind is collapsed\n * and the prompt trimmed.\n *\n * WIRED OUTPUT IS UNCHANGED BY CONSTRUCTION, on two counts:\n * - a token whose N binds (`isWired`) is returned verbatim — the expanders\n * already rendered every such token they own;\n * - the tidy runs only when at least one token was dropped, so a prompt whose\n * tokens all bind keeps every doubled space and indent its author typed.\n * (The video resolver tidies unconditionally; the image path never did, and\n * a wired image prompt stays byte-identical.)\n *\n * TWO PLACES KEEP A TOKEN AS TYPED, on purpose:\n * - a WIRED token the hybrid format never expands — its expansion covers the\n * scene only, so one typed into the negative prompt keeps its text in the\n * `Avoid:` line (rewriting it would move a wired output);\n * - the native negative prompt (`nativeNegativePrompt`, the models in\n * `NATIVE_NEGATIVE_PROMPT_MODELS` such as ideogram-v3) is never read by this\n * pass — it goes to the provider's own negative field as typed, wired or not.\n */\nfunction dropUnwiredImageTokens(prompt: string, isWired: (n: number) => boolean): string {\n let dropped = false\n const out = prompt.replace(IMAGE_TOKEN_PATTERN, (match: string, num: string, label?: string) => {\n if (isWired(parseInt(num, 10))) return match\n dropped = true\n return unboundReferenceTokenText(label)\n })\n return dropped ? tidyReferenceTokenGaps(out) : prompt\n}\n\ninterface ResolvedIdentity {\n imageIndex: number\n label: string // empty string = bare positional ref (no role)\n fidelity: IdentityFidelity\n customText?: string\n description?: string // from upstream connected reference\n /** `source` from the upstream ConnectedReference — used to opt the directive\n * builder into source-aware behavior (e.g. appending location canonical\n * description to wired-location bullets). Mirrors the character pattern\n * where `characterCanonicalDescription` is used by the Phase 0 mention\n * resolver, but for locations the consumer is the directive builder. */\n source?: ReferenceSource\n /** Location's canonical description, propagated from the wired-location\n * ConnectedReference. The directive builder appends this to the bullet\n * when source === \"wired-location\" AND the location's slug is NOT in\n * `suppressedCanonicalLocationIds`. */\n locationCanonicalDescription?: string | null\n /** Slug for the location source, used by `suppressedCanonicalLocationIds`\n * filtering. */\n locationSlug?: string\n /** Mirrors ConnectedReference.locationReferencePhotoKind — propagated so\n * `buildIdentityDirective` can annotate the subject line. */\n locationReferencePhotoKind?: string\n}\n\nfunction defaultFidelityForSource(source: ReferenceSource | undefined): IdentityFidelity {\n if (!source) return \"balanced\"\n return STRICT_DEFAULT_SOURCES.has(source) ? \"strict\" : \"balanced\"\n}\n\n/**\n * Return the unique set of identities to emit directives for: only the\n * `{image:N:label}` mentions actually present in the prompt.\n *\n * Connected references that the user hasn't mentioned still get sent to the\n * provider (via `referenceImageUrls`), but they get no auto-generated\n * directive — the user controls what's in the prompt by mentioning.\n */\nfunction collectIdentities(\n prompt: string,\n refs: readonly ConnectedReference[],\n meta: readonly IdentityMeta[],\n): ResolvedIdentity[] {\n const seen = new Set<string>()\n const mentions: Array<{ imageIndex: number; label: string }> = []\n for (const m of prompt.matchAll(IMAGE_TOKEN_PATTERN)) {\n const n = parseInt(m[1], 10)\n if (n < 1 || n > refs.length) continue\n const label = (m[2] ?? \"\").trim()\n if (!label) continue // bare {image:N} → no identity directive, just position\n const key = `${n}:${label}`\n if (seen.has(key)) continue\n seen.add(key)\n mentions.push({ imageIndex: n, label })\n }\n\n return mentions.map(({ imageIndex, label }) => {\n const ref = refs[imageIndex - 1]\n const m = meta.find((x) => x.imageIndex === imageIndex && x.label === label)\n return {\n imageIndex,\n label,\n fidelity: m?.fidelity ?? defaultFidelityForSource(ref?.source),\n customText: m?.customText?.trim() || undefined,\n // Per-use override ahead of the ref's own description; the directive\n // builder's location-canonical fallback only fires when BOTH are absent,\n // so an override outranks the stored location wording too.\n description: ref?.descriptionOverride?.trim() || ref?.description,\n source: ref?.source,\n locationCanonicalDescription: ref?.locationCanonicalDescription,\n locationSlug: ref?.locationSlug,\n locationReferencePhotoKind: ref?.locationReferencePhotoKind,\n }\n })\n}\n\n/** Labels that mean \"use as scene/setting\" — verb shifts away from \"match\". */\nconst BACKGROUND_LABELS: ReadonlySet<string> = new Set([\n \"background\", \"setting\", \"scene\", \"environment\", \"location\",\n])\n/** Labels that mean \"apply this look/material\" rather than \"include this thing\". */\nconst TEXTURE_LABELS: ReadonlySet<string> = new Set([\n \"texture\", \"style\", \"pattern\", \"look\", \"material\",\n])\n\n/**\n * Subject form for directive bullets: parenthetical label after the image\n * index so the model sees both the position binding and the role descriptor\n * in one tight phrase. Numeric indices (\"Image 1\") match the typed token\n * (e.g. `@kira:1:smile`) so users can trace the slug through to the final\n * assembled directive.\n *\n * \"dragon\" + 1 → \"Image 1 (dragon)\"\n * \"Danny\" + 2 → \"Image 2 (Danny)\"\n * \"dragon\" + 1 + desc \"red scales\" → \"Image 1 (dragon — red scales)\"\n * no label + 3 → \"Image 3\"\n */\nfunction formatDirectiveSubject(label: string, imageIndex: number, description?: string): string {\n if (!label && !description) return `Image ${imageIndex}`\n const inner = label && description\n ? `${label} — ${description}`\n : (label || description)!\n return `Image ${imageIndex} (${inner})`\n}\n\n/** Labels that mean \"a person / character\" — strengthen the directive so the\n * model holds the face + body + distinctive features. Folds the\n * identity-preservation language (previously appended as a trailing\n * global clause via `collectIdentityLockClause`) directly into the per-image\n * bullet so the model sees the identifier and the rule together. */\nconst PERSON_LABELS: ReadonlySet<string> = new Set([\n \"person\", \"character\", \"face\", \"subject\", \"people\",\n])\n\n/** Labels that mean \"a creature / animal subject\" — the animal analog of\n * PERSON_LABELS. A bound creature is a LIVING subject with its own identity\n * (a specific cat, dragon, beast), so the directive locks anatomy, markings,\n * coloration, and distinctive features instead of the person face/body\n * phrasing — and instead of the generic prop \"match exactly\" verb a\n * `wired-object` gets. */\nconst CREATURE_LABELS: ReadonlySet<string> = new Set([\n \"creature\", \"animal\", \"pet\", \"beast\", \"monster\",\n])\n\nfunction buildIdentityDirective(\n id: ResolvedIdentity,\n suppressedCanonicalLocationIds?: readonly string[],\n): string {\n if (id.fidelity === \"custom\" && id.customText) {\n return `- ${id.customText}`\n }\n\n // Location canonical-description injection (Phase 2 #1). Mirrors the\n // character canonical-description pattern (see `characterCanonicalDescription`\n // in the Phase 0 mention resolver above). When a wired-location ref has\n // canonical text AND the user hasn't suppressed it via the × button on the\n // Injected References list, the canonical description gets folded into the\n // directive subject so the model sees \"Image N (location — <canonical\n // description>)\" without the user typing it. Per-ref description (from the\n // user-typed Description field on the location node) still wins when present.\n let effectiveDescription = id.description\n if (\n !effectiveDescription\n && id.source === \"wired-location\"\n && id.locationCanonicalDescription\n && !(id.locationSlug && suppressedCanonicalLocationIds?.includes(id.locationSlug))\n ) {\n effectiveDescription = id.locationCanonicalDescription.trim() || undefined\n }\n\n // Phase 2 #3: kind-tagged reference-photo annotation. When the ref carries\n // a `locationReferencePhotoKind`, fold its human-friendly label into the\n // subject's parenthetical so the model sees the photo's role inline with\n // the location name (e.g. \"Image 1 (Old Library — wide-angle reference)\").\n // The annotation rides on the LABEL (not the description) so it survives\n // the description-overrides-canonical precedence above.\n let effectiveLabel = id.label\n if (id.locationReferencePhotoKind && effectiveLabel) {\n effectiveLabel = `${effectiveLabel} — ${locationReferencePhotoKindLabel(id.locationReferencePhotoKind as LocationReferencePhotoKind)}`\n }\n\n const subject = formatDirectiveSubject(effectiveLabel, id.imageIndex, effectiveDescription)\n const lower = id.label.toLowerCase()\n\n // Role-aware verbs — these read more naturally than \"match exactly\" for\n // background scenes or texture/style references.\n if (BACKGROUND_LABELS.has(lower)) {\n return `- ${subject} — use as the background/setting.`\n }\n if (TEXTURE_LABELS.has(lower)) {\n return `- ${subject} — apply this ${id.label}.`\n }\n\n // Person/character labels: strengthen the directive (regardless of fidelity)\n // so the global trailing identity-lock clause becomes redundant.\n // \"loose\" still gets the inspiration form so users can opt out.\n if (PERSON_LABELS.has(lower) && id.fidelity !== \"loose\") {\n return `- ${subject} — match exactly. Maintain perfect likeness (face, body proportions, distinctive features).`\n }\n\n // Creature/animal labels: the same identity-lock strength as a person, with\n // animal-subject phrasing — anatomy/markings/coloration are what make THIS\n // cat this cat. \"loose\" still opts out to the inspiration form below.\n if (CREATURE_LABELS.has(lower) && id.fidelity !== \"loose\") {\n return `- ${subject} — this is a creature/animal subject: match it exactly. Maintain perfect likeness (anatomy, markings, coloration, distinctive features).`\n }\n\n switch (id.fidelity) {\n case \"strict\":\n return `- ${subject} — match exactly. Maintain perfect likeness.`\n case \"loose\":\n return `- ${subject} — use loosely as inspiration.`\n case \"custom\": // custom without text falls through to balanced\n case \"balanced\":\n default:\n return `- ${subject} — match exactly.`\n }\n}\n\n/**\n * Build the non-character directive block for `buildImagePrompt`'s\n * connectedReferences path:\n * 1. `{image:N:label}` identity directives (legacy positional mentions), in\n * prompt-mention order, renumbered from their `nonCharacterRefs` index to\n * the ref's FINAL slot.\n * 2. Canonical-style fallback directives for `wired-location` / `wired-object`\n * / `wired-creature` refs that are present but neither `{image:N}`-referenced\n * nor @-mentioned (@-mentioned locations were already filtered out of\n * connectedReferences in Phase 0). Mirrors the character canonical fallback\n * so a wired setting / object / creature gets a directive with zero typing\n * required. Scoped to those three sources — opaque `manual` / `wired-image`\n * uploads carry no metadata to describe and keep their (intentional)\n * directive-free behavior.\n *\n * Every directive's `Image N` is numbered against `finalIndexByUrl` (the single\n * source of truth for the assembled URL order), so the index always matches the\n * URL slot. `coveredUrls` prevents a URL emitted via a token from being\n * re-emitted by the fallback AND dedupes a location/object wired twice.\n */\nfunction buildNonCharacterDirectives(\n prompt: string,\n nonCharacterRefs: readonly ConnectedReference[],\n identityMeta: readonly IdentityMeta[],\n finalIndexByUrl: ReadonlyMap<string, number>,\n suppressedCanonicalLocationIds: readonly string[],\n): string {\n const lines: string[] = []\n const coveredUrls = new Set<string>()\n\n for (const id of collectIdentities(prompt, nonCharacterRefs, identityMeta)) {\n const ref = nonCharacterRefs[id.imageIndex - 1]\n const finalIdx = ref?.url ? finalIndexByUrl.get(ref.url) : undefined\n const line = buildIdentityDirective(\n finalIdx ? { ...id, imageIndex: finalIdx } : id,\n suppressedCanonicalLocationIds,\n )\n if (line.length > 0) lines.push(line)\n if (ref?.url) coveredUrls.add(ref.url)\n }\n\n for (const ref of nonCharacterRefs) {\n if (ref.source !== \"wired-location\" && ref.source !== \"wired-object\" && ref.source !== \"wired-creature\") continue\n if (!ref.url || coveredUrls.has(ref.url)) continue\n const finalIdx = finalIndexByUrl.get(ref.url)\n if (!finalIdx) continue\n coveredUrls.add(ref.url)\n const line = buildIdentityDirective(\n {\n imageIndex: finalIdx,\n // A background label routes wired-location through the\n // \"use as the background/setting\" verb (and folds\n // locationCanonicalDescription); wired-creature routes through the\n // creature/animal-subject identity lock (CREATURE_LABELS);\n // wired-object falls through to the strict \"match exactly\" verb.\n label: ref.source === \"wired-location\"\n ? \"location\"\n : ref.source === \"wired-creature\"\n ? \"creature\"\n : \"object\",\n fidelity: defaultFidelityForSource(ref.source),\n description: ref.descriptionOverride?.trim() || ref.description?.trim() || undefined,\n source: ref.source,\n locationCanonicalDescription: ref.locationCanonicalDescription,\n locationSlug: ref.locationSlug,\n locationReferencePhotoKind: ref.locationReferencePhotoKind,\n },\n suppressedCanonicalLocationIds,\n )\n if (line.length > 0) lines.push(line)\n }\n\n return lines.join(\"\\n\")\n}\n\n/**\n * Replace `{image:N:label}` and `{image:N}` tokens with natural-language\n * phrases bound to a numbered image (Image 1 / 2 / 3 …).\n *\n * - `{image:N:label}` → `Image {N} ({label})`\n * - `{image:N}` → `Image {N}` (no role specified)\n *\n * Same parenthetical form as the directive subject so the model sees a\n * consistent identifier in both the bulleted list and the scene description.\n * Numeric indices match the user-typed slug format (`@kira:1:smile`).\n *\n * Out-of-range indices are left untouched by this helper. `buildImagePrompt`\n * then renders any such token by the unwired rule (`dropUnwiredImageTokens`):\n * its label, or nothing — never the raw token.\n */\nexport function expandImageRefTokens(prompt: string, imageCount: number): string {\n return prompt.replace(IMAGE_TOKEN_PATTERN, (match, num, label) => {\n const n = parseInt(num, 10)\n if (n < 1 || n > imageCount) return match\n return label ? `Image ${n} (${label})` : `Image ${n}`\n })\n}\n\n/**\n * Like `expandImageRefTokens`, but remaps each `{image:N}` token from its index\n * in `refs` (the non-character ref list the token was authored against) to the\n * ref's FINAL 1-based slot in the assembled URL list. Used by\n * `buildImagePrompt`'s connectedReferences path so body-text `Image N` markers\n * agree with the directive numbering after non-character URLs are appended.\n *\n * When the final slot equals the token index (no Phase-0 prefix shifting the\n * positions), the output is byte-identical to `expandImageRefTokens`.\n * Out-of-range tokens (or refs without a URL) are left untouched here; the\n * assembly's last step, `dropUnwiredImageTokens`, renders them by the unwired\n * rule with the same `tokenFinalSlot` binding test.\n */\nfunction expandImageRefTokensForRefs(\n prompt: string,\n refs: readonly ConnectedReference[],\n finalIndexByUrl: ReadonlyMap<string, number>,\n): string {\n return prompt.replace(IMAGE_TOKEN_PATTERN, (match, num, label) => {\n const finalIdx = tokenFinalSlot(parseInt(num, 10), refs, finalIndexByUrl)\n if (!finalIdx) return match\n return label ? `Image ${finalIdx} (${label})` : `Image ${finalIdx}`\n })\n}\n\n// ---------------------------------------------------------------------------\n// Hybrid reference format (images-only, flag-gated via\n// `BuildImagePromptConfig.referenceFormat === \"hybrid\"`). TOKEN EXPANSION ONLY:\n// every {image:N:label} token → \"the <label> from reference image <LETTER>\"\n// (letters map the FINAL 1-based slot, 1→A). NO reference-lock snippet is\n// auto-injected — authors prepend their own lock in the prompt text (it passes\n// through untouched); a caller may optionally prepend one via\n// `config.referenceLockSnippet`. Scope is the `{image:N:label}` non-character\n// path — characters/objects/locations still use the legacy wrap.\n// ---------------------------------------------------------------------------\n\n/** Map a 1-based reference slot to a letter (1→A, 2→B …). Slots beyond 26 fall\n * back to the numeric slot so we never emit a non-letter control character. */\nfunction slotToLetter(slot: number): string {\n return slot >= 1 && slot <= 26 ? String.fromCharCode(64 + slot) : String(slot)\n}\n\n/** Hybrid inline phrase for a `{image:N:label}` token bound to a lettered slot.\n * Uniform: \"the <label> from reference image <letter>\" — the label is used\n * verbatim (the global identity directive handles subject preservation, so no\n * per-role branching is needed). A label-less token → \"reference image <letter>\". */\nfunction hybridRolePhrase(label: string, letter: string): string {\n if (!label) return `reference image ${letter}`\n return `the ${label} from reference image ${letter}`\n}\n\n/**\n * Like `expandImageRefTokensForRefs`, but emits the hybrid lettered phrase\n * (\"the subject from reference image A\") instead of the legacy \"Image N\n * (label)\". Out-of-range tokens / URL-less refs are left untouched here and\n * rendered by the unwired rule at the end of assembly (`dropUnwiredImageTokens`).\n *\n * A `{image:N:label}` pill is a mention chip like any other: `buildRefPillNodes`\n * appends its own trailing space to EVERY pill it builds, the positional\n * `imageRef` node included, so `a man wearing {image:1:hat} in the park` is the\n * ordinary shape and it expanded to \"…the hat from reference image A in the\n * park\". Splice through `spliceMentionPhrase` for the same seam tidy the three\n * `@`-mention resolvers use, right-to-left over offsets taken against the\n * pre-splice string (its OFFSET SAFETY note covers exactly this loop). The\n * legacy `expandImageRefTokensForRefs` keeps its raw `.replace` — legacy output\n * is pinned byte-identical.\n */\nfunction expandImageRefTokensHybrid(\n prompt: string,\n refs: readonly ConnectedReference[],\n finalIndexByUrl: ReadonlyMap<string, number>,\n): string {\n const splices: Array<{ offset: number; length: number; phrase: string }> = []\n for (const m of prompt.matchAll(IMAGE_TOKEN_PATTERN)) {\n const finalIdx = tokenFinalSlot(parseInt(m[1], 10), refs, finalIndexByUrl)\n if (!finalIdx) continue\n splices.push({\n offset: m.index ?? 0,\n length: m[0].length,\n phrase: hybridRolePhrase((m[2] ?? \"\").trim(), slotToLetter(finalIdx)),\n })\n }\n\n // `matchAll` yields ascending offsets; splice back-to-front so the\n // not-yet-applied (smaller) offsets stay valid.\n let resolved = prompt\n for (let i = splices.length - 1; i >= 0; i--) {\n const s = splices[i]\n resolved = spliceMentionPhrase(resolved, s.offset, s.length, s.phrase)\n }\n return resolved\n}\n\n/** Capitalize the first alphabetic character of a string (line-initial). */\nfunction capitalizeLineInitial(line: string): string {\n return line.replace(/[a-zA-Z]/, (c) => c.toUpperCase())\n}\n\n/** Render the user prompt as the hybrid scene: each `{image:N:label}` token\n * expanded to its uniform lettered phrase, each line's first letter\n * capitalized. No per-role special-casing — the label drives the phrase.\n *\n * The capitalizer STOPS at the `[style]` section and everything after it: the\n * header would become `[Style]:`, and every catalog clause under it would gain\n * a capital it was not written with. The header line is matched EXACTLY — the\n * composer never indents it, and the whitespace collapses on this path are\n * horizontal-only (`[^\\S\\r\\n]`), so nothing can pad it before this runs. */\nfunction buildHybridScene(\n prompt: string,\n refs: readonly ConnectedReference[],\n finalIndexByUrl: ReadonlyMap<string, number>,\n): string {\n const lines = prompt.split(\"\\n\")\n const sectionAt = lines.indexOf(STYLE_SECTION_HEADER)\n return lines\n .map((line, i) => {\n const expanded = expandImageRefTokensHybrid(line, refs, finalIndexByUrl)\n return sectionAt >= 0 && i >= sectionAt ? expanded : capitalizeLineInitial(expanded)\n })\n .join(\"\\n\")\n}\n\n/** Build the combined per-identity directive intro for previews.\n * Each directive is emitted on its own line so the model (and the human\n * reading the FinalPromptPreview) can see the structure clearly. */\nexport function buildIdentityDirectives(\n prompt: string,\n refs: readonly ConnectedReference[],\n meta: readonly IdentityMeta[] = [],\n suppressedCanonicalLocationIds?: readonly string[],\n): string {\n return collectIdentities(prompt, refs, meta)\n .map((id) => buildIdentityDirective(id, suppressedCanonicalLocationIds))\n .filter((s) => s.length > 0)\n .join(\"\\n\")\n}\n\n// ---------------------------------------------------------------------------\n// Backward-compat shims — preview/test helpers used elsewhere still reference\n// the old names. Keep thin wrappers so we don't break callers in this round.\n// ---------------------------------------------------------------------------\n\n/** @deprecated Use `expandImageRefTokens` (label-aware). */\nexport function expandImagePositionRefs(\n prompt: string,\n imageCount: number,\n names?: readonly string[],\n): string {\n return prompt.replace(IMAGE_TOKEN_PATTERN, (match, num, label) => {\n const n = parseInt(num, 10)\n if (!hasImageAt(n, imageCount)) return match\n if (label) return `Image ${n} (${label})`\n if (names && names[n - 1]) return names[n - 1]\n return `Image ${n}`\n })\n}\n\n/** @deprecated Use `buildIdentityDirectives(prompt, refs, meta)`. */\nexport function buildReferenceBlocks(\n refs: readonly ConnectedReference[],\n _meta: readonly IdentityMeta[] = [],\n): string {\n // Legacy callers don't have prompt context — emit a default-label block per ref.\n const synthPrompt = \"\"\n return buildIdentityDirectives(synthPrompt, refs, _meta)\n}\n\n// ---------------------------------------------------------------------------\n// Scene prompt builder — shared between frontend DAG executor and backend\n// orchestrator. Builds a rich image-generation prompt from SceneNodeData.\n// ---------------------------------------------------------------------------\n\nexport const SCENE_PROMPT_MAX_LENGTH = 2000\nconst SCENE_PROMPT_SAFE_LENGTH = 1800\n\nexport const SHOT_LABELS: Record<string, string> = {\n \"extreme-wide\": \"EXTREME WIDE SHOT\",\n \"wide\": \"WIDE SHOT\",\n \"medium-wide\": \"MEDIUM WIDE SHOT\",\n \"medium\": \"MEDIUM SHOT\",\n \"medium-close\": \"MEDIUM CLOSE-UP\",\n \"close-up\": \"CLOSE-UP\",\n \"extreme-close-up\": \"EXTREME CLOSE-UP\",\n}\n\nexport const ANGLE_LABELS: Record<string, string> = {\n \"eye-level\": \"eye level\",\n \"low-angle\": \"low angle\",\n \"high-angle\": \"high angle\",\n \"birds-eye\": \"bird's eye view\",\n \"worms-eye\": \"worm's eye view\",\n \"dutch\": \"dutch angle\",\n}\n\nexport const ASPECT_RATIO_LABELS: Record<string, string> = {\n \"16:9\": \"wide landscape composition\",\n \"9:16\": \"vertical portrait composition\",\n \"1:1\": \"square composition\",\n \"4:3\": \"classic frame composition\",\n \"21:9\": \"ultrawide cinematic composition\",\n \"4:5\": \"tall portrait composition\",\n}\n\nexport const MOVEMENT_LABELS: Record<string, string> = {\n static: \"static camera\",\n pan: \"camera panning\",\n tilt: \"camera tilting\",\n dolly: \"dolly shot\",\n tracking: \"tracking shot\",\n crane: \"crane shot\",\n handheld: \"handheld camera\",\n zoom: \"zoom\",\n}\n\nexport function truncateText(text: string, maxLen: number): string {\n if (text.length <= maxLen) return text\n return text.slice(0, maxLen - 3) + \"...\"\n}\n\n/**\n * Build a rich image-generation prompt from scene node data + character\n * definitions. Used by both the frontend DAG executor and the backend\n * orchestrator so that scene prompts are identical regardless of\n * execution path.\n */\nexport function buildScenePrompt(\n data: SceneData,\n assets: readonly CharacterDef[],\n options?: { forDisplay?: boolean },\n): string {\n const noTruncate = options?.forDisplay === true\n const t = noTruncate ? (text: string, _max: number) => text : truncateText\n const highParts: string[] = []\n const medParts: string[] = []\n const lowParts: string[] = []\n\n // Shot type and angle (high)\n const shot = SHOT_LABELS[data.shotType] ?? \"MEDIUM SHOT\"\n const angle = ANGLE_LABELS[data.cameraAngle] ?? \"eye level\"\n highParts.push(`${shot}, ${angle}`)\n\n // Aspect ratio composition hint (medium)\n if (data.aspectRatio && data.aspectRatio !== \"16:9\") {\n const ratioLabel = ASPECT_RATIO_LABELS[data.aspectRatio]\n if (ratioLabel) medParts.push(ratioLabel)\n }\n\n // Characters with mood and action (high, but truncate descriptions)\n if (data.characters.length > 0) {\n const maxDescLen = data.characters.length > 2 ? 80 : 150\n const charDescs = data.characters.map((entry) => {\n const asset = assets.find((a) => a.id === entry.assetId)\n const name = asset?.name ?? \"a figure\"\n const desc = asset?.description ? `, ${t(asset.description, maxDescLen)}` : \"\"\n const mood = entry.mood ? `, ${entry.mood}` : \"\"\n const action = entry.action ? ` ${entry.action}` : \"\"\n const pos = entry.positionInFrame ? ` (${entry.positionInFrame})` : \"\"\n return `${name}${desc}${mood}${action}${pos}`\n })\n highParts.push(`of ${charDescs.join(\" and \")}`)\n }\n\n // Locations (high, but truncate names)\n if (data.locations && data.locations.length > 0) {\n const locDescs = data.locations.map((loc) => {\n const asset = assets.find((a) => a.id === loc.assetId)\n const rawName = loc.name ?? asset?.description ?? asset?.name ?? \"location\"\n const name = t(rawName, 120)\n const envParts: string[] = []\n const tod = loc.timeOfDay ?? data.timeOfDay\n const wth = loc.weather ?? data.weather\n const lit = loc.lighting ?? data.lighting\n if (tod !== \"noon\") envParts.push(`${tod} light`)\n if (wth !== \"clear\") envParts.push(wth)\n if (lit !== \"natural\") envParts.push(`${lit} lighting`)\n return envParts.length > 0 ? `${name} (${envParts.join(\", \")})` : name\n })\n highParts.push(`in ${locDescs.join(\" and \")}`)\n } else {\n const envParts: string[] = []\n if (data.timeOfDay !== \"noon\") envParts.push(`${data.timeOfDay} light`)\n if (data.weather !== \"clear\") envParts.push(data.weather)\n if (data.lighting !== \"natural\") envParts.push(`${data.lighting} lighting`)\n if (envParts.length > 0) highParts.push(envParts.join(\", \"))\n }\n\n // Objects (medium)\n if (data.objects.length > 0) {\n const objDescs = data.objects.map((o) => {\n const asset = assets.find((a) => a.id === o.assetId)\n return o.description ?? asset?.name ?? \"object\"\n })\n medParts.push(`with ${objDescs.join(\", \")}`)\n }\n\n // Mood (medium)\n if (data.mood.length > 0) {\n medParts.push(`${data.mood.join(\", \")} atmosphere`)\n }\n\n // Visual style (medium)\n if (data.visualStyle) {\n medParts.push(`${data.visualStyle} style`)\n }\n\n // Depth of field (low)\n if (data.depthOfField !== \"medium\") {\n lowParts.push(`${data.depthOfField} depth of field`)\n }\n\n // Lens (low)\n if (data.lensType !== \"normal\") {\n lowParts.push(`${data.lensType} lens`)\n }\n\n // Camera movement (medium)\n if (data.cameraMovement !== \"static\") {\n medParts.push(MOVEMENT_LABELS[data.cameraMovement] ?? data.cameraMovement)\n }\n\n // Color palette (low)\n if (data.colorPalette.length > 0) {\n lowParts.push(`${data.colorPalette.join(\", \")} color palette`)\n }\n\n // Summary as additional context (medium, truncated)\n if (data.summary.trim()) {\n medParts.push(t(data.summary.trim(), 300))\n }\n\n // Dialogue context (low, truncated)\n if (data.dialogue && data.dialogue.length > 0) {\n const dialogueDesc = data.dialogue\n .filter((d) => d.text.trim())\n .map((d) => `${d.characterName}${d.emotion ? ` (${d.emotion})` : \"\"}: \"${t(d.text.trim(), 80)}\"`)\n .join(\"; \")\n if (dialogueDesc) lowParts.push(`dialogue: ${t(dialogueDesc, 250)}`)\n }\n\n // Director notes (low, truncated)\n if (data.directorNotes?.trim()) {\n lowParts.push(t(data.directorNotes.trim(), 200))\n }\n\n // Assemble with progressive dropping\n let result = [...highParts, ...medParts, ...lowParts].join(\", \")\n\n if (!noTruncate) {\n if (result.length > SCENE_PROMPT_SAFE_LENGTH) {\n let dropCount = 0\n while (dropCount < lowParts.length && result.length > SCENE_PROMPT_SAFE_LENGTH) {\n dropCount++\n result = [...highParts, ...medParts, ...lowParts.slice(0, lowParts.length - dropCount)].join(\", \")\n }\n }\n if (result.length > SCENE_PROMPT_SAFE_LENGTH) {\n const medRemaining = [...medParts]\n while (medRemaining.length > 0 && result.length > SCENE_PROMPT_SAFE_LENGTH) {\n medRemaining.pop()\n result = [...highParts, ...medRemaining].join(\", \")\n }\n }\n if (result.length > SCENE_PROMPT_MAX_LENGTH) {\n result = result.slice(0, SCENE_PROMPT_MAX_LENGTH - 3) + \"...\"\n }\n }\n\n return result\n}\n\n","/**\n * Path-1 structured prompt fields → composed prompt fragment.\n *\n * Used by:\n * - Nodaro's MCP server (Phase 6 v1.1) — generate_image / generate_video verbs\n * accept these structured fields and run them through this helper before\n * passing the composite prompt to the underlying route.\n * - (Optional) Frontend editor — same logic so the editor and MCP produce\n * identical prompts for the same inputs.\n *\n * NOTE: this is a parallel utility to `prompt-builder.ts`. The latter does\n * image-specific composition (character/template/reference handling), while\n * this module handles the Path-1 structured-field shape that MCP verbs accept\n * (free-form strings under person/styling/setting/camera/lens/mood). Existing\n * frontend `buildPersonHints` / `buildStylingHints` helpers operate on catalog\n * IDs and are not interchangeable with this renderer.\n */\n\nexport interface StructuredPromptFields {\n person?: {\n age?: number\n gender?: \"man\" | \"woman\" | \"child\" | \"non-binary\"\n hair?: string\n eyes?: string\n expression?: string\n profession?: string\n warriorType?: string\n }\n styling?: {\n mood?: string\n lighting?: string\n aesthetic?: string\n colorLook?: string\n }\n setting?: {\n era?: string\n atmosphere?: string\n backdrop?: string\n }\n camera?: {\n framing?: string\n motion?: string\n format?: string\n }\n lens?: {\n focalLength?: string\n aperture?: string\n }\n /** Standalone shorthand mood (overrides styling.mood if both are set). */\n mood?: string\n}\n\n/**\n * Render structured fields → composite prompt fragment to be appended to the\n * user's free-text prompt. Returns \"\" if no fields populated.\n */\nexport function renderStructuredFields(fields: StructuredPromptFields): string {\n const parts: string[] = []\n if (fields.person) parts.push(renderPerson(fields.person))\n if (fields.styling) {\n // The standalone `mood` shorthand overrides styling.mood (per the type\n // doc) — drop styling.mood when the shorthand is set so the two don't both\n // render conflicting \"mood …\" / \"Mood: …\" directives.\n const styling = fields.mood ? { ...fields.styling, mood: undefined } : fields.styling\n parts.push(renderStyling(styling))\n }\n if (fields.setting) parts.push(renderSetting(fields.setting))\n if (fields.camera) parts.push(renderCamera(fields.camera))\n if (fields.lens) parts.push(renderLens(fields.lens))\n if (fields.mood) parts.push(`Mood: ${fields.mood}.`)\n return parts.filter((s) => s.length > 0).join(\" \")\n}\n\nfunction renderPerson(p: NonNullable<StructuredPromptFields[\"person\"]>): string {\n const bits: string[] = []\n if (p.age) bits.push(`${p.age} years old`)\n if (p.gender) bits.push(p.gender)\n if (p.profession) bits.push(p.profession)\n if (p.warriorType) bits.push(`(${p.warriorType})`)\n if (p.hair) bits.push(`with ${p.hair} hair`)\n if (p.eyes) bits.push(`${p.eyes} eyes`)\n if (p.expression) bits.push(`${p.expression} expression`)\n return bits.length > 0 ? `Subject: ${bits.join(\", \")}.` : \"\"\n}\n\nfunction renderStyling(s: NonNullable<StructuredPromptFields[\"styling\"]>): string {\n const bits: string[] = []\n if (s.mood) bits.push(`mood ${s.mood}`)\n if (s.lighting) bits.push(`${s.lighting} lighting`)\n if (s.aesthetic) bits.push(`${s.aesthetic} aesthetic`)\n if (s.colorLook) bits.push(`${s.colorLook} color`)\n return bits.length > 0 ? `Style: ${bits.join(\", \")}.` : \"\"\n}\n\nfunction renderSetting(s: NonNullable<StructuredPromptFields[\"setting\"]>): string {\n const bits: string[] = []\n if (s.era) bits.push(`${s.era} era`)\n if (s.atmosphere) bits.push(`${s.atmosphere} atmosphere`)\n if (s.backdrop) bits.push(`set in ${s.backdrop}`)\n return bits.length > 0 ? `Setting: ${bits.join(\", \")}.` : \"\"\n}\n\nfunction renderCamera(c: NonNullable<StructuredPromptFields[\"camera\"]>): string {\n const bits: string[] = []\n if (c.framing) bits.push(`${c.framing} framing`)\n if (c.motion) bits.push(c.motion)\n if (c.format) bits.push(`${c.format} format`)\n return bits.length > 0 ? `Camera: ${bits.join(\", \")}.` : \"\"\n}\n\nfunction renderLens(l: NonNullable<StructuredPromptFields[\"lens\"]>): string {\n const bits: string[] = []\n if (l.focalLength) bits.push(l.focalLength)\n if (l.aperture) bits.push(`f/${l.aperture}`)\n return bits.length > 0 ? `Lens: ${bits.join(\", \")}.` : \"\"\n}\n","/**\n * THE SUBJECT REGISTRY — the ordered table of every SUBJECT dimension the flat\n * `subject` channel carries (who is in the shot: Person, Styling, and the three\n * prop catalogs), plus the one renderer that folds it into prompt text.\n *\n * WHY A SECOND CHANNEL, NOT `StructuredPromptFields`: that type is FREE TEXT\n * (`person.hair?: string` → \"with {hair} hair\"), its reader is a hand-authored\n * field table whose totality is compile-time enforced by mapped types, its\n * values are bounded as prose (200 chars), and it renders as headed sentences\n * (\"Subject: …. Style: ….\"). None of those survive contact with ~50 CATALOG IDS\n * plus deployment-registered pack dimensions unknown at compile time, whose\n * hints are authored as comma-joinable compound clauses. `direction-registry.ts`\n * already has the four properties this channel needs — a platform-owned fold\n * order exported for client preview parity, a DERIVED wire schema and node\n * reader, unknown-key/unknown-id inertness, and shared bounds across both doors\n * — so this module mirrors it. `direction-registry.ts` hands this scope off by\n * name in its own header.\n *\n * WIRE VOCABULARY: the keys are the platform's OWN node-data field names — the\n * ones `PERSON_FIELD_BY_DIMENSION` / `STYLING_FIELD_BY_DIMENSION` and the prop\n * pickers' `valueField` already use (`hairBase`, `lipState`, `wardrobeState`,\n * `heldProp`, `material`, `animal`, …). A canvas person/styling node stores\n * exactly these, and every `build*Hints` already consumes them.\n *\n * THE WIRE IS A FLAT BAG, AND THE FLATNESS IS LOAD-BEARING (not a shortcut):\n * `collectStylingFragments` reads `data.lipState` — a PERSON field — to skip\n * `makeup-bold-lips` when `lip-state-bold-red` is already selected. That dedupe\n * only fires for a consumer folding both pickers off ONE shared value map,\n * which is precisely what this channel is. Nesting `person` / `styling` as\n * sub-records would hand the styling builder a bag with no `lipState` in it and\n * the lipstick clause would silently double. Hence: flat wire, and the group\n * rows below receive the WHOLE normalized bag rather than a slice of it.\n *\n * PRE/POST FREE TEXT IS DELIBERATELY OFF THE WIRE (v1): `PersonValue` and\n * `StylingValue` BOTH declare `preText`/`postText` and both `collect*Fragments`\n * read them, so a shared flat bag would emit the same prose twice. They are the\n * only genuine key collision in the set and are simply not `SUBJECT_KEYS`, so\n * the normalizer drops them. Per-subject free text is the one future need that\n * would force either nesting or suffixed keys (`personPreText` / …).\n *\n * IMPORT RULE (hard, inherited from the direction registry): this module\n * imports only `get*PromptHint` / `get*Term` / `build*Hints` FUNCTIONS and the\n * `*_FIELD_BY_DIMENSION` / `*_DIMENSION_ORDER` maps — never a raw UPPERCASE\n * catalog array (`PEOPLE`, `STYLINGS`, `ANIMALS`). `catalog-funnel-ratchet.test.ts`\n * derives its watch set from `picker-catalogs.ts`'s uppercase value imports and\n * can only SHRINK, so a raw array import here would be a new offender — which\n * is exactly why the animal getters live in `@nodaro/shared`. Nothing here\n * reads an environment variable either (`content-free-contract.test.ts`):\n * verbosity and surface are threaded parameters, never deployment state.\n *\n * DISJOINT FROM `direction` BY CONTRACT: `SUBJECT_KEYS ∩ DIRECTION_KEYS = ∅`,\n * pinned by a test. `pose` rides `direction` even though the picker wiring files\n * it under \"Subject / Object\"; keeping the two key sets disjoint is what stops\n * one selection emitting two clauses.\n */\nimport type { PickerHintMode } from \"./term.js\"\nimport {\n DIRECTION_ARRAY_CEILING,\n DIRECTION_ID_MAX_CHARS,\n} from \"./direction-registry.js\"\nimport {\n buildPersonHints,\n getPersonDimensionLimit,\n PERSON_DIMENSION_ORDER,\n PERSON_FIELD_BY_DIMENSION,\n type PersonDimension,\n type PersonValue,\n} from \"./person.js\"\nimport {\n getRegisteredPersonDimensionOrder,\n getRegisteredPersonFieldByDimension,\n} from \"./person-packs.js\"\nimport {\n buildStylingHints,\n getStylingDimensionLimit,\n STYLING_DIMENSION_ORDER,\n STYLING_FIELD_BY_DIMENSION,\n type StylingDimension,\n type StylingValue,\n} from \"./styling.js\"\nimport { buildHeldPropHints } from \"./held-prop.js\"\nimport { buildMaterialHints } from \"./materials.js\"\nimport { curatedAnimalPromptHint, curatedAnimalTerm } from \"./shared-catalog-overlay.js\"\n\n/** Which generation stages fold a dimension (mirrors `DirectionSurface`). */\nexport type SubjectSurface = \"image\" | \"video\" | \"both\"\n\n/**\n * Flat subject ids — the wire shape and the canvas node-data shape.\n *\n * Keys are the platform's own field names; a value is one id, a list of ids, or\n * (for `customAge` alone) a number. Absent ≠ empty: a missing key means \"no\n * hint\", never a default.\n */\nexport type SubjectFields = Readonly<Record<string, string | readonly string[] | number>>\n\n/**\n * A fold row whose render consumes the WHOLE normalized bag and returns ONE\n * already-joined clause.\n *\n * Two reasons this kind exists rather than one row per person/styling field:\n * 1. the cross-catalog dedupe described in the module header needs the whole\n * bag in one call;\n * 2. these builders emit FRAGMENTS, not clauses — 30 person fragments handed\n * to the `\". \"` prompt-hint join read as \"a beautiful woman. in her 30s.\n * East Asian.\" The catalogs' own grammar is a comma-joined compound clause,\n * so the row joins with \", \" and hands back a single piece.\n */\nexport interface SubjectGroupFieldSpec {\n /** Fold-row id. NOT a wire key — a group row reads many of them. */\n readonly key: string\n readonly kind: \"group\"\n readonly surface: SubjectSurface\n /** The whole normalized bag in, one joined clause out (`[]` when empty). */\n readonly render: (subject: SubjectFields, mode: PickerHintMode) => string[]\n}\n\n/** A fold row that reads ONE wire key holding catalog ids (the prop catalogs). */\nexport interface SubjectIdsFieldSpec {\n /** Wire key AND fold-row id — these rows are one key each. */\n readonly key: string\n readonly kind: \"ids\"\n readonly surface: SubjectSurface\n /** Ids honored. Extras are SLICED by the normalizer, never a 400. */\n readonly maxPicks: number\n readonly render: (ids: readonly string[], mode: PickerHintMode) => string[]\n}\n\nexport type SubjectFieldSpec = SubjectGroupFieldSpec | SubjectIdsFieldSpec\n\n// ── Render adapters (module-private) ────────────────────────────────────────\n\n/**\n * The shape both group builders accept. Their declared parameters are\n * `Record<string, unknown> & PersonValue` and `… & StylingValue`; the\n * intersection is assignable to both, so ONE adapter serves both rows without\n * erasing the argument type — a builder signature change fails to typecheck\n * here rather than silently passing the wrong bag.\n */\ntype SubjectBuilderData = Record<string, unknown> & PersonValue & StylingValue\n\n/** A `build*Hints` that returns FRAGMENTS → one comma-joined clause. */\nconst viaFragmentBuilder =\n (build: (data: SubjectBuilderData, mode: PickerHintMode) => string[]) =>\n (subject: SubjectFields, mode: PickerHintMode): string[] => {\n const clause = build(subject as unknown as SubjectBuilderData, mode)\n .filter((s) => s.length > 0)\n .join(\", \")\n return clause.length > 0 ? [clause] : []\n }\n\n/** A catalog whose own builder already returns a clause LIST (held props). */\nconst viaListBuilder =\n (build: (v: unknown, mode: PickerHintMode) => string[]) =>\n (ids: readonly string[], mode: PickerHintMode): string[] =>\n build(ids.length === 1 ? ids[0] : [...ids], mode).filter((s) => s.length > 0)\n\n/** A catalog whose own builder returns ONE blended clause (materials). */\nconst viaStringBuilder =\n (build: (v: unknown, mode: PickerHintMode) => string) =>\n (ids: readonly string[], mode: PickerHintMode): string[] => {\n const s = build(ids.length === 1 ? ids[0] : [...ids], mode)\n return s.length > 0 ? [s] : []\n }\n\n/**\n * Independent per-id emission — the same doctrine as the direction registry's\n * `perId`. Only ever receives NON-EMPTY ids (the normalizer drops empties).\n */\nconst perId =\n (full: (id: string) => string, compact: (id: string) => string) =>\n (ids: readonly string[], mode: PickerHintMode): string[] => {\n const out: string[] = []\n for (const id of ids) {\n const frag = mode === \"compact\" ? compact(id) : full(id)\n if (frag.length > 0) out.push(frag)\n }\n return out\n }\n\n/**\n * THE TABLE. Declaration order IS fold order (`SUBJECT_FOLD_KEYS`), pinned by\n * `__tests__/subject-registry.test.ts`.\n *\n * Person leads (who), then how they are styled, then what they hold, what it is\n * made of, and finally the animal in frame. Both group rows run over the SAME\n * normalized bag, in this order, which is what keeps the styling builder's\n * `lipState` dedupe alive.\n *\n * SECOND MEANING OF POSITION (same as `DIRECTION_FIELDS`): both cap-aware\n * assemblers fold this table AHEAD of the direction table into ONE sheddable\n * list and shed it TAIL-FIRST through `hint-shedding.ts`, so a row's position\n * here is also its survival order under a provider's prompt cap — subject\n * clauses outlive every direction clause, and within this block `animal` leaves\n * before `person`. A compatibility order, not a ranking; anything needing a\n * real ranking adds an explicit priority column rather than reordering rows.\n */\nexport const SUBJECT_FIELDS = [\n { key: \"person\", kind: \"group\", surface: \"both\", render: viaFragmentBuilder(buildPersonHints) },\n { key: \"styling\", kind: \"group\", surface: \"both\", render: viaFragmentBuilder(buildStylingHints) },\n { key: \"heldProp\", kind: \"ids\", surface: \"both\", maxPicks: 2, render: viaListBuilder(buildHeldPropHints) },\n { key: \"material\", kind: \"ids\", surface: \"both\", maxPicks: 2, render: viaStringBuilder(buildMaterialHints) },\n { key: \"animal\", kind: \"ids\", surface: \"both\", maxPicks: 1, render: perId(curatedAnimalPromptHint, curatedAnimalTerm) },\n] as const satisfies ReadonlyArray<SubjectFieldSpec>\n\nexport type SubjectFieldRow = (typeof SUBJECT_FIELDS)[number]\n\n/**\n * Table order — THE canonical fold order, over ROWS (not wire keys). Exported\n * so a client's \"will inject into prompt\" preview folds in the exact order the\n * server does, the way `DIRECTION_KEYS` does for direction.\n */\nexport const SUBJECT_FOLD_KEYS: ReadonlyArray<string> = SUBJECT_FIELDS.map((f) => f.key)\n\n/** The prop rows — the wire keys a fold row owns one-to-one. */\nconst IDS_ROWS: ReadonlyArray<SubjectIdsFieldSpec> = (\n SUBJECT_FIELDS as ReadonlyArray<SubjectFieldSpec>\n).filter((f): f is SubjectIdsFieldSpec => f.kind === \"ids\")\n\n/**\n * The one person field that is a NUMBER, not ids: the literal age in years,\n * consulted only when `age === \"age-custom\"` (`buildAgeFragment`). It has no\n * styling twin, so it rides the flat bag without collision.\n */\nexport const SUBJECT_CUSTOM_AGE_KEY = \"customAge\"\n\n/** `customAge` bounds, mirroring `buildAgeFragment`'s own clamp. */\nconst CUSTOM_AGE_MIN = 0\nconst CUSTOM_AGE_MAX = 120\n\n/**\n * THE WIRE KEY SET, derived — every person field, `customAge`, every styling\n * field, then the prop rows, in fold order. Never hand-listed: a dimension\n * added to either catalog joins the channel by construction.\n *\n * BASE ONLY, deliberately: a deployment-registered person pack adds dimensions\n * at RUNTIME, so the pack-aware set is computed per call inside\n * `normalizeSubjectFields` (and inside `readSubjectFields`). This constant is\n * what a client enumerates to build its projection; a pack dimension it cannot\n * know about still rides the wire and still folds.\n *\n * ONE CONSEQUENCE, noted rather than fixed: the person builder's legacy `lips`\n * fallback field is not a dimension and so is not here, making it unreachable\n * through this channel. Intended — the wire speaks the current vocabulary; the\n * fallback stays for node blobs written before the split.\n */\nexport const SUBJECT_KEYS: ReadonlyArray<string> = [\n ...PERSON_DIMENSION_ORDER.map((d) => PERSON_FIELD_BY_DIMENSION[d]),\n SUBJECT_CUSTOM_AGE_KEY,\n ...STYLING_DIMENSION_ORDER.map((d) => STYLING_FIELD_BY_DIMENSION[d]),\n ...IDS_ROWS.map((f) => f.key),\n]\n\n/**\n * `SUBJECT_KEYS` plus whatever a deployment-registered person pack added — the\n * set the DOORS accept (`readSubjectFields`, and any route-side normalize).\n *\n * Rebuilt per call because pack registration happens at boot, after this module\n * is imported. With no packs registered it is `SUBJECT_KEYS` exactly, pinned by\n * a test.\n */\nexport function getRegisteredSubjectKeys(): ReadonlyArray<string> {\n const fieldByDimension = getRegisteredPersonFieldByDimension()\n const personFields: string[] = []\n for (const dimension of getRegisteredPersonDimensionOrder()) {\n const field = fieldByDimension[dimension]\n if (field) personFields.push(field)\n }\n return [\n ...personFields,\n SUBJECT_CUSTOM_AGE_KEY,\n ...STYLING_DIMENSION_ORDER.map((d) => STYLING_FIELD_BY_DIMENSION[d]),\n ...IDS_ROWS.map((f) => f.key),\n ]\n}\n\n/** Verbosity for a whole subject fold. No family split — subject is one family. */\nexport type SubjectHintMode = PickerHintMode\n\n/** Image policy: the full mechanism clause for every dimension. */\nexport const SUBJECT_IMAGE_HINT_MODE_DEFAULT: SubjectHintMode = \"full\"\n\n/**\n * Video policy: the compact professional term.\n *\n * A fully specified person at `\"full\"` is ~30 paragraph clauses, and on the\n * video stage the start frame already carries the subject's identity — the\n * clip's prompt needs the subject NAMED, not re-described. (The image stage,\n * which is where the subject is actually being built, keeps `\"full\"`.)\n */\nexport const SUBJECT_VIDEO_HINT_MODE_DEFAULT: SubjectHintMode = \"compact\"\n\n/**\n * Wire tolerance ceiling for an array-valued subject key, and the ceiling for\n * one id's length. DEFINED AS the direction constants rather than re-typed, so\n * ONE literal governs both channels and both doors (the route schema and the\n * persisted-node reader) — the wire and the canvas cannot start disagreeing\n * about which strings are ids at all.\n */\nexport const SUBJECT_ARRAY_CEILING = DIRECTION_ARRAY_CEILING\nexport const SUBJECT_ID_MAX_CHARS = DIRECTION_ID_MAX_CHARS\n\n/**\n * Bound on the NUMBER of keys in a subject bag. `SUBJECT_KEYS` is 54 today;\n * this leaves generous headroom for deployment-registered pack dimensions while\n * still closing an otherwise unbounded record that lands verbatim in\n * `jobs.input_data`. Unknown keys are inert (the renderer never reads them), so\n * this is storage hygiene, not validation.\n */\nexport const MAX_SUBJECT_KEYS = 128\n\n/** Bound on the LENGTH of one wire key. Field names are short identifiers. */\nexport const SUBJECT_KEY_MAX_CHARS = 64\n\n/**\n * `string | string[]` → deduped, non-empty, capped id list.\n *\n * Byte-for-byte the direction registry's `normalizeDirectionIds`, including the\n * `ids.length >= maxPicks` bail — load-bearing, not an optimization: the dedupe\n * is an `includes` scan, so without it the cost is quadratic in the CALLER's\n * array length, and one caller reads untrusted persisted JSONB. Bailing is\n * semantics-preserving: once `maxPicks` unique ids exist, no later entry can\n * change the sliced result.\n */\nfunction normalizeIds(value: unknown, maxPicks: number): string[] {\n const ids: string[] = []\n if (typeof value === \"string\") {\n if (value) ids.push(value)\n } else if (Array.isArray(value)) {\n for (const v of value) {\n if (ids.length >= maxPicks) break\n if (typeof v === \"string\" && v && !ids.includes(v)) ids.push(v)\n }\n }\n return ids.slice(0, maxPicks)\n}\n\n/**\n * Pack-aware field → per-dimension pick limit, rebuilt per call.\n *\n * Person's dimension→field map is pack-composed at runtime\n * (`getRegisteredPersonFieldByDimension`), so this cannot be a module constant;\n * a pack dimension is single-select today (`getPersonDimensionLimit` knows only\n * the base union and resolves a pack key to 1 — see `PersonPack.dimensions`).\n * Styling has no pack seam and reads its static map.\n */\nfunction limitByField(): Map<string, number> {\n const out = new Map<string, number>()\n const personFieldByDimension = getRegisteredPersonFieldByDimension()\n for (const dimension of getRegisteredPersonDimensionOrder()) {\n const field = personFieldByDimension[dimension]\n if (field) out.set(field, getPersonDimensionLimit(dimension as PersonDimension))\n }\n for (const dimension of STYLING_DIMENSION_ORDER) {\n out.set(\n STYLING_FIELD_BY_DIMENSION[dimension],\n getStylingDimensionLimit(dimension as StylingDimension),\n )\n }\n for (const row of IDS_ROWS) out.set(row.key, row.maxPicks)\n return out\n}\n\n/**\n * THE NORMALIZER — a known-key, per-dimension-capped copy of a subject bag.\n *\n * WHY IT EXISTS (and why the fold is unusable without it): the subject builders\n * do NOT cap. `collectPersonFragments` / `collectStylingFragments` /\n * `emitIndependentFragments` emit EVERY id they are handed; `normalizePickIds`\n * and `pickHeldPropIds` dedupe but never slice; only `buildMaterialHints` caps,\n * and only structurally at 2. `MAX_SELECTED_BY_DIMENSION`'s own doc names its\n * consumers as the picker UI, the analyzer schema and the Zod validator — NOT\n * the builders. Straight off the wire, then, a bag is a clause amplifier: 8 ids\n * (the array ceiling) on each of ~50 dimensions. This is where the per-dimension\n * cap actually gets enforced.\n *\n * It also:\n * - DROPS UNKNOWN KEYS, so `jobs.input_data` stays the platform's vocabulary\n * (unknown IDS stay inert instead — every getter resolves a miss to `\"\"`);\n * - UNWRAPS a single-id array to a bare string. Load-bearing:\n * `collectPersonFragments` reads a single-pick dimension with\n * `typeof raw === \"string\"`, so a legitimate `[\"hair-base-long\"]` from a\n * client's array-shaped store would otherwise contribute NOTHING;\n * - clamps `customAge` to a whole `0..120`, mirroring `buildAgeFragment`.\n *\n * Copy-on-write: the caller's object is never mutated. Idempotent, so calling it\n * at a door AND inside the renderer is free.\n */\nexport function normalizeSubjectFields(\n subject: SubjectFields | undefined,\n): SubjectFields | undefined {\n if (!subject || typeof subject !== \"object\" || Array.isArray(subject)) return undefined\n const src = subject as Record<string, unknown>\n const limits = limitByField()\n const out: Record<string, string | string[] | number> = {}\n\n const rawAge = src[SUBJECT_CUSTOM_AGE_KEY]\n if (typeof rawAge === \"number\" && Number.isFinite(rawAge)) {\n out[SUBJECT_CUSTOM_AGE_KEY] = Math.max(\n CUSTOM_AGE_MIN,\n Math.min(CUSTOM_AGE_MAX, Math.round(rawAge)),\n )\n }\n\n for (const [field, limit] of limits) {\n const ids = normalizeIds(src[field], limit)\n if (ids.length === 0) continue\n out[field] = ids.length === 1 ? ids[0]! : ids\n }\n\n return Object.keys(out).length > 0 ? out : undefined\n}\n\n/** The rows a given generation stage folds, in table order. */\nexport function subjectFieldsForSurface(\n surface: \"image\" | \"video\",\n): ReadonlyArray<SubjectFieldSpec> {\n return SUBJECT_FIELDS.filter((f) => f.surface === \"both\" || f.surface === surface)\n}\n\n/**\n * Every clause the `subject` channel injects, in canonical table order.\n *\n * NORMALIZES ONCE, at the top, and hands THE SAME bag to both group rows — that\n * single shared bag is the mechanism behind the styling builder's cross-catalog\n * `lipState` dedupe, and it must not depend on a door having normalized first\n * (the normalizer is idempotent, so a door may do it too).\n *\n * Iterates the TABLE, never the caller's object: unknown wire keys contribute\n * nothing, the order is platform-owned, and an off-surface row is inert.\n * Unknown IDS are skipped too — every `get*PromptHint` returns `\"\"` on a miss,\n * so a retired or pack-only id costs no clause rather than a 400.\n *\n * DEDUPE by exact clause string, FIRST OCCURRENCE WINS (order-preserving),\n * matching `renderDirectionHints`.\n *\n * Exported so a client's \"will inject into prompt\" preview renders the exact\n * server output — called on the very object the client sends — instead of\n * re-implementing the fold.\n */\nexport function renderSubjectHints(\n subject: SubjectFields | undefined,\n opts: { surface: \"image\" | \"video\"; mode?: SubjectHintMode },\n): string[] {\n const bag = normalizeSubjectFields(subject)\n if (!bag) return []\n const mode = opts.mode ?? \"full\"\n const out: string[] = []\n const seen = new Set<string>()\n for (const spec of SUBJECT_FIELDS) {\n if (spec.surface !== \"both\" && spec.surface !== opts.surface) continue\n const hints =\n spec.kind === \"group\"\n ? spec.render(bag, mode)\n : spec.render(normalizeIds((bag as Record<string, unknown>)[spec.key], spec.maxPicks), mode)\n for (const hint of hints) {\n if (hint.length > 0 && !seen.has(hint)) {\n seen.add(hint)\n out.push(hint)\n }\n }\n }\n return out\n}\n"]}
|