@vanillaskyai/video 0.7.1 → 0.8.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.
Files changed (89) hide show
  1. package/CHANGELOG.md +63 -0
  2. package/PUBLIC-API.md +83 -79
  3. package/README.md +20 -15
  4. package/dist/assets/vanillasky-logo.svg +151 -0
  5. package/dist/{builtin-server-KB7FKF6A.js → builtin-server-CUYPIDE7.js} +2 -2
  6. package/dist/check-runtime.js +1 -1
  7. package/dist/{chunk-2PYO6VAC.js → chunk-2DOLF4QN.js} +1 -43
  8. package/dist/{chunk-GAIOHGNR.js → chunk-2OKB27TG.js} +42 -45
  9. package/dist/{chunk-K746NUIP.js → chunk-2USVB3CY.js} +80 -29
  10. package/dist/{chunk-RE4IMWJR.js → chunk-3VRMKFM7.js} +87 -14
  11. package/dist/{chunk-JNN3EYVP.js → chunk-4UNKZEAT.js} +46 -46
  12. package/dist/{chunk-2XT4MZ76.js → chunk-APQKY6P3.js} +36 -3
  13. package/dist/{chunk-LLPMVDJZ.js → chunk-L7QGGKJ2.js} +69 -38
  14. package/dist/{chunk-RGF452LL.js → chunk-OWBT45EN.js} +1 -1
  15. package/dist/{chunk-LKBZX7GV.js → chunk-PP3MCPN4.js} +4 -4
  16. package/dist/chunk-ZD2VTUYR.js +28 -0
  17. package/dist/cli.js +131 -24
  18. package/dist/{compose-video-PD6LKKRK.js → compose-video-2NFH4DZY.js} +3 -3
  19. package/dist/{events-B6qS1Lsb.d.ts → events-BQ6z264n.d.ts} +1 -1
  20. package/dist/index.d.ts +5 -67
  21. package/dist/index.js +2 -4
  22. package/dist/{kit-8g46H2RZ.d.ts → kit-tQnCPMOM.d.ts} +1 -1
  23. package/dist/react.d.ts +33 -53
  24. package/dist/react.js +982 -648
  25. package/dist/server.d.ts +11 -13
  26. package/dist/server.js +170 -81
  27. package/dist/template-catalog.js +1 -1
  28. package/dist/templates.d.ts +3 -3
  29. package/dist/test.d.ts +2 -2
  30. package/dist/test.js +3 -3
  31. package/dist/{text-stream-ROTNGSD4.js → text-stream-54LXABJW.js} +1 -1
  32. package/dist/{types-2wHBqtg8.d.ts → types-CEh9eUFu.d.ts} +1 -1
  33. package/dist/{types-DrABlRa7.d.ts → types-DWFO6qca.d.ts} +1 -1
  34. package/docs/agent-integration.md +9 -3
  35. package/docs/architecture.md +8 -10
  36. package/docs/concepts.md +16 -40
  37. package/docs/custom-templates.md +27 -23
  38. package/docs/customization.md +23 -55
  39. package/docs/errors.md +58 -68
  40. package/docs/getting-started.md +21 -14
  41. package/docs/immersive-interface.md +87 -0
  42. package/docs/media-and-audio.md +2 -2
  43. package/docs/performance.md +69 -0
  44. package/docs/persistence.md +12 -27
  45. package/docs/production.md +2 -2
  46. package/docs/provider-integration.md +11 -5
  47. package/docs/reference/design-system.html +115 -0
  48. package/docs/reference/provider-adapters.md +37 -89
  49. package/docs/security.md +1 -1
  50. package/docs/streaming-protocol.md +2 -2
  51. package/examples/custom-template/README.md +6 -6
  52. package/package.json +6 -7
  53. package/registry/items/barChart.json +2 -2
  54. package/registry/items/bigNumber.json +2 -2
  55. package/registry/items/brandMessage.json +2 -2
  56. package/registry/items/cardList.json +2 -2
  57. package/registry/items/codeEditor.json +2 -2
  58. package/registry/items/ctaLogo.json +2 -2
  59. package/registry/items/ctaMedia.json +2 -2
  60. package/registry/items/incomingCall.json +2 -2
  61. package/registry/items/media.json +2 -2
  62. package/registry/items/milestone.json +2 -2
  63. package/registry/items/notification.json +2 -2
  64. package/registry/items/phoneMockup.json +2 -2
  65. package/registry/items/problemSolution.json +2 -2
  66. package/registry/items/progressRing.json +2 -2
  67. package/registry/items/promptInput.json +2 -2
  68. package/registry/items/reaction.json +2 -2
  69. package/registry/items/reviewStack.json +2 -2
  70. package/registry/items/steps.json +2 -2
  71. package/registry/items/terminal.json +2 -2
  72. package/registry/items/testimonial.json +2 -2
  73. package/registry/items/tripleStats.json +2 -2
  74. package/registry/items/tweet.json +2 -2
  75. package/registry/items/webMockup.json +2 -2
  76. package/starters/video-chat/.env.example +4 -2
  77. package/starters/video-chat/README.md +17 -5
  78. package/starters/video-chat/index.html +2 -1
  79. package/starters/video-chat/package.json +2 -4
  80. package/starters/video-chat/providers/speech.ts +20 -0
  81. package/starters/video-chat/providers/video.ts +66 -0
  82. package/starters/video-chat/providers.ts +3 -0
  83. package/starters/video-chat/server.ts +4 -80
  84. package/starters/video-chat/stock.ts +114 -99
  85. package/styles/video-chat.css +650 -246
  86. package/dist/chunk-SKRGRKHY.js +0 -142
  87. package/dist/state-DZcKuS32.d.ts +0 -3
  88. package/docs/branding-and-personalization.md +0 -87
  89. package/examples/custom-template/supplied-media.tsx +0 -92
@@ -1,5 +1,4 @@
1
1
  import {
2
- VIDEO_PROTOCOL_VERSION,
3
2
  VIDEO_SCHEMA_VERSION
4
3
  } from "./chunk-AOWSXU2K.js";
5
4
  import {
@@ -501,52 +500,11 @@ function parseVideo(value) {
501
500
  }
502
501
  }
503
502
 
504
- // src/protocol/stable-json.ts
505
- function stableJson(value) {
506
- if (value == null || typeof value !== "object") return JSON.stringify(value);
507
- if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
508
- const entries = Object.entries(value).filter(([, child]) => child !== void 0).sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0);
509
- return `{${entries.map(([key, child]) => `${JSON.stringify(key)}:${stableJson(child)}`).join(",")}}`;
510
- }
511
-
512
- // src/protocol/checksum.ts
513
- function checksumVideo(config) {
514
- const input = stableJson(config);
515
- let hash = 2166136261;
516
- for (let index = 0; index < input.length; index += 1) {
517
- hash ^= input.charCodeAt(index);
518
- hash = Math.imul(hash, 16777619) >>> 0;
519
- }
520
- return `fnv1a32:${hash.toString(16).padStart(8, "0")}`;
521
- }
522
-
523
- // src/protocol/events.ts
524
- function createVideoEventFactory(options) {
525
- let sequence = options.initialSequence ?? 0;
526
- return {
527
- create(type, data) {
528
- const currentSequence = sequence;
529
- sequence += 1;
530
- return {
531
- protocolVersion: VIDEO_PROTOCOL_VERSION,
532
- runId: options.runId,
533
- sequence: currentSequence,
534
- eventId: `${options.runId}:${currentSequence}`,
535
- type,
536
- data
537
- };
538
- }
539
- };
540
- }
541
-
542
503
  export {
543
504
  MAX_RETAINED_SOURCE_LENGTH,
544
505
  MAX_RETAINED_INSTRUCTIONS_LENGTH,
545
506
  MAX_RETAINED_MEDIA_URLS,
546
507
  MAX_RETAINED_MEDIA_URL_LENGTH,
547
508
  VideoValidationError,
548
- parseVideo,
549
- stableJson,
550
- checksumVideo,
551
- createVideoEventFactory
509
+ parseVideo
552
510
  };
@@ -2,13 +2,48 @@ import {
2
2
  parseVideoEvent
3
3
  } from "./chunk-MMUXVA47.js";
4
4
  import {
5
- checksumVideo,
6
- stableJson
7
- } from "./chunk-2PYO6VAC.js";
8
- import {
5
+ VIDEO_PROTOCOL_VERSION,
9
6
  VIDEO_SCHEMA_VERSION
10
7
  } from "./chunk-AOWSXU2K.js";
11
8
 
9
+ // src/protocol/stable-json.ts
10
+ function stableJson(value) {
11
+ if (value == null || typeof value !== "object") return JSON.stringify(value);
12
+ if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
13
+ const entries = Object.entries(value).filter(([, child]) => child !== void 0).sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0);
14
+ return `{${entries.map(([key, child]) => `${JSON.stringify(key)}:${stableJson(child)}`).join(",")}}`;
15
+ }
16
+
17
+ // src/protocol/checksum.ts
18
+ function checksumVideo(config) {
19
+ const input = stableJson(config);
20
+ let hash = 2166136261;
21
+ for (let index = 0; index < input.length; index += 1) {
22
+ hash ^= input.charCodeAt(index);
23
+ hash = Math.imul(hash, 16777619) >>> 0;
24
+ }
25
+ return `fnv1a32:${hash.toString(16).padStart(8, "0")}`;
26
+ }
27
+
28
+ // src/protocol/events.ts
29
+ function createVideoEventFactory(options) {
30
+ let sequence = options.initialSequence ?? 0;
31
+ return {
32
+ create(type, data) {
33
+ const currentSequence = sequence;
34
+ sequence += 1;
35
+ return {
36
+ protocolVersion: VIDEO_PROTOCOL_VERSION,
37
+ runId: options.runId,
38
+ sequence: currentSequence,
39
+ eventId: `${options.runId}:${currentSequence}`,
40
+ type,
41
+ data
42
+ };
43
+ }
44
+ };
45
+ }
46
+
12
47
  // src/protocol/state.ts
13
48
  function createVideoState() {
14
49
  return {
@@ -133,47 +168,9 @@ function applyVideoEvent(state, untrustedEvent) {
133
168
  throw new Error(`Reducer does not yet support ${event.type}`);
134
169
  }
135
170
 
136
- // src/replayable-stream.ts
137
- function createReplayableStream(source, onError) {
138
- const buffered = [];
139
- const waiters = /* @__PURE__ */ new Set();
140
- let done = false;
141
- let streamError;
142
- const notify = () => {
143
- for (const waiter of waiters) waiter();
144
- waiters.clear();
145
- };
146
- void (async () => {
147
- try {
148
- for await (const item of source) {
149
- buffered.push(item);
150
- notify();
151
- }
152
- } catch (cause) {
153
- streamError = cause;
154
- onError(cause);
155
- } finally {
156
- done = true;
157
- notify();
158
- }
159
- })();
160
- return {
161
- async *[Symbol.asyncIterator]() {
162
- let index = 0;
163
- while (true) {
164
- while (index < buffered.length) yield buffered[index++];
165
- if (done) {
166
- if (streamError) throw streamError;
167
- return;
168
- }
169
- await new Promise((resolve) => waiters.add(resolve));
170
- }
171
- }
172
- };
173
- }
174
-
175
171
  export {
172
+ checksumVideo,
173
+ createVideoEventFactory,
176
174
  createVideoState,
177
- applyVideoEvent,
178
- createReplayableStream
175
+ applyVideoEvent
179
176
  };
@@ -21,9 +21,11 @@ import {
21
21
  // src/player/video-frame.tsx
22
22
  import {
23
23
  createElement,
24
+ Component,
24
25
  lazy,
25
26
  Suspense,
26
27
  useState,
28
+ useEffect,
27
29
  useSyncExternalStore
28
30
  } from "react";
29
31
 
@@ -46,6 +48,54 @@ function scaleSafeZone(zone, factor) {
46
48
 
47
49
  // src/player/video-frame.tsx
48
50
  import { jsx, jsxs } from "react/jsx-runtime";
51
+ function PresentedScene({ notify }) {
52
+ useEffect(() => {
53
+ if (!notify) return;
54
+ const frame = requestAnimationFrame(() => {
55
+ try {
56
+ void Promise.resolve(notify()).catch(() => void 0);
57
+ } catch {
58
+ }
59
+ });
60
+ return () => cancelAnimationFrame(frame);
61
+ }, [notify]);
62
+ return null;
63
+ }
64
+ function SafeScene({ scene, onFramePresented }) {
65
+ const copy = scene.narration?.trim() || Object.values(scene.variables).filter((value) => typeof value === "string" && !/^https?:/i.test(value)).join(" ");
66
+ return /* @__PURE__ */ jsxs(
67
+ "div",
68
+ {
69
+ "data-scene-fallback": "true",
70
+ style: {
71
+ width: "100%",
72
+ height: "100%",
73
+ display: "grid",
74
+ placeContent: "center",
75
+ boxSizing: "border-box",
76
+ padding: "8%",
77
+ background: "#090712",
78
+ color: "#fff",
79
+ font: "500 clamp(20px, 4vw, 64px)/1.3 system-ui",
80
+ overflow: "hidden"
81
+ },
82
+ children: [
83
+ /* @__PURE__ */ jsx(PresentedScene, { notify: onFramePresented }),
84
+ /* @__PURE__ */ jsx("p", { children: copy.slice(0, 600) || "Your response continues." }),
85
+ /* @__PURE__ */ jsx("small", { style: { fontSize: "0.3em" }, role: "status", children: "This scene uses a simpler layout." })
86
+ ]
87
+ }
88
+ );
89
+ }
90
+ var SceneBoundary = class extends Component {
91
+ state = { failed: false };
92
+ static getDerivedStateFromError() {
93
+ return { failed: true };
94
+ }
95
+ render() {
96
+ return this.state.failed ? /* @__PURE__ */ jsx(SafeScene, { scene: this.props.scene, onFramePresented: this.props.onFramePresented }) : this.props.children;
97
+ }
98
+ };
49
99
  var SCENE_TRANSITION_SECONDS = 0.3;
50
100
  var SceneVideoBackdrop = lazy(() => import("./scene-video-backdrop-XFPX4O3I.js").then((module) => ({ default: module.SceneVideoBackdrop })));
51
101
  var MEDIA_PREROLL_SECONDS = 1.2;
@@ -102,6 +152,7 @@ function sceneBackgroundChanges(left, right) {
102
152
  return mediaUrl(left) !== mediaUrl(right);
103
153
  }
104
154
  function SceneLayer({
155
+ onFramePresented,
105
156
  kit,
106
157
  config,
107
158
  range,
@@ -146,41 +197,42 @@ function SceneLayer({
146
197
  "--vanillasky-transition-semantic-visibility": layer === "incoming" ? "hidden" : "visible",
147
198
  "--vanillasky-template-surface": externalVideoBackdrop !== false ? "transparent" : void 0
148
199
  },
149
- children: template ? /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(
200
+ children: template ? /* @__PURE__ */ jsx(SceneBoundary, { scene: range.scene, onFramePresented, children: /* @__PURE__ */ jsxs(Suspense, { fallback: /* @__PURE__ */ jsx(
150
201
  "div",
151
202
  {
152
203
  "data-template-loading": range.scene.templateId,
153
204
  style: { position: "absolute", inset: 0 }
154
205
  }
155
- ), children: createElement(template.component, {
156
- variables: {
157
- ...template.defaults ?? getTemplateDefaults(template.schema),
158
- ...range.scene.variables
159
- },
160
- style: config.style,
161
- progress,
162
- motionProgress,
163
- beatIntensity: 0,
164
- width,
165
- height,
166
- textArchetype: range.scene.textArchetype ?? config.style.defaultTextArchetype,
167
- backgroundEffect: range.scene.backgroundEffect ?? config.style.defaultBackgroundEffect,
168
- safeZone: scaleSafeZone(
169
- getSafeZone(config.orientation),
170
- resolveDensity(config.style.density).safeZoneScale
171
- ),
172
- sceneDuration: duration,
173
- isPlaying: playing
174
- }) }) : /* @__PURE__ */ jsxs("div", { style: { width, height, background: "#090712", color: "#fff" }, children: [
175
- "Unsupported template: ",
176
- range.scene.templateId
177
- ] })
206
+ ), children: [
207
+ /* @__PURE__ */ jsx(PresentedScene, { notify: onFramePresented }),
208
+ createElement(template.component, {
209
+ variables: {
210
+ ...template.defaults ?? getTemplateDefaults(template.schema),
211
+ ...range.scene.variables
212
+ },
213
+ style: config.style,
214
+ progress,
215
+ motionProgress,
216
+ beatIntensity: 0,
217
+ width,
218
+ height,
219
+ textArchetype: range.scene.textArchetype ?? config.style.defaultTextArchetype,
220
+ backgroundEffect: range.scene.backgroundEffect ?? config.style.defaultBackgroundEffect,
221
+ safeZone: scaleSafeZone(
222
+ getSafeZone(config.orientation),
223
+ resolveDensity(config.style.density).safeZoneScale
224
+ ),
225
+ sceneDuration: duration,
226
+ isPlaying: playing
227
+ })
228
+ ] }) }, range.scene.id) : /* @__PURE__ */ jsx(SafeScene, { scene: range.scene, onFramePresented })
178
229
  }
179
230
  )
180
231
  }
181
232
  );
182
233
  }
183
234
  function VideoFrame({
235
+ onFramePresented,
184
236
  kit,
185
237
  config,
186
238
  time,
@@ -212,17 +264,14 @@ function VideoFrame({
212
264
  );
213
265
  }
214
266
  if (!kit.getTemplate(active.scene.templateId)) {
215
- return /* @__PURE__ */ jsxs(
267
+ return /* @__PURE__ */ jsx(
216
268
  "div",
217
269
  {
218
270
  "data-video-frame": "unsupported",
219
271
  "data-template-id": active.scene.templateId,
220
272
  className,
221
273
  style: { width, height, background: "#090712", color: "#fff", ...style },
222
- children: [
223
- "Unsupported template: ",
224
- active.scene.templateId
225
- ]
274
+ children: /* @__PURE__ */ jsx(SafeScene, { scene: active.scene, onFramePresented })
226
275
  }
227
276
  );
228
277
  }
@@ -386,6 +435,7 @@ function VideoFrame({
386
435
  /* @__PURE__ */ jsx(
387
436
  SceneLayer,
388
437
  {
438
+ onFramePresented,
389
439
  kit,
390
440
  config,
391
441
  range: active,
@@ -429,6 +479,7 @@ function VideoFrame({
429
479
  /* @__PURE__ */ jsx(
430
480
  SceneLayer,
431
481
  {
482
+ onFramePresented,
432
483
  kit,
433
484
  config,
434
485
  range: active,
@@ -3,9 +3,10 @@ import {
3
3
  } from "./chunk-E7CL7UPB.js";
4
4
  import {
5
5
  applyVideoEvent,
6
- createReplayableStream,
6
+ checksumVideo,
7
+ createVideoEventFactory,
7
8
  createVideoState
8
- } from "./chunk-GAIOHGNR.js";
9
+ } from "./chunk-2OKB27TG.js";
9
10
  import {
10
11
  parseVideoPlanPart,
11
12
  safePublicDiagnostic
@@ -15,10 +16,8 @@ import {
15
16
  MAX_RETAINED_MEDIA_URLS,
16
17
  MAX_RETAINED_MEDIA_URL_LENGTH,
17
18
  MAX_RETAINED_SOURCE_LENGTH,
18
- checksumVideo,
19
- createVideoEventFactory,
20
19
  parseVideo
21
- } from "./chunk-2PYO6VAC.js";
20
+ } from "./chunk-2DOLF4QN.js";
22
21
  import {
23
22
  VIDEO_SCHEMA_VERSION,
24
23
  createVideoRequest
@@ -32,6 +31,45 @@ import {
32
31
  resolveVideoBrand
33
32
  } from "./chunk-XGRA2MUV.js";
34
33
 
34
+ // src/replayable-stream.ts
35
+ function createReplayableStream(source, onError) {
36
+ const buffered = [];
37
+ const waiters = /* @__PURE__ */ new Set();
38
+ let done = false;
39
+ let streamError;
40
+ const notify = () => {
41
+ for (const waiter of waiters) waiter();
42
+ waiters.clear();
43
+ };
44
+ void (async () => {
45
+ try {
46
+ for await (const item of source) {
47
+ buffered.push(item);
48
+ notify();
49
+ }
50
+ } catch (cause) {
51
+ streamError = cause;
52
+ onError(cause);
53
+ } finally {
54
+ done = true;
55
+ notify();
56
+ }
57
+ })();
58
+ return {
59
+ async *[Symbol.asyncIterator]() {
60
+ let index = 0;
61
+ while (true) {
62
+ while (index < buffered.length) yield buffered[index++];
63
+ if (done) {
64
+ if (streamError) throw streamError;
65
+ return;
66
+ }
67
+ await new Promise((resolve) => waiters.add(resolve));
68
+ }
69
+ }
70
+ };
71
+ }
72
+
35
73
  // src/server/prompts/user-prompt.ts
36
74
  var SUPPLIED_MEDIA_REFERENCE_BASE = "https://vanillasky.invalid/supplied/";
37
75
  function suppliedMediaReferences(input) {
@@ -543,14 +581,18 @@ function createId(prefix) {
543
581
  }
544
582
  function createProviderLifecycle() {
545
583
  const results = [];
584
+ const reportedWarnings = [];
546
585
  const sink = {
586
+ reportWarning(warning) {
587
+ reportedWarnings.push(warning);
588
+ },
547
589
  registerProviderResult(result) {
548
590
  results.push(result);
549
591
  }
550
592
  };
551
593
  const settle = async () => {
552
594
  const resolved = await Promise.all(results);
553
- const warnings = resolved.flatMap((result) => result.warnings);
595
+ const warnings = [...reportedWarnings, ...resolved.flatMap((result) => result.warnings)];
554
596
  const uniqueWarnings = [...new Map(warnings.map((warning) => [
555
597
  `${warning.code}\0${warning.category}\0${warning.message}\0${warning.sceneId ?? ""}`,
556
598
  warning
@@ -605,6 +647,14 @@ function createVideo(rawInput, options) {
605
647
  const eventSource = (async function* () {
606
648
  let state = createVideoState();
607
649
  let composition = createCompositionSession();
650
+ lifecycle.recoverGeneratedParts = options.invalidPartBehavior === "drop";
651
+ lifecycle.rejectPart = (error) => {
652
+ reportError(error);
653
+ if (options.invalidPartBehavior !== "drop") return false;
654
+ composition = rejectCompositionScene(composition);
655
+ lifecycle.reportWarning?.({ code: "provider_warning", category: "provider", message: "Some generated content was skipped.", recoverable: true });
656
+ return true;
657
+ };
608
658
  const compositionOptions = {
609
659
  maxDurationSec: input.maxDurationSec ?? 30,
610
660
  closerReserveSec,
@@ -686,13 +736,8 @@ function createVideo(rawInput, options) {
686
736
  }
687
737
  reportError(error);
688
738
  if ((options.invalidPartBehavior ?? "fail") === "fail") throw error;
689
- yield emit(events.create("response.error", {
690
- error: {
691
- code: "invalid_generated_part",
692
- message: "Generated content was skipped",
693
- recoverable: true
694
- },
695
- terminal: false
739
+ yield emit(events.create("response.warning", {
740
+ warning: { code: "provider_warning", category: "provider", message: "Some generated content was skipped.", recoverable: true }
696
741
  }));
697
742
  }
698
743
  }
@@ -749,7 +794,7 @@ function createVideo(rawInput, options) {
749
794
  }
750
795
  try {
751
796
  if (state.config) {
752
- const recovery = recoverComposition(composition, state.config, compositionOptions);
797
+ const recovery = options.invalidPartBehavior === "drop" && !composition.planCompleted ? advanceComposition(composition, { type: "plan.complete", finishReason: "other" }, state.config, compositionOptions) : recoverComposition(composition, state.config, compositionOptions);
753
798
  for (const action of recovery.actions) yield emitCompositionAction(action);
754
799
  composition = recovery.session;
755
800
  }
@@ -763,6 +808,33 @@ function createVideo(rawInput, options) {
763
808
  }
764
809
  const error = cause instanceof Error ? cause : new Error(String(cause));
765
810
  reportError(error);
811
+ if (options.invalidPartBehavior === "drop" && state.config?.scenes.length && (composition.acceptedSceneCount > 0 || !requiresGeneratedScene)) {
812
+ const snapshot = parseVideo(state.config);
813
+ yield emit(events.create("response.warning", {
814
+ warning: { code: "plan_incomplete", category: "provider", message: "The response is ready; some content could not be completed.", recoverable: true }
815
+ }));
816
+ const completeEvent = emit(events.create("response.complete", {
817
+ finishReason: "other",
818
+ snapshot,
819
+ checksum: checksumVideo(snapshot)
820
+ }));
821
+ finish(state);
822
+ invokeIsolated(options.onComplete, {
823
+ finishReason: "other",
824
+ ...provider.usage ? { usage: provider.usage } : {},
825
+ ...provider.providerMetadata !== void 0 ? { providerMetadata: provider.providerMetadata } : {},
826
+ ...provider.requestedModelId ? { requestedModelId: provider.requestedModelId } : {},
827
+ ...provider.resolvedModelId ? { resolvedModelId: provider.resolvedModelId } : {},
828
+ ...timeToFirstSceneMs != null ? { timeToFirstSceneMs } : {},
829
+ totalDurationMs: Math.max(0, monotonicNow() - startedAt),
830
+ acceptedSceneCount: composition.acceptedSceneCount,
831
+ rejectedSceneCount: composition.rejectedSceneCount,
832
+ videoDurationSec: snapshot.scenes.at(-1)?.timing.endTime ?? 0,
833
+ warnings: state.warnings.map(cloneWarning)
834
+ });
835
+ yield completeEvent;
836
+ return;
837
+ }
766
838
  const emptyResult = error.message === "The planner completed without adding a scene";
767
839
  const errorEvent = emit(events.create("response.error", {
768
840
  error: {
@@ -805,5 +877,6 @@ function createVideo(rawInput, options) {
805
877
  }
806
878
 
807
879
  export {
880
+ invokeIsolated,
808
881
  createVideo
809
882
  };