@vanillaskyai/video 0.4.0 → 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.
- package/CHANGELOG.md +89 -0
- package/PUBLIC-API.md +12 -5
- package/README.md +14 -17
- package/dist/{builtin-server-BRTZN4Q7.js → builtin-server-YHEZ2JRF.js} +2 -2
- package/dist/check-runtime.js +1 -1
- package/dist/{chunk-BKF3A357.js → chunk-34O5BY6X.js} +1 -1
- package/dist/{chunk-LHFADNWJ.js → chunk-3ROGEU5A.js} +179 -342
- package/dist/{chunk-XAMUOSX7.js → chunk-3RV4YKB3.js} +0 -1
- package/dist/{chunk-GHJEAP4O.js → chunk-66MNRUCR.js} +1 -1
- package/dist/{chunk-EE6PK6XC.js → chunk-AOWSXU2K.js} +1 -1
- package/dist/{chunk-GR4I3MN2.js → chunk-EFL34TXF.js} +3 -3
- package/dist/{chunk-I5YWVQ5R.js → chunk-FVTMYS6U.js} +1 -1
- package/dist/{chunk-STIFILQG.js → chunk-FZHMQFG3.js} +46 -38
- package/dist/{chunk-JW47XCRL.js → chunk-G66Z5CWR.js} +30 -72
- package/dist/{chunk-RBQN3VSY.js → chunk-HVCPEAQF.js} +83 -1265
- package/dist/{chunk-N3KUA7VP.js → chunk-K6YVQODK.js} +4 -1
- package/dist/{chunk-WHPZED7X.js → chunk-PNS52FL4.js} +2 -5
- package/dist/{chunk-S5ZU5WUU.js → chunk-ZQQQAAKP.js} +2 -2
- package/dist/cli.js +20 -14
- package/dist/compose-video-QJHKTOQ7.js +13 -0
- package/dist/{events-D_1F6gw5.d.ts → events-BBP30j3c.d.ts} +3 -14
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/{kit-DLeCr3d0.d.ts → kit-DEG3fcaL.d.ts} +1 -1
- package/dist/react.d.ts +7 -6
- package/dist/react.js +1000 -349
- package/dist/server.d.ts +3 -3
- package/dist/server.js +18 -79
- package/dist/{system-prompt-NMYHLAMJ.js → system-prompt-4I6Z5HK3.js} +1 -1
- package/dist/template-catalog.js +1 -1
- package/dist/templates.d.ts +3 -3
- package/dist/templates.js +87 -4
- package/dist/test.d.ts +3 -27
- package/dist/test.js +3 -3
- package/dist/{text-stream-UPGUD2TD.js → text-stream-J6EDDJP4.js} +3 -3
- package/dist/{types-Cg0Onj7l.d.ts → types-BV9IqExh.d.ts} +1 -16
- package/docs/agent-integration.md +4 -3
- package/docs/concepts.md +4 -4
- package/docs/custom-templates.md +2 -2
- package/docs/getting-started.md +13 -18
- package/docs/integrate-nextjs.md +12 -8
- package/docs/live-channels.md +5 -2
- package/docs/media-and-audio.md +7 -0
- package/docs/persistence.md +1 -1
- package/docs/prompt-and-input.md +2 -2
- package/docs/reference/protocol.md +9 -12
- package/docs/reference/provider-adapters.md +5 -5
- package/docs/testing.md +1 -1
- package/examples/nextjs-quickstart/.env.example +2 -2
- package/examples/nextjs-quickstart/README.md +4 -1
- package/examples/nextjs-quickstart/package.json +4 -4
- package/examples/nextjs-quickstart/src/app/api/video/route.ts +4 -2
- package/package.json +8 -8
- package/dist/chunk-CR7FE7BW.js +0 -109
- package/dist/compose-video-6UQ33DOO.js +0 -13
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
# Video Response Protocol 0.
|
|
1
|
+
# Video Response Protocol 0.5
|
|
2
2
|
|
|
3
3
|
## Transport
|
|
4
4
|
|
|
5
5
|
The public transport is UTF-8 Server-Sent Events returned from a `POST` request.
|
|
6
6
|
Responses use `Content-Type: text/event-stream`,
|
|
7
|
-
`x-vanillasky-video-stream: 0.
|
|
7
|
+
`x-vanillasky-video-stream: 0.5`, `Cache-Control: no-cache, no-transform`, and
|
|
8
8
|
`X-Accel-Buffering: no`. Each block has an SSE `id`, the event name
|
|
9
9
|
`video`, and one JSON envelope in `data`. A final `data: [DONE]`
|
|
10
10
|
closes the transport after a terminal protocol event. Comment heartbeats do not
|
|
@@ -14,7 +14,7 @@ change protocol state.
|
|
|
14
14
|
|
|
15
15
|
```ts
|
|
16
16
|
type VideoEvent<T extends string, D> = {
|
|
17
|
-
protocolVersion: "0.
|
|
17
|
+
protocolVersion: "0.5";
|
|
18
18
|
runId: string;
|
|
19
19
|
sequence: number;
|
|
20
20
|
eventId: string; // exactly `${runId}:${sequence}`
|
|
@@ -33,10 +33,8 @@ midstream and events cannot follow a terminal state.
|
|
|
33
33
|
1. `response.start` establishes request ID, orientation, style, and negotiated
|
|
34
34
|
templates/extensions.
|
|
35
35
|
2. Optional `audio.set` occurs at most once and before the first scene.
|
|
36
|
-
3. `scene.add` appends one trusted-template scene
|
|
37
|
-
4.
|
|
38
|
-
A host must reject patches after the scene has played.
|
|
39
|
-
5. Exactly one terminal event ends the run:
|
|
36
|
+
3. `scene.add` appends one complete, immutable trusted-template scene.
|
|
37
|
+
4. Exactly one terminal event ends the run:
|
|
40
38
|
`response.complete`, terminal `response.error`, or `response.abort`.
|
|
41
39
|
|
|
42
40
|
`response.complete` carries the complete replayable `Video`, a
|
|
@@ -55,8 +53,8 @@ server callback.
|
|
|
55
53
|
|
|
56
54
|
### Duration ceiling
|
|
57
55
|
|
|
58
|
-
`maxDurationSec` is enforced by the runtime for scene additions
|
|
59
|
-
|
|
56
|
+
`maxDurationSec` is enforced by the runtime for scene additions. A final scene
|
|
57
|
+
may be shortened to the remaining duration. If a later
|
|
60
58
|
scene would start at the ceiling, the runtime preserves the partial response
|
|
61
59
|
and emits `response.complete` with `finishReason: "length"`; reaching the
|
|
62
60
|
declared maximum is normal completion, not a generation error. The value is a
|
|
@@ -73,9 +71,8 @@ change core video state.
|
|
|
73
71
|
## Planning boundary
|
|
74
72
|
|
|
75
73
|
LLMs do not emit public protocol envelopes. A server-only planner emits
|
|
76
|
-
validated `scene.add
|
|
77
|
-
|
|
78
|
-
snapshots, and checksums. Generated HTML, React, JavaScript, CSS, component
|
|
74
|
+
validated `scene.add` or `plan.complete` parts. The runtime assigns sequences,
|
|
75
|
+
IDs, terminal snapshots, and checksums. Generated HTML, React, JavaScript, CSS, component
|
|
79
76
|
source, audio events, protocol envelopes, and unknown part types are rejected.
|
|
80
77
|
|
|
81
78
|
A planner may add `placement: "closer"` to exactly one `scene.add`. The
|
|
@@ -14,21 +14,21 @@ community, AI Gateway, OpenAI-compatible, and custom providers.
|
|
|
14
14
|
Install the AI SDK plus the provider package your application chooses:
|
|
15
15
|
|
|
16
16
|
```bash
|
|
17
|
-
npm install ai @ai-sdk/
|
|
17
|
+
npm install ai @ai-sdk/anthropic
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
```ts
|
|
21
|
-
import {
|
|
21
|
+
import { anthropic } from "@ai-sdk/anthropic";
|
|
22
22
|
import { streamText } from "ai";
|
|
23
23
|
import { createVideoHandler } from "@vanillaskyai/video/server";
|
|
24
24
|
|
|
25
|
-
const modelId = process.env.
|
|
26
|
-
if (!modelId) throw new Error("Set
|
|
25
|
+
const modelId = process.env.ANTHROPIC_MODEL;
|
|
26
|
+
if (!modelId) throw new Error("Set ANTHROPIC_MODEL in the server environment");
|
|
27
27
|
|
|
28
28
|
export const POST = createVideoHandler({
|
|
29
29
|
authorize: verifySession,
|
|
30
30
|
streamText: ({ systemPrompt, userPrompt, signal }) => streamText({
|
|
31
|
-
model:
|
|
31
|
+
model: anthropic(modelId),
|
|
32
32
|
system: systemPrompt,
|
|
33
33
|
prompt: userPrompt,
|
|
34
34
|
abortSignal: signal,
|
package/docs/testing.md
CHANGED
|
@@ -28,7 +28,7 @@ describe("POST /api/video", () => {
|
|
|
28
28
|
const response = await handle(new Request("https://app.test/api/video", {
|
|
29
29
|
method: "POST",
|
|
30
30
|
body: JSON.stringify({
|
|
31
|
-
protocolVersion: "0.
|
|
31
|
+
protocolVersion: "0.5",
|
|
32
32
|
requestId: "route-test",
|
|
33
33
|
input: videoFixtures.portrait.input,
|
|
34
34
|
}),
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
ANTHROPIC_API_KEY=replace-me
|
|
2
|
+
ANTHROPIC_MODEL=replace-with-current-sonnet-model
|
|
@@ -12,7 +12,10 @@ npm run dev
|
|
|
12
12
|
```
|
|
13
13
|
<!-- verify:end -->
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
Before selecting **Generate video**, add your Anthropic API key and replace the
|
|
16
|
+
model placeholder with a current Claude Sonnet model ID available to your
|
|
17
|
+
account. Provider and model selection happen here, after SDK installation, so
|
|
18
|
+
VanillaSky never silently chooses either one.
|
|
16
19
|
|
|
17
20
|
Open <http://localhost:3000> and select **Generate video**.
|
|
18
21
|
|
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
"start": "next start"
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"@ai-sdk/
|
|
12
|
-
"@vanillaskyai/video": "0.
|
|
13
|
-
"ai": "^7.0.
|
|
14
|
-
"next": "16.3.
|
|
11
|
+
"@ai-sdk/anthropic": "^4.0.41",
|
|
12
|
+
"@vanillaskyai/video": "0.5.0",
|
|
13
|
+
"ai": "^7.0.77",
|
|
14
|
+
"next": "16.3.2",
|
|
15
15
|
"react": "19.2.8",
|
|
16
16
|
"react-dom": "19.2.8"
|
|
17
17
|
},
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { anthropic } from "@ai-sdk/anthropic";
|
|
2
2
|
import { streamText } from "ai";
|
|
3
3
|
import { createVideoHandler } from "@vanillaskyai/video/server";
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const modelId = process.env.ANTHROPIC_MODEL;
|
|
6
|
+
if (!modelId) throw new Error("Set ANTHROPIC_MODEL in the server environment");
|
|
7
|
+
const model = anthropic(modelId);
|
|
6
8
|
|
|
7
9
|
const handle = createVideoHandler({
|
|
8
10
|
authorize: (request) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vanillaskyai/video",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Open-source video response SDK for personalized AI applications.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"generative-video",
|
|
@@ -131,21 +131,21 @@
|
|
|
131
131
|
}
|
|
132
132
|
},
|
|
133
133
|
"devDependencies": {
|
|
134
|
-
"@anthropic-ai/sdk": "^0.
|
|
134
|
+
"@anthropic-ai/sdk": "^0.120.0",
|
|
135
135
|
"@eslint/js": "^9.39.1",
|
|
136
136
|
"@playwright/test": "1.62.0",
|
|
137
137
|
"@testing-library/react": "^16.3.0",
|
|
138
138
|
"@types/node": "^24.10.1",
|
|
139
|
-
"@types/react": "^
|
|
140
|
-
"@types/react-dom": "^
|
|
139
|
+
"@types/react": "^19.2.18",
|
|
140
|
+
"@types/react-dom": "^19.2.4",
|
|
141
141
|
"es-module-lexer": "^1.7.0",
|
|
142
142
|
"eslint": "^9.39.1",
|
|
143
143
|
"globals": "^16.5.0",
|
|
144
144
|
"jsdom": "^26.1.0",
|
|
145
145
|
"mdast-util-from-markdown": "2.0.3",
|
|
146
|
-
"openai": "^7.
|
|
147
|
-
"react": "^
|
|
148
|
-
"react-dom": "^
|
|
146
|
+
"openai": "^7.5.0",
|
|
147
|
+
"react": "^19.2.8",
|
|
148
|
+
"react-dom": "^19.2.8",
|
|
149
149
|
"tsup": "^8.5.1",
|
|
150
150
|
"tsx": "^4.23.12",
|
|
151
151
|
"typescript": "^5.9.3",
|
|
@@ -156,7 +156,7 @@
|
|
|
156
156
|
"esbuild": "^0.28.2"
|
|
157
157
|
},
|
|
158
158
|
"engines": {
|
|
159
|
-
"node": ">=
|
|
159
|
+
"node": ">=22"
|
|
160
160
|
},
|
|
161
161
|
"packageManager": "npm@11.17.0",
|
|
162
162
|
"publishConfig": {
|
package/dist/chunk-CR7FE7BW.js
DELETED
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
assertTemplateTransitionMetadata
|
|
3
|
-
} from "./chunk-2E6T633S.js";
|
|
4
|
-
|
|
5
|
-
// src/visual-system/catalog/kit.ts
|
|
6
|
-
function toMetadata(template) {
|
|
7
|
-
return {
|
|
8
|
-
id: template.id,
|
|
9
|
-
label: template.label,
|
|
10
|
-
description: template.description,
|
|
11
|
-
category: template.category,
|
|
12
|
-
family: template.family,
|
|
13
|
-
usesGlobalTextEffect: template.usesGlobalTextEffect,
|
|
14
|
-
usesGlobalTransition: template.usesGlobalTransition,
|
|
15
|
-
transitionTiming: template.transitionTiming,
|
|
16
|
-
usesGlobalBackgroundEffect: template.usesGlobalBackgroundEffect,
|
|
17
|
-
textCanvas: template.textCanvas,
|
|
18
|
-
jobs: template.jobs,
|
|
19
|
-
register: template.register,
|
|
20
|
-
useWhen: template.useWhen,
|
|
21
|
-
avoidWhen: template.avoidWhen,
|
|
22
|
-
schema: template.schema,
|
|
23
|
-
minDuration: template.minDuration,
|
|
24
|
-
preferredDuration: template.preferredDuration,
|
|
25
|
-
timing: template.timing
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
function isTemplateJsonSchema(value) {
|
|
29
|
-
if (typeof value !== "object" || value == null) return false;
|
|
30
|
-
const schema = value;
|
|
31
|
-
return schema.type === "object" && typeof schema.properties === "object" && schema.properties != null;
|
|
32
|
-
}
|
|
33
|
-
function defineTemplate(definition) {
|
|
34
|
-
if (!/^[A-Za-z][A-Za-z0-9_-]*$/.test(definition.id)) {
|
|
35
|
-
throw new Error(`Invalid template id: ${definition.id}`);
|
|
36
|
-
}
|
|
37
|
-
const suppliedSchema = "schema" in definition ? definition.schema : void 0;
|
|
38
|
-
const standard = suppliedSchema && "~standard" in suppliedSchema ? suppliedSchema["~standard"] : void 0;
|
|
39
|
-
const convertedSchema = standard?.jsonSchema ? standard.jsonSchema.input({ target: "draft-07" }) : suppliedSchema && !("~standard" in suppliedSchema) ? suppliedSchema : void 0;
|
|
40
|
-
if (standard && !standard.jsonSchema) {
|
|
41
|
-
throw new Error("Template schemas must expose Standard JSON Schema so the server registry can be generated safely");
|
|
42
|
-
}
|
|
43
|
-
if (!convertedSchema || !isTemplateJsonSchema(convertedSchema)) {
|
|
44
|
-
throw new Error("Template schema must describe a JSON object");
|
|
45
|
-
}
|
|
46
|
-
const schema = { ...convertedSchema, additionalProperties: convertedSchema.additionalProperties ?? false };
|
|
47
|
-
const transitionMetadata = {
|
|
48
|
-
id: definition.id,
|
|
49
|
-
usesGlobalTransition: definition.usesGlobalTransition ?? false,
|
|
50
|
-
transitionTiming: definition.transitionTiming
|
|
51
|
-
};
|
|
52
|
-
assertTemplateTransitionMetadata(transitionMetadata);
|
|
53
|
-
const { schema: _runtimeSchema, duration, ...definitionWithoutSchema } = definition;
|
|
54
|
-
return Object.freeze({
|
|
55
|
-
label: definition.id,
|
|
56
|
-
description: "",
|
|
57
|
-
usesGlobalTextEffect: false,
|
|
58
|
-
usesGlobalTransition: false,
|
|
59
|
-
usesGlobalBackgroundEffect: false,
|
|
60
|
-
...definitionWithoutSchema,
|
|
61
|
-
schema,
|
|
62
|
-
...duration == null ? {} : { preferredDuration: duration }
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
function createRenderTemplateRegistry(options) {
|
|
66
|
-
const byId = /* @__PURE__ */ new Map();
|
|
67
|
-
for (const template of options.templates) {
|
|
68
|
-
assertTemplateTransitionMetadata(template);
|
|
69
|
-
if (byId.has(template.id)) throw new Error(`Duplicate template id: ${template.id}`);
|
|
70
|
-
byId.set(template.id, template);
|
|
71
|
-
}
|
|
72
|
-
const templates = Object.freeze([...options.templates]);
|
|
73
|
-
if (options.metadata && options.metadata.map(({ id }) => id).join("\0") !== templates.map(({ id }) => id).join("\0")) {
|
|
74
|
-
throw new Error("Template metadata does not match render templates");
|
|
75
|
-
}
|
|
76
|
-
const metadata = new Map((options.metadata ?? templates.map(toMetadata)).map((template) => [template.id, template]));
|
|
77
|
-
const capabilities = { templates: templates.map(({ id }) => id) };
|
|
78
|
-
return Object.freeze({
|
|
79
|
-
templates,
|
|
80
|
-
capabilities,
|
|
81
|
-
getTemplate: (id) => byId.get(id),
|
|
82
|
-
getTemplateMetadata: (id) => metadata.get(id),
|
|
83
|
-
listTemplateMetadata: () => [...metadata.values()]
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
function overlayTemplateRegistry(defaults, customer) {
|
|
87
|
-
const customerTemplates = new Map(customer.templates.map((template) => [template.id, template]));
|
|
88
|
-
const defaultIds = new Set(defaults.templates.map(({ id }) => id));
|
|
89
|
-
const templates = [
|
|
90
|
-
...defaults.templates.map((template) => customerTemplates.get(template.id) ?? template),
|
|
91
|
-
...customer.templates.filter(({ id }) => !defaultIds.has(id))
|
|
92
|
-
];
|
|
93
|
-
const customerMetadataList = customer.listTemplateMetadata();
|
|
94
|
-
const customerMetadata = new Map(customerMetadataList.map((template) => [template.id, template]));
|
|
95
|
-
const metadata = [
|
|
96
|
-
...defaults.listTemplateMetadata().map((template) => customerMetadata.get(template.id) ?? template),
|
|
97
|
-
...customerMetadataList.filter(({ id }) => !defaultIds.has(id))
|
|
98
|
-
];
|
|
99
|
-
return createRenderTemplateRegistry({ templates, metadata });
|
|
100
|
-
}
|
|
101
|
-
function createTemplateRegistry(options) {
|
|
102
|
-
return createRenderTemplateRegistry({ templates: options.definitions });
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
export {
|
|
106
|
-
defineTemplate,
|
|
107
|
-
overlayTemplateRegistry,
|
|
108
|
-
createTemplateRegistry
|
|
109
|
-
};
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createVideo
|
|
3
|
-
} from "./chunk-LHFADNWJ.js";
|
|
4
|
-
import "./chunk-E7CL7UPB.js";
|
|
5
|
-
import "./chunk-STIFILQG.js";
|
|
6
|
-
import "./chunk-JW47XCRL.js";
|
|
7
|
-
import "./chunk-GHJEAP4O.js";
|
|
8
|
-
import "./chunk-EE6PK6XC.js";
|
|
9
|
-
import "./chunk-3O7OMMMF.js";
|
|
10
|
-
import "./chunk-XGRA2MUV.js";
|
|
11
|
-
export {
|
|
12
|
-
createVideo
|
|
13
|
-
};
|