@vanillaskyai/video 0.4.1 → 0.5.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.
Files changed (53) hide show
  1. package/CHANGELOG.md +83 -0
  2. package/PUBLIC-API.md +12 -5
  3. package/README.md +14 -17
  4. package/dist/{builtin-server-BRTZN4Q7.js → builtin-server-YHEZ2JRF.js} +2 -2
  5. package/dist/check-runtime.js +1 -1
  6. package/dist/{chunk-BKF3A357.js → chunk-34O5BY6X.js} +1 -1
  7. package/dist/{chunk-LHFADNWJ.js → chunk-3ROGEU5A.js} +179 -342
  8. package/dist/{chunk-XAMUOSX7.js → chunk-3RV4YKB3.js} +0 -1
  9. package/dist/{chunk-GHJEAP4O.js → chunk-66MNRUCR.js} +1 -1
  10. package/dist/{chunk-EE6PK6XC.js → chunk-AOWSXU2K.js} +1 -1
  11. package/dist/{chunk-GR4I3MN2.js → chunk-EFL34TXF.js} +3 -3
  12. package/dist/{chunk-I5YWVQ5R.js → chunk-FVTMYS6U.js} +1 -1
  13. package/dist/{chunk-STIFILQG.js → chunk-FZHMQFG3.js} +46 -38
  14. package/dist/{chunk-JW47XCRL.js → chunk-G66Z5CWR.js} +30 -72
  15. package/dist/{chunk-RBQN3VSY.js → chunk-HVCPEAQF.js} +83 -1265
  16. package/dist/{chunk-N3KUA7VP.js → chunk-K6YVQODK.js} +4 -1
  17. package/dist/{chunk-WHPZED7X.js → chunk-PNS52FL4.js} +2 -5
  18. package/dist/{chunk-S5ZU5WUU.js → chunk-ZQQQAAKP.js} +2 -2
  19. package/dist/cli.js +20 -14
  20. package/dist/compose-video-QJHKTOQ7.js +13 -0
  21. package/dist/{events-D_1F6gw5.d.ts → events-BBP30j3c.d.ts} +3 -14
  22. package/dist/index.d.ts +2 -2
  23. package/dist/index.js +2 -2
  24. package/dist/{kit-DLeCr3d0.d.ts → kit-DEG3fcaL.d.ts} +1 -1
  25. package/dist/react.d.ts +6 -5
  26. package/dist/react.js +999 -348
  27. package/dist/server.d.ts +3 -3
  28. package/dist/server.js +18 -79
  29. package/dist/{system-prompt-NMYHLAMJ.js → system-prompt-4I6Z5HK3.js} +1 -1
  30. package/dist/template-catalog.js +1 -1
  31. package/dist/templates.d.ts +3 -3
  32. package/dist/templates.js +87 -4
  33. package/dist/test.d.ts +3 -27
  34. package/dist/test.js +3 -3
  35. package/dist/{text-stream-UPGUD2TD.js → text-stream-J6EDDJP4.js} +3 -3
  36. package/dist/{types-Cg0Onj7l.d.ts → types-BV9IqExh.d.ts} +1 -16
  37. package/docs/agent-integration.md +4 -3
  38. package/docs/concepts.md +4 -4
  39. package/docs/custom-templates.md +2 -2
  40. package/docs/getting-started.md +13 -18
  41. package/docs/integrate-nextjs.md +12 -8
  42. package/docs/persistence.md +1 -1
  43. package/docs/prompt-and-input.md +2 -2
  44. package/docs/reference/protocol.md +9 -12
  45. package/docs/reference/provider-adapters.md +5 -5
  46. package/docs/testing.md +1 -1
  47. package/examples/nextjs-quickstart/.env.example +2 -2
  48. package/examples/nextjs-quickstart/README.md +4 -1
  49. package/examples/nextjs-quickstart/package.json +4 -4
  50. package/examples/nextjs-quickstart/src/app/api/video/route.ts +4 -2
  51. package/package.json +8 -8
  52. package/dist/chunk-CR7FE7BW.js +0 -109
  53. package/dist/compose-video-6UQ33DOO.js +0 -13
@@ -3545,7 +3545,6 @@ function getBuiltinTemplateMetadata(id) {
3545
3545
 
3546
3546
  export {
3547
3547
  BUILTIN_TEMPLATE_CATALOG,
3548
- BUILTIN_TEMPLATE_CAPABILITIES,
3549
3548
  listBuiltinTemplateMetadata,
3550
3549
  getBuiltinTemplateMetadata
3551
3550
  };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  VIDEO_SCHEMA_VERSION
3
- } from "./chunk-EE6PK6XC.js";
3
+ } from "./chunk-AOWSXU2K.js";
4
4
  import {
5
5
  validateVideoBrand
6
6
  } from "./chunk-XGRA2MUV.js";
@@ -1,5 +1,5 @@
1
1
  // src/protocol/types.ts
2
- var VIDEO_PROTOCOL_VERSION = "0.4";
2
+ var VIDEO_PROTOCOL_VERSION = "0.5";
3
3
  var VIDEO_SCHEMA_VERSION = "0.1";
4
4
  function createVideoRequest(input, options) {
5
5
  return {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createVideoSystemPrompt
3
- } from "./chunk-WHPZED7X.js";
3
+ } from "./chunk-PNS52FL4.js";
4
4
  import {
5
5
  PACING_PLANNER_RULES
6
6
  } from "./chunk-3O7OMMMF.js";
@@ -108,7 +108,7 @@ function createTemplateSystemPrompt(options) {
108
108
  const ids = new Set(templates.map(({ id }) => id));
109
109
  const fields = new Set(templates.flatMap(({ schema }) => Object.keys(schema.properties)));
110
110
  const basePrompt = createVideoSystemPrompt(options.knowledgeMode).split("\n").filter(
111
- (line) => !line.includes("Never use media, ctaMedia, or reaction as the first generated body template") && !(resolverMediaAvailable && line.includes("Never expose a loading placeholder or unresolved media keyword")) && !(resolverMediaAvailable && line.includes("Prefer resolved media on scene.add. Use asset.patch")) && !(resolverMediaAvailable && line.includes('{"type":"asset.patch","sceneId":"stable-id"'))
111
+ (line) => !line.includes("Never use media, ctaMedia, or reaction as the first generated body template") && !(resolverMediaAvailable && line.includes("Never expose a loading placeholder or unresolved media keyword"))
112
112
  ).join("\n");
113
113
  const factRules = [
114
114
  ...ids.has("cardList") ? ["cardList needs two or three unused parallel facts"] : [],
@@ -142,7 +142,7 @@ ${options.basePrompt.trim()}` : void 0,
142
142
  mediaTemplates.length > 0 ? `For streaming startup, ${mediaTemplateNames} ${mediaTemplates.length === 1 ? "is" : "are"} forbidden as the first generated body template, even when mediaType is gradient. Start with a content-fit non-media template.` : void 0,
143
143
  listFields.length > 0 ? `For list variables (${listFields.join(", ")}), emit actual JSON arrays. Keep list labels to 1\u20133 words. Keep step labels to 1\u20132 words and at most 18 characters. Do not use pipes or newlines as list delimiters.` : void 0,
144
144
  fields.has("bars") ? 'For bars, emit an actual JSON array of 2\u20136 grounded objects with "label" and "value" fields. Use comparable units and avoid a largest-to-smallest positive ratio above 20. Do not encode bars as a string.' : void 0,
145
- resolverMediaAvailable ? "Prefer a relevant resolved image or video background on later media-capable scenes whenever the permitted factual basis names a concrete person, place, product context, activity, or outcome that can be depicted honestly. Emit mediaKeyword on scene.add as a specific 2\u20138 word semantic query of at most 80 characters; never put mediaKeyword in scene.patch or asset.patch. The host removes mediaKeyword before the scene reaches the browser and replaces it with an approved asset. Use mediaType=gradient for abstract, sensitive, unsafe, or visually ambiguous material. Never emit or invent mediaUrl or mediaPoster." : mediaTemplates.length > 0 ? `Use exact grounded values for required fields. mediaUrl must come verbatim from supplied input. Stock queries are not available. Do not select ${mediaTemplateNames} without a supplied mediaUrl; if another template has no mediaUrl, explicitly use mediaType=gradient. mediaType auto detects a URL, while gradient deliberately uses no external asset.` : "Use exact grounded values for required fields.",
145
+ resolverMediaAvailable ? "Prefer a relevant resolved image or video background on later media-capable scenes whenever the permitted factual basis names a concrete person, place, product context, activity, or outcome that can be depicted honestly. Emit mediaKeyword on scene.add as a specific 2\u20138 word semantic query of at most 80 characters. The host removes mediaKeyword before the complete scene reaches the browser and replaces it with an approved asset. Use mediaType=gradient for abstract, sensitive, unsafe, or visually ambiguous material. Never emit or invent mediaUrl or mediaPoster." : mediaTemplates.length > 0 ? `Use exact grounded values for required fields. mediaUrl must come verbatim from supplied input. Stock queries are not available. Do not select ${mediaTemplateNames} without a supplied mediaUrl; if another template has no mediaUrl, explicitly use mediaType=gradient. mediaType auto detects a URL, while gradient deliberately uses no external asset.` : "Use exact grounded values for required fields.",
146
146
  "Catalog guidance describes composition; it is not a factual source and must never replace the permitted factual basis.",
147
147
  JSON.stringify(plannerCatalog(templates, resolverMediaAvailable))
148
148
  ].filter((line) => line != null).join("\n");
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  BUILTIN_TEMPLATE_CATALOG
3
- } from "./chunk-XAMUOSX7.js";
3
+ } from "./chunk-3RV4YKB3.js";
4
4
  import {
5
5
  assertTemplateTransitionMetadata
6
6
  } from "./chunk-2E6T633S.js";
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  parseVideoEvent
3
- } from "./chunk-JW47XCRL.js";
3
+ } from "./chunk-G66Z5CWR.js";
4
4
  import {
5
5
  VIDEO_SCHEMA_VERSION
6
- } from "./chunk-EE6PK6XC.js";
6
+ } from "./chunk-AOWSXU2K.js";
7
7
 
8
8
  // src/protocol/stable-json.ts
9
9
  function stableJson(value) {
@@ -29,14 +29,13 @@ function createVideoState() {
29
29
  return {
30
30
  status: "idle",
31
31
  lastSequence: -1,
32
- sceneRevisions: {},
33
32
  appliedEvents: {},
34
33
  extensions: [],
35
34
  errors: [],
36
35
  warnings: []
37
36
  };
38
37
  }
39
- function applyVideoEvent(state, untrustedEvent, options = {}) {
38
+ function applyVideoEvent(state, untrustedEvent) {
40
39
  const event = parseVideoEvent(untrustedEvent);
41
40
  const signature = stableJson(event);
42
41
  const priorSignature = state.appliedEvents[event.eventId];
@@ -91,43 +90,12 @@ function applyVideoEvent(state, untrustedEvent, options = {}) {
91
90
  if (event.data.position !== state.config.scenes.length) {
92
91
  throw new Error(`scene.add position must be ${state.config.scenes.length}`);
93
92
  }
94
- if (event.data.revision !== 0) throw new Error("A new scene must start at revision 0");
95
- if (state.sceneRevisions[event.data.scene.id] != null) {
93
+ if (state.config.scenes.some(({ id }) => id === event.data.scene.id)) {
96
94
  throw new Error(`Scene ${event.data.scene.id} already exists`);
97
95
  }
98
96
  return {
99
97
  ...base,
100
- config: { ...state.config, scenes: [...state.config.scenes, event.data.scene] },
101
- sceneRevisions: { ...state.sceneRevisions, [event.data.scene.id]: 0 }
102
- };
103
- }
104
- if (event.type === "scene.patch" || event.type === "asset.patch") {
105
- const sceneId = event.data.sceneId;
106
- const currentRevision = state.sceneRevisions[sceneId];
107
- if (currentRevision == null) throw new Error(`Scene ${sceneId} does not exist`);
108
- if (options.mutableSceneIds && !options.mutableSceneIds.has(sceneId)) {
109
- throw new Error(`Cannot patch scene ${sceneId} after it has already played`);
110
- }
111
- if (event.data.revision !== currentRevision + 1) {
112
- throw new Error(`Scene ${sceneId} expected revision ${currentRevision + 1}`);
113
- }
114
- const sceneIndex = state.config.scenes.findIndex((item) => item.id === sceneId);
115
- const currentScene = state.config.scenes[sceneIndex];
116
- const nextScene = event.type === "scene.patch" ? {
117
- ...currentScene,
118
- ...event.data.patch,
119
- variables: event.data.patch.variables ? { ...currentScene.variables, ...event.data.patch.variables } : currentScene.variables,
120
- timing: event.data.patch.timing ? { ...currentScene.timing, ...event.data.patch.timing } : currentScene.timing
121
- } : {
122
- ...currentScene,
123
- variables: { ...currentScene.variables, ...event.data.variables }
124
- };
125
- const scenes = [...state.config.scenes];
126
- scenes[sceneIndex] = nextScene;
127
- return {
128
- ...base,
129
- config: { ...state.config, scenes },
130
- sceneRevisions: { ...state.sceneRevisions, [sceneId]: event.data.revision }
98
+ config: { ...state.config, scenes: [...state.config.scenes, event.data.scene] }
131
99
  };
132
100
  }
133
101
  if (event.type === "response.complete") {
@@ -180,8 +148,48 @@ function applyVideoEvent(state, untrustedEvent, options = {}) {
180
148
  throw new Error(`Reducer does not yet support ${event.type}`);
181
149
  }
182
150
 
151
+ // src/replayable-stream.ts
152
+ function createReplayableStream(source, onError) {
153
+ const buffered = [];
154
+ const waiters = /* @__PURE__ */ new Set();
155
+ let done = false;
156
+ let streamError;
157
+ const notify = () => {
158
+ for (const waiter of waiters) waiter();
159
+ waiters.clear();
160
+ };
161
+ void (async () => {
162
+ try {
163
+ for await (const item of source) {
164
+ buffered.push(item);
165
+ notify();
166
+ }
167
+ } catch (cause) {
168
+ streamError = cause;
169
+ onError(cause);
170
+ } finally {
171
+ done = true;
172
+ notify();
173
+ }
174
+ })();
175
+ return {
176
+ async *[Symbol.asyncIterator]() {
177
+ let index = 0;
178
+ while (true) {
179
+ while (index < buffered.length) yield buffered[index++];
180
+ if (done) {
181
+ if (streamError) throw streamError;
182
+ return;
183
+ }
184
+ await new Promise((resolve) => waiters.add(resolve));
185
+ }
186
+ }
187
+ };
188
+ }
189
+
183
190
  export {
184
191
  checksumVideo,
185
192
  createVideoState,
186
- applyVideoEvent
193
+ applyVideoEvent,
194
+ createReplayableStream
187
195
  };
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  VIDEO_PROTOCOL_VERSION,
3
3
  VIDEO_SCHEMA_VERSION
4
- } from "./chunk-EE6PK6XC.js";
4
+ } from "./chunk-AOWSXU2K.js";
5
5
  import {
6
6
  validateVideoBrand
7
7
  } from "./chunk-XGRA2MUV.js";
@@ -11,7 +11,6 @@ var VIDEO_WARNING_CATEGORIES = {
11
11
  scene_duration_adjusted: "readability",
12
12
  scene_omitted_unreadable: "readability",
13
13
  scene_omitted_for_closer: "readability",
14
- scene_patch_rejected_readability: "readability",
15
14
  chart_scale_imbalance: "readability",
16
15
  plan_incomplete: "provider",
17
16
  plan_missing_closer: "provider",
@@ -34,18 +33,7 @@ function safePublicDiagnostic(value, fallback) {
34
33
  return `${redacted.slice(0, MAX_PUBLIC_DIAGNOSTIC_LENGTH - 1).trimEnd()}\u2026`;
35
34
  }
36
35
 
37
- // src/protocol/validation.ts
38
- var CORE_EVENT_TYPES = /* @__PURE__ */ new Set([
39
- "response.start",
40
- "audio.set",
41
- "scene.add",
42
- "scene.patch",
43
- "asset.patch",
44
- "response.warning",
45
- "response.complete",
46
- "response.error",
47
- "response.abort"
48
- ]);
36
+ // src/protocol/json-validation.ts
49
37
  var DANGEROUS_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
50
38
  function record(value, path) {
51
39
  if (!value || typeof value !== "object" || Array.isArray(value)) {
@@ -63,17 +51,6 @@ function string(value, path) {
63
51
  if (typeof value !== "string" || !value.trim()) throw new Error(`${path} must be a non-empty string`);
64
52
  return value;
65
53
  }
66
- function publicDiagnostic(value, path) {
67
- const result = string(value, path);
68
- if (result.length > MAX_PUBLIC_DIAGNOSTIC_LENGTH) {
69
- throw new Error(`${path} must be at most ${MAX_PUBLIC_DIAGNOSTIC_LENGTH} characters`);
70
- }
71
- if (Array.from(result).some((character) => {
72
- const code = character.codePointAt(0) ?? 0;
73
- return code < 32 || code === 127;
74
- })) throw new Error(`${path} contains control characters`);
75
- return result;
76
- }
77
54
  function finite(value, path) {
78
55
  if (typeof value !== "number" || !Number.isFinite(value)) throw new Error(`${path} must be finite`);
79
56
  return value;
@@ -102,6 +79,28 @@ function jsonValue(value, path, seen = /* @__PURE__ */ new Set()) {
102
79
  }
103
80
  seen.delete(value);
104
81
  }
82
+
83
+ // src/protocol/validation.ts
84
+ var CORE_EVENT_TYPES = /* @__PURE__ */ new Set([
85
+ "response.start",
86
+ "audio.set",
87
+ "scene.add",
88
+ "response.warning",
89
+ "response.complete",
90
+ "response.error",
91
+ "response.abort"
92
+ ]);
93
+ function publicDiagnostic(value, path) {
94
+ const result = string(value, path);
95
+ if (result.length > MAX_PUBLIC_DIAGNOSTIC_LENGTH) {
96
+ throw new Error(`${path} must be at most ${MAX_PUBLIC_DIAGNOSTIC_LENGTH} characters`);
97
+ }
98
+ if (Array.from(result).some((character) => {
99
+ const code = character.codePointAt(0) ?? 0;
100
+ return code < 32 || code === 127;
101
+ })) throw new Error(`${path} contains control characters`);
102
+ return result;
103
+ }
105
104
  function timing(value, path) {
106
105
  const result = record(value, path);
107
106
  allowedKeys(result, [
@@ -137,22 +136,6 @@ function scene(value, path) {
137
136
  if (result.backgroundEffect != null) string(result.backgroundEffect, `${path}.backgroundEffect`);
138
137
  return result;
139
138
  }
140
- function scenePatch(value, path) {
141
- const patch = record(value, path);
142
- allowedKeys(patch, [
143
- "variables",
144
- "textArchetype",
145
- "backgroundEffect",
146
- "timing"
147
- ], path);
148
- if (patch.variables != null) {
149
- record(patch.variables, `${path}.variables`);
150
- jsonValue(patch.variables, `${path}.variables`);
151
- }
152
- if (patch.timing != null) timing(patch.timing, `${path}.timing`);
153
- if (patch.textArchetype != null) string(patch.textArchetype, `${path}.textArchetype`);
154
- if (patch.backgroundEffect != null) string(patch.backgroundEffect, `${path}.backgroundEffect`);
155
- }
156
139
  function capabilities(value, path) {
157
140
  const result = record(value, path);
158
141
  allowedKeys(result, ["templates", "extensions"], path);
@@ -267,21 +250,9 @@ function validateCoreData(type, value) {
267
250
  allowedKeys(data, ["audio"], "event.data");
268
251
  audio(data.audio, "event.data.audio");
269
252
  } else if (type === "scene.add") {
270
- allowedKeys(data, ["scene", "position", "revision"], "event.data");
253
+ allowedKeys(data, ["scene", "position"], "event.data");
271
254
  scene(data.scene, "event.data.scene");
272
255
  nonNegativeInteger(data.position, "event.data.position");
273
- nonNegativeInteger(data.revision, "event.data.revision");
274
- } else if (type === "scene.patch") {
275
- allowedKeys(data, ["sceneId", "revision", "patch"], "event.data");
276
- string(data.sceneId, "event.data.sceneId");
277
- nonNegativeInteger(data.revision, "event.data.revision");
278
- scenePatch(data.patch, "event.data.patch");
279
- } else if (type === "asset.patch") {
280
- allowedKeys(data, ["sceneId", "revision", "variables"], "event.data");
281
- string(data.sceneId, "event.data.sceneId");
282
- nonNegativeInteger(data.revision, "event.data.revision");
283
- record(data.variables, "event.data.variables");
284
- jsonValue(data.variables, "event.data.variables");
285
256
  } else if (type === "response.complete") {
286
257
  allowedKeys(data, ["finishReason", "snapshot", "checksum"], "event.data");
287
258
  if (!["stop", "length", "content-filter", "error", "other"].includes(String(data.finishReason))) {
@@ -354,29 +325,11 @@ function parseVideoPlanPart(value) {
354
325
  throw new Error("plan part.placement is unsupported");
355
326
  }
356
327
  scene(part.scene, "plan part.scene");
357
- } else if (type === "scene.patch") {
358
- allowedKeys(part, ["type", "sceneId", "patch"], "plan part");
359
- string(part.sceneId, "plan part.sceneId");
360
- scenePatch(part.patch, "plan part.patch");
361
- } else if (type === "asset.patch") {
362
- allowedKeys(part, ["type", "sceneId", "variables"], "plan part");
363
- string(part.sceneId, "plan part.sceneId");
364
- record(part.variables, "plan part.variables");
365
- jsonValue(part.variables, "plan part.variables");
366
328
  } else if (type === "plan.complete") {
367
329
  allowedKeys(part, ["type", "finishReason"], "plan part");
368
330
  if (part.finishReason != null && !["stop", "length", "content-filter", "other"].includes(String(part.finishReason))) {
369
331
  throw new Error("plan part.finishReason is unsupported");
370
332
  }
371
- } else if (type === "plan.error") {
372
- allowedKeys(part, ["type", "error"], "plan part");
373
- const error = record(part.error, "plan part.error");
374
- allowedKeys(error, ["message", "code", "recoverable"], "plan part.error");
375
- string(error.message, "plan part.error.message");
376
- if (error.code != null) string(error.code, "plan part.error.code");
377
- if (error.recoverable != null && typeof error.recoverable !== "boolean") {
378
- throw new Error("plan part.error.recoverable must be boolean");
379
- }
380
333
  } else {
381
334
  throw new Error(`plan part.type ${type} is unsupported`);
382
335
  }
@@ -385,6 +338,11 @@ function parseVideoPlanPart(value) {
385
338
 
386
339
  export {
387
340
  safePublicDiagnostic,
341
+ record,
342
+ allowedKeys,
343
+ string,
344
+ nonNegativeInteger,
345
+ jsonValue,
388
346
  parseVideoEvent,
389
347
  parseVideoPlanPart
390
348
  };