@ai-sdk/workflow 2.0.8 → 2.0.12

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.
@@ -0,0 +1,24 @@
1
+ import { experimental_startVideo, GetVideoStatusResult } from 'ai';
2
+
3
+ type StartVideoOptions = Parameters<typeof experimental_startVideo>[0];
4
+ /**
5
+ * Options for durable video generation in a workflow.
6
+ */
7
+ type WorkflowGenerateVideoOptions = Omit<StartVideoOptions, 'abortSignal' | 'webhookUrl'>;
8
+ /**
9
+ * A completed video generation result containing provider video data.
10
+ * Hosted videos remain URLs and are not downloaded automatically.
11
+ */
12
+ type WorkflowGenerateVideoResult = Extract<GetVideoStatusResult, {
13
+ status: 'completed';
14
+ }>;
15
+ /**
16
+ * Generates a video durably inside a workflow using a provider webhook.
17
+ *
18
+ * The workflow suspends without consuming compute until the provider calls the
19
+ * generated webhook URL. The returned video data is not downloaded, allowing
20
+ * the workflow to decide how to handle provider-hosted URLs.
21
+ */
22
+ declare function experimental_generateVideo(options: WorkflowGenerateVideoOptions): Promise<WorkflowGenerateVideoResult>;
23
+
24
+ export { type WorkflowGenerateVideoOptions, type WorkflowGenerateVideoResult, experimental_generateVideo };
package/dist/video.js ADDED
@@ -0,0 +1,80 @@
1
+ import {
2
+ __callDispose,
3
+ __using
4
+ } from "./chunk-UAWBPTDW.js";
5
+
6
+ // src/generate-video.ts
7
+ import {
8
+ experimental_getVideoStatus,
9
+ experimental_startVideo
10
+ } from "ai";
11
+ import { createWebhook, getStepMetadata } from "workflow";
12
+ async function startVideoStep(options) {
13
+ "use step";
14
+ var _a;
15
+ const hasIdempotencyKey = Object.keys((_a = options.headers) != null ? _a : {}).some(
16
+ (key) => key.toLowerCase() === "idempotency-key"
17
+ );
18
+ return experimental_startVideo({
19
+ ...options,
20
+ headers: {
21
+ ...options.headers,
22
+ ...hasIdempotencyKey ? {} : {
23
+ "idempotency-key": `aisdk_workflow_video_${getStepMetadata().stepId}`
24
+ }
25
+ }
26
+ });
27
+ }
28
+ startVideoStep.maxRetries = 0;
29
+ async function getVideoStatusStep(model, options) {
30
+ "use step";
31
+ return experimental_getVideoStatus(model, options);
32
+ }
33
+ getVideoStatusStep.maxRetries = 0;
34
+ async function experimental_generateVideo(options) {
35
+ if (typeof options.model !== "string" && (options.model.specificationVersion !== "v4" || options.model.handleWebhookOption == null)) {
36
+ throw new Error(
37
+ "Workflow video generation requires a model with native webhook support."
38
+ );
39
+ }
40
+ let operation;
41
+ let startWarnings;
42
+ {
43
+ var _stack = [];
44
+ try {
45
+ const webhook = __using(_stack, createWebhook());
46
+ const startResult = await startVideoStep({
47
+ ...options,
48
+ webhookUrl: webhook.url
49
+ });
50
+ operation = startResult.operation;
51
+ startWarnings = startResult.warnings;
52
+ await webhook;
53
+ } catch (_) {
54
+ var _error = _, _hasError = true;
55
+ } finally {
56
+ __callDispose(_stack, _error, _hasError);
57
+ }
58
+ }
59
+ const statusResult = await getVideoStatusStep(options.model, {
60
+ operation,
61
+ headers: options.headers,
62
+ maxRetries: options.maxRetries
63
+ });
64
+ if (statusResult.status === "error") {
65
+ throw new Error(statusResult.error);
66
+ }
67
+ if (statusResult.status !== "completed") {
68
+ throw new Error(
69
+ "Video generation did not complete after webhook notification."
70
+ );
71
+ }
72
+ return {
73
+ ...statusResult,
74
+ warnings: [...startWarnings, ...statusResult.warnings]
75
+ };
76
+ }
77
+ export {
78
+ experimental_generateVideo
79
+ };
80
+ //# sourceMappingURL=video.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/generate-video.ts"],"sourcesContent":["import {\n experimental_getVideoStatus,\n experimental_startVideo,\n type GetVideoStatusResult,\n type StartVideoResult,\n} from 'ai';\nimport { createWebhook, getStepMetadata } from 'workflow';\n\ntype StartVideoOptions = Parameters<typeof experimental_startVideo>[0];\ntype GetVideoStatusOptions = Parameters<typeof experimental_getVideoStatus>[1];\n\n/**\n * Options for durable video generation in a workflow.\n */\nexport type WorkflowGenerateVideoOptions = Omit<\n StartVideoOptions,\n 'abortSignal' | 'webhookUrl'\n>;\n\n/**\n * A completed video generation result containing provider video data.\n * Hosted videos remain URLs and are not downloaded automatically.\n */\nexport type WorkflowGenerateVideoResult = Extract<\n GetVideoStatusResult,\n { status: 'completed' }\n>;\n\nasync function startVideoStep(\n options: StartVideoOptions,\n): Promise<StartVideoResult> {\n 'use step';\n\n const hasIdempotencyKey = Object.keys(options.headers ?? {}).some(\n key => key.toLowerCase() === 'idempotency-key',\n );\n\n return experimental_startVideo({\n ...options,\n headers: {\n ...options.headers,\n ...(hasIdempotencyKey\n ? {}\n : {\n 'idempotency-key': `aisdk_workflow_video_${getStepMetadata().stepId}`,\n }),\n },\n });\n}\n\nstartVideoStep.maxRetries = 0;\n\nasync function getVideoStatusStep(\n model: StartVideoOptions['model'],\n options: GetVideoStatusOptions,\n): Promise<GetVideoStatusResult> {\n 'use step';\n\n return experimental_getVideoStatus(model, options);\n}\n\ngetVideoStatusStep.maxRetries = 0;\n\n/**\n * Generates a video durably inside a workflow using a provider webhook.\n *\n * The workflow suspends without consuming compute until the provider calls the\n * generated webhook URL. The returned video data is not downloaded, allowing\n * the workflow to decide how to handle provider-hosted URLs.\n */\nexport async function experimental_generateVideo(\n options: WorkflowGenerateVideoOptions,\n): Promise<WorkflowGenerateVideoResult> {\n if (\n typeof options.model !== 'string' &&\n (options.model.specificationVersion !== 'v4' ||\n options.model.handleWebhookOption == null)\n ) {\n throw new Error(\n 'Workflow video generation requires a model with native webhook support.',\n );\n }\n\n let operation: StartVideoResult['operation'];\n let startWarnings: StartVideoResult['warnings'];\n\n {\n using webhook = createWebhook();\n\n const startResult = await startVideoStep({\n ...options,\n webhookUrl: webhook.url,\n });\n\n operation = startResult.operation;\n startWarnings = startResult.warnings;\n await webhook;\n }\n\n const statusResult = await getVideoStatusStep(options.model, {\n operation,\n headers: options.headers,\n maxRetries: options.maxRetries,\n });\n\n if (statusResult.status === 'error') {\n throw new Error(statusResult.error);\n }\n\n if (statusResult.status !== 'completed') {\n throw new Error(\n 'Video generation did not complete after webhook notification.',\n );\n }\n\n return {\n ...statusResult,\n warnings: [...startWarnings, ...statusResult.warnings],\n };\n}\n"],"mappings":";;;;;;AAAA;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AACP,SAAS,eAAe,uBAAuB;AAsB/C,eAAe,eACb,SAC2B;AAC3B;AA/BF;AAiCE,QAAM,oBAAoB,OAAO,MAAK,aAAQ,YAAR,YAAmB,CAAC,CAAC,EAAE;AAAA,IAC3D,SAAO,IAAI,YAAY,MAAM;AAAA,EAC/B;AAEA,SAAO,wBAAwB;AAAA,IAC7B,GAAG;AAAA,IACH,SAAS;AAAA,MACP,GAAG,QAAQ;AAAA,MACX,GAAI,oBACA,CAAC,IACD;AAAA,QACE,mBAAmB,wBAAwB,gBAAgB,EAAE,MAAM;AAAA,MACrE;AAAA,IACN;AAAA,EACF,CAAC;AACH;AAEA,eAAe,aAAa;AAE5B,eAAe,mBACb,OACA,SAC+B;AAC/B;AAEA,SAAO,4BAA4B,OAAO,OAAO;AACnD;AAEA,mBAAmB,aAAa;AAShC,eAAsB,2BACpB,SACsC;AACtC,MACE,OAAO,QAAQ,UAAU,aACxB,QAAQ,MAAM,yBAAyB,QACtC,QAAQ,MAAM,uBAAuB,OACvC;AACA,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,MAAI;AACJ,MAAI;AAEJ;AACE;AAAA;AAAA,YAAM,UAAU,8BAAc;AAE9B,YAAM,cAAc,MAAM,eAAe;AAAA,QACvC,GAAG;AAAA,QACH,YAAY,QAAQ;AAAA,MACtB,CAAC;AAED,kBAAY,YAAY;AACxB,sBAAgB,YAAY;AAC5B,YAAM;AAAA,aATN;AAAA;AAAA;AAAA;AAAA;AAAA,EAUF;AAEA,QAAM,eAAe,MAAM,mBAAmB,QAAQ,OAAO;AAAA,IAC3D;AAAA,IACA,SAAS,QAAQ;AAAA,IACjB,YAAY,QAAQ;AAAA,EACtB,CAAC;AAED,MAAI,aAAa,WAAW,SAAS;AACnC,UAAM,IAAI,MAAM,aAAa,KAAK;AAAA,EACpC;AAEA,MAAI,aAAa,WAAW,aAAa;AACvC,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,GAAG;AAAA,IACH,UAAU,CAAC,GAAG,eAAe,GAAG,aAAa,QAAQ;AAAA,EACvD;AACF;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/workflow",
3
- "version": "2.0.8",
3
+ "version": "2.0.12",
4
4
  "type": "module",
5
5
  "description": "WorkflowAgent for building AI agents with AI SDK",
6
6
  "license": "Apache-2.0",
@@ -23,23 +23,28 @@
23
23
  "types": "./dist/index.d.ts",
24
24
  "import": "./dist/index.js",
25
25
  "default": "./dist/index.js"
26
+ },
27
+ "./video": {
28
+ "types": "./dist/video.d.ts",
29
+ "import": "./dist/video.js",
30
+ "default": "./dist/video.js"
26
31
  }
27
32
  },
28
33
  "dependencies": {
29
- "ajv": "^8.20.0",
30
- "@ai-sdk/provider": "4.0.7",
31
- "@ai-sdk/provider-utils": "5.0.29",
32
- "ai": "7.0.78"
34
+ "@ai-sdk/provider": "4.0.8",
35
+ "@ai-sdk/provider-utils": "5.0.32",
36
+ "ai": "7.0.82",
37
+ "ajv": "^8.20.0"
33
38
  },
34
39
  "devDependencies": {
35
40
  "@types/node": "22.19.19",
41
+ "@vercel/ai-tsconfig": "0.0.0",
36
42
  "@workflow/vitest": "5.0.0-beta.42",
37
43
  "tsup": "^8.5.1",
38
44
  "typescript": "5.8.3",
39
45
  "vitest": "4.1.6",
40
46
  "workflow": "5.0.0-beta.42",
41
- "zod": "4.4.3",
42
- "@vercel/ai-tsconfig": "0.0.0"
47
+ "zod": "4.4.3"
43
48
  },
44
49
  "peerDependencies": {
45
50
  "workflow": "^5.0.0-beta.42",
@@ -0,0 +1,120 @@
1
+ import {
2
+ experimental_getVideoStatus,
3
+ experimental_startVideo,
4
+ type GetVideoStatusResult,
5
+ type StartVideoResult,
6
+ } from 'ai';
7
+ import { createWebhook, getStepMetadata } from 'workflow';
8
+
9
+ type StartVideoOptions = Parameters<typeof experimental_startVideo>[0];
10
+ type GetVideoStatusOptions = Parameters<typeof experimental_getVideoStatus>[1];
11
+
12
+ /**
13
+ * Options for durable video generation in a workflow.
14
+ */
15
+ export type WorkflowGenerateVideoOptions = Omit<
16
+ StartVideoOptions,
17
+ 'abortSignal' | 'webhookUrl'
18
+ >;
19
+
20
+ /**
21
+ * A completed video generation result containing provider video data.
22
+ * Hosted videos remain URLs and are not downloaded automatically.
23
+ */
24
+ export type WorkflowGenerateVideoResult = Extract<
25
+ GetVideoStatusResult,
26
+ { status: 'completed' }
27
+ >;
28
+
29
+ async function startVideoStep(
30
+ options: StartVideoOptions,
31
+ ): Promise<StartVideoResult> {
32
+ 'use step';
33
+
34
+ const hasIdempotencyKey = Object.keys(options.headers ?? {}).some(
35
+ key => key.toLowerCase() === 'idempotency-key',
36
+ );
37
+
38
+ return experimental_startVideo({
39
+ ...options,
40
+ headers: {
41
+ ...options.headers,
42
+ ...(hasIdempotencyKey
43
+ ? {}
44
+ : {
45
+ 'idempotency-key': `aisdk_workflow_video_${getStepMetadata().stepId}`,
46
+ }),
47
+ },
48
+ });
49
+ }
50
+
51
+ startVideoStep.maxRetries = 0;
52
+
53
+ async function getVideoStatusStep(
54
+ model: StartVideoOptions['model'],
55
+ options: GetVideoStatusOptions,
56
+ ): Promise<GetVideoStatusResult> {
57
+ 'use step';
58
+
59
+ return experimental_getVideoStatus(model, options);
60
+ }
61
+
62
+ getVideoStatusStep.maxRetries = 0;
63
+
64
+ /**
65
+ * Generates a video durably inside a workflow using a provider webhook.
66
+ *
67
+ * The workflow suspends without consuming compute until the provider calls the
68
+ * generated webhook URL. The returned video data is not downloaded, allowing
69
+ * the workflow to decide how to handle provider-hosted URLs.
70
+ */
71
+ export async function experimental_generateVideo(
72
+ options: WorkflowGenerateVideoOptions,
73
+ ): Promise<WorkflowGenerateVideoResult> {
74
+ if (
75
+ typeof options.model !== 'string' &&
76
+ (options.model.specificationVersion !== 'v4' ||
77
+ options.model.handleWebhookOption == null)
78
+ ) {
79
+ throw new Error(
80
+ 'Workflow video generation requires a model with native webhook support.',
81
+ );
82
+ }
83
+
84
+ let operation: StartVideoResult['operation'];
85
+ let startWarnings: StartVideoResult['warnings'];
86
+
87
+ {
88
+ using webhook = createWebhook();
89
+
90
+ const startResult = await startVideoStep({
91
+ ...options,
92
+ webhookUrl: webhook.url,
93
+ });
94
+
95
+ operation = startResult.operation;
96
+ startWarnings = startResult.warnings;
97
+ await webhook;
98
+ }
99
+
100
+ const statusResult = await getVideoStatusStep(options.model, {
101
+ operation,
102
+ headers: options.headers,
103
+ maxRetries: options.maxRetries,
104
+ });
105
+
106
+ if (statusResult.status === 'error') {
107
+ throw new Error(statusResult.error);
108
+ }
109
+
110
+ if (statusResult.status !== 'completed') {
111
+ throw new Error(
112
+ 'Video generation did not complete after webhook notification.',
113
+ );
114
+ }
115
+
116
+ return {
117
+ ...statusResult,
118
+ warnings: [...startWarnings, ...statusResult.warnings],
119
+ };
120
+ }
@@ -2,12 +2,12 @@ import type { UIMessageChunk } from 'ai';
2
2
 
3
3
  /**
4
4
  * Tracks, for one part family (text or reasoning), which part ids are open or
5
- * ended within the current step.
5
+ * have ended since the latest step boundary.
6
6
  */
7
7
  interface PartFrameState {
8
- /** A `*-start` was seen and not yet ended in the current step. */
8
+ /** A `*-start` was seen and has not yet received its explicit `*-end`. */
9
9
  open: Set<string>;
10
- /** A part that was opened and ended in the current step. */
10
+ /** A part that ended since the latest step boundary. */
11
11
  ended: Set<string>;
12
12
  }
13
13
 
@@ -18,7 +18,7 @@ const newPartFrameState = (): PartFrameState => ({
18
18
 
19
19
  /**
20
20
  * Repairs the framing for a single `*-start` / `*-delta` / `*-end` chunk
21
- * against the running per-step state, yielding the chunks the consumer should
21
+ * against the running framing state, yielding the chunks the consumer should
22
22
  * see. Text and reasoning parts share this logic (`startType` differentiates
23
23
  * the synthesized start chunk).
24
24
  *
@@ -32,7 +32,8 @@ function* repairPart(
32
32
  startType: 'text-start' | 'reasoning-start',
33
33
  ): Generator<UIMessageChunk> {
34
34
  if (kind === 'start') {
35
- // Drop a duplicate/replayed start for a part already framed this step.
35
+ // Drop a duplicate/replayed start for a part that is still open or has
36
+ // already ended since the latest step boundary.
36
37
  if (state.open.has(id) || state.ended.has(id)) {
37
38
  return;
38
39
  }
@@ -70,10 +71,9 @@ function* repairPart(
70
71
  * whole turn. Two properties of the durable streaming model make that error
71
72
  * reachable:
72
73
  *
73
- * - A workflow run owns a single shared stream, and the consumer resets its
74
- * active-part maps on every `finish-step`. Multi-step turns reuse the same
75
- * part id (commonly `"0"`) in each step, so a single dropped or duplicated
76
- * `*-start` across a step boundary orphans the rest of that step's content.
74
+ * - A workflow run owns a single shared stream. Multi-step turns can reuse the
75
+ * same part id (commonly `"0"`), so a dropped or duplicated `*-start` can
76
+ * orphan the rest of that part's content.
77
77
  * - The same stream is read across reconnects, and a stream-producing step can
78
78
  * run more than once (retry/redelivery, or the concurrent-worker duplication
79
79
  * tracked in vercel/workflow#2331 and #2039). Either can interleave or
@@ -86,11 +86,12 @@ function* repairPart(
86
86
  *
87
87
  * ## What it does
88
88
  *
89
- * Mirrors the consumer's part-lifetime state machine, per part type, per step:
90
- * - resets tracking on `finish-step` (exactly where the consumer resets);
89
+ * Mirrors the consumer's explicit-end part-lifetime state machine per part type:
90
+ * - keeps open parts active across `finish-step`, while allowing ended ids to
91
+ * be reused by a later step;
91
92
  * - synthesizes a missing `*-start` when an orphaned `*-delta`/`*-end` arrives;
92
93
  * - drops a re-delivered `*-start`/`*-delta`/`*-end` for a part already
93
- * open or ended in the current step (reconnect/replay overlap).
94
+ * open or ended since the latest step boundary (reconnect/replay overlap).
94
95
  *
95
96
  * A well-formed stream passes through unchanged.
96
97
  *
@@ -126,11 +127,10 @@ export async function* normalizeUIMessageStreamParts(
126
127
  break;
127
128
 
128
129
  case 'finish-step':
129
- // The consumer clears its active-part maps here, so part ids may be
130
- // legitimately reused in the next step. Reset to match.
131
- text.open.clear();
130
+ // Open parts are closed only by explicit end chunks. A finish-step can
131
+ // come from another interleaved execution while a part is still open.
132
+ // Ended ids may be reused by the next step.
132
133
  text.ended.clear();
133
- reasoning.open.clear();
134
134
  reasoning.ended.clear();
135
135
  yield chunk;
136
136
  break;
@@ -27,6 +27,10 @@ import Ajv from 'ajv';
27
27
  export type SerializableToolDef = {
28
28
  description?: string;
29
29
  inputSchema: JSONSchema7;
30
+ /** Input examples forwarded to providers that support them. */
31
+ inputExamples?: Array<{ input: unknown }>;
32
+ /** Provider-specific options attached to the tool definition. */
33
+ providerOptions?: Tool['providerOptions'];
30
34
  /** Present on provider tools (e.g. anthropic.tools.webSearch). */
31
35
  type?: 'provider';
32
36
  /** Provider tool is executed by the provider. */
@@ -38,10 +42,9 @@ export type SerializableToolDef = {
38
42
  };
39
43
 
40
44
  /**
41
- * Converts a ToolSet (with zod/standard schemas and execute functions) to a
42
- * serializable record of tool definitions. Only description and inputSchema
43
- * (as JSON Schema) are preserved execute functions are stripped since they
44
- * run outside the step.
45
+ * Converts a ToolSet (with Zod/standard schemas and execute functions) to a
46
+ * serializable record of tool definitions. Execution functions and callbacks
47
+ * are stripped because they run outside the step.
45
48
  */
46
49
  export function serializeToolSet<TOOLS extends ToolSet>(
47
50
  tools: TOOLS,
@@ -63,6 +66,8 @@ export function serializeToolSet<TOOLS extends ToolSet>(
63
66
  experimental_sandbox: sandbox,
64
67
  }),
65
68
  inputSchema: asSchema(t.inputSchema).jsonSchema as JSONSchema7,
69
+ inputExamples: t.inputExamples,
70
+ providerOptions: t.providerOptions,
66
71
  };
67
72
 
68
73
  // Preserve provider tool identity so the Gateway can recognize
@@ -125,6 +130,7 @@ export function resolveSerializableTools(
125
130
  args: t.args ?? {},
126
131
  isProviderExecuted: t.isProviderExecuted ?? false,
127
132
  inputSchema: jsonSchema(t.inputSchema),
133
+ providerOptions: t.providerOptions,
128
134
  }),
129
135
  ];
130
136
  }
@@ -135,6 +141,8 @@ export function resolveSerializableTools(
135
141
  name,
136
142
  tool({
137
143
  description: t.description,
144
+ inputExamples: t.inputExamples,
145
+ providerOptions: t.providerOptions,
138
146
  inputSchema: jsonSchema(t.inputSchema, {
139
147
  validate: value => {
140
148
  if (validateFn(value)) {
@@ -0,0 +1,87 @@
1
+ import type { Experimental_VideoModelV4 } from '@ai-sdk/provider';
2
+ import {
3
+ WORKFLOW_DESERIALIZE,
4
+ WORKFLOW_SERIALIZE,
5
+ } from '@ai-sdk/provider-utils';
6
+ import { resumeWebhook } from 'workflow/api';
7
+
8
+ class SerializableVideoModel implements Experimental_VideoModelV4 {
9
+ readonly specificationVersion = 'v4';
10
+ readonly provider = 'workflow-test';
11
+ readonly modelId = 'workflow-test-video';
12
+ readonly maxVideosPerCall = 1;
13
+
14
+ static [WORKFLOW_SERIALIZE]() {
15
+ return {};
16
+ }
17
+
18
+ static [WORKFLOW_DESERIALIZE]() {
19
+ return new SerializableVideoModel();
20
+ }
21
+
22
+ async handleWebhookOption({
23
+ webhook,
24
+ }: Parameters<
25
+ NonNullable<Experimental_VideoModelV4['handleWebhookOption']>
26
+ >[0]) {
27
+ const result = await webhook();
28
+ return { webhookUrl: result.url, received: result.received };
29
+ }
30
+
31
+ async doStart(
32
+ options: Parameters<NonNullable<Experimental_VideoModelV4['doStart']>>[0],
33
+ ) {
34
+ if (options.webhookUrl == null) {
35
+ throw new Error('Expected a webhook URL.');
36
+ }
37
+
38
+ const webhookUrl = new URL(options.webhookUrl);
39
+ const token = webhookUrl.pathname.split('/').at(-1);
40
+ if (token == null || token.length === 0) {
41
+ throw new Error('Expected a webhook token.');
42
+ }
43
+
44
+ const response = await resumeWebhook(
45
+ token,
46
+ new Request(options.webhookUrl, { method: 'POST' }),
47
+ );
48
+ if (!response.ok) {
49
+ throw new Error(
50
+ `Webhook delivery failed with status ${response.status}.`,
51
+ );
52
+ }
53
+
54
+ return {
55
+ operation: { id: 'operation-1' },
56
+ warnings: [{ type: 'other' as const, message: 'start warning' }],
57
+ response: {
58
+ timestamp: new Date(0),
59
+ modelId: this.modelId,
60
+ headers: {},
61
+ },
62
+ };
63
+ }
64
+
65
+ async doStatus() {
66
+ return {
67
+ status: 'completed' as const,
68
+ videos: [
69
+ {
70
+ type: 'url' as const,
71
+ url: 'https://example.com/video.mp4',
72
+ mediaType: 'video/mp4',
73
+ },
74
+ ],
75
+ warnings: [],
76
+ response: {
77
+ timestamp: new Date(0),
78
+ modelId: this.modelId,
79
+ headers: {},
80
+ },
81
+ };
82
+ }
83
+ }
84
+
85
+ export function createSerializableVideoModel(): Experimental_VideoModelV4 {
86
+ return new SerializableVideoModel();
87
+ }
@@ -0,0 +1,11 @@
1
+ import { experimental_generateVideo } from '../generate-video.js';
2
+ import { createSerializableVideoModel } from './serializable-video-model.js';
3
+
4
+ export async function videoGenerationWorkflow() {
5
+ 'use workflow';
6
+
7
+ return experimental_generateVideo({
8
+ model: createSerializableVideoModel(),
9
+ prompt: 'A lighthouse in fog',
10
+ });
11
+ }
package/src/video.ts ADDED
@@ -0,0 +1,5 @@
1
+ export {
2
+ experimental_generateVideo,
3
+ type WorkflowGenerateVideoOptions,
4
+ type WorkflowGenerateVideoResult,
5
+ } from './generate-video.js';