@vanillaskyai/video 0.8.8 → 0.10.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 +42 -0
- package/PUBLIC-API.md +5 -8
- package/dist/{builtin-server-CUYPIDE7.js → builtin-server-W4PLJUZ5.js} +2 -2
- package/dist/{catalog-types-BIhSpOWK.d.ts → catalog-types-WTbLP6Jh.d.ts} +5 -1
- package/dist/chapter-title-YRLIQY3V.js +7 -0
- package/dist/check-runtime.js +5 -14
- package/dist/{chunk-AITKH6QT.js → chunk-2HFO22K2.js} +15 -40
- package/dist/chunk-4YM2M62S.js +13 -0
- package/dist/chunk-4ZJLPHBV.js +684 -0
- package/dist/chunk-77VY4O7A.js +390 -0
- package/dist/{chunk-MMUXVA47.js → chunk-7M56IUUX.js} +9 -8
- package/dist/chunk-7NZOMTAL.js +63 -0
- package/dist/{chunk-2DOLF4QN.js → chunk-AUPC6MDK.js} +12 -14
- package/dist/{chunk-352ZZCET.js → chunk-EGVQODKU.js} +2 -2
- package/dist/{chunk-2USVB3CY.js → chunk-ELVOT2FQ.js} +284 -177
- package/dist/chunk-EWWCQFTI.js +18 -0
- package/dist/{chunk-KT3M7KDL.js → chunk-HKUI5BTB.js} +3 -3
- package/dist/chunk-IIN5M5HW.js +697 -0
- package/dist/{chunk-LMG3GHLL.js → chunk-IQMYK5DX.js} +29 -3
- package/dist/{chunk-OWBT45EN.js → chunk-IR44XKBI.js} +1 -1
- package/dist/{chunk-MXZSDGZQ.js → chunk-NMFDC2W2.js} +4 -6
- package/dist/{chunk-5SLENAJW.js → chunk-PAJ44TFW.js} +1 -2
- package/dist/{chunk-L7QGGKJ2.js → chunk-PDQFQIQW.js} +1 -1
- package/dist/{chunk-WJ6FLKNC.js → chunk-R3XAOMKP.js} +14 -0
- package/dist/{chunk-2OKB27TG.js → chunk-RXTN2CW6.js} +2 -2
- package/dist/{chunk-XWWLKRNU.js → chunk-TVIU23OM.js} +38 -49
- package/dist/chunk-XX4GXKTX.js +35 -0
- package/dist/chunk-Z67Q5KUW.js +16 -0
- package/dist/{chunk-3VRMKFM7.js → chunk-ZDJNFA52.js} +11 -24
- package/dist/cinema-media-C7OUPNSH.js +12 -0
- package/dist/cli.js +18 -9
- package/dist/comparison-GNZOR7MF.js +37 -0
- package/dist/compose-video-TBFTONUC.js +12 -0
- package/dist/editorial-timeline-EMV5335S.js +43 -0
- package/dist/{events-BQ6z264n.d.ts → events-B4YCc4vc.d.ts} +1 -1
- package/dist/index.d.ts +4 -6
- package/dist/index.js +3 -7
- package/dist/key-figure-P37VK425.js +30 -0
- package/dist/{kit-tQnCPMOM.d.ts → kit-DrRpdn0p.d.ts} +2 -2
- package/dist/mobile-message-OF7T62B7.js +50 -0
- package/dist/quote-T6WYLN7A.js +33 -0
- package/dist/react.d.ts +21 -11
- package/dist/react.js +585 -826
- package/dist/scene-video-backdrop-PCTARAAJ.js +7 -0
- package/dist/server.d.ts +7 -8
- package/dist/server.js +179 -84
- package/dist/{system-prompt-RRXIWDDD.js → system-prompt-SYRT5DWM.js} +1 -1
- package/dist/template-catalog.d.ts +392 -16
- package/dist/template-catalog.js +1 -1
- package/dist/templates.d.ts +5 -5
- package/dist/test.d.ts +3 -3
- package/dist/test.js +18 -18
- package/dist/text-stream-LD364KBI.js +9 -0
- package/dist/{types-DWFO6qca.d.ts → types-CdBmNTGD.d.ts} +1 -1
- package/dist/{types-CEh9eUFu.d.ts → types-DdZw4GRQ.d.ts} +17 -48
- package/dist/validate-4OUD2CLX.js +10 -0
- package/docs/architecture.md +1 -1
- package/docs/concepts.md +1 -1
- package/docs/custom-templates.md +13 -28
- package/docs/customization.md +11 -59
- package/docs/getting-started.md +2 -2
- package/docs/immersive-interface.md +3 -4
- package/docs/maintainers/cinematic-migration.md +38 -0
- package/docs/media-and-audio.md +14 -14
- package/docs/motion-and-effects.md +6 -14
- package/docs/persistence.md +3 -3
- package/docs/production.md +11 -9
- package/docs/provider-integration.md +9 -16
- package/docs/reference/design-system.html +1 -1
- package/docs/reference/protocol.md +14 -4
- package/docs/testing.md +1 -1
- package/package.json +6 -3
- package/registry/items/backgrounds.json +1 -1
- package/registry/items/chapterTitle.json +80 -0
- package/registry/items/cinemaMedia.json +136 -0
- package/registry/items/comparison.json +168 -0
- package/registry/items/editorialTimeline.json +172 -0
- package/registry/items/keyFigure.json +162 -0
- package/registry/items/mobileMessage.json +153 -0
- package/registry/items/quote.json +161 -0
- package/registry/items/template-context.json +1 -1
- package/registry/items/theme.json +1 -1
- package/starters/video-chat/README.md +24 -26
- package/starters/video-chat/package.json +1 -1
- package/starters/video-chat/providers/video.ts +6 -5
- package/starters/video-chat/stock.ts +35 -151
- package/styles/fonts/OFL.txt +93 -0
- package/styles/fonts/manifest.json +66 -0
- package/styles/fonts/roboto-v51-cyrillic-ext.woff2 +0 -0
- package/styles/fonts/roboto-v51-cyrillic.woff2 +0 -0
- package/styles/fonts/roboto-v51-greek-ext.woff2 +0 -0
- package/styles/fonts/roboto-v51-greek.woff2 +0 -0
- package/styles/fonts/roboto-v51-latin-ext.woff2 +0 -0
- package/styles/fonts/roboto-v51-latin.woff2 +0 -0
- package/styles/fonts/roboto-v51-math.woff2 +0 -0
- package/styles/fonts/roboto-v51-symbols.woff2 +0 -0
- package/styles/fonts/roboto-v51-vietnamese.woff2 +0 -0
- package/styles/fonts/roboto.css +91 -0
- package/styles/video-chat.css +30 -22
- package/dist/bg-confetti-HITCGLGD.js +0 -89
- package/dist/bg-emoji-VU4UZYZN.js +0 -150
- package/dist/bg-media-L34PDQXJ.js +0 -106
- package/dist/brand-message-FUJ4STFO.js +0 -256
- package/dist/chart-bar-EGPHJATL.js +0 -310
- package/dist/chart-counter-5FFWQNZO.js +0 -306
- package/dist/chart-progress-ring-JMXQLMLC.js +0 -302
- package/dist/chunk-4UNKZEAT.js +0 -3575
- package/dist/chunk-5CDAM24P.js +0 -31
- package/dist/chunk-AOWSXU2K.js +0 -18
- package/dist/chunk-CJ7F2CE6.js +0 -104
- package/dist/chunk-FRN6WKHA.js +0 -185
- package/dist/chunk-G5JPHBX7.js +0 -336
- package/dist/chunk-L5BTTCZV.js +0 -97
- package/dist/chunk-P22HHFDK.js +0 -43
- package/dist/chunk-PP3MCPN4.js +0 -1998
- package/dist/chunk-QAAO7OAY.js +0 -19
- package/dist/chunk-S7HFLYNN.js +0 -35
- package/dist/chunk-W3VDIBGR.js +0 -217
- package/dist/chunk-XGRA2MUV.js +0 -242
- package/dist/chunk-XTOXFMLM.js +0 -105
- package/dist/chunk-YJJC4N4D.js +0 -761
- package/dist/compose-video-2NFH4DZY.js +0 -13
- package/dist/cta-logo-YR7LYUR5.js +0 -212
- package/dist/cta-media-DQJBKUO2.js +0 -221
- package/dist/incoming-call-54KQ7O5A.js +0 -323
- package/dist/infographic-before-after-ROS52GOW.js +0 -460
- package/dist/infographic-feature-list-E7MGUDAN.js +0 -272
- package/dist/infographic-problem-solution-3S6NGO5N.js +0 -343
- package/dist/infographic-stat-row-SYB7AB7H.js +0 -247
- package/dist/infographic-steps-KCE6JWE2.js +0 -406
- package/dist/prompt-input-MHX4O42G.js +0 -239
- package/dist/reaction-SLEGR3BE.js +0 -122
- package/dist/scene-video-backdrop-XFPX4O3I.js +0 -10
- package/dist/showcase-code-2HLAVKBM.js +0 -357
- package/dist/showcase-phone-Q4HEO4LH.js +0 -278
- package/dist/showcase-terminal-DL45LUFG.js +0 -312
- package/dist/showcase-web-2QZO73FZ.js +0 -396
- package/dist/social-conversation-75SD2637.js +0 -695
- package/dist/social-milestone-GEFUQSBF.js +0 -296
- package/dist/social-notification-FJ5VHVLK.js +0 -247
- package/dist/social-review-stack-KXQCKFRP.js +0 -242
- package/dist/social-testimonial-JZ7CHC7S.js +0 -287
- package/dist/social-tweet-UCDXM25F.js +0 -298
- package/dist/text-stream-54LXABJW.js +0 -10
- package/dist/validate-T7GBU2YF.js +0 -8
- package/registry/items/barChart.json +0 -245
- package/registry/items/beforeAfter.json +0 -180
- package/registry/items/bigNumber.json +0 -232
- package/registry/items/brandMessage.json +0 -164
- package/registry/items/cardList.json +0 -214
- package/registry/items/chatMessenger.json +0 -151
- package/registry/items/chatWhatsapp.json +0 -151
- package/registry/items/codeEditor.json +0 -191
- package/registry/items/confetti.json +0 -107
- package/registry/items/ctaLogo.json +0 -167
- package/registry/items/ctaMedia.json +0 -200
- package/registry/items/emojiBurst.json +0 -101
- package/registry/items/incomingCall.json +0 -177
- package/registry/items/media.json +0 -187
- package/registry/items/milestone.json +0 -212
- package/registry/items/notification.json +0 -189
- package/registry/items/phoneMockup.json +0 -261
- package/registry/items/problemSolution.json +0 -193
- package/registry/items/progressRing.json +0 -206
- package/registry/items/promptInput.json +0 -155
- package/registry/items/reaction.json +0 -176
- package/registry/items/reviewStack.json +0 -231
- package/registry/items/steps.json +0 -215
- package/registry/items/terminal.json +0 -219
- package/registry/items/testimonial.json +0 -171
- package/registry/items/tripleStats.json +0 -235
- package/registry/items/tweet.json +0 -210
- package/registry/items/webMockup.json +0 -280
package/dist/server.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as VideoFinishReason, V as VideoWarning, b as VideoEvent } from './events-
|
|
3
|
-
export { c as VideoWarningCategory } from './events-
|
|
4
|
-
import { S as SceneTemplateMetadata } from './catalog-types-
|
|
5
|
-
import { f as VideoChatWelcomeOptions } from './types-
|
|
6
|
-
export { d as VideoChatCapabilities, g as VideoChatConversationTurn, V as VideoChatMode, h as VideoChatWelcomePrompt } from './types-
|
|
1
|
+
import { k as VideoGenerationContext, l as VideoPlanner, m as VideoRequest, a as VideoCapabilities, j as VideoInput, d as VideoAudio, n as VideoSceneValidator, g as VideoTemplatePacing, o as VideoSnapshotRetention, p as VideoResumeCursor, q as VideoSceneValidationContext, e as VideoScene, b as VideoOrientation } from './types-DdZw4GRQ.js';
|
|
2
|
+
import { a as VideoFinishReason, V as VideoWarning, b as VideoEvent } from './events-B4YCc4vc.js';
|
|
3
|
+
export { c as VideoWarningCategory } from './events-B4YCc4vc.js';
|
|
4
|
+
import { S as SceneTemplateMetadata } from './catalog-types-WTbLP6Jh.js';
|
|
5
|
+
import { f as VideoChatWelcomeOptions } from './types-CdBmNTGD.js';
|
|
6
|
+
export { d as VideoChatCapabilities, g as VideoChatConversationTurn, V as VideoChatMode, h as VideoChatWelcomePrompt } from './types-CdBmNTGD.js';
|
|
7
7
|
|
|
8
8
|
interface VideoProviderUsage {
|
|
9
9
|
inputTokens?: number;
|
|
@@ -170,8 +170,7 @@ interface VideoHandlerOptions extends Omit<VideoStreamHandlerOptions, "generate"
|
|
|
170
170
|
*
|
|
171
171
|
* Unbounded by default, which is right when media is searched for and wrong
|
|
172
172
|
* when it is generated: the planner decides the scene count, and every scene
|
|
173
|
-
* is then a paid clip. Past the ceiling a scene
|
|
174
|
-
* gradient, and a `media_budget_reached` warning says it happened.
|
|
173
|
+
* is then a paid clip. Past the ceiling a scene uses its grounded text fallback, and a `media_budget_reached` warning says it happened.
|
|
175
174
|
*/
|
|
176
175
|
maxResolvedMedia?: number;
|
|
177
176
|
/**
|
package/dist/server.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createTextDeltaVideoPlanner
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-PDQFQIQW.js";
|
|
4
4
|
import {
|
|
5
5
|
createVideo,
|
|
6
6
|
invokeIsolated
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-ZDJNFA52.js";
|
|
8
8
|
import {
|
|
9
9
|
getGenerationLifecycleSink
|
|
10
10
|
} from "./chunk-E7CL7UPB.js";
|
|
@@ -12,10 +12,11 @@ import {
|
|
|
12
12
|
BUILTIN_SERVER_TEMPLATE_KIT,
|
|
13
13
|
createServerTemplateRegistry,
|
|
14
14
|
overlayServerTemplateRegistry
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-IR44XKBI.js";
|
|
16
16
|
import {
|
|
17
|
-
createTemplateSceneValidator
|
|
18
|
-
|
|
17
|
+
createTemplateSceneValidator,
|
|
18
|
+
validateTemplateSceneStructure
|
|
19
|
+
} from "./chunk-IQMYK5DX.js";
|
|
19
20
|
import {
|
|
20
21
|
MEDIA_RECOVERY_NOTICE,
|
|
21
22
|
decodeVideoSse,
|
|
@@ -23,8 +24,8 @@ import {
|
|
|
23
24
|
sanitizeVideoChatMedia,
|
|
24
25
|
videoSseHeaders,
|
|
25
26
|
withDeadline
|
|
26
|
-
} from "./chunk-
|
|
27
|
-
import "./chunk-
|
|
27
|
+
} from "./chunk-HKUI5BTB.js";
|
|
28
|
+
import "./chunk-RXTN2CW6.js";
|
|
28
29
|
import {
|
|
29
30
|
allowedKeys,
|
|
30
31
|
createClippedVariableWarning,
|
|
@@ -32,30 +33,91 @@ import {
|
|
|
32
33
|
jsonValue,
|
|
33
34
|
nonNegativeInteger,
|
|
34
35
|
parseVideoEvent,
|
|
36
|
+
parseVideoPlanPart,
|
|
35
37
|
record,
|
|
36
38
|
safePublicDiagnostic,
|
|
37
39
|
string
|
|
38
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-7M56IUUX.js";
|
|
39
41
|
import {
|
|
40
42
|
MAX_RETAINED_MEDIA_URL_LENGTH
|
|
41
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-AUPC6MDK.js";
|
|
42
44
|
import {
|
|
43
45
|
VIDEO_PROTOCOL_VERSION
|
|
44
|
-
} from "./chunk-
|
|
46
|
+
} from "./chunk-7NZOMTAL.js";
|
|
45
47
|
import {
|
|
46
48
|
createTemplateSystemPrompt,
|
|
47
49
|
getStandardMediaResolverContract
|
|
48
|
-
} from "./chunk-
|
|
49
|
-
import "./chunk-
|
|
50
|
-
import "./chunk-
|
|
51
|
-
import "./chunk-
|
|
50
|
+
} from "./chunk-2HFO22K2.js";
|
|
51
|
+
import "./chunk-PAJ44TFW.js";
|
|
52
|
+
import "./chunk-EGVQODKU.js";
|
|
53
|
+
import "./chunk-IIN5M5HW.js";
|
|
52
54
|
import "./chunk-3O7OMMMF.js";
|
|
53
55
|
import "./chunk-2E6T633S.js";
|
|
54
|
-
import {
|
|
55
|
-
validateBrandInput
|
|
56
|
-
} from "./chunk-XGRA2MUV.js";
|
|
57
56
|
import "./chunk-73NTSFFI.js";
|
|
58
57
|
|
|
58
|
+
// src/server/opening-continuity.ts
|
|
59
|
+
function continueAfterOpening(narration, earlier) {
|
|
60
|
+
const words = (value) => Array.from(value.matchAll(/[\p{L}\p{N}]+(?:['’][\p{L}\p{N}]+)*/gu));
|
|
61
|
+
let remaining = narration;
|
|
62
|
+
for (const previous of [...earlier].reverse()) {
|
|
63
|
+
const known = words(previous), current = words(remaining);
|
|
64
|
+
if (known.length < 5 || known.length > current.length) continue;
|
|
65
|
+
if (!known.every((word, index) => word[0].toLowerCase() === current[index][0].toLowerCase())) continue;
|
|
66
|
+
if (known.length === current.length) return "";
|
|
67
|
+
const last = current[known.length - 1];
|
|
68
|
+
const suffix = remaining.slice(last.index + last[0].length);
|
|
69
|
+
const boundary = suffix.match(/^[”"'’\])]*[.!?…]+[\s”"'’\])]*/u);
|
|
70
|
+
if (boundary) remaining = suffix.slice(boundary[0].length).trim();
|
|
71
|
+
}
|
|
72
|
+
return remaining;
|
|
73
|
+
}
|
|
74
|
+
function createOpeningContinuation(initialOpening) {
|
|
75
|
+
const earlier = initialOpening ? [initialOpening] : [];
|
|
76
|
+
let bodyStarted = false;
|
|
77
|
+
const copy = (authored, narration) => {
|
|
78
|
+
if (continueAfterOpening(authored, earlier) !== "") return authored;
|
|
79
|
+
const next = continueAfterOpening(narration, earlier).trim();
|
|
80
|
+
return next && [...next].length <= 65 && /[.!?…][”"’')\]]*$/u.test(next) ? next : authored;
|
|
81
|
+
};
|
|
82
|
+
return {
|
|
83
|
+
copy,
|
|
84
|
+
remember(line) {
|
|
85
|
+
if (line.trim()) earlier.push(line);
|
|
86
|
+
},
|
|
87
|
+
narration(line) {
|
|
88
|
+
return continueAfterOpening(line, earlier);
|
|
89
|
+
},
|
|
90
|
+
line(rawLine) {
|
|
91
|
+
if (bodyStarted || earlier.length === 0) return rawLine;
|
|
92
|
+
let part;
|
|
93
|
+
try {
|
|
94
|
+
part = JSON.parse(rawLine);
|
|
95
|
+
} catch {
|
|
96
|
+
return rawLine;
|
|
97
|
+
}
|
|
98
|
+
if (!part || part.type !== "scene.add" || part.placement === "closer") return rawLine;
|
|
99
|
+
const scene = part.scene;
|
|
100
|
+
if (!scene) return rawLine;
|
|
101
|
+
if (typeof scene.narration !== "string") {
|
|
102
|
+
bodyStarted = true;
|
|
103
|
+
return rawLine;
|
|
104
|
+
}
|
|
105
|
+
const narration = continueAfterOpening(scene.narration, earlier);
|
|
106
|
+
if (!narration && scene.templateId === "cinemaMedia") return null;
|
|
107
|
+
const variables = scene.variables;
|
|
108
|
+
if (!narration && scene.templateId === "chapterTitle" && typeof variables?.title === "string" && !continueAfterOpening(variables.title, earlier)) return null;
|
|
109
|
+
bodyStarted = true;
|
|
110
|
+
if (!narration) return rawLine;
|
|
111
|
+
const field = scene.templateId === "cinemaMedia" ? "fallbackText" : scene.templateId === "chapterTitle" ? "title" : void 0;
|
|
112
|
+
const authored = field && variables?.[field];
|
|
113
|
+
const updated = typeof authored === "string" ? copy(authored, narration) : void 0;
|
|
114
|
+
const copyChanged = typeof authored === "string" && updated !== authored;
|
|
115
|
+
if (narration === scene.narration && !copyChanged) return rawLine;
|
|
116
|
+
return JSON.stringify({ ...part, scene: { ...scene, narration, ...copyChanged ? { variables: { ...variables, [field]: updated } } : {} } });
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
59
121
|
// src/server/request-validation.ts
|
|
60
122
|
var MAX_GENERATED_LOOK_LENGTH = 1e3;
|
|
61
123
|
function boundedString(value, path) {
|
|
@@ -109,7 +171,6 @@ function parseVideoRequest(value) {
|
|
|
109
171
|
"orientation",
|
|
110
172
|
"style",
|
|
111
173
|
"opening",
|
|
112
|
-
"brand",
|
|
113
174
|
"personalization",
|
|
114
175
|
"suppliedMedia",
|
|
115
176
|
"audio"
|
|
@@ -224,7 +285,6 @@ function parseVideoRequest(value) {
|
|
|
224
285
|
);
|
|
225
286
|
}
|
|
226
287
|
}
|
|
227
|
-
if (input.brand != null) validateBrandInput(input.brand, "request.input.brand");
|
|
228
288
|
jsonValue(input, "request.input");
|
|
229
289
|
if (request.capabilities != null) capabilities(request.capabilities, "request.capabilities");
|
|
230
290
|
if (request.resume != null) {
|
|
@@ -473,7 +533,8 @@ function fallbackVariables(variables) {
|
|
|
473
533
|
delete fallback.mediaKeyword;
|
|
474
534
|
delete fallback.mediaUrl;
|
|
475
535
|
delete fallback.mediaPoster;
|
|
476
|
-
fallback.mediaType
|
|
536
|
+
delete fallback.mediaType;
|
|
537
|
+
delete fallback.mediaSource;
|
|
477
538
|
return fallback;
|
|
478
539
|
}
|
|
479
540
|
async function resolveVariables(options) {
|
|
@@ -559,7 +620,18 @@ async function resolvePartVariables(options) {
|
|
|
559
620
|
scene: options.part.scene,
|
|
560
621
|
variables: options.part.scene.variables
|
|
561
622
|
});
|
|
562
|
-
|
|
623
|
+
if (options.templateId === "cinemaMedia" && !variables.mediaUrl) {
|
|
624
|
+
const title = variables.fallbackText;
|
|
625
|
+
if (typeof title !== "string" || !title.trim() || [...title].length > 65) {
|
|
626
|
+
throw new Error("A media scene without a usable asset requires grounded fallbackText (1\u201365 characters)");
|
|
627
|
+
}
|
|
628
|
+
return { ...options.part, scene: { ...options.part.scene, templateId: "chapterTitle", variables: { title: title.trim() } } };
|
|
629
|
+
}
|
|
630
|
+
const rendered = { ...variables };
|
|
631
|
+
delete rendered.mediaSource;
|
|
632
|
+
delete rendered.fallbackText;
|
|
633
|
+
delete rendered.shotDirection;
|
|
634
|
+
return { ...options.part, scene: { ...options.part.scene, variables: rendered } };
|
|
563
635
|
}
|
|
564
636
|
return options.part;
|
|
565
637
|
}
|
|
@@ -579,6 +651,25 @@ function createMediaResolvingPlanner(options) {
|
|
|
579
651
|
}
|
|
580
652
|
return false;
|
|
581
653
|
};
|
|
654
|
+
const preflight = (part) => {
|
|
655
|
+
try {
|
|
656
|
+
parseVideoPlanPart(part);
|
|
657
|
+
if (part.type === "scene.add") {
|
|
658
|
+
const { templateId, variables } = part.scene;
|
|
659
|
+
if (context.request.capabilities?.templates && !context.request.capabilities.templates.includes(templateId)) {
|
|
660
|
+
throw new Error(`Scene template ${templateId} was not negotiated`);
|
|
661
|
+
}
|
|
662
|
+
const template = options.templates.getTemplateMetadata(templateId);
|
|
663
|
+
if (!template) throw new Error(`Template ${templateId} is not installed`);
|
|
664
|
+
validateTemplateSceneStructure(template.schema, variables, true);
|
|
665
|
+
}
|
|
666
|
+
return true;
|
|
667
|
+
} catch (cause) {
|
|
668
|
+
const error = cause instanceof Error ? cause : new Error(String(cause));
|
|
669
|
+
if (!getGenerationLifecycleSink(context)?.rejectPart?.(error)) throw error;
|
|
670
|
+
return false;
|
|
671
|
+
}
|
|
672
|
+
};
|
|
582
673
|
const resolveOne = (part, openingReady2) => resolvePartVariables({
|
|
583
674
|
part,
|
|
584
675
|
requestId: context.request.requestId,
|
|
@@ -598,7 +689,9 @@ function createMediaResolvingPlanner(options) {
|
|
|
598
689
|
})
|
|
599
690
|
});
|
|
600
691
|
if (limit === 1) {
|
|
601
|
-
for await (const part of options.planner(context))
|
|
692
|
+
for await (const part of options.planner(context)) {
|
|
693
|
+
if (preflight(part)) yield await resolveOne(part);
|
|
694
|
+
}
|
|
602
695
|
return;
|
|
603
696
|
}
|
|
604
697
|
let openingReady = options.isOpeningReady(context.request.input);
|
|
@@ -631,6 +724,7 @@ function createMediaResolvingPlanner(options) {
|
|
|
631
724
|
const next = await iterator.next();
|
|
632
725
|
if (next.done || consumerClosed) break;
|
|
633
726
|
const part = next.value;
|
|
727
|
+
if (!preflight(part)) continue;
|
|
634
728
|
pending.push(resolveOne(part, openingReady).then(
|
|
635
729
|
(resolved) => ({ part: resolved }),
|
|
636
730
|
(cause) => ({ cause })
|
|
@@ -680,6 +774,7 @@ function clipText(value, maxLength) {
|
|
|
680
774
|
}
|
|
681
775
|
function boundValue(value, schema) {
|
|
682
776
|
if (!schema) return value;
|
|
777
|
+
if (schema.format === "grounded-stat" || schema.format === "grounded-quote") return value;
|
|
683
778
|
if (typeof value === "string") {
|
|
684
779
|
return typeof schema.maxLength === "number" ? clipText(value, schema.maxLength) : value;
|
|
685
780
|
}
|
|
@@ -707,10 +802,10 @@ function createBoundedVariablePlanner(options) {
|
|
|
707
802
|
}
|
|
708
803
|
try {
|
|
709
804
|
const lifecycle = getGenerationLifecycleSink(context);
|
|
710
|
-
if (!options.templates.getTemplateMetadata(part.scene.templateId) && lifecycle?.recoverGeneratedParts && (context.request.capabilities?.templates == null || context.request.capabilities.templates.includes("
|
|
805
|
+
if (!options.templates.getTemplateMetadata(part.scene.templateId) && lifecycle?.recoverGeneratedParts && (context.request.capabilities?.templates == null || context.request.capabilities.templates.includes("chapterTitle"))) {
|
|
711
806
|
const copy = [part.scene.variables.texts, part.scene.variables.title, part.scene.variables.message, part.scene.narration].find((value) => typeof value === "string" && Boolean(value.trim()) && !/https?:\/\/|\b(?:api[_-]?key|authorization|secret|token|password)\s*[:=]/i.test(value));
|
|
712
807
|
if (copy) {
|
|
713
|
-
part = { ...part, scene: { ...part.scene, templateId: "
|
|
808
|
+
part = { ...part, scene: { ...part.scene, templateId: "chapterTitle", variables: { title: copy } } };
|
|
714
809
|
lifecycle.reportWarning?.({ code: "provider_warning", category: "provider", message: "Some scenes use a simpler layout.", recoverable: true });
|
|
715
810
|
}
|
|
716
811
|
}
|
|
@@ -830,30 +925,20 @@ function createVideoHandler(options) {
|
|
|
830
925
|
}
|
|
831
926
|
|
|
832
927
|
// src/server/video-chat-prompts.ts
|
|
833
|
-
|
|
834
|
-
function createVideoChatResponseInstructions(fullAiVideo, openingAlreadyProvided = false, maxGeneratedVideos = 5) {
|
|
928
|
+
function createVideoChatResponseInstructions(generatedVideoAvailable, openingAlreadyProvided = false, maxGeneratedVideos = 5) {
|
|
835
929
|
return [
|
|
836
|
-
"
|
|
837
|
-
"
|
|
838
|
-
|
|
839
|
-
"
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
"2.
|
|
845
|
-
"
|
|
846
|
-
"
|
|
847
|
-
"
|
|
848
|
-
"No scene may repeat another scene's job. If a scene could be deleted without weakening the response, replace it.",
|
|
849
|
-
"The prompt is already on screen, so never spend the opening scene restating it.",
|
|
850
|
-
"If the input includes an OPENING ALREADY SPOKEN transcript, continue directly from that exact hook. Never repeat, paraphrase, contradict, or render it as the first scene's copy.",
|
|
851
|
-
"For factual requests, distinguish supplied facts from stable general knowledge and never invent statistics, quotations, sources, or personal experience.",
|
|
852
|
-
"For creative requests, create the requested material directly rather than explaining how one might create it.",
|
|
853
|
-
fullAiVideo ? "Use the media template for every scene you emit. Every scene must set mediaType to video and carry a mediaKeyword: a concrete, filmable subject, a real object doing a real thing, never a diagram or an abstraction. Never use mediaType gradient and never omit mediaKeyword - a scene without one has nothing to film. If a beat seems too abstract to film, film the closest real thing that shows it." : "Choose the template that fits each beat honestly - a figure belongs in a number scene, an ordered process in steps, a comparison in a chart - rather than repeating one shape. Give any scene that would be stronger over real footage a mediaKeyword: a concrete, filmable subject, a real object doing a real thing, never a diagram or an abstraction. Use the media template for the one or two beats most worth watching happen.",
|
|
854
|
-
fullAiVideo ? 'Mark the final scene placement:"closer". Use the media template for it, as for every other beat.' : 'Mark the final scene placement:"closer" and use either the milestone or the media template for it. Those are the only two here that may close, so the response must end on one.',
|
|
855
|
-
"Every scene must carry a timing object, even an empty one. A scene without it fails the whole response.",
|
|
856
|
-
"Never mention the video, the scenes, or yourself."
|
|
930
|
+
"Respond as a coherent short film: establish, develop, then land a useful or emotional payoff. Match the user's requested form.",
|
|
931
|
+
generatedVideoAvailable ? 'First emit one host-consumed opening JSON object: {"type":"video-chat.opening","spokenHook":"6-9 words","mediaKeyword":"literal subject","firstShot":{"text":"short grounded fallback","narration":"one natural sentence advancing the hook","mediaKeyword":"2-8 concrete words","shotDirection":"optional framing and action"}}. Include firstShot only when a distinctive illustrative shot serves the story; omit it for an abstract explanation best opened with graphics. When present, the host inserts it once and begins generation immediately; do not emit it again.' : openingAlreadyProvided ? "Start directly with scene.add; the opening has already been supplied." : 'First emit {"type":"video-chat.opening","spokenHook":"6-9 words","mediaKeyword":"literal subject"}. This is host-consumed, not a scene.',
|
|
932
|
+
openingAlreadyProvided ? "Preserve the supplied opening exactly; continue it without repeating its words or claim." : void 0,
|
|
933
|
+
"The spokenHook is already heard before the first scene. Start firstShot.narration with the next fact, cause, action or consequence; never restate the hook. The first ordinary scene must then advance beyond firstShot rather than repeat its narration or opening claim. If firstShot is omitted, that first scene must advance the hook directly. firstShot.text, fallbackText and chapter titles must also express that new beat, not reuse the hook or prior shot copy; write a short complete grounded thought within the schema budget, never a clipped statistic or qualifying clause.",
|
|
934
|
+
"Continue with only as many scenes as the story and duration need. Never pad to a fixed count. Every emitted scene carries narration beside variables and timing; no additional narration request should be needed.",
|
|
935
|
+
"Make most of the film relevant footage: use full-bleed media for action, subjects and atmosphere, with graphics only to clarify a specific relationship or piece of evidence. Maintain consistent setting, lighting and subject while varying shot scale. Avoid unrelated cinematic montages.",
|
|
936
|
+
"Use the installed catalog: ordered events, comparison, exact quote, one key figure, chapter or a message only when its narrative job fits. At most one graphic-led explanatory beat per 30 seconds, plus a brief chapter opening when needed. Do not place graphic beats consecutively unless no honest relevant media is available. Give media-capable graphics a relevant background when it supports the meaning; keep black when no matching media exists. Do not force every template into a video or use lists of bullets.",
|
|
937
|
+
`At most ${generatedVideoAvailable ? maxGeneratedVideos : 0} generated-video attempts are available. Media scenes choose mediaSource=generate for distinctive illustrative shots or mediaSource=stock for generic verified imagery. A stock miss is not permission to broaden essential details. Do not spend generation on every scene.`,
|
|
938
|
+
"Each mediaKeyword is a literal filmable subject/action, 2\u20138 words, maximum 80 characters. Use optional shotDirection for action, camera framing and continuity; it does not change the literal stock subject. Supply a short grounded fallbackText when the schema declares it. Do not put visible headline text over full-bleed footage.",
|
|
939
|
+
"No invented quotations, attribution, statistics, personal evidence or URLs. Creative stories may be invented when requested; do not present generated illustration as historical evidence.",
|
|
940
|
+
'Emit exactly one final placement:"closer" scene using a catalog template with a suitable payoff or ask job. It should land the meaning, not recap the whole answer.',
|
|
941
|
+
"Every scene needs timing, even an empty object. Narration forms one continuous spoken explanation, uses natural sentence lengths, and does not read every on-screen word back. Finish with plan.complete."
|
|
857
942
|
].filter((line) => line != null).join("\n");
|
|
858
943
|
}
|
|
859
944
|
var VIDEO_CHAT_NARRATION_PROMPT = [
|
|
@@ -944,10 +1029,10 @@ function boundedString2(value, label, maximum = MAX_PROMPT_CHARACTERS) {
|
|
|
944
1029
|
}
|
|
945
1030
|
function parseResponseRequest(value) {
|
|
946
1031
|
const body = record2(value, "request");
|
|
947
|
-
allowedKeys2(body, ["prompt", "opening", "mode", "orientation", "conversation", "
|
|
948
|
-
const mode = body.mode ?? "
|
|
949
|
-
if (mode !== "
|
|
950
|
-
throw new Error("request.mode must be
|
|
1032
|
+
allowedKeys2(body, ["prompt", "opening", "mode", "orientation", "conversation", "style"], "request");
|
|
1033
|
+
const mode = body.mode ?? "cinematic";
|
|
1034
|
+
if (mode !== "cinematic") {
|
|
1035
|
+
throw new Error("request.mode must be cinematic");
|
|
951
1036
|
}
|
|
952
1037
|
const orientation = body.orientation ?? "landscape";
|
|
953
1038
|
if (orientation !== "portrait" && orientation !== "landscape") {
|
|
@@ -970,7 +1055,6 @@ function parseResponseRequest(value) {
|
|
|
970
1055
|
...turn.response == null ? {} : { response: boundedString2(turn.response, `request.conversation[${index}].response`, MAX_CONVERSATION_RESPONSE_CHARACTERS) }
|
|
971
1056
|
};
|
|
972
1057
|
}),
|
|
973
|
-
...body.brand == null ? {} : { brand: body.brand },
|
|
974
1058
|
...body.style == null ? {} : { style: body.style }
|
|
975
1059
|
};
|
|
976
1060
|
}
|
|
@@ -1015,10 +1099,11 @@ function readGeneratedFirstShot(value) {
|
|
|
1015
1099
|
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
1016
1100
|
const shot = value;
|
|
1017
1101
|
const bounded = (field, maximum) => typeof field === "string" ? [...field.trim()].slice(0, maximum).join("").trim() : "";
|
|
1018
|
-
const text = bounded(shot.text,
|
|
1102
|
+
const text = bounded(shot.text, 65);
|
|
1019
1103
|
const narration = bounded(shot.narration, 300);
|
|
1020
1104
|
const mediaKeyword = bounded(shot.mediaKeyword, 80).match(/\S+/gu)?.slice(0, 8).join(" ") ?? "";
|
|
1021
|
-
|
|
1105
|
+
const shotDirection = bounded(shot.shotDirection, 220);
|
|
1106
|
+
return text && narration && mediaKeyword ? { text, narration, mediaKeyword, ...shotDirection ? { shotDirection } : {} } : void 0;
|
|
1022
1107
|
}
|
|
1023
1108
|
function boundedWords(value, maximum, characters) {
|
|
1024
1109
|
if (typeof value !== "string") return "";
|
|
@@ -1044,9 +1129,11 @@ function reservedFirstScene(requestId, firstShot) {
|
|
|
1044
1129
|
type: "scene.add",
|
|
1045
1130
|
scene: {
|
|
1046
1131
|
id: `${requestId}-first-shot`,
|
|
1047
|
-
templateId: "
|
|
1132
|
+
templateId: "cinemaMedia",
|
|
1048
1133
|
variables: {
|
|
1049
|
-
|
|
1134
|
+
fallbackText: firstShot.text,
|
|
1135
|
+
mediaSource: "generate",
|
|
1136
|
+
...firstShot.shotDirection ? { shotDirection: firstShot.shotDirection } : {},
|
|
1050
1137
|
mediaType: "video",
|
|
1051
1138
|
mediaKeyword: firstShot.mediaKeyword
|
|
1052
1139
|
},
|
|
@@ -1088,6 +1175,19 @@ function interceptOpeningPlan(source, options) {
|
|
|
1088
1175
|
const textStream = (async function* () {
|
|
1089
1176
|
let buffer = "";
|
|
1090
1177
|
let decided = !options.expectOpening;
|
|
1178
|
+
const continuation = createOpeningContinuation(options.openingLine);
|
|
1179
|
+
const acceptOpening = (opening) => {
|
|
1180
|
+
if (!options.openingProvided) {
|
|
1181
|
+
options.publish(opening.line ? opening : void 0);
|
|
1182
|
+
continuation.remember(opening.line);
|
|
1183
|
+
}
|
|
1184
|
+
if (!options.generatedVideoAvailable || !opening.firstShot) return void 0;
|
|
1185
|
+
const narration = continuation.narration(opening.firstShot.narration);
|
|
1186
|
+
if (!narration) return void 0;
|
|
1187
|
+
const text = continuation.copy(opening.firstShot.text, narration);
|
|
1188
|
+
continuation.remember(narration);
|
|
1189
|
+
return JSON.stringify(reservedFirstScene(options.requestId, { ...opening.firstShot, text, narration }));
|
|
1190
|
+
};
|
|
1091
1191
|
try {
|
|
1092
1192
|
for await (const delta of upstream) {
|
|
1093
1193
|
if (typeof delta !== "string") throw new Error("The LLM adapter returned a non-text delta");
|
|
@@ -1101,17 +1201,16 @@ function interceptOpeningPlan(source, options) {
|
|
|
1101
1201
|
const opening = readOpeningPlanLine(line);
|
|
1102
1202
|
decided = true;
|
|
1103
1203
|
if (opening) {
|
|
1104
|
-
|
|
1105
|
-
if (
|
|
1106
|
-
yield `${JSON.stringify(reservedFirstScene(options.requestId, opening.firstShot))}
|
|
1204
|
+
const firstScene = acceptOpening(opening);
|
|
1205
|
+
if (firstScene) yield `${firstScene}
|
|
1107
1206
|
`;
|
|
1108
|
-
}
|
|
1109
1207
|
newline = buffer.indexOf("\n");
|
|
1110
1208
|
continue;
|
|
1111
1209
|
}
|
|
1112
1210
|
options.publish(void 0);
|
|
1113
1211
|
}
|
|
1114
|
-
|
|
1212
|
+
const continued = continuation.line(rawLine);
|
|
1213
|
+
if (continued != null) yield `${continued}
|
|
1115
1214
|
`;
|
|
1116
1215
|
newline = buffer.indexOf("\n");
|
|
1117
1216
|
}
|
|
@@ -1122,17 +1221,17 @@ function interceptOpeningPlan(source, options) {
|
|
|
1122
1221
|
const opening = readOpeningPlanLine(line);
|
|
1123
1222
|
decided = true;
|
|
1124
1223
|
if (opening) {
|
|
1125
|
-
|
|
1126
|
-
if (
|
|
1127
|
-
yield `${JSON.stringify(reservedFirstScene(options.requestId, opening.firstShot))}
|
|
1224
|
+
const firstScene = acceptOpening(opening);
|
|
1225
|
+
if (firstScene) yield `${firstScene}
|
|
1128
1226
|
`;
|
|
1129
|
-
}
|
|
1130
1227
|
} else {
|
|
1131
1228
|
options.publish(void 0);
|
|
1132
|
-
|
|
1229
|
+
const continued = continuation.line(buffer);
|
|
1230
|
+
if (continued != null) yield continued;
|
|
1133
1231
|
}
|
|
1134
1232
|
} else {
|
|
1135
|
-
|
|
1233
|
+
const continued = continuation.line(buffer);
|
|
1234
|
+
if (continued != null) yield continued;
|
|
1136
1235
|
}
|
|
1137
1236
|
}
|
|
1138
1237
|
} finally {
|
|
@@ -1303,21 +1402,20 @@ function createVideoChatHandler(options) {
|
|
|
1303
1402
|
generatedVideo: generateVideo != null,
|
|
1304
1403
|
stockMedia: searchMedia != null,
|
|
1305
1404
|
transcription: transcribe != null,
|
|
1306
|
-
modes:
|
|
1405
|
+
modes: ["cinematic"]
|
|
1307
1406
|
};
|
|
1308
1407
|
const welcomePrompts = (welcomeOptions?.prompts ?? DEFAULT_WELCOME_PROMPTS).slice(0, 4);
|
|
1309
1408
|
const heroQuery = welcomeOptions?.heroQuery;
|
|
1310
1409
|
let welcomeResponse;
|
|
1311
1410
|
let requestSequence = 0;
|
|
1312
|
-
const responseHandler = (
|
|
1313
|
-
const
|
|
1314
|
-
const fullAiVideo = mode === "full";
|
|
1411
|
+
const responseHandler = (requestId, openingProvided, openingChannel, openingLine) => {
|
|
1412
|
+
const generatedVideoAvailable = generateVideo != null && maxGeneratedVideos > 0;
|
|
1315
1413
|
let lifecycle;
|
|
1316
1414
|
let generatedAttempts = 0;
|
|
1317
1415
|
const completedVideos = /* @__PURE__ */ new Map();
|
|
1318
1416
|
const reusedUrls = /* @__PURE__ */ new Set();
|
|
1319
1417
|
const resolveSelected = generateVideo || searchMedia ? async (query, context) => {
|
|
1320
|
-
const reuseKey = JSON.stringify([query, context.generatedLook ?? ""]);
|
|
1418
|
+
const reuseKey = JSON.stringify([query, context.generatedLook ?? "", context.scene.variables.shotDirection ?? "", context.input.orientation ?? "landscape"]);
|
|
1321
1419
|
const remember = (media) => {
|
|
1322
1420
|
if (media?.type === "video") completedVideos.set(reuseKey, media);
|
|
1323
1421
|
return media;
|
|
@@ -1349,7 +1447,7 @@ function createVideoChatHandler(options) {
|
|
|
1349
1447
|
return null;
|
|
1350
1448
|
}
|
|
1351
1449
|
};
|
|
1352
|
-
if (
|
|
1450
|
+
if (generatedVideoAvailable && context.scene.variables.mediaSource === "generate") {
|
|
1353
1451
|
const generated = generatedAttempts < maxGeneratedVideos ? (generatedAttempts++, await attempt(generateVideo, generateVideoTimeoutMs)) : null;
|
|
1354
1452
|
if (generated) return remember(generated);
|
|
1355
1453
|
lifecycle?.reportWarning?.({
|
|
@@ -1361,7 +1459,7 @@ function createVideoChatHandler(options) {
|
|
|
1361
1459
|
}
|
|
1362
1460
|
const stock = await attempt(searchMedia, 3e3);
|
|
1363
1461
|
if (stock) return remember(stock);
|
|
1364
|
-
if (
|
|
1462
|
+
if (generatedVideoAvailable) {
|
|
1365
1463
|
const previous = completedVideos.get(reuseKey);
|
|
1366
1464
|
if (previous && !reusedUrls.has(previous.url)) {
|
|
1367
1465
|
reusedUrls.add(previous.url);
|
|
@@ -1376,10 +1474,11 @@ function createVideoChatHandler(options) {
|
|
|
1376
1474
|
lifecycle = getGenerationLifecycleSink(context);
|
|
1377
1475
|
try {
|
|
1378
1476
|
return interceptOpeningPlan(videoOptions.streamText(context), {
|
|
1379
|
-
expectOpening:
|
|
1477
|
+
expectOpening: generatedVideoAvailable || !openingProvided,
|
|
1380
1478
|
openingProvided,
|
|
1479
|
+
openingLine,
|
|
1381
1480
|
requestId,
|
|
1382
|
-
|
|
1481
|
+
generatedVideoAvailable,
|
|
1383
1482
|
publish: openingChannel.publish
|
|
1384
1483
|
});
|
|
1385
1484
|
} catch (cause) {
|
|
@@ -1392,7 +1491,7 @@ function createVideoChatHandler(options) {
|
|
|
1392
1491
|
allowCredentials,
|
|
1393
1492
|
maxBodyBytes,
|
|
1394
1493
|
mediaConcurrency,
|
|
1395
|
-
basePrompt: [createVideoChatResponseInstructions(
|
|
1494
|
+
basePrompt: [createVideoChatResponseInstructions(generatedVideoAvailable, openingProvided, maxGeneratedVideos), instructions?.trim()].filter(Boolean).join("\n\nAPPLICATION GUIDANCE\n"),
|
|
1396
1495
|
narrate: true,
|
|
1397
1496
|
resolveMedia: resolveSelected
|
|
1398
1497
|
});
|
|
@@ -1518,8 +1617,6 @@ function createVideoChatHandler(options) {
|
|
|
1518
1617
|
} catch (cause) {
|
|
1519
1618
|
return jsonError2(400, "invalid_request", cause instanceof Error ? cause.message : "Request is invalid", headers);
|
|
1520
1619
|
}
|
|
1521
|
-
const mode = input.mode !== "templates" && !generateVideo ? "templates" : input.mode;
|
|
1522
|
-
const fullAiVideo = mode === "full";
|
|
1523
1620
|
const requestId = `video-chat-${Date.now()}-${requestSequence += 1}`;
|
|
1524
1621
|
const openingChannel = createOpeningChannel(input.opening ? { line: input.opening, keyword: "" } : void 0);
|
|
1525
1622
|
const forwardedHeaders = new Headers(request.headers);
|
|
@@ -1529,16 +1626,14 @@ function createVideoChatHandler(options) {
|
|
|
1529
1626
|
headers: forwardedHeaders,
|
|
1530
1627
|
signal: request.signal,
|
|
1531
1628
|
body: JSON.stringify({
|
|
1532
|
-
protocolVersion:
|
|
1629
|
+
protocolVersion: VIDEO_PROTOCOL_VERSION,
|
|
1533
1630
|
requestId,
|
|
1534
|
-
...fullAiVideo ? { capabilities: { templates: ["media"] } } : {},
|
|
1535
1631
|
input: {
|
|
1536
1632
|
input: conversationInput(input.prompt, input.conversation, input.opening),
|
|
1537
1633
|
knowledgeMode: "general",
|
|
1538
1634
|
opening: false,
|
|
1539
1635
|
orientation: input.orientation,
|
|
1540
1636
|
maxDurationSec: 40,
|
|
1541
|
-
...input.brand ? { brand: input.brand } : {},
|
|
1542
1637
|
style: {
|
|
1543
1638
|
density: "airy",
|
|
1544
1639
|
motion: "calm",
|
|
@@ -1549,10 +1644,10 @@ function createVideoChatHandler(options) {
|
|
|
1549
1644
|
})
|
|
1550
1645
|
});
|
|
1551
1646
|
const response = await responseHandler(
|
|
1552
|
-
mode,
|
|
1553
1647
|
requestId,
|
|
1554
1648
|
input.opening != null,
|
|
1555
|
-
openingChannel
|
|
1649
|
+
openingChannel,
|
|
1650
|
+
input.opening
|
|
1556
1651
|
)(videoRequest);
|
|
1557
1652
|
return streamVideoChatOpening(response, openingChannel.ready);
|
|
1558
1653
|
}
|