@vanillaskyai/video 0.10.12 → 0.10.14

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,14 @@ VanillaSky follows semantic versioning. This changelog begins with the 0.1 beta.
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## 0.10.14
8
+
9
+ - Attach content-free record-shape diagnostics to rejected chat plans without accepting alternate formats or exposing model output.
10
+
11
+ ## 0.10.13
12
+
13
+ - Plan concise AI answers around the configured video-attempt budget, including the ending, while retaining complete authored narration and chapter recovery.
14
+
7
15
  ## 0.10.12
8
16
 
9
17
  - Use query context to choose between equally relevant Pexels subject matches in the starter, while preserving subject, activity and equipment priority.
package/dist/server.js CHANGED
@@ -892,6 +892,24 @@ function continueAfterOpening(narration, earlier) {
892
892
 
893
893
  // src/server/chat-shot-planner.ts
894
894
  var object = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
895
+ function planShapeError(value) {
896
+ const part = object(value);
897
+ const has = (key) => Boolean(part && Object.hasOwn(part, key));
898
+ const shape = value === null ? "null" : Array.isArray(value) ? "array" : typeof value;
899
+ const discriminator = !has("type") ? "missing" : part.type === "answer" || part.type === "shot" ? part.type : typeof part.type === "string" ? "other-string" : "non-string";
900
+ return new Error("Chat plan requires an answer brief followed by shots", { cause: {
901
+ code: "chat_plan_shape",
902
+ shape,
903
+ discriminator,
904
+ fields: {
905
+ opening: has("opening"),
906
+ subject: has("subject"),
907
+ development: has("development"),
908
+ visualDirection: has("visualDirection"),
909
+ ending: has("ending")
910
+ }
911
+ } });
912
+ }
895
913
  function text(value, maximum) {
896
914
  return typeof value === "string" && value.trim().length <= maximum ? value.trim() : "";
897
915
  }
@@ -993,7 +1011,8 @@ function createChatShotPlanner(options) {
993
1011
  const line = (raw) => {
994
1012
  const trimmed = raw.trim();
995
1013
  if (!trimmed || /^```(?:json|ndjson)?$/i.test(trimmed)) return;
996
- const part = object(JSON.parse(trimmed));
1014
+ const value = JSON.parse(trimmed);
1015
+ const part = object(value);
997
1016
  if (part?.type === "answer") {
998
1017
  if (brief) throw new Error("Chat answer brief was emitted more than once");
999
1018
  brief = { opening: text(part.opening, 300), subject: text(part.subject, 80), visualDirection: text(part.visualDirection, 600), development: text(part.development, 2e3) };
@@ -1007,7 +1026,7 @@ function createChatShotPlanner(options) {
1007
1026
  options.publishOpening(brief.opening ? { line: brief.opening, keyword: brief.subject } : void 0);
1008
1027
  return;
1009
1028
  }
1010
- if (part?.type !== "shot") throw new Error("Chat plan requires an answer brief followed by shots");
1029
+ if (part?.type !== "shot") throw planShapeError(value);
1011
1030
  if (!brief) throw new Error("Chat shot arrived before its answer brief");
1012
1031
  const shot = readShot(part, clipDurationSec, brief.subject);
1013
1032
  if (shot.narration === brief.ending?.narration) return;
@@ -1177,7 +1196,8 @@ function createVideoChatResponseInstructions(generatedVideoAvailable, openingAlr
1177
1196
  "Write a complete, intentful video answer as newline-delimited JSON. Match the user's form and tone; mixed intents can combine directions.",
1178
1197
  `First write one brief: {"type":"answer","intent":"explanation|story|comedy|imagination|practical","opening":"a short inviting spoken introduction of 6\u20139 words","subject":"literal visual subject","development":"the essential development of this answer","visualDirection":"consistent subjects, appearance and visual approach","ending":{"title":"short meaningful chapter title, at most 65 characters","narration":"the authored payoff","subject":"literal subject","action":"visible action or change","durationSec":${clipDurationSec},"continuity":"cut|continue"}}.`,
1179
1198
  `Then stream each developing shot on its own line: {"type":"shot","title":"short meaningful chapter title, at most 65 characters","narration":"the exact spoken beat","subject":"2\u20138 literal filmable words, at most 80 characters","action":"concrete subject, action or visible change and useful framing","durationSec":${clipDurationSec},"continuity":"cut|continue"}.`,
1180
- `The selected footage mode is ${mode === "pexels" ? "Pexels stock search: use literal filmable subjects; never imply stock proves a mechanism or depicts fictional events exactly" : `AI video, with at most ${generatedVideoAvailable ? maxGeneratedVideos : 0} generation attempts`}. Missing footage becomes the authored chapter title, with complete narration. Preserve the full answer rather than shortening it to fit credits. The host selects providers; do not make source choices.`,
1199
+ `The selected footage mode is ${mode === "pexels" ? "Pexels stock search: use literal filmable subjects; never imply stock proves a mechanism or depicts fictional events exactly" : `AI video, with at most ${generatedVideoAvailable ? maxGeneratedVideos : 0} generation attempts`}. Missing footage becomes the authored chapter title, with complete narration. Never truncate already-authored narration when footage fails. The host selects providers; do not make source choices.`,
1200
+ ...mode === "cinematic" ? [generatedVideoAvailable && maxGeneratedVideos > 0 ? `Plan at most ${maxGeneratedVideos} generated-video beats in total, including the saved ending. Use at most ${maxGeneratedVideos - 1} developing shot records; the ending uses the remaining beat. The opening chapter does not consume a generated clip. Before writing, choose a concise, complete treatment that fits this budget: combine related ideas, preserve essential facts and qualifiers, and finish the requested answer. Do not plan an extra chapter tail simply because generation attempts will run out.${maxGeneratedVideos === 1 ? " Put the complete answer in the saved ending, set development to an empty string, and emit no developing shot records." : ""}` : "No generated-video attempts are available; plan a complete chapter-led answer with a useful ending. Do not omit the answer to satisfy a zero clip budget."] : [],
1181
1201
  ...mode === "pexels" ? ["Stock queries must retain the essential subject, activity and distinguishing equipment in the shot's subject field, within its word limit. That field alone is the search query; action and visualDirection do not refine it. Prefer common observable actions with usable framing. Do not replace the required actor or activity with scenery, a different sport or a loosely related setting. Preserve fictional or comic narration, but do not depend on stock showing an exact invented expression or sequence; choose an illustrative action that supports the beat."] : [],
1182
1202
  ...mode === "pexels" ? ['Include stockSelection on every shot and the saved ending when the essential subject is known: "stockSelection":{"subject":"essential actor or object category","activity":"optional literal activity","equipment":"optional distinguishing equipment","exclude":["optional contradictory subject or activity"]}. Each phrase must be 1\u20134 words and at most 48 characters; exclude has at most 3 phrases. The essential subject is separate from the setting: do not use scenery, mood, camera framing or incidental appearance as the actor. Keep the search query broad enough to find footage; the optional hint helps select results without substituting a different actor or task. Use exclusions only for actual contradictions, not every detail absent from the story. Omit unknown fields or the whole hint rather than inventing an anchor. This is selection guidance, not verification that footage depicts the exact narration.'] : [],
1183
1203
  "For a very short answer whose ending alone fulfills the request, development may be empty and no developing shots are needed. Otherwise, develop the essential content before the ending.",
@@ -96,7 +96,10 @@ stream-reconnect contract.
96
96
 
97
97
  Set `maxGeneratedVideos` on `createVideoChatHandler` to a nonnegative safe integer
98
98
  (default `5`). This is a per-response generation attempt limit, including
99
- failures. AI mode uses authored chapter recovery after the allowance is reached;
99
+ failures. The default AI planner is instructed to fit a concise, complete answer
100
+ within that many visual beats, including the ending. This is model guidance, not
101
+ a guaranteed shot count: already-authored content is retained if the model
102
+ exceeds the budget. AI mode uses authored chapter recovery after the allowance is reached;
100
103
  `0` skips all generated footage. Pexels mode searches stock independently and
101
104
  never consumes the generated-video allowance. Retries inside your
102
105
  provider callback can incur additional charges; bound those separately. Never
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vanillaskyai/video",
3
- "version": "0.10.12",
3
+ "version": "0.10.14",
4
4
  "description": "Open-source voice-and-video chat SDK for AI applications.",
5
5
  "keywords": [
6
6
  "video-chat",
@@ -9,7 +9,7 @@
9
9
  "preview": "vite preview"
10
10
  },
11
11
  "dependencies": {
12
- "@vanillaskyai/video": "0.10.12",
12
+ "@vanillaskyai/video": "0.10.14",
13
13
  "react": "^19.2.8",
14
14
  "react-dom": "^19.2.8",
15
15
  "@ai-sdk/anthropic": "^3.0.0",