@vanillaskyai/video 0.5.0 → 0.5.2

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 CHANGED
@@ -4,6 +4,17 @@ VanillaSky follows semantic versioning. This changelog begins with the 0.1 beta.
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## 0.5.2
8
+
9
+ - Refactors composition state transitions into a deterministic, directly
10
+ tested session engine without changing the public API, event stream,
11
+ checksums, or runtime behavior.
12
+
13
+ ## 0.5.1
14
+
15
+ - Removes the redundant README version badge. Package registries and release
16
+ pages remain the authoritative source for the current version.
17
+
7
18
  ## 0.5.0
8
19
 
9
20
  ### Breaking changes
package/README.md CHANGED
@@ -1,7 +1,5 @@
1
1
  # Give your AI a video output
2
2
 
3
- ![npm version](https://img.shields.io/npm/v/@vanillaskyai/video?label=version)
4
-
5
3
  **VanillaSky is the open-source video response layer.** Turn text, structured
6
4
  data, and live application context into personalized video responses that start
7
5
  playing while your LLM composes them.
@@ -349,6 +349,193 @@ function createSceneQualityWarnings(scene) {
349
349
  }];
350
350
  }
351
351
 
352
+ // src/server/composition-session.ts
353
+ var warningActions = (warnings) => warnings.map((warning) => ({ type: "response.warning", warning }));
354
+ function createCompositionSession() {
355
+ return {
356
+ acceptedSceneCount: 0,
357
+ rejectedSceneCount: 0,
358
+ planCompleted: false,
359
+ runtimeDurationLimited: false,
360
+ deferredForCloser: [],
361
+ closerCommitted: false,
362
+ plannerReportedLength: false,
363
+ finishReason: "stop"
364
+ };
365
+ }
366
+ function pace(scene, video, options, closerReserveSec) {
367
+ return paceScene(scene, {
368
+ previousScenes: video.scenes,
369
+ audio: video.audio,
370
+ maxDurationSec: options.maxDurationSec,
371
+ closerReserveSec,
372
+ getTemplatePacing: options.getTemplatePacing
373
+ });
374
+ }
375
+ function commitScene(session, result, includeQualityWarnings) {
376
+ return {
377
+ session: {
378
+ ...session,
379
+ acceptedSceneCount: session.acceptedSceneCount + 1
380
+ },
381
+ actions: [
382
+ ...warningActions(result.warnings),
383
+ ...includeQualityWarnings ? warningActions(createSceneQualityWarnings(result.scene)) : [],
384
+ { type: "scene.add", scene: result.scene }
385
+ ]
386
+ };
387
+ }
388
+ function completePlan(session, reportedFinishReason, requireCloser) {
389
+ const missingCloser = requireCloser && !session.closerCommitted;
390
+ const finishReason = session.runtimeDurationLimited ? "length" : reportedFinishReason != null && reportedFinishReason !== "stop" ? reportedFinishReason : missingCloser ? "other" : "stop";
391
+ return {
392
+ session: {
393
+ ...session,
394
+ planCompleted: true,
395
+ plannerReportedLength: reportedFinishReason === "length",
396
+ finishReason
397
+ },
398
+ actions: missingCloser ? [{ type: "response.warning", warning: createMissingCloserWarning() }] : []
399
+ };
400
+ }
401
+ function advanceComposition(session, part, video, options) {
402
+ if (session.planCompleted) {
403
+ throw new Error(part.type === "plan.complete" ? "The planner emitted plan.complete more than once" : "The planner emitted content after plan.complete");
404
+ }
405
+ if (part.type === "plan.complete") {
406
+ if (!session.pendingCloser) {
407
+ let next2 = { ...session, deferredForCloser: [] };
408
+ let currentVideo = video;
409
+ const actions2 = [];
410
+ for (const deferred of session.deferredForCloser) {
411
+ const recovered = pace(deferred, currentVideo, options, 0);
412
+ if (!recovered.scene) {
413
+ next2 = {
414
+ ...next2,
415
+ rejectedSceneCount: next2.rejectedSceneCount + 1,
416
+ runtimeDurationLimited: true
417
+ };
418
+ actions2.push(...warningActions(recovered.warnings));
419
+ continue;
420
+ }
421
+ const committed2 = commitScene(next2, { ...recovered, scene: recovered.scene }, true);
422
+ next2 = committed2.session;
423
+ actions2.push(...committed2.actions);
424
+ currentVideo = { ...currentVideo, scenes: [...currentVideo.scenes, recovered.scene] };
425
+ }
426
+ const completed2 = completePlan(next2, part.finishReason, options.requireCloser);
427
+ return {
428
+ session: completed2.session,
429
+ actions: [...actions2, ...completed2.actions]
430
+ };
431
+ }
432
+ let next = {
433
+ ...session,
434
+ rejectedSceneCount: session.rejectedSceneCount + session.deferredForCloser.length,
435
+ runtimeDurationLimited: session.runtimeDurationLimited || session.deferredForCloser.length > 0,
436
+ deferredForCloser: []
437
+ };
438
+ const actions = session.deferredForCloser.map((scene) => ({
439
+ type: "response.warning",
440
+ warning: createOmittedForCloserWarning(scene.id)
441
+ }));
442
+ const closer = pace(session.pendingCloser, video, options, 0);
443
+ if (!closer.scene) {
444
+ next = {
445
+ ...next,
446
+ rejectedSceneCount: next.rejectedSceneCount + 1,
447
+ runtimeDurationLimited: true
448
+ };
449
+ actions.push(...warningActions(closer.warnings));
450
+ const completed2 = completePlan(next, part.finishReason, options.requireCloser);
451
+ return {
452
+ session: completed2.session,
453
+ actions: [...actions, ...completed2.actions]
454
+ };
455
+ }
456
+ const committed = commitScene(next, { ...closer, scene: closer.scene }, false);
457
+ next = { ...committed.session, closerCommitted: true };
458
+ const completed = completePlan(next, part.finishReason, options.requireCloser);
459
+ return {
460
+ session: completed.session,
461
+ actions: [...actions, ...committed.actions, ...completed.actions]
462
+ };
463
+ }
464
+ const metadata = options.getTemplatePacing?.(part.scene.templateId);
465
+ const isAsk = metadata?.jobs?.includes("ask") === true;
466
+ const isPayoff = metadata?.jobs?.includes("payoff") === true;
467
+ if (part.placement === "closer" && metadata && !isAsk && !isPayoff) {
468
+ throw new Error(`Scene template ${part.scene.templateId} cannot be used as a closer`);
469
+ }
470
+ if (part.placement === "closer" || isAsk) {
471
+ if (session.pendingCloser) {
472
+ return {
473
+ session: {
474
+ ...session,
475
+ rejectedSceneCount: session.rejectedSceneCount + 1
476
+ },
477
+ actions: [{
478
+ type: "response.warning",
479
+ warning: createDuplicateCloserWarning()
480
+ }]
481
+ };
482
+ }
483
+ return { session: { ...session, pendingCloser: part.scene }, actions: [] };
484
+ }
485
+ if (session.deferredForCloser.length > 0) {
486
+ return {
487
+ session: { ...session, deferredForCloser: [...session.deferredForCloser, part.scene] },
488
+ actions: []
489
+ };
490
+ }
491
+ const paced = pace(
492
+ part.scene,
493
+ video,
494
+ options,
495
+ session.pendingCloser ? pendingCloserReserve(session.pendingCloser, options.getTemplatePacing) : options.closerReserveSec
496
+ );
497
+ if (!paced.scene) {
498
+ if (paced.warnings.some(({ code }) => code === "scene_omitted_for_closer")) {
499
+ return {
500
+ session: { ...session, deferredForCloser: [...session.deferredForCloser, part.scene] },
501
+ actions: []
502
+ };
503
+ }
504
+ return {
505
+ session: {
506
+ ...session,
507
+ rejectedSceneCount: session.rejectedSceneCount + 1,
508
+ runtimeDurationLimited: true
509
+ },
510
+ actions: warningActions(paced.warnings)
511
+ };
512
+ }
513
+ return commitScene(session, { ...paced, scene: paced.scene }, true);
514
+ }
515
+ function rejectCompositionScene(session) {
516
+ return {
517
+ ...session,
518
+ rejectedSceneCount: session.rejectedSceneCount + 1
519
+ };
520
+ }
521
+ function recoverComposition(session, video, options) {
522
+ if (!session.pendingCloser || session.closerCommitted || video.scenes.length === 0) {
523
+ return { session, actions: [] };
524
+ }
525
+ const closer = pace(session.pendingCloser, video, options, 0);
526
+ if (!closer.scene) {
527
+ return {
528
+ session,
529
+ actions: warningActions(closer.warnings)
530
+ };
531
+ }
532
+ const committed = commitScene(session, { ...closer, scene: closer.scene }, false);
533
+ return {
534
+ session: { ...committed.session, closerCommitted: true },
535
+ actions: committed.actions
536
+ };
537
+ }
538
+
352
539
  // src/server/composition-runtime.ts
353
540
  function invokeIsolated(callback, value) {
354
541
  if (!callback) return;
@@ -422,8 +609,6 @@ function createVideo(rawInput, options) {
422
609
  rejectResult = reject;
423
610
  });
424
611
  const startedAt = monotonicNow();
425
- let acceptedSceneCount = 0;
426
- let rejectedSceneCount = 0;
427
612
  let timeToFirstSceneMs;
428
613
  const { sink: lifecycle, settle: settleProviderLifecycle } = createProviderLifecycle();
429
614
  const reportedErrors = /* @__PURE__ */ new WeakSet();
@@ -434,6 +619,13 @@ function createVideo(rawInput, options) {
434
619
  };
435
620
  const eventSource = (async function* () {
436
621
  let state = createVideoState();
622
+ let composition = createCompositionSession();
623
+ const compositionOptions = {
624
+ maxDurationSec: input.maxDurationSec ?? 30,
625
+ closerReserveSec,
626
+ requireCloser: options.requireCloser ?? false,
627
+ getTemplatePacing: options.getTemplatePacing
628
+ };
437
629
  const emit = (event) => {
438
630
  state = applyVideoEvent(state, event);
439
631
  if (event.type === "response.warning") {
@@ -442,21 +634,23 @@ function createVideo(rawInput, options) {
442
634
  options.onEvent?.(event);
443
635
  return event;
444
636
  };
637
+ const emitCompositionAction = (action) => {
638
+ if (action.type === "response.warning") {
639
+ return emit(events.create("response.warning", { warning: action.warning }));
640
+ }
641
+ const event = emit(events.create("scene.add", {
642
+ scene: action.scene,
643
+ position: state.config?.scenes.length ?? 0
644
+ }));
645
+ timeToFirstSceneMs ??= Math.max(0, monotonicNow() - startedAt);
646
+ return event;
647
+ };
445
648
  const finish = (finalState) => {
446
649
  if (!settled) {
447
650
  settled = true;
448
651
  resolveResult(finalState);
449
652
  }
450
653
  };
451
- let planCompleted = false;
452
- let generatedSceneCount = 0;
453
- let runtimeDurationLimited = false;
454
- let pendingCloser;
455
- const deferredForCloser = [];
456
- let plannerReportedLength = false;
457
- let closerCommitted = false;
458
- let missingCloser = false;
459
- let finishReason = "stop";
460
654
  try {
461
655
  yield emit(events.create("response.start", {
462
656
  requestId,
@@ -484,8 +678,8 @@ function createVideo(rawInput, options) {
484
678
  const part = resolveSuppliedMediaPlanPart(parseVideoPlanPart(untrustedPart), input);
485
679
  attemptedScene = part.type === "scene.add";
486
680
  if (controller.signal.aborted) throw controller.signal.reason ?? new Error(abortReason);
487
- if (planCompleted && part.type !== "plan.complete") {
488
- throw new Error("The planner emitted content after plan.complete");
681
+ if (composition.planCompleted) {
682
+ throw new Error(part.type === "plan.complete" ? "The planner emitted plan.complete more than once" : "The planner emitted content after plan.complete");
489
683
  }
490
684
  if (part.type === "scene.add") {
491
685
  if (options.capabilities?.templates != null && !options.capabilities.templates.includes(part.scene.templateId)) {
@@ -495,138 +689,16 @@ function createVideo(rawInput, options) {
495
689
  input,
496
690
  previousScenes: state.config?.scenes ?? []
497
691
  });
498
- const templatePacing = options.getTemplatePacing?.(part.scene.templateId);
499
- const isAskCandidate = templatePacing?.jobs?.includes("ask") === true;
500
- const isPayoffCandidate = templatePacing?.jobs?.includes("payoff") === true;
501
- if (part.placement === "closer" && templatePacing && !isAskCandidate && !isPayoffCandidate) {
502
- throw new Error(`Scene template ${part.scene.templateId} cannot be used as a closer`);
503
- }
504
- const isCloserCandidate = part.placement === "closer" || isAskCandidate;
505
- if (isCloserCandidate) {
506
- if (pendingCloser) {
507
- rejectedSceneCount += 1;
508
- yield emit(events.create("response.warning", {
509
- warning: createDuplicateCloserWarning()
510
- }));
511
- } else {
512
- pendingCloser = part.scene;
513
- }
514
- continue;
515
- }
516
- if (deferredForCloser.length) {
517
- deferredForCloser.push(part.scene);
518
- continue;
519
- }
520
- const paced = paceScene(part.scene, {
521
- previousScenes: state.config?.scenes ?? [],
522
- audio: state.config?.audio,
523
- maxDurationSec: input.maxDurationSec ?? 30,
524
- closerReserveSec: pendingCloser ? pendingCloserReserve(pendingCloser, options.getTemplatePacing) : closerReserveSec,
525
- getTemplatePacing: options.getTemplatePacing
526
- });
527
- if (!paced.scene) {
528
- if (paced.warnings.some(({ code }) => code === "scene_omitted_for_closer")) {
529
- deferredForCloser.push(part.scene);
530
- continue;
531
- }
532
- for (const warning of paced.warnings) {
533
- yield emit(events.create("response.warning", { warning }));
534
- }
535
- runtimeDurationLimited = true;
536
- rejectedSceneCount += 1;
537
- continue;
538
- }
539
- const scene = paced.scene;
540
- for (const warning of paced.warnings) {
541
- yield emit(events.create("response.warning", { warning }));
542
- }
543
- for (const warning of createSceneQualityWarnings(scene)) {
544
- yield emit(events.create("response.warning", { warning }));
545
- }
546
- yield emit(events.create("scene.add", {
547
- scene,
548
- position: state.config?.scenes.length ?? 0
549
- }));
550
- generatedSceneCount += 1;
551
- acceptedSceneCount += 1;
552
- timeToFirstSceneMs ??= Math.max(0, monotonicNow() - startedAt);
553
- } else if (part.type === "plan.complete") {
554
- if (planCompleted) throw new Error("The planner emitted plan.complete more than once");
555
- if (pendingCloser) {
556
- if (deferredForCloser.length) runtimeDurationLimited = true;
557
- for (const deferred of deferredForCloser.splice(0)) {
558
- rejectedSceneCount += 1;
559
- yield emit(events.create("response.warning", {
560
- warning: createOmittedForCloserWarning(deferred.id)
561
- }));
562
- }
563
- const pacedCloser = paceScene(pendingCloser, {
564
- previousScenes: state.config?.scenes ?? [],
565
- audio: state.config?.audio,
566
- maxDurationSec: input.maxDurationSec ?? 30,
567
- closerReserveSec: 0,
568
- getTemplatePacing: options.getTemplatePacing
569
- });
570
- for (const warning of pacedCloser.warnings) {
571
- yield emit(events.create("response.warning", { warning }));
572
- }
573
- if (pacedCloser.scene) {
574
- yield emit(events.create("scene.add", {
575
- scene: pacedCloser.scene,
576
- position: state.config?.scenes.length ?? 0
577
- }));
578
- generatedSceneCount += 1;
579
- acceptedSceneCount += 1;
580
- timeToFirstSceneMs ??= Math.max(0, monotonicNow() - startedAt);
581
- closerCommitted = true;
582
- } else {
583
- runtimeDurationLimited = true;
584
- rejectedSceneCount += 1;
585
- }
586
- } else if (deferredForCloser.length) {
587
- for (const deferred of deferredForCloser.splice(0)) {
588
- const recovered = paceScene(deferred, {
589
- previousScenes: state.config?.scenes ?? [],
590
- audio: state.config?.audio,
591
- maxDurationSec: input.maxDurationSec ?? 30,
592
- closerReserveSec: 0,
593
- getTemplatePacing: options.getTemplatePacing
594
- });
595
- for (const warning of recovered.warnings) {
596
- yield emit(events.create("response.warning", { warning }));
597
- }
598
- if (!recovered.scene) {
599
- runtimeDurationLimited = true;
600
- rejectedSceneCount += 1;
601
- continue;
602
- }
603
- for (const warning of createSceneQualityWarnings(recovered.scene)) {
604
- yield emit(events.create("response.warning", { warning }));
605
- }
606
- yield emit(events.create("scene.add", {
607
- scene: recovered.scene,
608
- position: state.config?.scenes.length ?? 0
609
- }));
610
- generatedSceneCount += 1;
611
- acceptedSceneCount += 1;
612
- timeToFirstSceneMs ??= Math.max(0, monotonicNow() - startedAt);
613
- }
614
- }
615
- if (options.requireCloser && !closerCommitted) {
616
- missingCloser = true;
617
- yield emit(events.create("response.warning", {
618
- warning: createMissingCloserWarning()
619
- }));
620
- }
621
- planCompleted = true;
622
- const reportedFinishReason = part.finishReason ?? "stop";
623
- finishReason = runtimeDurationLimited ? "length" : reportedFinishReason !== "stop" ? reportedFinishReason : missingCloser ? "other" : "stop";
624
- plannerReportedLength = part.finishReason === "length";
625
- continue;
626
692
  }
693
+ if (!state.config) throw new Error("response.start did not initialize composition state");
694
+ const transition = advanceComposition(composition, part, state.config, compositionOptions);
695
+ for (const action of transition.actions) yield emitCompositionAction(action);
696
+ composition = transition.session;
627
697
  } catch (cause) {
628
698
  const error = cause instanceof Error ? cause : new Error(String(cause));
629
- if (attemptedScene || untrustedPart != null && typeof untrustedPart === "object" && untrustedPart.type === "scene.add") rejectedSceneCount += 1;
699
+ if (attemptedScene || untrustedPart != null && typeof untrustedPart === "object" && untrustedPart.type === "scene.add") {
700
+ composition = rejectCompositionScene(composition);
701
+ }
630
702
  reportError(error);
631
703
  if ((options.invalidPartBehavior ?? "fail") === "fail") throw error;
632
704
  yield emit(events.create("response.error", {
@@ -646,35 +718,35 @@ function createVideo(rawInput, options) {
646
718
  for (const warning of provider.warnings) {
647
719
  yield emit(events.create("response.warning", { warning }));
648
720
  }
649
- if (!planCompleted) throw new Error("The planner stream ended before plan.complete");
650
- if (plannerReportedLength && generatedSceneCount === 0) {
721
+ if (!composition.planCompleted) throw new Error("The planner stream ended before plan.complete");
722
+ if (composition.plannerReportedLength && composition.acceptedSceneCount === 0) {
651
723
  throw new Error("The planner was truncated before adding a generated scene");
652
724
  }
653
- if (plannerReportedLength) {
725
+ if (composition.plannerReportedLength) {
654
726
  yield emit(events.create("response.warning", {
655
727
  warning: createIncompletePlanWarning()
656
728
  }));
657
729
  }
658
- if (generatedSceneCount === 0 && requiresGeneratedScene) {
730
+ if (composition.acceptedSceneCount === 0 && requiresGeneratedScene) {
659
731
  throw new Error("The planner completed without adding a scene");
660
732
  }
661
733
  const snapshot = parseVideo(state.config);
662
734
  const completeEvent = emit(events.create("response.complete", {
663
- finishReason,
735
+ finishReason: composition.finishReason,
664
736
  snapshot,
665
737
  checksum: checksumVideo(snapshot)
666
738
  }));
667
739
  finish(state);
668
740
  const summary = {
669
- finishReason,
741
+ finishReason: composition.finishReason,
670
742
  ...provider.usage ? { usage: provider.usage } : {},
671
743
  ...provider.providerMetadata !== void 0 ? { providerMetadata: provider.providerMetadata } : {},
672
744
  ...provider.requestedModelId ? { requestedModelId: provider.requestedModelId } : {},
673
745
  ...provider.resolvedModelId ? { resolvedModelId: provider.resolvedModelId } : {},
674
746
  ...timeToFirstSceneMs != null ? { timeToFirstSceneMs } : {},
675
747
  totalDurationMs: Math.max(0, monotonicNow() - startedAt),
676
- acceptedSceneCount,
677
- rejectedSceneCount,
748
+ acceptedSceneCount: composition.acceptedSceneCount,
749
+ rejectedSceneCount: composition.rejectedSceneCount,
678
750
  videoDurationSec: snapshot.scenes.at(-1)?.timing.endTime ?? 0,
679
751
  warnings: state.warnings.map(cloneWarning)
680
752
  };
@@ -691,30 +763,16 @@ function createVideo(rawInput, options) {
691
763
  return;
692
764
  }
693
765
  try {
694
- if (pendingCloser && !closerCommitted && state.config?.scenes.length) {
695
- const pacedCloser = paceScene(pendingCloser, {
696
- previousScenes: state.config.scenes,
697
- audio: state.config.audio,
698
- maxDurationSec: input.maxDurationSec ?? 30,
699
- closerReserveSec: 0,
700
- getTemplatePacing: options.getTemplatePacing
701
- });
702
- for (const warning of pacedCloser.warnings) {
703
- yield emit(events.create("response.warning", { warning }));
704
- }
705
- if (pacedCloser.scene) {
706
- yield emit(events.create("scene.add", {
707
- scene: pacedCloser.scene,
708
- position: state.config.scenes.length
709
- }));
710
- generatedSceneCount += 1;
711
- acceptedSceneCount += 1;
712
- closerCommitted = true;
713
- }
766
+ if (state.config) {
767
+ const recovery = recoverComposition(composition, state.config, compositionOptions);
768
+ for (const action of recovery.actions) yield emitCompositionAction(action);
769
+ composition = recovery.session;
714
770
  }
715
771
  const provider = await settleProviderLifecycle();
716
772
  for (const warning of provider.warnings) {
717
- if (!state.warnings.some((existing) => existing.code === warning.code && existing.message === warning.message)) {
773
+ if (!state.warnings.some(
774
+ (existing) => existing.code === warning.code && existing.message === warning.message
775
+ )) {
718
776
  yield emit(events.create("response.warning", { warning }));
719
777
  }
720
778
  }
@@ -752,7 +810,6 @@ function createVideo(rawInput, options) {
752
810
  return {
753
811
  request,
754
812
  initialConfig,
755
- initialStyle: initialConfig.style,
756
813
  stream,
757
814
  result,
758
815
  abort(reason = "user cancelled") {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createVideo
3
- } from "./chunk-3ROGEU5A.js";
3
+ } from "./chunk-D6I2UQ5W.js";
4
4
  import "./chunk-E7CL7UPB.js";
5
5
  import "./chunk-FZHMQFG3.js";
6
6
  import "./chunk-G66Z5CWR.js";
package/dist/server.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-34O5BY6X.js";
4
4
  import {
5
5
  createVideo
6
- } from "./chunk-3ROGEU5A.js";
6
+ } from "./chunk-D6I2UQ5W.js";
7
7
  import "./chunk-E7CL7UPB.js";
8
8
  import {
9
9
  BUILTIN_SERVER_TEMPLATE_KIT,
package/dist/test.js CHANGED
@@ -233,7 +233,7 @@ async function* simulateVideoStream(parts, options = {}) {
233
233
  if (timeoutMs != null && (!Number.isFinite(timeoutMs) || timeoutMs < 0)) {
234
234
  throw new Error("Simulation timeoutMs must be a non-negative finite number");
235
235
  }
236
- const { createVideo } = await import("./compose-video-QJHKTOQ7.js");
236
+ const { createVideo } = await import("./compose-video-KMQEDOI7.js");
237
237
  const { createTextDeltaVideoPlanner } = await import("./text-stream-J6EDDJP4.js");
238
238
  const { BUILTIN_SERVER_TEMPLATE_KIT } = await import("./builtin-server-YHEZ2JRF.js");
239
239
  const { createTemplateSceneValidator } = await import("./validate-T7GBU2YF.js");
@@ -9,7 +9,7 @@
9
9
  },
10
10
  "dependencies": {
11
11
  "@ai-sdk/anthropic": "^4.0.41",
12
- "@vanillaskyai/video": "0.5.0",
12
+ "@vanillaskyai/video": "0.5.2",
13
13
  "ai": "^7.0.77",
14
14
  "next": "16.3.2",
15
15
  "react": "19.2.8",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vanillaskyai/video",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "Open-source video response SDK for personalized AI applications.",
5
5
  "keywords": [
6
6
  "generative-video",