@vanillaskyai/video 0.1.1 → 0.3.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/CHANGELOG.md +35 -1
- package/PUBLIC-API.md +20 -2
- package/README.md +14 -6
- package/dist/{builtin-server-F7YXRVCH.js → builtin-server-BRTZN4Q7.js} +2 -2
- package/dist/check-runtime.js +1 -1
- package/dist/{chunk-EVG2ZYIY.js → chunk-3O7OMMMF.js} +7 -4
- package/dist/{chunk-GRMUV7QY.js → chunk-BKF3A357.js} +1 -1
- package/dist/{chunk-YC5MFXA5.js → chunk-GR4I3MN2.js} +37 -15
- package/dist/{chunk-A2X45FET.js → chunk-I5YWVQ5R.js} +1 -1
- package/dist/{chunk-ERY4S6QV.js → chunk-JW47XCRL.js} +6 -1
- package/dist/{chunk-XB7LH4J2.js → chunk-QTMHS7JD.js} +2 -1
- package/dist/{chunk-W2XJKG6C.js → chunk-RBQN3VSY.js} +2 -2
- package/dist/{chunk-OOPIETLW.js → chunk-S5ZU5WUU.js} +1 -1
- package/dist/{chunk-ABPKM4GK.js → chunk-STIFILQG.js} +1 -1
- package/dist/chunk-WHPZED7X.js +57 -0
- package/dist/{chunk-CHLGW22F.js → chunk-XAMUOSX7.js} +3 -3
- package/dist/{chunk-IXCUY3B3.js → chunk-XYZOJ5NZ.js} +195 -52
- package/dist/cli.js +5 -5
- package/dist/{compose-video-CN3VSWST.js → compose-video-TQOHDXNW.js} +4 -4
- package/dist/{events-_wfjbmEp.d.ts → events-CTIsANzz.d.ts} +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/{kit-BMNcHqa9.d.ts → kit-DA2cfJ96.d.ts} +1 -1
- package/dist/react.d.ts +7 -4
- package/dist/react.js +226 -30
- package/dist/server.d.ts +21 -4
- package/dist/server.js +205 -18
- package/dist/system-prompt-NMYHLAMJ.js +10 -0
- package/dist/template-catalog.js +1 -1
- package/dist/templates.d.ts +3 -3
- package/dist/test.d.ts +3 -2
- package/dist/test.js +3 -3
- package/dist/{text-stream-6XHC7J47.js → text-stream-UPGUD2TD.js} +2 -2
- package/dist/{types-B-PZR6G_.d.ts → types-CkO2EYr4.d.ts} +8 -4
- package/docs/concepts.md +11 -1
- package/docs/custom-templates.md +34 -6
- package/docs/customization.md +2 -1
- package/docs/errors.md +3 -1
- package/docs/getting-started.md +13 -10
- package/docs/input-and-first-scene.md +17 -6
- package/docs/integrate-nextjs.md +6 -3
- package/docs/media-and-audio.md +73 -14
- package/docs/prompt-and-input.md +27 -5
- package/docs/provider-integration.md +45 -2
- package/docs/reference/protocol.md +9 -0
- package/examples/nextjs-quickstart/README.md +3 -1
- package/examples/nextjs-quickstart/package.json +3 -2
- package/examples/nextjs-quickstart/src/app/api/video/route.ts +1 -1
- package/package.json +1 -1
- package/registry/items/brandMessage.json +1 -2
- package/registry/items/media.json +2 -1
- package/dist/chunk-FQ47WXAJ.js +0 -38
- package/dist/system-prompt-A6UXNTPK.js +0 -8
|
@@ -5,11 +5,11 @@ import {
|
|
|
5
5
|
applyVideoEvent,
|
|
6
6
|
checksumVideo,
|
|
7
7
|
createVideoState
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-STIFILQG.js";
|
|
9
9
|
import {
|
|
10
10
|
parseVideoPlanPart,
|
|
11
11
|
safePublicDiagnostic
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-JW47XCRL.js";
|
|
13
13
|
import {
|
|
14
14
|
MAX_RETAINED_INSTRUCTIONS_LENGTH,
|
|
15
15
|
MAX_RETAINED_MEDIA_URLS,
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
getCloserReserve,
|
|
27
27
|
getReadableSceneDuration,
|
|
28
28
|
paceScene
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-3O7OMMMF.js";
|
|
30
30
|
import {
|
|
31
31
|
resolveVideoBrand
|
|
32
32
|
} from "./chunk-XGRA2MUV.js";
|
|
@@ -95,19 +95,24 @@ function resolveSuppliedMediaPlanPart(part, input) {
|
|
|
95
95
|
function buildVideoUserPrompt(input, openingDurationSec = 0) {
|
|
96
96
|
return [
|
|
97
97
|
"Compose a video response from the structured customer input below.",
|
|
98
|
+
`Knowledge mode: ${input.knowledgeMode ?? "input-only"}.`,
|
|
98
99
|
`Maximum duration: ${input.maxDurationSec ?? 30} seconds, including the supplied opening.`,
|
|
99
100
|
input.opening?.trim() ? `The host has already added the opening scene, which consumes ${openingDurationSec} seconds. Continue after it and do not repeat or rewrite it.` : "Add the first grounded scene as soon as it is complete.",
|
|
100
101
|
"The first generated body scene must be fully playable without external media. Use a content-fit text, data, comparison, list, or device-free template with no media URL or keyword.",
|
|
101
102
|
"Never use media, ctaMedia, or reaction as the first generated body template, even with mediaType=gradient. Choose a non-media template first.",
|
|
102
103
|
"Add that scene before resolving any stock or supplied asset. Media belongs on later body scenes and must arrive without blocking scene additions.",
|
|
103
|
-
"
|
|
104
|
+
"Use only claims supported by the factual basis permitted by the trusted system prompt.",
|
|
104
105
|
"Select the most decision-relevant grounded takeaways that fit the duration; represent each selected takeaway once before completing the response.",
|
|
105
106
|
"For a long source, summarize instead of attempting to represent every fact, unless the creative instructions explicitly request complete fact coverage that fits the duration.",
|
|
106
|
-
"
|
|
107
|
+
"When selecting claims from the raw input, preserve their exact wording and numbers. Preserve qualifiers, units, denominators, ranges, and comparison direction; for example, do not shorten 4.8 out of 5 to 4.8.",
|
|
107
108
|
"Choose the scene count from the distinct grounded material and the duration budget. Use fewer scenes for sparse input; continue beyond five when rich input warrants it and timing allows.",
|
|
109
|
+
"If the creative instructions explicitly require one separate scene per named item, release, section, or list entry, do not merge, group, or omit those required items. Keep related required scenes adjacent in a coherent progression while preserving each item as its own scene.",
|
|
110
|
+
"Before emitting, verify that the explicitly requested structure can fit readably within the maximum duration. If it cannot, preserve readability and the requested separation for the scenes that fit, then finish with plan.complete using finishReason length rather than silently changing the structure.",
|
|
111
|
+
"For ordinary multi-fact input, form at least three distinct beats: hook, comprehension, and payoff. Use only one or two beats when the source genuinely contains no more than two independent grounded takeaways. This is a narrative guideline, never permission to repeat facts or add filler.",
|
|
112
|
+
"After the first playable body scene, emit exactly one scene.add with placement closer. Generate a short grounded conclusion that answers the story's so-what; it must not repeat hook language or imply another scene follows.",
|
|
108
113
|
"Use a different suitable template for each body scene when the catalog supports it.",
|
|
109
114
|
"Never add filler to satisfy a count or diversity target.",
|
|
110
|
-
input.suppliedMedia?.length ? "Select zero or more relevant opaque supplied-media references for visible later scenes. Never invent or transform a reference, and
|
|
115
|
+
input.suppliedMedia?.length ? "Select zero or more relevant opaque supplied-media references for visible later scenes. Never invent or transform a reference. Only emit mediaKeyword when the trusted system catalog explicitly exposes it, and only on later scenes. Never invent mediaUrl or mediaPoster." : "No supplied media URL is available. Use asset-free templates unless the trusted system catalog explicitly permits host-resolved media intent. Only emit mediaKeyword when the trusted system catalog explicitly exposes it, and only on later scenes. Never invent mediaUrl or mediaPoster.",
|
|
111
116
|
"",
|
|
112
117
|
"RAW INPUT",
|
|
113
118
|
input.input.trim(),
|
|
@@ -130,6 +135,20 @@ function buildVideoUserPrompt(input, openingDurationSec = 0) {
|
|
|
130
135
|
}
|
|
131
136
|
|
|
132
137
|
// src/server/compose-video.ts
|
|
138
|
+
var DEFAULT_OPENING_TEXT = "Creating your video...";
|
|
139
|
+
function resolveVideoInput(input) {
|
|
140
|
+
return {
|
|
141
|
+
...input,
|
|
142
|
+
opening: input.opening?.trim() || DEFAULT_OPENING_TEXT
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
function resolveStreamCapabilities(capabilities) {
|
|
146
|
+
if (capabilities?.templates == null) return capabilities;
|
|
147
|
+
return {
|
|
148
|
+
...capabilities,
|
|
149
|
+
templates: [.../* @__PURE__ */ new Set(["media", ...capabilities.templates])]
|
|
150
|
+
};
|
|
151
|
+
}
|
|
133
152
|
function invokeIsolated(callback, value) {
|
|
134
153
|
if (!callback) return;
|
|
135
154
|
try {
|
|
@@ -158,12 +177,12 @@ function buildInitialConfig(input, audio, snapshotRetention, closerReserveSec, g
|
|
|
158
177
|
const openingText = input.opening?.trim();
|
|
159
178
|
const rawScenes = openingText ? [{
|
|
160
179
|
id: "supplied-opening",
|
|
161
|
-
templateId: "
|
|
180
|
+
templateId: "media",
|
|
162
181
|
variables: {
|
|
163
|
-
|
|
164
|
-
|
|
182
|
+
texts: openingText,
|
|
183
|
+
mediaType: "gradient"
|
|
165
184
|
},
|
|
166
|
-
timing: { fixedDuration:
|
|
185
|
+
timing: { fixedDuration: 3 }
|
|
167
186
|
}] : [];
|
|
168
187
|
const scenes = [];
|
|
169
188
|
const warnings = [];
|
|
@@ -213,6 +232,9 @@ function buildInitialConfig(input, audio, snapshotRetention, closerReserveSec, g
|
|
|
213
232
|
}
|
|
214
233
|
function validateInput(input) {
|
|
215
234
|
if (!input.input.trim()) throw new Error("Video response input is required");
|
|
235
|
+
if (input.knowledgeMode != null && input.knowledgeMode !== "input-only" && input.knowledgeMode !== "general") {
|
|
236
|
+
throw new Error("Video response knowledge mode must be input-only or general");
|
|
237
|
+
}
|
|
216
238
|
if (input.maxDurationSec != null && (!Number.isFinite(input.maxDurationSec) || input.maxDurationSec < 5 || input.maxDurationSec > 120)) {
|
|
217
239
|
throw new Error("Video response maximum duration must be between 5 and 120 seconds");
|
|
218
240
|
}
|
|
@@ -252,11 +274,42 @@ function createOmittedForCloserWarning(sceneId) {
|
|
|
252
274
|
return {
|
|
253
275
|
code: "scene_omitted_for_closer",
|
|
254
276
|
category: "readability",
|
|
255
|
-
message: "Scene was omitted because the
|
|
277
|
+
message: "Scene was omitted because the reserved closer must remain the last scene.",
|
|
256
278
|
sceneId,
|
|
257
279
|
recoverable: true
|
|
258
280
|
};
|
|
259
281
|
}
|
|
282
|
+
function createDuplicateCloserWarning() {
|
|
283
|
+
return {
|
|
284
|
+
code: "scene_omitted_for_closer",
|
|
285
|
+
category: "readability",
|
|
286
|
+
message: "An additional closer was omitted because the first valid closer is already reserved.",
|
|
287
|
+
recoverable: true
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
function createIncompletePlanWarning() {
|
|
291
|
+
return {
|
|
292
|
+
code: "plan_incomplete",
|
|
293
|
+
category: "provider",
|
|
294
|
+
message: "The planner stopped at a length limit; some requested scenes or the ending may be missing.",
|
|
295
|
+
recoverable: true
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
function createMissingCloserWarning() {
|
|
299
|
+
return {
|
|
300
|
+
code: "plan_missing_closer",
|
|
301
|
+
category: "provider",
|
|
302
|
+
message: "The planner completed without a valid closer; the video may end on a body scene.",
|
|
303
|
+
recoverable: true
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
function pendingCloserReserve(scene, getTemplatePacing) {
|
|
307
|
+
const metadata = getTemplatePacing?.(scene.templateId);
|
|
308
|
+
const readableMinimum = getReadableSceneDuration(scene, metadata);
|
|
309
|
+
const explicitRange = scene.timing.startTime != null && scene.timing.endTime != null ? Math.max(0, scene.timing.endTime - scene.timing.startTime) : void 0;
|
|
310
|
+
const requested = explicitRange ?? scene.timing.fixedDuration ?? metadata?.preferredDuration ?? readableMinimum;
|
|
311
|
+
return Math.max(readableMinimum, requested);
|
|
312
|
+
}
|
|
260
313
|
function sceneSlotDuration(scene) {
|
|
261
314
|
return Math.max(0, (scene.timing.endTime ?? 0) - (scene.timing.startTime ?? 0));
|
|
262
315
|
}
|
|
@@ -276,11 +329,10 @@ function createSceneQualityWarnings(scene) {
|
|
|
276
329
|
recoverable: true
|
|
277
330
|
}];
|
|
278
331
|
}
|
|
279
|
-
function createVideo(
|
|
280
|
-
validateInput(
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
}
|
|
332
|
+
function createVideo(rawInput, options) {
|
|
333
|
+
validateInput(rawInput);
|
|
334
|
+
const usesDefaultOpening = rawInput.opening == null;
|
|
335
|
+
const input = resolveVideoInput(rawInput);
|
|
284
336
|
const requestId = options.requestId ?? createId("request");
|
|
285
337
|
const runId = options.runId ?? createId("run");
|
|
286
338
|
const request = createVideoRequest(input, {
|
|
@@ -379,13 +431,22 @@ function createVideo(input, options) {
|
|
|
379
431
|
resolveResult(finalState);
|
|
380
432
|
}
|
|
381
433
|
};
|
|
434
|
+
let planCompleted = false;
|
|
435
|
+
let generatedSceneCount = 0;
|
|
436
|
+
let runtimeDurationLimited = false;
|
|
437
|
+
let pendingCloser;
|
|
438
|
+
const deferredForCloser = [];
|
|
439
|
+
let plannerReportedLength = false;
|
|
440
|
+
let closerCommitted = false;
|
|
441
|
+
let missingCloser = false;
|
|
442
|
+
let finishReason = "stop";
|
|
382
443
|
try {
|
|
383
444
|
yield emit(events.create("response.start", {
|
|
384
445
|
requestId,
|
|
385
446
|
format: { orientation: initialConfig.orientation ?? "portrait" },
|
|
386
447
|
style: initialConfig.style,
|
|
387
448
|
meta: initialConfig.meta,
|
|
388
|
-
capabilities: options.capabilities
|
|
449
|
+
capabilities: resolveStreamCapabilities(options.capabilities)
|
|
389
450
|
}));
|
|
390
451
|
if (initialConfig.audio) yield emit(events.create("audio.set", { audio: initialConfig.audio }));
|
|
391
452
|
for (const warning of initial.warnings) {
|
|
@@ -398,14 +459,7 @@ function createVideo(input, options) {
|
|
|
398
459
|
revision: 0
|
|
399
460
|
}));
|
|
400
461
|
}
|
|
401
|
-
|
|
402
|
-
let generatedSceneCount = 0;
|
|
403
|
-
let runtimeDurationLimited = false;
|
|
404
|
-
let askAccepted = false;
|
|
405
|
-
const deferredForCloser = [];
|
|
406
|
-
let plannerReportedLength = false;
|
|
407
|
-
let finishReason = "stop";
|
|
408
|
-
const systemPrompt = options.systemPrompt ?? (await import("./system-prompt-A6UXNTPK.js")).DEFAULT_VIDEO_SYSTEM_PROMPT;
|
|
462
|
+
const systemPrompt = options.systemPrompt ?? (await import("./system-prompt-NMYHLAMJ.js")).createVideoSystemPrompt(input.knowledgeMode);
|
|
409
463
|
const context = { request, systemPrompt, userPrompt, initialConfig, signal: controller.signal };
|
|
410
464
|
attachGenerationLifecycleSink(context, lifecycle);
|
|
411
465
|
for await (const untrustedPart of options.generate(context)) {
|
|
@@ -421,21 +475,29 @@ function createVideo(input, options) {
|
|
|
421
475
|
if (options.capabilities?.templates != null && !options.capabilities.templates.includes(part.scene.templateId)) {
|
|
422
476
|
throw new Error(`Scene template ${part.scene.templateId} was not negotiated`);
|
|
423
477
|
}
|
|
424
|
-
if (askAccepted) {
|
|
425
|
-
runtimeDurationLimited = true;
|
|
426
|
-
rejectedSceneCount += 1;
|
|
427
|
-
yield emit(events.create("response.warning", {
|
|
428
|
-
warning: createOmittedForCloserWarning(part.scene.id)
|
|
429
|
-
}));
|
|
430
|
-
continue;
|
|
431
|
-
}
|
|
432
478
|
options.validateScene?.(part.scene, {
|
|
433
479
|
input,
|
|
434
480
|
previousScenes: state.config?.scenes ?? []
|
|
435
481
|
});
|
|
436
482
|
const templatePacing = options.getTemplatePacing?.(part.scene.templateId);
|
|
437
483
|
const isAskCandidate = templatePacing?.jobs?.includes("ask") === true;
|
|
438
|
-
|
|
484
|
+
const isPayoffCandidate = templatePacing?.jobs?.includes("payoff") === true;
|
|
485
|
+
if (part.placement === "closer" && templatePacing && !isAskCandidate && !isPayoffCandidate) {
|
|
486
|
+
throw new Error(`Scene template ${part.scene.templateId} cannot be used as a closer`);
|
|
487
|
+
}
|
|
488
|
+
const isCloserCandidate = part.placement === "closer" || isAskCandidate;
|
|
489
|
+
if (isCloserCandidate) {
|
|
490
|
+
if (pendingCloser) {
|
|
491
|
+
rejectedSceneCount += 1;
|
|
492
|
+
yield emit(events.create("response.warning", {
|
|
493
|
+
warning: createDuplicateCloserWarning()
|
|
494
|
+
}));
|
|
495
|
+
} else {
|
|
496
|
+
pendingCloser = part.scene;
|
|
497
|
+
}
|
|
498
|
+
continue;
|
|
499
|
+
}
|
|
500
|
+
if (deferredForCloser.length) {
|
|
439
501
|
deferredForCloser.push(part.scene);
|
|
440
502
|
continue;
|
|
441
503
|
}
|
|
@@ -443,7 +505,7 @@ function createVideo(input, options) {
|
|
|
443
505
|
previousScenes: state.config?.scenes ?? [],
|
|
444
506
|
audio: state.config?.audio,
|
|
445
507
|
maxDurationSec: input.maxDurationSec ?? 30,
|
|
446
|
-
closerReserveSec,
|
|
508
|
+
closerReserveSec: pendingCloser ? pendingCloserReserve(pendingCloser, options.getTemplatePacing) : closerReserveSec,
|
|
447
509
|
getTemplatePacing: options.getTemplatePacing
|
|
448
510
|
});
|
|
449
511
|
if (!paced.scene) {
|
|
@@ -459,16 +521,6 @@ function createVideo(input, options) {
|
|
|
459
521
|
continue;
|
|
460
522
|
}
|
|
461
523
|
const scene = paced.scene;
|
|
462
|
-
const isAsk = isAskCandidate;
|
|
463
|
-
if (isAsk && deferredForCloser.length) {
|
|
464
|
-
runtimeDurationLimited = true;
|
|
465
|
-
for (const deferred of deferredForCloser.splice(0)) {
|
|
466
|
-
rejectedSceneCount += 1;
|
|
467
|
-
yield emit(events.create("response.warning", {
|
|
468
|
-
warning: createOmittedForCloserWarning(deferred.id)
|
|
469
|
-
}));
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
524
|
for (const warning of paced.warnings) {
|
|
473
525
|
yield emit(events.create("response.warning", { warning }));
|
|
474
526
|
}
|
|
@@ -480,13 +532,24 @@ function createVideo(input, options) {
|
|
|
480
532
|
position: state.config?.scenes.length ?? 0,
|
|
481
533
|
revision: 0
|
|
482
534
|
}));
|
|
483
|
-
if (isAsk) {
|
|
484
|
-
askAccepted = true;
|
|
485
|
-
}
|
|
486
535
|
generatedSceneCount += 1;
|
|
487
536
|
acceptedSceneCount += 1;
|
|
488
537
|
timeToFirstSceneMs ??= Math.max(0, now() - startedAt);
|
|
489
538
|
} else if (part.type === "scene.patch") {
|
|
539
|
+
if (pendingCloser?.id === part.sceneId) {
|
|
540
|
+
const nextPendingCloser = {
|
|
541
|
+
...pendingCloser,
|
|
542
|
+
...part.patch,
|
|
543
|
+
variables: part.patch.variables ? { ...pendingCloser.variables, ...part.patch.variables } : pendingCloser.variables,
|
|
544
|
+
timing: part.patch.timing ? { ...pendingCloser.timing, ...part.patch.timing } : pendingCloser.timing
|
|
545
|
+
};
|
|
546
|
+
options.validateScene?.(nextPendingCloser, {
|
|
547
|
+
input,
|
|
548
|
+
previousScenes: state.config?.scenes ?? []
|
|
549
|
+
});
|
|
550
|
+
pendingCloser = nextPendingCloser;
|
|
551
|
+
continue;
|
|
552
|
+
}
|
|
490
553
|
const scenes = state.config?.scenes ?? [];
|
|
491
554
|
const sceneIndex = scenes.findIndex((scene) => scene.id === part.sceneId);
|
|
492
555
|
if (sceneIndex < 0) throw new Error(`Scene ${part.sceneId} does not exist`);
|
|
@@ -521,7 +584,7 @@ function createVideo(input, options) {
|
|
|
521
584
|
previousScenes: scenes.slice(0, sceneIndex),
|
|
522
585
|
audio: state.config?.audio,
|
|
523
586
|
maxDurationSec: input.maxDurationSec ?? 30,
|
|
524
|
-
closerReserveSec,
|
|
587
|
+
closerReserveSec: pendingCloser ? pendingCloserReserve(pendingCloser, options.getTemplatePacing) : closerReserveSec,
|
|
525
588
|
getTemplatePacing: options.getTemplatePacing
|
|
526
589
|
});
|
|
527
590
|
if (!pacedPatch.scene) {
|
|
@@ -561,6 +624,18 @@ function createVideo(input, options) {
|
|
|
561
624
|
patch
|
|
562
625
|
}));
|
|
563
626
|
} else if (part.type === "asset.patch") {
|
|
627
|
+
if (pendingCloser?.id === part.sceneId) {
|
|
628
|
+
const nextPendingCloser = {
|
|
629
|
+
...pendingCloser,
|
|
630
|
+
variables: { ...pendingCloser.variables, ...part.variables }
|
|
631
|
+
};
|
|
632
|
+
options.validateScene?.(nextPendingCloser, {
|
|
633
|
+
input,
|
|
634
|
+
previousScenes: state.config?.scenes ?? []
|
|
635
|
+
});
|
|
636
|
+
pendingCloser = nextPendingCloser;
|
|
637
|
+
continue;
|
|
638
|
+
}
|
|
564
639
|
const scenes = state.config?.scenes ?? [];
|
|
565
640
|
const scene = scenes.find((item) => item.id === part.sceneId);
|
|
566
641
|
if (!scene) throw new Error(`Scene ${part.sceneId} does not exist`);
|
|
@@ -604,7 +679,39 @@ function createVideo(input, options) {
|
|
|
604
679
|
yield errorEvent;
|
|
605
680
|
} else if (part.type === "plan.complete") {
|
|
606
681
|
if (planCompleted) throw new Error("The planner emitted plan.complete more than once");
|
|
607
|
-
if (
|
|
682
|
+
if (pendingCloser) {
|
|
683
|
+
if (deferredForCloser.length) runtimeDurationLimited = true;
|
|
684
|
+
for (const deferred of deferredForCloser.splice(0)) {
|
|
685
|
+
rejectedSceneCount += 1;
|
|
686
|
+
yield emit(events.create("response.warning", {
|
|
687
|
+
warning: createOmittedForCloserWarning(deferred.id)
|
|
688
|
+
}));
|
|
689
|
+
}
|
|
690
|
+
const pacedCloser = paceScene(pendingCloser, {
|
|
691
|
+
previousScenes: state.config?.scenes ?? [],
|
|
692
|
+
audio: state.config?.audio,
|
|
693
|
+
maxDurationSec: input.maxDurationSec ?? 30,
|
|
694
|
+
closerReserveSec: 0,
|
|
695
|
+
getTemplatePacing: options.getTemplatePacing
|
|
696
|
+
});
|
|
697
|
+
for (const warning of pacedCloser.warnings) {
|
|
698
|
+
yield emit(events.create("response.warning", { warning }));
|
|
699
|
+
}
|
|
700
|
+
if (pacedCloser.scene) {
|
|
701
|
+
yield emit(events.create("scene.add", {
|
|
702
|
+
scene: pacedCloser.scene,
|
|
703
|
+
position: state.config?.scenes.length ?? 0,
|
|
704
|
+
revision: 0
|
|
705
|
+
}));
|
|
706
|
+
generatedSceneCount += 1;
|
|
707
|
+
acceptedSceneCount += 1;
|
|
708
|
+
timeToFirstSceneMs ??= Math.max(0, now() - startedAt);
|
|
709
|
+
closerCommitted = true;
|
|
710
|
+
} else {
|
|
711
|
+
runtimeDurationLimited = true;
|
|
712
|
+
rejectedSceneCount += 1;
|
|
713
|
+
}
|
|
714
|
+
} else if (deferredForCloser.length) {
|
|
608
715
|
for (const deferred of deferredForCloser.splice(0)) {
|
|
609
716
|
const recovered = paceScene(deferred, {
|
|
610
717
|
previousScenes: state.config?.scenes ?? [],
|
|
@@ -634,8 +741,15 @@ function createVideo(input, options) {
|
|
|
634
741
|
timeToFirstSceneMs ??= Math.max(0, now() - startedAt);
|
|
635
742
|
}
|
|
636
743
|
}
|
|
744
|
+
if (options.requireCloser && !closerCommitted) {
|
|
745
|
+
missingCloser = true;
|
|
746
|
+
yield emit(events.create("response.warning", {
|
|
747
|
+
warning: createMissingCloserWarning()
|
|
748
|
+
}));
|
|
749
|
+
}
|
|
637
750
|
planCompleted = true;
|
|
638
|
-
|
|
751
|
+
const reportedFinishReason = part.finishReason ?? "stop";
|
|
752
|
+
finishReason = runtimeDurationLimited ? "length" : reportedFinishReason !== "stop" ? reportedFinishReason : missingCloser ? "other" : "stop";
|
|
639
753
|
plannerReportedLength = part.finishReason === "length";
|
|
640
754
|
continue;
|
|
641
755
|
}
|
|
@@ -665,7 +779,14 @@ function createVideo(input, options) {
|
|
|
665
779
|
if (plannerReportedLength && generatedSceneCount === 0) {
|
|
666
780
|
throw new Error("The planner was truncated before adding a generated scene");
|
|
667
781
|
}
|
|
668
|
-
if (
|
|
782
|
+
if (plannerReportedLength) {
|
|
783
|
+
yield emit(events.create("response.warning", {
|
|
784
|
+
warning: createIncompletePlanWarning()
|
|
785
|
+
}));
|
|
786
|
+
}
|
|
787
|
+
if (generatedSceneCount === 0 && usesDefaultOpening) {
|
|
788
|
+
throw new Error("The planner completed without adding a scene");
|
|
789
|
+
}
|
|
669
790
|
const snapshot = parseVideo(state.config);
|
|
670
791
|
const completeEvent = emit(events.create("response.complete", {
|
|
671
792
|
finishReason,
|
|
@@ -699,6 +820,28 @@ function createVideo(input, options) {
|
|
|
699
820
|
return;
|
|
700
821
|
}
|
|
701
822
|
try {
|
|
823
|
+
if (pendingCloser && !closerCommitted && state.config?.scenes.length) {
|
|
824
|
+
const pacedCloser = paceScene(pendingCloser, {
|
|
825
|
+
previousScenes: state.config.scenes,
|
|
826
|
+
audio: state.config.audio,
|
|
827
|
+
maxDurationSec: input.maxDurationSec ?? 30,
|
|
828
|
+
closerReserveSec: 0,
|
|
829
|
+
getTemplatePacing: options.getTemplatePacing
|
|
830
|
+
});
|
|
831
|
+
for (const warning of pacedCloser.warnings) {
|
|
832
|
+
yield emit(events.create("response.warning", { warning }));
|
|
833
|
+
}
|
|
834
|
+
if (pacedCloser.scene) {
|
|
835
|
+
yield emit(events.create("scene.add", {
|
|
836
|
+
scene: pacedCloser.scene,
|
|
837
|
+
position: state.config.scenes.length,
|
|
838
|
+
revision: 0
|
|
839
|
+
}));
|
|
840
|
+
generatedSceneCount += 1;
|
|
841
|
+
acceptedSceneCount += 1;
|
|
842
|
+
closerCommitted = true;
|
|
843
|
+
}
|
|
844
|
+
}
|
|
702
845
|
const provider = await settleProviderLifecycle();
|
|
703
846
|
for (const warning of provider.warnings) {
|
|
704
847
|
if (!state.warnings.some((existing) => existing.code === warning.code && existing.message === warning.message)) {
|
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import "./chunk-
|
|
3
|
-
import "./chunk-
|
|
4
|
-
import "./chunk-
|
|
2
|
+
import "./chunk-GR4I3MN2.js";
|
|
3
|
+
import "./chunk-WHPZED7X.js";
|
|
4
|
+
import "./chunk-3O7OMMMF.js";
|
|
5
5
|
import {
|
|
6
6
|
isTemplatePropertyFormatSupported,
|
|
7
7
|
validateTemplateSchemaValue
|
|
@@ -9,13 +9,13 @@ import {
|
|
|
9
9
|
import {
|
|
10
10
|
getBuiltinTemplateMetadata,
|
|
11
11
|
listBuiltinTemplateMetadata
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-XAMUOSX7.js";
|
|
13
13
|
import {
|
|
14
14
|
assertTemplateTransitionMetadata
|
|
15
15
|
} from "./chunk-2E6T633S.js";
|
|
16
16
|
import {
|
|
17
17
|
BUILTIN_TEMPLATE_MANIFEST
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-RBQN3VSY.js";
|
|
19
19
|
import {
|
|
20
20
|
getTemplateDefaults,
|
|
21
21
|
isMeaningfullyPresentTemplateValue,
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createVideo
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-XYZOJ5NZ.js";
|
|
4
4
|
import "./chunk-E7CL7UPB.js";
|
|
5
|
-
import "./chunk-
|
|
6
|
-
import "./chunk-
|
|
5
|
+
import "./chunk-STIFILQG.js";
|
|
6
|
+
import "./chunk-JW47XCRL.js";
|
|
7
7
|
import "./chunk-GHJEAP4O.js";
|
|
8
8
|
import "./chunk-EE6PK6XC.js";
|
|
9
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-3O7OMMMF.js";
|
|
10
10
|
import "./chunk-XGRA2MUV.js";
|
|
11
11
|
export {
|
|
12
12
|
createVideo
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { f as VideoOrientation, h as VideoStyle, V as Video, k as VideoCapabilities, a as VideoAudio, g as VideoScene, l as VIDEO_PROTOCOL_VERSION } from './types-CkO2EYr4.js';
|
|
2
2
|
|
|
3
3
|
type VideoWarningCategory = "validation" | "readability" | "grounding" | "provider" | "media" | "protocol";
|
|
4
|
-
type VideoWarningCode = "scene_duration_adjusted" | "scene_omitted_unreadable" | "scene_omitted_for_closer" | "scene_patch_rejected_readability" | "chart_scale_imbalance" | "provider_warning" | "provider_diagnostics_unavailable";
|
|
4
|
+
type VideoWarningCode = "scene_duration_adjusted" | "scene_omitted_unreadable" | "scene_omitted_for_closer" | "scene_patch_rejected_readability" | "chart_scale_imbalance" | "plan_incomplete" | "plan_missing_closer" | "provider_warning" | "provider_diagnostics_unavailable";
|
|
5
5
|
/** A bounded, client-safe diagnostic that never includes provider payloads. */
|
|
6
6
|
interface VideoWarning {
|
|
7
7
|
code: VideoWarningCode;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { V as Video } from './types-
|
|
2
|
-
export { a as VideoAudio, b as VideoBackground, c as VideoBrand, d as VideoInput, e as
|
|
1
|
+
import { V as Video } from './types-CkO2EYr4.js';
|
|
2
|
+
export { a as VideoAudio, b as VideoBackground, c as VideoBrand, d as VideoInput, e as VideoKnowledgeMode, f as VideoOrientation, g as VideoScene, h as VideoStyle, i as VideoStyleOptions, j as VideoSuppliedMedia } from './types-CkO2EYr4.js';
|
|
3
3
|
export { V as VideoStatus } from './state-DZcKuS32.js';
|
|
4
4
|
|
|
5
5
|
type VideoValidationErrorCode = "invalid_video" | "unsupported_video_version";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { h as VideoStyle, k as VideoCapabilities } from './types-CkO2EYr4.js';
|
|
2
2
|
import { ComponentType } from 'react';
|
|
3
3
|
import { S as SceneTemplateMetadata, d as TemplateJsonSchema, f as TemplateJsonSchemaProperty } from './catalog-types-BIhSpOWK.js';
|
|
4
4
|
|
package/dist/react.d.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { CSSProperties, ReactElement } from 'react';
|
|
2
|
-
import { V as VideoEvent, a as VideoWarning } from './events-
|
|
3
|
-
import {
|
|
4
|
-
import { T as TemplateRegistry } from './kit-
|
|
2
|
+
import { V as VideoEvent, a as VideoWarning } from './events-CTIsANzz.js';
|
|
3
|
+
import { f as VideoOrientation, V as Video, d as VideoInput } from './types-CkO2EYr4.js';
|
|
4
|
+
import { T as TemplateRegistry } from './kit-DA2cfJ96.js';
|
|
5
5
|
import { V as VideoStatus } from './state-DZcKuS32.js';
|
|
6
6
|
import './catalog-types-BIhSpOWK.js';
|
|
7
7
|
|
|
8
|
+
type VideoPlaybackMode = "manual" | "muted-autoplay" | "autoplay-with-sound" | "autoplay-after-interaction";
|
|
8
9
|
interface VideoPlayerSharedProps {
|
|
10
|
+
/** High-level startup policy. When set, this overrides autoPlay and startMuted. */
|
|
11
|
+
playbackMode?: VideoPlaybackMode;
|
|
9
12
|
/** Initial playback state. Reduced-motion preferences take precedence. */
|
|
10
13
|
autoPlay?: boolean;
|
|
11
14
|
startMuted?: boolean;
|
|
@@ -78,4 +81,4 @@ interface UseVideoResult {
|
|
|
78
81
|
}
|
|
79
82
|
declare function useVideo(options?: UseVideoOptions): UseVideoResult;
|
|
80
83
|
|
|
81
|
-
export { type UseVideoOptions, type UseVideoResult, VideoError, type VideoErrorOptions, VideoPlayer, type VideoPlayerProps, useVideo };
|
|
84
|
+
export { type UseVideoOptions, type UseVideoResult, VideoError, type VideoErrorOptions, type VideoPlaybackMode, VideoPlayer, type VideoPlayerProps, useVideo };
|