@nodaro/prompts 1.13.0 → 1.14.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/index.d.cts CHANGED
@@ -2921,6 +2921,11 @@ interface GeminiOmniI2vInputsArgs {
2921
2921
  refImageUrls?: Array<string | undefined>;
2922
2922
  /** A connected source video occupies 2 of the 7 input slots (KIE quota). */
2923
2923
  videoConnected?: boolean;
2924
+ /** The Omni SKU this run targets — defaults to `gemini-omni-video` for
2925
+ * back-compat. Both SKUs cap at 7 today, so passing it is behaviour-neutral;
2926
+ * it stops the flash path from silently reading the pro model's quota if the
2927
+ * two ever diverge. */
2928
+ provider?: string;
2924
2929
  }
2925
2930
  interface GeminiOmniI2vInputsResult {
2926
2931
  /** `[firstFrameUrl, ...keptRefs]` — the `image_urls` payload, quota-fitted. */
@@ -3962,6 +3967,11 @@ interface MultiPickerAnalyzerSpec {
3962
3967
  readonly schema: z.ZodType<Record<string, unknown>, unknown>;
3963
3968
  readonly toolName: string;
3964
3969
  readonly legend: string;
3970
+ /** Compact bullet list of the pickers NOT wired into this spec (PICKER_TYPES
3971
+ * minus `types`), keyed by picker-type key so the LLM can ATTRIBUTE a gap to
3972
+ * the right picker even when it was not wired. Names + dimension labels only,
3973
+ * never catalog ids. Empty string when every picker is already wired. */
3974
+ readonly otherPickersLegend: string;
3965
3975
  }
3966
3976
  /** Build ONE forced-tool schema spanning the given pickers (each section
3967
3977
  * optional so an omitted picker doesn't trigger a validation retry) plus the
@@ -6083,7 +6093,7 @@ declare function getStylingDimensionLimit(dimension: StylingDimension): number;
6083
6093
  interface StylingValue {
6084
6094
  makeup?: string;
6085
6095
  eyewear?: string;
6086
- headwear?: string;
6096
+ headwear?: string | ReadonlyArray<string>;
6087
6097
  /** Hair cut / styling choice — bob, wolf cut, braids, ponytail, etc.
6088
6098
  * Pairs with Person.hair-base (texture + length). */
6089
6099
  hairCut?: string;
package/dist/index.d.ts CHANGED
@@ -2921,6 +2921,11 @@ interface GeminiOmniI2vInputsArgs {
2921
2921
  refImageUrls?: Array<string | undefined>;
2922
2922
  /** A connected source video occupies 2 of the 7 input slots (KIE quota). */
2923
2923
  videoConnected?: boolean;
2924
+ /** The Omni SKU this run targets — defaults to `gemini-omni-video` for
2925
+ * back-compat. Both SKUs cap at 7 today, so passing it is behaviour-neutral;
2926
+ * it stops the flash path from silently reading the pro model's quota if the
2927
+ * two ever diverge. */
2928
+ provider?: string;
2924
2929
  }
2925
2930
  interface GeminiOmniI2vInputsResult {
2926
2931
  /** `[firstFrameUrl, ...keptRefs]` — the `image_urls` payload, quota-fitted. */
@@ -3962,6 +3967,11 @@ interface MultiPickerAnalyzerSpec {
3962
3967
  readonly schema: z.ZodType<Record<string, unknown>, unknown>;
3963
3968
  readonly toolName: string;
3964
3969
  readonly legend: string;
3970
+ /** Compact bullet list of the pickers NOT wired into this spec (PICKER_TYPES
3971
+ * minus `types`), keyed by picker-type key so the LLM can ATTRIBUTE a gap to
3972
+ * the right picker even when it was not wired. Names + dimension labels only,
3973
+ * never catalog ids. Empty string when every picker is already wired. */
3974
+ readonly otherPickersLegend: string;
3965
3975
  }
3966
3976
  /** Build ONE forced-tool schema spanning the given pickers (each section
3967
3977
  * optional so an omitted picker doesn't trigger a validation retry) plus the
@@ -6083,7 +6093,7 @@ declare function getStylingDimensionLimit(dimension: StylingDimension): number;
6083
6093
  interface StylingValue {
6084
6094
  makeup?: string;
6085
6095
  eyewear?: string;
6086
- headwear?: string;
6096
+ headwear?: string | ReadonlyArray<string>;
6087
6097
  /** Hair cut / styling choice — bob, wolf cut, braids, ponytail, etc.
6088
6098
  * Pairs with Person.hair-base (texture + length). */
6089
6099
  hairCut?: string;
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { ANIMAL_SUBCATEGORY_LABELS, ANIMAL_SUBCATEGORY_ORDER, VEHICLE_SUBCATEGORY_LABELS, VEHICLE_SUBCATEGORY_ORDER, WEAPON_SUBCATEGORY_LABELS, WEAPON_SUBCATEGORY_ORDER, FURNITURE_SUBCATEGORY_LABELS, FURNITURE_SUBCATEGORY_ORDER, VIDEO_REF_LIMITS_BY_PROVIDER, SOCIAL_POST_NODE_TYPES, FURNITURE, WEAPONS, VEHICLES, ANIMALS, PASSTHROUGH_TYPES, registerCatalogSidecars, resetCatalogSidecars, pickIds, getAnimalPromptHint, getFurniture, getWeapon, getVehicle, DEFAULT_USAGE_MODE, usageModeDirective, DEFAULT_LOCATION_USAGE_MODE, imageReferenceLimit, knownImageSlugsFromRefs, findImageMentionTokens, knownEntitySlugsFromRefs, findEntityMentionTokens, findCharacterMentionTokens, findLocationMentionTokens, NATIVE_NEGATIVE_PROMPT_MODELS, getMaxNegativePromptChars, getMaxImagePromptChars, MODELS_WITH_REFERENCE_IMAGE_SUPPORT, getAnimalTerm, roleToPhrase, resolveDefaultRole, SEEDANCE_2_REF_LIMITS, NON_EN_LOCALE_IDS, readPromptAffixes, setRegisteredPersonPackFields, PLACEHOLDER_CHARACTER_NAME, REFERENCE_ROLE_PRESETS, imageMentionSlugForRef, entityMentionSlugForRef, defaultRoleForSource, locationReferencePhotoKindLabel, resolveNodeRefs, normalizeRoleSlug } from '@nodaro/shared';
1
+ import { ANIMAL_SUBCATEGORY_LABELS, ANIMAL_SUBCATEGORY_ORDER, VEHICLE_SUBCATEGORY_LABELS, VEHICLE_SUBCATEGORY_ORDER, WEAPON_SUBCATEGORY_LABELS, WEAPON_SUBCATEGORY_ORDER, FURNITURE_SUBCATEGORY_LABELS, FURNITURE_SUBCATEGORY_ORDER, SOCIAL_POST_NODE_TYPES, FURNITURE, WEAPONS, VEHICLES, ANIMALS, PASSTHROUGH_TYPES, registerCatalogSidecars, resetCatalogSidecars, pickIds, getAnimalPromptHint, getFurniture, getWeapon, getVehicle, DEFAULT_USAGE_MODE, usageModeDirective, DEFAULT_LOCATION_USAGE_MODE, imageReferenceLimit, knownImageSlugsFromRefs, findImageMentionTokens, knownEntitySlugsFromRefs, findEntityMentionTokens, findCharacterMentionTokens, findLocationMentionTokens, NATIVE_NEGATIVE_PROMPT_MODELS, getMaxNegativePromptChars, getMaxImagePromptChars, MODELS_WITH_REFERENCE_IMAGE_SUPPORT, getAnimalTerm, roleToPhrase, resolveDefaultRole, SEEDANCE_2_REF_LIMITS, NON_EN_LOCALE_IDS, readPromptAffixes, setRegisteredPersonPackFields, PLACEHOLDER_CHARACTER_NAME, REFERENCE_ROLE_PRESETS, imageMentionSlugForRef, entityMentionSlugForRef, defaultRoleForSource, locationReferencePhotoKindLabel, VIDEO_REF_LIMITS_BY_PROVIDER, resolveNodeRefs, normalizeRoleSlug } from '@nodaro/shared';
2
2
 
3
3
  var __defProp = Object.defineProperty;
4
4
  var __export = (target, all) => {
@@ -1764,7 +1764,8 @@ var STYLES = [
1764
1764
  { id: "pastel", label: "Pastel", description: "Degas-era soft chalk pastel", promptHint: "rendered as a soft chalk pastel drawing, dry powdery pigment laid in feathered strokes on tinted paper with luminous dusty colors, gently blended edges and the dreamy Degas-era atmosphere of dancers in stage light", term: "soft pastel drawing" },
1765
1765
  { id: "acrylic-paint", label: "Acrylic Paint", description: "Fast-drying opaque acrylic on canvas", promptHint: "rendered as an acrylic painting on canvas, fast-drying opaque pigment with crisp sharp edges, confident quick brush strokes, high-key saturated color and a flatter more graphic finish than traditional oil paint", term: "acrylic painting" },
1766
1766
  { id: "mixed-media", label: "Mixed Media", description: "Collage + paint + ink hybrid", promptHint: "rendered as a mixed-media artwork combining torn paper collage, acrylic paint, ink and graphite on a layered substrate, heterogeneous textures, visible tape and stitching, and an exuberant hand-assembled studio-art quality" },
1767
- { id: "manga", label: "Manga", description: "Inked B&W Japanese comic panel", promptHint: "rendered as inked manga panel art, crisp black ink on white with confident line weight variation, screen-tone dot patterns for shading, dramatic speed lines and the distinctly Japanese black-and-white comic aesthetic \u2014 separate from full-color anime" }
1767
+ { id: "manga", label: "Manga", description: "Inked B&W Japanese comic panel", promptHint: "rendered as inked manga panel art, crisp black ink on white with confident line weight variation, screen-tone dot patterns for shading, dramatic speed lines and the distinctly Japanese black-and-white comic aesthetic \u2014 separate from full-color anime" },
1768
+ { id: "early-color-photo", label: "Early Color Photo", description: "Prokudin-Gorsky / autochrome early-1900s color", promptHint: "rendered as an early-1900s color photograph in the Prokudin-Gorsky / autochrome tradition \u2014 soft three-colour-separation registration, muted dye-toned palette, fine grain and a gentle antique warmth", term: "early autochrome color photograph" }
1768
1769
  ];
1769
1770
  var styleById = new Map(STYLES.map((s) => [s.id, s]));
1770
1771
  function getStyle(id) {
@@ -1830,6 +1831,7 @@ var SETTINGS = [
1830
1831
  { id: "parking-lot", label: "Parking Lot", category: "urban", description: "Suburban parking lot at dusk", promptHint: "set in an empty suburban parking lot at dusk with sodium-vapor lamps casting orange pools, scattered shopping carts and painted lane lines" },
1831
1832
  { id: "penthouse", label: "Penthouse", category: "urban", description: "Luxury penthouse with skyline view", promptHint: "set in a luxury penthouse interior with panoramic skyline views, marble floors, modernist furniture and low warm ambient light" },
1832
1833
  { id: "gas-station", label: "Gas Station", category: "urban", description: "Lonely highway gas station at night", promptHint: "set at a lonely highway gas station at night with a fluorescent canopy, bug-swarmed sodium lamps and cracked asphalt" },
1834
+ { id: "open-air-market", label: "Open-Air Market", category: "urban", description: "Bustling market of vendor stalls under canopies", term: "open-air market", promptHint: "set in a bustling open-air market \u2014 rows of vendor stalls under thatched and canvas canopies, produce piled high, warm dusty light and crowds moving between the stalls" },
1833
1835
  // -------------------- Nature --------------------
1834
1836
  { id: "forest", label: "Forest Clearing", category: "nature", description: "Sunlit mossy clearing", promptHint: "set in a sunlit forest clearing with moss-covered stones, dappled light through tall trees and a soft carpet of fallen leaves" },
1835
1837
  { id: "beach", label: "Beach", category: "nature", description: "Wide sandy beach with surf", promptHint: "set on a wide sandy beach with gentle breaking surf, footprints in wet sand and a pastel horizon" },
@@ -2956,6 +2958,9 @@ var PEOPLE = [
2956
2958
  { id: "mumbai-bollywood", label: "Mumbai Bollywood", group: "Asia", dimension: "regional-aesthetic", description: "Mumbai Indian film-industry aesthetic", promptHint: "a Mumbai Bollywood aesthetic \u2014 Indian film-industry vibe, vibrant statement-glamour", term: "mumbai bollywood aesthetic" },
2957
2959
  { id: "south-india-traditional", label: "South India Traditional", group: "Asia", dimension: "regional-aesthetic", description: "Tamil / Kerala temple-town classical aesthetic", promptHint: "a South Indian traditional aesthetic \u2014 Tamil / Kerala temple-town vibe, classical refinement", term: "south indian traditional aesthetic" },
2958
2960
  { id: "bangkok-street", label: "Bangkok Street", group: "Asia", dimension: "regional-aesthetic", description: "Bangkok Thai night-market neon-urban aesthetic", promptHint: "a Bangkok street aesthetic \u2014 Thai night-market energy, neon-and-warmth urban vibe", term: "bangkok street aesthetic" },
2961
+ // ----- Central Asia -----
2962
+ { id: "samarkand-silk-road", label: "Samarkand Silk Road", group: "Central Asia", dimension: "regional-aesthetic", description: "Uzbek Silk Road bazaar aesthetic (Samarkand / Bukhara)", promptHint: "a Central Asian Silk Road aesthetic \u2014 Samarkand / Bukhara bazaar vibe, ikat-and-suzani textiles, sun-baked adobe and blue-tiled madrasa mood", term: "samarkand silk road aesthetic" },
2963
+ { id: "tashkent-modern", label: "Tashkent Modern", group: "Central Asia", dimension: "regional-aesthetic", description: "Contemporary Uzbek metropolitan Central Asian aesthetic", promptHint: "a modern Tashkent aesthetic \u2014 contemporary Uzbek metropolitan vibe, Soviet-modern-meets-Silk-Road blend, warm steppe-city confidence", term: "tashkent modern aesthetic" },
2959
2964
  // ----- Latin America -----
2960
2965
  { id: "carioca-rio", label: "Carioca (Rio)", group: "Latin America", dimension: "regional-aesthetic", description: "Rio de Janeiro beach-and-favela-music Brazilian aesthetic", promptHint: "a Carioca aesthetic \u2014 Rio de Janeiro beach-and-favela-music vibe, sun-warmed Brazilian energy", term: "carioca aesthetic" },
2961
2966
  { id: "paulista", label: "Paulista (S\xE3o Paulo)", group: "Latin America", dimension: "regional-aesthetic", description: "S\xE3o Paulo metropolitan Brazilian creative-class aesthetic", promptHint: "a Paulista aesthetic \u2014 S\xE3o Paulo metropolitan vibe, urban-Brazilian creative-class polish", term: "paulista aesthetic" },
@@ -3796,6 +3801,9 @@ var STYLINGS = [
3796
3801
  { id: "outfit-fairy", label: "Fairy", dimension: "outfit", description: "Fantasy fairy: gauzy wings, flower crown, ethereal dress", promptHint: "wearing a fantasy fairy costume \u2014 gauzy translucent wings, a flower crown, and an ethereal flowing dress", term: "fairy costume with wings" },
3797
3802
  { id: "outfit-mermaid", label: "Mermaid", dimension: "outfit", description: "Fantasy mermaid: scaled tail/skirt, shell top, flowing hair", promptHint: "wearing a fantasy mermaid costume \u2014 a scaled tail or fitted scaled skirt, a shell top, and long flowing hair", term: "mermaid costume" },
3798
3803
  { id: "outfit-pharaoh", label: "Pharaoh Regalia", dimension: "outfit", description: "Ancient Egyptian royalty: usekh collar, pectoral, pleated kilt", promptHint: "wearing ancient Egyptian pharaoh regalia \u2014 a broad beaded usekh collar, a jeweled falcon pectoral, and a pleated linen shendyt kilt with golden arm cuffs" },
3804
+ { id: "outfit-workwear-overalls", label: "Workwear Overalls", dimension: "outfit", description: "Denim bib overalls over a plaid flannel shirt", promptHint: "dressed in a farmer's workwear outfit \u2014 denim bib overalls over a checked plaid flannel shirt, sturdy and worn-in", term: "denim overalls and plaid shirt" },
3805
+ { id: "outfit-chapan", label: "Chapan Robe", dimension: "outfit", description: "Central Asian long quilted ikat robe", promptHint: "dressed in a traditional Central Asian chapan \u2014 a long quilted robe with an ikat-striped weave, tied at the waist with a sash" },
3806
+ { id: "outfit-caftan", label: "Caftan", dimension: "outfit", description: "Long flowing Middle-Eastern / North-African robe", promptHint: "dressed in a long flowing caftan robe, a full-length garment worn across the Middle East and North Africa" },
3799
3807
  // -------------------- Top (upper-body garment) --------------------
3800
3808
  { id: "top-tshirt", label: "T-Shirt", dimension: "top", description: "Plain crewneck t-shirt", promptHint: "wearing a fitted plain crewneck t-shirt with short sleeves" },
3801
3809
  { id: "top-tank", label: "Tank Top", dimension: "top", description: "Scoop-neck tank top", promptHint: "wearing a fitted scoop-neck tank top with thin shoulder straps" },
@@ -3970,6 +3978,8 @@ var STYLING_FIELD_BY_DIMENSION = {
3970
3978
  "wardrobe-state": "wardrobeState"
3971
3979
  };
3972
3980
  var MAX_SELECTED_BY_STYLING_DIMENSION = {
3981
+ headwear: 2,
3982
+ // a hat layered over a wrap/turban
3973
3983
  jewelry: 3,
3974
3984
  "wardrobe-state": 3,
3975
3985
  "hair-state": 2
@@ -6324,7 +6334,8 @@ var HELD_PROPS = [
6324
6334
  { id: "flashlight", label: "Flashlight", category: "occupational", description: "Modern flashlight cutting a beam", promptHint: "holding a modern flashlight raised forward in one hand, a sharp white beam cutting through the darkness ahead and side-lighting the face", term: "holding a flashlight raised forward" },
6325
6335
  { id: "compass", label: "Compass", category: "occupational", description: "Vintage handheld nautical compass", promptHint: "holding a vintage brass nautical compass open in one cupped palm at chest height, the needle clearly visible as the eyes drift down to read the bearing", term: "holding an open brass nautical compass" },
6326
6336
  { id: "bow-and-arrow", label: "Bow and Arrow", category: "occupational", description: "Drawn archery bow with arrow nocked", promptHint: "holding an archery bow drawn at full tension with one hand on the grip and the other pulling the string back to the cheek, an arrow nocked and aimed forward", term: "drawing an archery bow with a nocked arrow" },
6327
- { id: "shield", label: "Shield", category: "occupational", description: "Handheld medieval shield", promptHint: "holding a medieval shield raised across the body with one arm strapped through the back, the front face angled forward in a defensive stance", term: "holding a raised medieval shield" }
6337
+ { id: "shield", label: "Shield", category: "occupational", description: "Handheld medieval shield", promptHint: "holding a medieval shield raised across the body with one arm strapped through the back, the front face angled forward in a defensive stance", term: "holding a raised medieval shield" },
6338
+ { id: "work-gloves", label: "Work Gloves", category: "occupational", description: "Worn leather work gloves held in hand", promptHint: "holding a worn pair of tan leather work gloves in both hands at waist height, the thick weathered leather clearly visible", term: "holding a pair of leather work gloves" }
6328
6339
  ];
6329
6340
  var heldPropById = new Map(HELD_PROPS.map((p) => [p.id, p]));
6330
6341
  function getHeldProp(id) {
@@ -13020,10 +13031,13 @@ function resolveSeedance2Inputs(args) {
13020
13031
  droppedRefImages
13021
13032
  };
13022
13033
  }
13023
- var GEMINI_OMNI_INPUT_SLOTS = VIDEO_REF_LIMITS_BY_PROVIDER["gemini-omni-video"]?.images ?? 7;
13034
+ var DEFAULT_GEMINI_OMNI_PROVIDER = "gemini-omni-video";
13035
+ function geminiOmniInputSlots(provider) {
13036
+ return VIDEO_REF_LIMITS_BY_PROVIDER[provider ?? DEFAULT_GEMINI_OMNI_PROVIDER]?.images ?? 7;
13037
+ }
13024
13038
  function resolveGeminiOmniI2vInputs(args) {
13025
13039
  const refs = (args.refImageUrls ?? []).filter((u) => typeof u === "string" && u.length > 0);
13026
- const slots = GEMINI_OMNI_INPUT_SLOTS - (args.videoConnected ? 2 : 0);
13040
+ const slots = geminiOmniInputSlots(args.provider) - (args.videoConnected ? 2 : 0);
13027
13041
  const refSlots = Math.max(0, slots - 1);
13028
13042
  const kept = refs.slice(0, refSlots);
13029
13043
  const droppedRefImages = refs.length - kept.length;
@@ -27862,6 +27876,23 @@ var GAPS_SCHEMA = external_exports.object({
27862
27876
  ).max(8).default([])
27863
27877
  }).default({ missingItems: [], missingCategories: [] });
27864
27878
  var MULTI_CACHE = /* @__PURE__ */ new Map();
27879
+ function pickerDisplayName(type) {
27880
+ return type.split("-").map((w) => w.length > 0 ? w[0].toUpperCase() + w.slice(1) : w).join(" ");
27881
+ }
27882
+ function buildOtherPickersLegend(sorted) {
27883
+ const otherTypes = PICKER_TYPES.filter((t) => !sorted.includes(t));
27884
+ if (otherTypes.length === 0) return "";
27885
+ const lines = otherTypes.map((type) => {
27886
+ const descriptor = PICKER_ANALYZER_REGISTRY[type];
27887
+ if (descriptor.kind === "flat") {
27888
+ return `- ${type}: ${descriptor.label}`;
27889
+ }
27890
+ const dims = descriptor.order.map((k) => descriptor.labels[k]).filter(Boolean).join(", ");
27891
+ return `- ${type}: ${pickerDisplayName(type)}${dims ? ` \u2014 ${dims}` : ""}`;
27892
+ });
27893
+ return `Non-wired pickers \u2014 use one of these keys in a gap's \`picker\` when an attribute belongs to it:
27894
+ ${lines.join("\n")}`;
27895
+ }
27865
27896
  function buildMultiPickerAnalyzerSpec(types) {
27866
27897
  const sorted = [...new Set(types)].sort();
27867
27898
  const key = sorted.join(",");
@@ -27879,7 +27910,8 @@ ${buildPickerLegend(spec)}`);
27879
27910
  const result = {
27880
27911
  schema: external_exports.object(shape).strict(),
27881
27912
  toolName: "emit_pickers",
27882
- legend: legendParts.join("\n\n")
27913
+ legend: legendParts.join("\n\n"),
27914
+ otherPickersLegend: buildOtherPickersLegend(sorted)
27883
27915
  };
27884
27916
  MULTI_CACHE.set(key, result);
27885
27917
  return result;
@@ -28285,8 +28317,8 @@ Sources: Google Cloud "Ultimate prompting guide for Veo 3.1"
28285
28317
  KIE VEO API docs (docs.kie.ai/veo3-api/generate-veo-3-video). Captured 2026-08-09.`
28286
28318
  };
28287
28319
  var GEMINI_OMNI_DOCTRINE = {
28288
- providers: ["gemini-omni-video"],
28289
- heading: "Gemini Omni Video (gemini-omni-video)",
28320
+ providers: ["gemini-omni-video", "gemini-omni-flash"],
28321
+ heading: "Gemini Omni (gemini-omni-video, gemini-omni-flash)",
28290
28322
  tips: [
28291
28323
  "Multimodal Google video with native audio: text-to-video, image-to-video, and video-edit through the same prompt surface. 4/6/8/10s; 720p/1080p or 4K tier.",
28292
28324
  "Structure like the platform default: subject \u2192 action \u2192 scene \u2192 lighting \u2192 camera \u2192 style. Quote dialogue lines to have them spoken; describe SFX/ambience plainly in the prompt.",
@@ -28308,6 +28340,7 @@ subject \u2192 action \u2192 scene/environment \u2192 lighting \u2192 camera mov
28308
28340
 
28309
28341
  **Duration & tiers**
28310
28342
  - 4 / 6 / 8 / 10 seconds. 720p/1080p tier or the pricier 4K tier \u2014 pick 4K only when the deliverable needs it (nearly 2\xD7 the credits).
28343
+ - gemini-omni-flash is the faster/cheaper tier with the identical request surface \u2014 same 4/6/8/10s, same 720p/1080p and 4K tiers, same video-edit path. Everything above applies verbatim.
28311
28344
 
28312
28345
  Source: KIE gemini-omni-video market contract (parameters + live behavior probed for the
28313
28346
  aspect-ratio hard-reject, see providers/kie/video.ts). Captured 2026-08-09.`
@@ -28377,6 +28410,45 @@ push-in (intimacy/tension), pull-out (scale/isolation), tracking shot, orbit, fi
28377
28410
  Source: Alibaba Cloud Model Studio \u2014 "Text-to-video / image-to-video prompt guide"
28378
28411
  (alibabacloud.com/help/en/model-studio/text-to-video-prompt). Captured 2026-08-09.`
28379
28412
  };
28413
+ var WAN_3_DOCTRINE = {
28414
+ providers: ["wan-3", "wan-3-prime"],
28415
+ heading: "Wan 3.0 (wan-3, wan-3-prime)",
28416
+ tips: [
28417
+ "Two INPUT MODES, exclusive on the wire: first/last frame, OR reference mode (images + videos + audio). With any reference wired the platform folds the frame into the references and names it in the prompt.",
28418
+ `References bind by ordinal token in array order: Image1, Image2, Video1, Audio1 \u2014 no space, unlike Wan 2.x's "Image 1". Name every wired asset or it may be ignored.`,
28419
+ "Reference caps: 10 images / 5 videos / 5 audio clips; each video and each audio clip 1-15s, with \u226415s combined per array. With reference videos, input seconds + output duration \u2264 30.",
28420
+ "2-30 seconds (default 5); 480p/720p/1080p; aspect adaptive (default, matches the input media) or 16:9 / 4:3 / 1:1 / 3:4 / 9:16. Prompt cap 20,000 chars \u2014 excess is truncated silently.",
28421
+ '`audio` is a boolean, ON by default: the clip comes back with an ambient/SFX track. Cue the sound you want in the prompt, or state the exclusion ("no music") \u2014 it is not a dialogue guarantee.',
28422
+ "wan-3-prime is the HIGH-SPEED tier: identical surface and limits, faster turnaround at a higher per-second rate. It is not a quality upgrade \u2014 choose it for latency, not for looks."
28423
+ ],
28424
+ doctrine: `Prompt structure (no public Wan 3.0 prompt guide exists \u2014 the KIE API contract is the
28425
+ doctrine source, like MiniMax H3 and HappyHorse; platform-standard structure applies):
28426
+ subject \u2192 action \u2192 scene/environment \u2192 lighting \u2192 camera movement \u2192 style \u2192 constraints.
28427
+
28428
+ **Modes (mutually exclusive at the provider)**
28429
+ - Frame mode: first_frame_url, optionally with last_frame_url, and NO references \u2014 the frames anchor the shot exactly, so describe MOTION and camera, not the still.
28430
+ - Reference mode: image / video / audio reference arrays. The provider CANNOT take these together with the first/last frame parameters, so when both are wired the platform folds \u2014 the frame is appended to the reference images (after the caller's own, ordinals unchanged) and bound in the prompt as the opening/closing frame. Write for reference mode whenever a reference is attached.
28431
+ - Text-only runs are supported and are the model's default mode.
28432
+
28433
+ **Reference binding**
28434
+ - Assets bind by ORDINAL TOKEN in array order: Image1, Image2, \u2026, Video1, \u2026, Audio1, \u2026. Note the format has NO space \u2014 Wan 2.x's "Image 1" is a different generation and does not apply here.
28435
+ - Write the binding into the prompt explicitly ("Image1 walks into the room described in Image2"); an unnamed reference may simply be ignored.
28436
+ - Caps: up to 10 images, 5 videos, 5 audio clips. Each video and each audio clip must be 1-15s with \u226415s combined per array. Audio should not be the only media input \u2014 pair it with an image or a video.
28437
+
28438
+ **Duration, resolution, aspect**
28439
+ - 2-30 seconds (provider default 5). With reference videos there is an extra ceiling: input video duration + output duration \u2264 30 seconds.
28440
+ - 480p / 720p / 1080p. Aspect "adaptive" (the default \u2014 the model selects the ratio from the input media and intent) or 16:9 / 4:3 / 1:1 / 3:4 / 9:16. There is no 21:9.
28441
+ - Prompts accept Chinese and English, up to 20,000 characters; anything beyond is truncated silently, so front-load the load-bearing content.
28442
+
28443
+ **Audio**
28444
+ - The "audio" boolean defaults ON and produces an ambient/SFX track with the clip. Describe the soundscape you want plainly ("rain on glass, distant traffic"), or state the exclusion, or turn the toggle off. The contract documents no lip-synced dialogue guarantee \u2014 plan spoken lines as a separate TTS + lip-sync pass.
28445
+
28446
+ **Tiers**
28447
+ - wan-3 and wan-3-prime take identical inputs. Prime trades a higher per-second rate for faster turnaround; it is not documented as a quality tier.
28448
+
28449
+ Source: KIE Wan 3.0 market contract (docs.kie.ai/market/wan/3-0-video,
28450
+ docs.kie.ai/market/wan/3-0-video-prime). Captured 2026-09-01.`
28451
+ };
28380
28452
  var HAPPYHORSE_DOCTRINE = {
28381
28453
  providers: ["happyhorse", "happyhorse-i2v", "happyhorse-ref2v", "happyhorse-edit"],
28382
28454
  heading: "HappyHorse 1.1 (happyhorse, happyhorse-i2v, happyhorse-ref2v)",
@@ -28432,6 +28504,7 @@ var PROVIDER_PROMPT_DOCTRINES = [
28432
28504
  GEMINI_OMNI_DOCTRINE,
28433
28505
  GROK_IMAGINE_DOCTRINE,
28434
28506
  WAN_DOCTRINE,
28507
+ WAN_3_DOCTRINE,
28435
28508
  HAPPYHORSE_DOCTRINE,
28436
28509
  RUNWAY_KIE_DOCTRINE
28437
28510
  ];
@@ -28656,6 +28729,9 @@ var PROVIDER_CAPABILITIES = {
28656
28729
  "ltx-2.3-pro": "Lightricks LTX 2.3 Pro \u2014 text/image/audio\u2192video, 6\u201310s, up to 4K",
28657
28730
  "ltx-2.3-fast": "Lightricks LTX 2.3 Fast \u2014 text/image\u2192video, 6\u201320s, up to 4K",
28658
28731
  "gemini-omni-video": "Google Gemini Omni \u2014 multimodal video with native audio, 4\u201310s, up to 4K.",
28732
+ "gemini-omni-flash": "Google Gemini Omni Flash \u2014 faster, cheaper Omni tier; multimodal video with native audio, 4\u201310s, up to 4K.",
28733
+ "wan-3": "Wan 3.0 \u2014 multimodal refs (10 images / 5 videos / 5 audio) or first+last frame, native audio, 2\u201330s, 480p/720p/1080p",
28734
+ "wan-3-prime": "Wan 3.0 Prime \u2014 high-speed Wan 3.0 tier; same surface, faster turnaround at a higher rate",
28659
28735
  "grok-imagine-video-1.5": "Grok Imagine 1.5 \u2014 image-to-video only; requires an input image"
28660
28736
  },
28661
28737
  "image-to-video": {
@@ -28689,6 +28765,9 @@ var PROVIDER_CAPABILITIES = {
28689
28765
  "ltx-2.3-pro": "Lightricks LTX 2.3 Pro \u2014 start/end frame i2v + audio\u2192video, 6\u201310s, up to 4K",
28690
28766
  "ltx-2.3-fast": "Lightricks LTX 2.3 Fast \u2014 start/end frame i2v, 6\u201320s, up to 4K",
28691
28767
  "gemini-omni-video": "Google Gemini Omni \u2014 multimodal video with native audio, 4\u201310s, up to 4K.",
28768
+ "gemini-omni-flash": "Google Gemini Omni Flash \u2014 faster, cheaper Omni tier; multimodal video with native audio, 4\u201310s, up to 4K.",
28769
+ "wan-3": "Wan 3.0 \u2014 multimodal refs (10 images / 5 videos / 5 audio) or first+last frame, native audio, 2\u201330s, 480p/720p/1080p",
28770
+ "wan-3-prime": "Wan 3.0 Prime \u2014 high-speed Wan 3.0 tier; same surface, faster turnaround at a higher rate",
28692
28771
  "grok-imagine-video-1.5": "Grok Imagine 1.5 \u2014 stylized animation, 1\u201315s, 480p/720p (image required)"
28693
28772
  },
28694
28773
  "video-to-video": {