mulmocast 2.8.1 → 2.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,7 +3,7 @@
3
3
  * (No Node.js built-ins like fs, path, dotenv, etc.)
4
4
  * Works in both Node.js and modern browsers.
5
5
  */
6
- import { BeatSessionType, MulmoStudioContext, SessionProgressCallback, SessionType, MulmoBeat, SpeechOptions } from "../types/index.js";
6
+ import { BeatSessionType, MulmoStudioContext, SessionProgressCallback, SessionType, MulmoBeat, MulmoStudioBeat, SpeechOptions } from "../types/index.js";
7
7
  import { provider2TTSAgent } from "../types/provider2agent.js";
8
8
  export declare const addSessionProgressCallback: (cb: SessionProgressCallback) => void;
9
9
  export declare const removeSessionProgressCallback: (cb: SessionProgressCallback) => void;
@@ -18,6 +18,11 @@ export declare const MulmoStudioContextMethods: {
18
18
  setBeatSessionState(context: MulmoStudioContext, sessionType: BeatSessionType | undefined, index: number, id: string | undefined, value: boolean): void;
19
19
  needTranslate(context: MulmoStudioContext, includeCaption?: boolean): boolean | "" | undefined;
20
20
  getIntroPadding(context: MulmoStudioContext): number;
21
+ getExtraPadding(context: MulmoStudioContext, index: number): number;
22
+ getBeatDuration(context: MulmoStudioContext, index: number): number;
23
+ getVoiceOverGroupDuration(context: MulmoStudioContext, index: number): number;
24
+ isMovieBeat(context: MulmoStudioContext, studioBeat: MulmoStudioBeat, beat: MulmoBeat): boolean;
25
+ getSegmentDuration(context: MulmoStudioContext, index: number): number;
21
26
  getAudioParam(context: MulmoStudioContext, beat: MulmoBeat, lang?: string): {
22
27
  provider: keyof typeof provider2TTSAgent;
23
28
  voiceId: string;
@@ -3,10 +3,11 @@
3
3
  * (No Node.js built-ins like fs, path, dotenv, etc.)
4
4
  * Works in both Node.js and modern browsers.
5
5
  */
6
- import { text2SpeechProviderSchema, } from "../types/index.js";
6
+ import { ImageMediaType, text2SpeechProviderSchema, } from "../types/index.js";
7
7
  import { beatId } from "../utils/utils.js";
8
8
  import { GraphAILogger } from "graphai";
9
9
  import { MulmoPresentationStyleMethods } from "./mulmo_presentation_style.js";
10
+ import { MulmoBeatMethods } from "./mulmo_beat.js";
10
11
  const sessionProgressCallbacks = new Set();
11
12
  export const addSessionProgressCallback = (cb) => {
12
13
  sessionProgressCallbacks.add(cb);
@@ -92,6 +93,40 @@ export const MulmoStudioContextMethods = {
92
93
  }
93
94
  return context.presentationStyle.audioParams.introPadding;
94
95
  },
96
+ // Intro/outro padding is the only padding not already folded into studio.beats[].duration.
97
+ getExtraPadding(context, index) {
98
+ if (index === 0) {
99
+ return MulmoStudioContextMethods.getIntroPadding(context);
100
+ }
101
+ else if (index === context.studio.beats.length - 1) {
102
+ return context.presentationStyle.audioParams.outroPadding;
103
+ }
104
+ return 0;
105
+ },
106
+ // The duration this beat occupies on the audio timeline.
107
+ getBeatDuration(context, index) {
108
+ return (context.studio.beats[index]?.duration ?? 0) + MulmoStudioContextMethods.getExtraPadding(context, index);
109
+ },
110
+ // The total duration of the voice_over beats which follow (and share the shot of) this beat.
111
+ getVoiceOverGroupDuration(context, index) {
112
+ const trailingBeats = context.studio.script.beats.slice(index + 1);
113
+ const groupEnd = trailingBeats.findIndex((beat) => !MulmoBeatMethods.isVoiceOver(beat));
114
+ const groupSize = groupEnd < 0 ? trailingBeats.length : groupEnd;
115
+ return trailingBeats.slice(0, groupSize).reduce((total, _, offset) => total + MulmoStudioContextMethods.getBeatDuration(context, index + 1 + offset), 0);
116
+ },
117
+ // Whether this beat's source is a movie (as opposed to a still which has to be looped).
118
+ isMovieBeat(context, studioBeat, beat) {
119
+ return !!(studioBeat.lipSyncFile ||
120
+ studioBeat.movieFile ||
121
+ MulmoPresentationStyleMethods.getImageType(context.presentationStyle, beat) === ImageMediaType.Movie);
122
+ },
123
+ // How long this beat's video segment is: its own duration plus the trailing voice_over beats which
124
+ // share its shot (they have no video segment of their own), never shorter than its movie. This is
125
+ // the single rule for a segment's length -- createVideo builds from it and transitions clamp against it.
126
+ getSegmentDuration(context, index) {
127
+ const ownDuration = MulmoStudioContextMethods.getBeatDuration(context, index) + MulmoStudioContextMethods.getVoiceOverGroupDuration(context, index);
128
+ return Math.max(ownDuration, context.studio.beats[index]?.movieDuration ?? 0);
129
+ },
95
130
  getAudioParam(context, beat, lang) {
96
131
  const speaker = MulmoPresentationStyleMethods.getSpeaker(context, beat, lang);
97
132
  const speechOptions = { ...speaker.speechOptions, ...beat.speechOptions };
@@ -64,6 +64,7 @@ export declare const provider2ImageAgent: {
64
64
  models: string[];
65
65
  keyName: string;
66
66
  baseURLKeyName: string;
67
+ maxReferenceImages: number;
67
68
  };
68
69
  google: {
69
70
  agentName: string;
@@ -74,6 +75,9 @@ export declare const provider2ImageAgent: {
74
75
  replicate: {
75
76
  agentName: string;
76
77
  defaultModel: string;
78
+ imageModelParams: Record<string, {
79
+ maxReferenceImages?: number;
80
+ }>;
77
81
  models: string[];
78
82
  keyName: string;
79
83
  };
@@ -213,6 +217,17 @@ export declare const defaultProviders: {
213
217
  export declare const llm: (keyof typeof provider2LLMAgent)[];
214
218
  export type LLM = keyof typeof provider2LLMAgent;
215
219
  export declare const htmlLLMProvider: string[];
220
+ export declare const ProviderName: {
221
+ readonly OpenAI: "openai";
222
+ readonly Google: "google";
223
+ readonly Gemini: "gemini";
224
+ readonly Anthropic: "anthropic";
225
+ readonly Replicate: "replicate";
226
+ readonly ElevenLabs: "elevenlabs";
227
+ readonly Mock: "mock";
228
+ };
229
+ export declare const isImageProvider: (provider: string | undefined) => provider is keyof typeof provider2ImageAgent;
230
+ export declare const getMaxImageReferenceImages: (provider: string | undefined, model: string) => number | undefined;
216
231
  export declare const getModelAudio: (provider: keyof typeof provider2MovieAgent, model: string) => MovieAudioSpec | undefined;
217
232
  export declare const getModelDuration: (provider: keyof typeof provider2MovieAgent, model: string, movieDuration?: number) => number | undefined;
218
233
  export type ModelPricing = {
@@ -64,6 +64,10 @@ export const deprecatedGoogleImageModelHints = {
64
64
  // See https://cloud.google.com/vertex-ai/generative-ai/docs/models/gemini/3-pro-image
65
65
  // and https://cloud.google.com/vertex-ai/generative-ai/docs/models/gemini/3-1-flash-image
66
66
  export const vertexAIGlobalOnlyImageModels = new Set(["gemini-3-pro-image-preview", "gemini-3.1-flash-image-preview"]);
67
+ // Per-model reference image limits (image_input array). Only verified entries; unlisted models are not truncated.
68
+ const replicateImageModelParams = {
69
+ "bytedance/seedream-4": { maxReferenceImages: 10 },
70
+ };
67
71
  export const provider2ImageAgent = {
68
72
  openai: {
69
73
  agentName: "imageOpenaiAgent",
@@ -71,6 +75,7 @@ export const provider2ImageAgent = {
71
75
  models: [...gptImages],
72
76
  keyName: "OPENAI_API_KEY",
73
77
  baseURLKeyName: "OPENAI_BASE_URL",
78
+ maxReferenceImages: 16, // images.edit accepts up to 16 input images
74
79
  },
75
80
  google: {
76
81
  agentName: "imageGenAIAgent",
@@ -81,6 +86,7 @@ export const provider2ImageAgent = {
81
86
  replicate: {
82
87
  agentName: "imageReplicateAgent",
83
88
  defaultModel: "bytedance/seedream-4",
89
+ imageModelParams: replicateImageModelParams,
84
90
  models: [
85
91
  "bytedance/seedream-4",
86
92
  "qwen/qwen-image",
@@ -527,6 +533,31 @@ export const defaultProviders = {
527
533
  };
528
534
  export const llm = Object.keys(provider2LLMAgent);
529
535
  export const htmlLLMProvider = ["openai", "anthropic", "mock"];
536
+ // Provider name literals. Compare via these identifiers (e.g. provider === ProviderName.Replicate)
537
+ // instead of raw strings.
538
+ export const ProviderName = {
539
+ OpenAI: "openai",
540
+ Google: "google",
541
+ Gemini: "gemini",
542
+ Anthropic: "anthropic",
543
+ Replicate: "replicate",
544
+ ElevenLabs: "elevenlabs",
545
+ Mock: "mock",
546
+ };
547
+ export const isImageProvider = (provider) => {
548
+ return provider !== undefined && provider in provider2ImageAgent;
549
+ };
550
+ // Max reference images an image model accepts as input; undefined means no known limit (no truncation).
551
+ export const getMaxImageReferenceImages = (provider, model) => {
552
+ if (!isImageProvider(provider)) {
553
+ return undefined;
554
+ }
555
+ if (provider === ProviderName.Replicate) {
556
+ return provider2ImageAgent.replicate.imageModelParams[model]?.maxReferenceImages;
557
+ }
558
+ const agentInfo = provider2ImageAgent[provider];
559
+ return "maxReferenceImages" in agentInfo ? agentInfo.maxReferenceImages : undefined;
560
+ };
530
561
  export const getModelAudio = (provider, model) => {
531
562
  const modelParams = provider2MovieAgent[provider]?.modelParams;
532
563
  return modelParams?.[model]?.audio;
@@ -263,6 +263,15 @@ export declare const mulmoMarkdownMediaSchema: z.ZodObject<{
263
263
  opacity: z.ZodOptional<z.ZodNumber>;
264
264
  }, z.core.$strip>]>>>;
265
265
  }, z.core.$strict>;
266
+ export declare const ImageMediaType: {
267
+ readonly Image: "image";
268
+ readonly ImagePrompt: "imagePrompt";
269
+ readonly Movie: "movie";
270
+ readonly MoviePrompt: "moviePrompt";
271
+ readonly Beat: "beat";
272
+ readonly VoiceOver: "voice_over";
273
+ };
274
+ export declare const beatImageTypesWithoutOwnStill: readonly string[];
266
275
  export declare const mulmoImageMediaSchema: z.ZodObject<{
267
276
  type: z.ZodLiteral<"image">;
268
277
  source: z.ZodDiscriminatedUnion<[z.ZodObject<{
@@ -4135,6 +4144,21 @@ export declare const mulmoAudioAssetSchema: z.ZodUnion<readonly [z.ZodObject<{
4135
4144
  type: z.ZodLiteral<"midi">;
4136
4145
  source: z.ZodString;
4137
4146
  }, z.core.$strict>]>;
4147
+ export declare const BEAT_IMAGE_SENTINEL = "$beatImage";
4148
+ export declare const mulmoImageReferenceSchema: z.ZodObject<{
4149
+ name: z.ZodOptional<z.ZodString>;
4150
+ source: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
4151
+ kind: z.ZodLiteral<"url">;
4152
+ url: z.ZodURL;
4153
+ }, z.core.$strict>, z.ZodObject<{
4154
+ kind: z.ZodLiteral<"base64">;
4155
+ data: z.ZodString;
4156
+ }, z.core.$strict>, z.ZodObject<{
4157
+ kind: z.ZodLiteral<"path">;
4158
+ path: z.ZodString;
4159
+ }, z.core.$strict>], "kind">>;
4160
+ label: z.ZodOptional<z.ZodString>;
4161
+ }, z.core.$strict>;
4138
4162
  export declare const mulmoImagePromptMediaSchema: z.ZodObject<{
4139
4163
  type: z.ZodLiteral<"imagePrompt">;
4140
4164
  prompt: z.ZodString;
@@ -4153,6 +4177,20 @@ export declare const mulmoImagePromptMediaSchema: z.ZodObject<{
4153
4177
  kind: z.ZodLiteral<"path">;
4154
4178
  path: z.ZodString;
4155
4179
  }, z.core.$strict>], "kind">>;
4180
+ references: z.ZodOptional<z.ZodArray<z.ZodObject<{
4181
+ name: z.ZodOptional<z.ZodString>;
4182
+ source: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
4183
+ kind: z.ZodLiteral<"url">;
4184
+ url: z.ZodURL;
4185
+ }, z.core.$strict>, z.ZodObject<{
4186
+ kind: z.ZodLiteral<"base64">;
4187
+ data: z.ZodString;
4188
+ }, z.core.$strict>, z.ZodObject<{
4189
+ kind: z.ZodLiteral<"path">;
4190
+ path: z.ZodString;
4191
+ }, z.core.$strict>], "kind">>;
4192
+ label: z.ZodOptional<z.ZodString>;
4193
+ }, z.core.$strict>>>;
4156
4194
  }, z.core.$strict>;
4157
4195
  export declare const mulmoImageParamsImagesValueSchema: z.ZodUnion<readonly [z.ZodObject<{
4158
4196
  type: z.ZodLiteral<"image">;
@@ -4184,6 +4222,20 @@ export declare const mulmoImageParamsImagesValueSchema: z.ZodUnion<readonly [z.Z
4184
4222
  kind: z.ZodLiteral<"path">;
4185
4223
  path: z.ZodString;
4186
4224
  }, z.core.$strict>], "kind">>;
4225
+ references: z.ZodOptional<z.ZodArray<z.ZodObject<{
4226
+ name: z.ZodOptional<z.ZodString>;
4227
+ source: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
4228
+ kind: z.ZodLiteral<"url">;
4229
+ url: z.ZodURL;
4230
+ }, z.core.$strict>, z.ZodObject<{
4231
+ kind: z.ZodLiteral<"base64">;
4232
+ data: z.ZodString;
4233
+ }, z.core.$strict>, z.ZodObject<{
4234
+ kind: z.ZodLiteral<"path">;
4235
+ path: z.ZodString;
4236
+ }, z.core.$strict>], "kind">>;
4237
+ label: z.ZodOptional<z.ZodString>;
4238
+ }, z.core.$strict>>>;
4187
4239
  }, z.core.$strict>, z.ZodObject<{
4188
4240
  type: z.ZodLiteral<"movie">;
4189
4241
  source: z.ZodDiscriminatedUnion<[z.ZodObject<{
@@ -4231,6 +4283,20 @@ export declare const mulmoImageParamsImagesSchema: z.ZodRecord<z.ZodString, z.Zo
4231
4283
  kind: z.ZodLiteral<"path">;
4232
4284
  path: z.ZodString;
4233
4285
  }, z.core.$strict>], "kind">>;
4286
+ references: z.ZodOptional<z.ZodArray<z.ZodObject<{
4287
+ name: z.ZodOptional<z.ZodString>;
4288
+ source: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
4289
+ kind: z.ZodLiteral<"url">;
4290
+ url: z.ZodURL;
4291
+ }, z.core.$strict>, z.ZodObject<{
4292
+ kind: z.ZodLiteral<"base64">;
4293
+ data: z.ZodString;
4294
+ }, z.core.$strict>, z.ZodObject<{
4295
+ kind: z.ZodLiteral<"path">;
4296
+ path: z.ZodString;
4297
+ }, z.core.$strict>], "kind">>;
4298
+ label: z.ZodOptional<z.ZodString>;
4299
+ }, z.core.$strict>>>;
4234
4300
  }, z.core.$strict>, z.ZodObject<{
4235
4301
  type: z.ZodLiteral<"movie">;
4236
4302
  source: z.ZodDiscriminatedUnion<[z.ZodObject<{
@@ -4330,6 +4396,20 @@ export declare const mulmoImageParamsSchema: z.ZodObject<{
4330
4396
  kind: z.ZodLiteral<"path">;
4331
4397
  path: z.ZodString;
4332
4398
  }, z.core.$strict>], "kind">>;
4399
+ references: z.ZodOptional<z.ZodArray<z.ZodObject<{
4400
+ name: z.ZodOptional<z.ZodString>;
4401
+ source: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
4402
+ kind: z.ZodLiteral<"url">;
4403
+ url: z.ZodURL;
4404
+ }, z.core.$strict>, z.ZodObject<{
4405
+ kind: z.ZodLiteral<"base64">;
4406
+ data: z.ZodString;
4407
+ }, z.core.$strict>, z.ZodObject<{
4408
+ kind: z.ZodLiteral<"path">;
4409
+ path: z.ZodString;
4410
+ }, z.core.$strict>], "kind">>;
4411
+ label: z.ZodOptional<z.ZodString>;
4412
+ }, z.core.$strict>>>;
4333
4413
  }, z.core.$strict>, z.ZodObject<{
4334
4414
  type: z.ZodLiteral<"movie">;
4335
4415
  source: z.ZodDiscriminatedUnion<[z.ZodObject<{
@@ -8800,6 +8880,20 @@ export declare const mulmoBeatSchema: z.ZodObject<{
8800
8880
  kind: z.ZodLiteral<"path">;
8801
8881
  path: z.ZodString;
8802
8882
  }, z.core.$strict>], "kind">>;
8883
+ references: z.ZodOptional<z.ZodArray<z.ZodObject<{
8884
+ name: z.ZodOptional<z.ZodString>;
8885
+ source: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
8886
+ kind: z.ZodLiteral<"url">;
8887
+ url: z.ZodURL;
8888
+ }, z.core.$strict>, z.ZodObject<{
8889
+ kind: z.ZodLiteral<"base64">;
8890
+ data: z.ZodString;
8891
+ }, z.core.$strict>, z.ZodObject<{
8892
+ kind: z.ZodLiteral<"path">;
8893
+ path: z.ZodString;
8894
+ }, z.core.$strict>], "kind">>;
8895
+ label: z.ZodOptional<z.ZodString>;
8896
+ }, z.core.$strict>>>;
8803
8897
  }, z.core.$strict>, z.ZodObject<{
8804
8898
  type: z.ZodLiteral<"movie">;
8805
8899
  source: z.ZodDiscriminatedUnion<[z.ZodObject<{
@@ -8942,6 +9036,20 @@ export declare const mulmoPresentationStyleSchema: z.ZodObject<{
8942
9036
  kind: z.ZodLiteral<"path">;
8943
9037
  path: z.ZodString;
8944
9038
  }, z.core.$strict>], "kind">>;
9039
+ references: z.ZodOptional<z.ZodArray<z.ZodObject<{
9040
+ name: z.ZodOptional<z.ZodString>;
9041
+ source: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
9042
+ kind: z.ZodLiteral<"url">;
9043
+ url: z.ZodURL;
9044
+ }, z.core.$strict>, z.ZodObject<{
9045
+ kind: z.ZodLiteral<"base64">;
9046
+ data: z.ZodString;
9047
+ }, z.core.$strict>, z.ZodObject<{
9048
+ kind: z.ZodLiteral<"path">;
9049
+ path: z.ZodString;
9050
+ }, z.core.$strict>], "kind">>;
9051
+ label: z.ZodOptional<z.ZodString>;
9052
+ }, z.core.$strict>>>;
8945
9053
  }, z.core.$strict>, z.ZodObject<{
8946
9054
  type: z.ZodLiteral<"movie">;
8947
9055
  source: z.ZodDiscriminatedUnion<[z.ZodObject<{
@@ -9455,6 +9563,20 @@ export declare const mulmoScriptSchema: z.ZodObject<{
9455
9563
  kind: z.ZodLiteral<"path">;
9456
9564
  path: z.ZodString;
9457
9565
  }, z.core.$strict>], "kind">>;
9566
+ references: z.ZodOptional<z.ZodArray<z.ZodObject<{
9567
+ name: z.ZodOptional<z.ZodString>;
9568
+ source: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
9569
+ kind: z.ZodLiteral<"url">;
9570
+ url: z.ZodURL;
9571
+ }, z.core.$strict>, z.ZodObject<{
9572
+ kind: z.ZodLiteral<"base64">;
9573
+ data: z.ZodString;
9574
+ }, z.core.$strict>, z.ZodObject<{
9575
+ kind: z.ZodLiteral<"path">;
9576
+ path: z.ZodString;
9577
+ }, z.core.$strict>], "kind">>;
9578
+ label: z.ZodOptional<z.ZodString>;
9579
+ }, z.core.$strict>>>;
9458
9580
  }, z.core.$strict>, z.ZodObject<{
9459
9581
  type: z.ZodLiteral<"movie">;
9460
9582
  source: z.ZodDiscriminatedUnion<[z.ZodObject<{
@@ -13913,6 +14035,20 @@ export declare const mulmoScriptSchema: z.ZodObject<{
13913
14035
  kind: z.ZodLiteral<"path">;
13914
14036
  path: z.ZodString;
13915
14037
  }, z.core.$strict>], "kind">>;
14038
+ references: z.ZodOptional<z.ZodArray<z.ZodObject<{
14039
+ name: z.ZodOptional<z.ZodString>;
14040
+ source: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
14041
+ kind: z.ZodLiteral<"url">;
14042
+ url: z.ZodURL;
14043
+ }, z.core.$strict>, z.ZodObject<{
14044
+ kind: z.ZodLiteral<"base64">;
14045
+ data: z.ZodString;
14046
+ }, z.core.$strict>, z.ZodObject<{
14047
+ kind: z.ZodLiteral<"path">;
14048
+ path: z.ZodString;
14049
+ }, z.core.$strict>], "kind">>;
14050
+ label: z.ZodOptional<z.ZodString>;
14051
+ }, z.core.$strict>>>;
13916
14052
  }, z.core.$strict>, z.ZodObject<{
13917
14053
  type: z.ZodLiteral<"movie">;
13918
14054
  source: z.ZodDiscriminatedUnion<[z.ZodObject<{
@@ -14131,6 +14267,20 @@ export declare const mulmoStudioSchema: z.ZodObject<{
14131
14267
  kind: z.ZodLiteral<"path">;
14132
14268
  path: z.ZodString;
14133
14269
  }, z.core.$strict>], "kind">>;
14270
+ references: z.ZodOptional<z.ZodArray<z.ZodObject<{
14271
+ name: z.ZodOptional<z.ZodString>;
14272
+ source: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
14273
+ kind: z.ZodLiteral<"url">;
14274
+ url: z.ZodURL;
14275
+ }, z.core.$strict>, z.ZodObject<{
14276
+ kind: z.ZodLiteral<"base64">;
14277
+ data: z.ZodString;
14278
+ }, z.core.$strict>, z.ZodObject<{
14279
+ kind: z.ZodLiteral<"path">;
14280
+ path: z.ZodString;
14281
+ }, z.core.$strict>], "kind">>;
14282
+ label: z.ZodOptional<z.ZodString>;
14283
+ }, z.core.$strict>>>;
14134
14284
  }, z.core.$strict>, z.ZodObject<{
14135
14285
  type: z.ZodLiteral<"movie">;
14136
14286
  source: z.ZodDiscriminatedUnion<[z.ZodObject<{
@@ -18589,6 +18739,20 @@ export declare const mulmoStudioSchema: z.ZodObject<{
18589
18739
  kind: z.ZodLiteral<"path">;
18590
18740
  path: z.ZodString;
18591
18741
  }, z.core.$strict>], "kind">>;
18742
+ references: z.ZodOptional<z.ZodArray<z.ZodObject<{
18743
+ name: z.ZodOptional<z.ZodString>;
18744
+ source: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
18745
+ kind: z.ZodLiteral<"url">;
18746
+ url: z.ZodURL;
18747
+ }, z.core.$strict>, z.ZodObject<{
18748
+ kind: z.ZodLiteral<"base64">;
18749
+ data: z.ZodString;
18750
+ }, z.core.$strict>, z.ZodObject<{
18751
+ kind: z.ZodLiteral<"path">;
18752
+ path: z.ZodString;
18753
+ }, z.core.$strict>], "kind">>;
18754
+ label: z.ZodOptional<z.ZodString>;
18755
+ }, z.core.$strict>>>;
18592
18756
  }, z.core.$strict>, z.ZodObject<{
18593
18757
  type: z.ZodLiteral<"movie">;
18594
18758
  source: z.ZodDiscriminatedUnion<[z.ZodObject<{
@@ -18742,6 +18906,20 @@ export declare const mulmoPromptTemplateSchema: z.ZodObject<{
18742
18906
  kind: z.ZodLiteral<"path">;
18743
18907
  path: z.ZodString;
18744
18908
  }, z.core.$strict>], "kind">>;
18909
+ references: z.ZodOptional<z.ZodArray<z.ZodObject<{
18910
+ name: z.ZodOptional<z.ZodString>;
18911
+ source: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
18912
+ kind: z.ZodLiteral<"url">;
18913
+ url: z.ZodURL;
18914
+ }, z.core.$strict>, z.ZodObject<{
18915
+ kind: z.ZodLiteral<"base64">;
18916
+ data: z.ZodString;
18917
+ }, z.core.$strict>, z.ZodObject<{
18918
+ kind: z.ZodLiteral<"path">;
18919
+ path: z.ZodString;
18920
+ }, z.core.$strict>], "kind">>;
18921
+ label: z.ZodOptional<z.ZodString>;
18922
+ }, z.core.$strict>>>;
18745
18923
  }, z.core.$strict>, z.ZodObject<{
18746
18924
  type: z.ZodLiteral<"movie">;
18747
18925
  source: z.ZodDiscriminatedUnion<[z.ZodObject<{
@@ -19249,6 +19427,20 @@ export declare const mulmoPromptTemplateFileSchema: z.ZodObject<{
19249
19427
  kind: z.ZodLiteral<"path">;
19250
19428
  path: z.ZodString;
19251
19429
  }, z.core.$strict>], "kind">>;
19430
+ references: z.ZodOptional<z.ZodArray<z.ZodObject<{
19431
+ name: z.ZodOptional<z.ZodString>;
19432
+ source: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
19433
+ kind: z.ZodLiteral<"url">;
19434
+ url: z.ZodURL;
19435
+ }, z.core.$strict>, z.ZodObject<{
19436
+ kind: z.ZodLiteral<"base64">;
19437
+ data: z.ZodString;
19438
+ }, z.core.$strict>, z.ZodObject<{
19439
+ kind: z.ZodLiteral<"path">;
19440
+ path: z.ZodString;
19441
+ }, z.core.$strict>], "kind">>;
19442
+ label: z.ZodOptional<z.ZodString>;
19443
+ }, z.core.$strict>>>;
19252
19444
  }, z.core.$strict>, z.ZodObject<{
19253
19445
  type: z.ZodLiteral<"movie">;
19254
19446
  source: z.ZodDiscriminatedUnion<[z.ZodObject<{
@@ -130,9 +130,22 @@ const mulmoPdfMediaSchema = z
130
130
  source: mediaSourceSchema,
131
131
  })
132
132
  .strict();
133
+ // Media type literals shared by imageParams.images entries and beat images. Compare via
134
+ // these identifiers (e.g. entry.type === ImageMediaType.ImagePrompt) instead of raw strings.
135
+ export const ImageMediaType = {
136
+ Image: "image",
137
+ ImagePrompt: "imagePrompt",
138
+ Movie: "movie",
139
+ MoviePrompt: "moviePrompt",
140
+ Beat: "beat",
141
+ VoiceOver: "voice_over",
142
+ };
143
+ // Beat image types whose still derives from the movie or another beat — they cannot supply
144
+ // their own still for the $beatImage frame sentinel.
145
+ export const beatImageTypesWithoutOwnStill = [ImageMediaType.Movie, ImageMediaType.Beat, ImageMediaType.VoiceOver];
133
146
  export const mulmoImageMediaSchema = z
134
147
  .object({
135
- type: z.literal("image"),
148
+ type: z.literal(ImageMediaType.Image),
136
149
  source: mediaSourceSchema,
137
150
  })
138
151
  .strict();
@@ -144,13 +157,13 @@ const mulmoSvgMediaSchema = z
144
157
  .strict();
145
158
  export const mulmoMovieMediaSchema = z
146
159
  .object({
147
- type: z.literal("movie"),
160
+ type: z.literal(ImageMediaType.Movie),
148
161
  source: mediaSourceSchema,
149
162
  })
150
163
  .strict();
151
164
  export const mulmoMoviePromptMediaSchema = z
152
165
  .object({
153
- type: z.literal("moviePrompt"),
166
+ type: z.literal(ImageMediaType.MoviePrompt),
154
167
  prompt: z.string().min(1),
155
168
  imageName: z.string().optional().describe("Reference an imageRefs key to use as image-to-video input"),
156
169
  })
@@ -292,13 +305,13 @@ export const mulmoHtmlTailwindMediaSchema = z
292
305
  .strict();
293
306
  export const mulmoBeatReferenceMediaSchema = z
294
307
  .object({
295
- type: z.literal("beat"),
308
+ type: z.literal(ImageMediaType.Beat),
296
309
  id: z.string().optional().describe("Specifies the beat to reference."),
297
310
  })
298
311
  .strict();
299
312
  export const mulmoVoiceOverMediaSchema = z
300
313
  .object({
301
- type: z.literal("voice_over"),
314
+ type: z.literal(ImageMediaType.VoiceOver),
302
315
  startAt: z.number().optional().describe("The time to start the voice over the video in seconds."),
303
316
  })
304
317
  .strict();
@@ -339,13 +352,26 @@ const mulmoMidiMediaSchema = z
339
352
  .strict();
340
353
  export const mulmoAudioAssetSchema = z.union([mulmoAudioMediaSchema, mulmoMidiMediaSchema]);
341
354
  const imageIdSchema = z.string();
355
+ // Sentinel for movieParams.firstFrameImageName / lastFrameImageName: "this beat's own generated image".
356
+ export const BEAT_IMAGE_SENTINEL = "$beatImage";
357
+ // imageRefs keys may not start with "$": that prefix is reserved for sentinels like $beatImage.
358
+ const imageRefKeySchema = imageIdSchema.refine((key) => !key.startsWith("$"), { message: 'image keys must not start with the reserved prefix "$"' });
359
+ export const mulmoImageReferenceSchema = z
360
+ .object({
361
+ name: imageIdSchema.optional().describe("An imageRefs key to use as a reference image"),
362
+ source: mediaSourceSchema.optional().describe("Direct source (path/url) to use as a reference image"),
363
+ label: z.string().optional().describe("Role of this reference (e.g. 'the firefighter Travis Kane'), injected into the prompt as a preamble"),
364
+ })
365
+ .strict()
366
+ .refine((ref) => (ref.name === undefined) !== (ref.source === undefined), { message: "specify exactly one of name or source" });
342
367
  export const mulmoImagePromptMediaSchema = z
343
368
  .object({
344
- type: z.literal("imagePrompt"),
369
+ type: z.literal(ImageMediaType.ImagePrompt),
345
370
  prompt: z.string().min(1),
346
371
  canvasSize: z.object({ width: z.number(), height: z.number() }).strict().optional(),
347
- referenceImageName: imageIdSchema.optional().describe("Reference another imageRefs key as input for image generation"),
348
- referenceImage: mediaSourceSchema.optional().describe("Direct source (path/url/base64) as reference image for generation"),
372
+ referenceImageName: imageIdSchema.optional().describe("Reference another imageRefs key as input for image generation. Sugar for references[0].name"),
373
+ referenceImage: mediaSourceSchema.optional().describe("Direct source (path/url/base64) as reference image for generation. Sugar for references[0].source"),
374
+ references: z.array(mulmoImageReferenceSchema).optional().describe("Reference images (by imageRefs key or direct source) with optional role labels"),
349
375
  })
350
376
  .strict();
351
377
  export const mulmoImageParamsImagesValueSchema = z.union([
@@ -354,7 +380,7 @@ export const mulmoImageParamsImagesValueSchema = z.union([
354
380
  mulmoMovieMediaSchema,
355
381
  mulmoMoviePromptMediaSchema,
356
382
  ]);
357
- export const mulmoImageParamsImagesSchema = z.record(imageIdSchema, mulmoImageParamsImagesValueSchema);
383
+ export const mulmoImageParamsImagesSchema = z.record(imageRefKeySchema, mulmoImageParamsImagesValueSchema);
358
384
  export const mulmoFillOptionSchema = z
359
385
  .object({
360
386
  style: z.enum(["aspectFit", "aspectFill"]).optional().default("aspectFit"),
@@ -500,8 +526,12 @@ export const mulmoMovieParamsSchema = z.object({
500
526
  filters: z.array(mulmoVideoFilterSchema).optional(), // for movie.ts
501
527
  vertexai_project: z.string().optional(), // Google Cloud Project ID for Vertex AI
502
528
  vertexai_location: z.string().optional(), // Vertex AI location (default: us-central1)
503
- firstFrameImageName: imageIdSchema.optional().describe("Reference an imageRefs key for the first frame (image-to-video input)"),
504
- lastFrameImageName: imageIdSchema.optional().describe("Reference an imageRefs key for the last frame (image-to-video interpolation)"),
529
+ firstFrameImageName: imageIdSchema
530
+ .optional()
531
+ .describe("Reference an imageRefs key for the first frame (image-to-video input), or '$beatImage' for the beat's own generated image"),
532
+ lastFrameImageName: imageIdSchema
533
+ .optional()
534
+ .describe("Reference an imageRefs key for the last frame (image-to-video interpolation), or '$beatImage' for the beat's own generated image"),
505
535
  frameFillColor: z
506
536
  .string()
507
537
  .regex(/^(#|0x)?[0-9a-fA-F]{6}([0-9a-fA-F]{2})?$|^[a-zA-Z]+$/, "must be a hex color ('#RRGGBB[AA]', '0x' or no prefix) or a color name")
@@ -540,7 +570,7 @@ export const mulmoBeatSchema = z
540
570
  images: mulmoImageParamsImagesSchema
541
571
  .optional()
542
572
  .describe("Beat-local media references. Same schema as imageParams.images. Merged with global refs (local takes precedence)."),
543
- imageNames: z.array(imageIdSchema).optional(), // list of image names to use for image generation. The default is all images in the imageParams.images.
573
+ imageNames: z.array(imageRefKeySchema).optional(), // list of image names to use for image generation. The default is all images in the imageParams.images.
544
574
  imagePrompt: z.string().optional(),
545
575
  moviePrompt: z.string().optional(),
546
576
  soundEffectPrompt: z.string().optional(),
@@ -1,6 +1,6 @@
1
1
  import { type CallbackFunction } from "graphai";
2
2
  import type { UsageCollectorAPI } from "./usage.js";
3
- import { langSchema, localizedTextSchema, mulmoBeatSchema, mulmoScriptSchema, mulmoStudioSchema, mulmoStudioBeatSchema, mulmoStoryboardSchema, mulmoStoryboardSceneSchema, mulmoStudioMultiLingualSchema, mulmoStudioMultiLingualArraySchema, mulmoStudioMultiLingualDataSchema, mulmoStudioMultiLingualFileSchema, speakerDictionarySchema, speakerSchema, mulmoSpeechParamsSchema, mulmoImageParamsSchema, mulmoImageParamsImagesValueSchema, mulmoImageParamsImagesSchema, mulmoFillOptionSchema, mulmoTransitionSchema, mulmoVideoFilterSchema, mulmoMovieParamsSchema, mulmoSoundEffectParamsSchema, mulmoLipSyncParamsSchema, textSlideParamsSchema, speechOptionsSchema, speakerDataSchema, mulmoCanvasDimensionSchema, mulmoPromptTemplateSchema, mulmoPromptTemplateFileSchema, text2ImageProviderSchema, text2HtmlImageProviderSchema, text2MovieProviderSchema, text2SpeechProviderSchema, mulmoPresentationStyleSchema, multiLingualTextsSchema, mulmoImageAssetSchema, mulmoMermaidMediaSchema, mulmoTextSlideMediaSchema, mulmoMarkdownMediaSchema, mulmoImageMediaSchema, mulmoChartMediaSchema, mediaSourceSchema, mediaSourceMermaidSchema, backgroundImageSchema, backgroundImageSourceSchema, mulmoSessionStateSchema, mulmoOpenAIImageModelSchema, mulmoGoogleImageModelSchema, mulmoGoogleMovieModelSchema, mulmoReplicateMovieModelSchema, mulmoImagePromptMediaSchema, mulmoMovieMediaSchema, mulmoMoviePromptMediaSchema, markdownLayoutSchema, row2Schema, grid2x2Schema } from "./schema.js";
3
+ import { langSchema, localizedTextSchema, mulmoBeatSchema, mulmoScriptSchema, mulmoStudioSchema, mulmoStudioBeatSchema, mulmoStoryboardSchema, mulmoStoryboardSceneSchema, mulmoStudioMultiLingualSchema, mulmoStudioMultiLingualArraySchema, mulmoStudioMultiLingualDataSchema, mulmoStudioMultiLingualFileSchema, speakerDictionarySchema, speakerSchema, mulmoSpeechParamsSchema, mulmoImageParamsSchema, mulmoImageParamsImagesValueSchema, mulmoImageParamsImagesSchema, mulmoFillOptionSchema, mulmoTransitionSchema, mulmoVideoFilterSchema, mulmoMovieParamsSchema, mulmoSoundEffectParamsSchema, mulmoLipSyncParamsSchema, textSlideParamsSchema, speechOptionsSchema, speakerDataSchema, mulmoCanvasDimensionSchema, mulmoPromptTemplateSchema, mulmoPromptTemplateFileSchema, text2ImageProviderSchema, text2HtmlImageProviderSchema, text2MovieProviderSchema, text2SpeechProviderSchema, mulmoPresentationStyleSchema, multiLingualTextsSchema, mulmoImageAssetSchema, mulmoMermaidMediaSchema, mulmoTextSlideMediaSchema, mulmoMarkdownMediaSchema, mulmoImageMediaSchema, mulmoChartMediaSchema, mediaSourceSchema, mediaSourceMermaidSchema, backgroundImageSchema, backgroundImageSourceSchema, mulmoSessionStateSchema, mulmoOpenAIImageModelSchema, mulmoGoogleImageModelSchema, mulmoGoogleMovieModelSchema, mulmoReplicateMovieModelSchema, mulmoImagePromptMediaSchema, mulmoImageReferenceSchema, mulmoMovieMediaSchema, mulmoMoviePromptMediaSchema, markdownLayoutSchema, row2Schema, grid2x2Schema } from "./schema.js";
4
4
  import { pdf_modes, pdf_sizes, storyToScriptGenerateMode } from "./const.js";
5
5
  import type { LLM } from "./provider2agent.js";
6
6
  import { z } from "zod";
@@ -49,6 +49,7 @@ export type MulmoGoogleImageModel = z.infer<typeof mulmoGoogleImageModelSchema>;
49
49
  export type MulmoGoogleMovieModel = z.infer<typeof mulmoGoogleMovieModelSchema>;
50
50
  export type MulmoReplicateMovieModel = z.infer<typeof mulmoReplicateMovieModelSchema>;
51
51
  export type MulmoImagePromptMedia = z.infer<typeof mulmoImagePromptMediaSchema>;
52
+ export type MulmoImageReference = z.infer<typeof mulmoImageReferenceSchema>;
52
53
  export type MulmoMoviePromptMedia = z.infer<typeof mulmoMoviePromptMediaSchema>;
53
54
  export type MulmoMarkdownLayout = z.infer<typeof markdownLayoutSchema>;
54
55
  export type MulmoRow2 = z.infer<typeof row2Schema>;