@ai-sdk/workflow 2.0.9 → 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.
- package/CHANGELOG.md +27 -0
- package/README.md +25 -0
- package/dist/chunk-UAWBPTDW.js +51 -0
- package/dist/chunk-UAWBPTDW.js.map +1 -0
- package/dist/index.js +9 -2
- package/dist/index.js.map +1 -1
- package/dist/video.d.ts +24 -0
- package/dist/video.js +80 -0
- package/dist/video.js.map +1 -0
- package/package.json +8 -3
- package/src/generate-video.ts +120 -0
- package/src/serializable-schema.ts +12 -4
- package/src/test/serializable-video-model.ts +87 -0
- package/src/test/video-generation-workflow.ts +11 -0
- package/src/video.ts +5 -0
package/dist/video.d.ts
ADDED
|
@@ -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.
|
|
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,12 +23,17 @@
|
|
|
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
34
|
"@ai-sdk/provider": "4.0.8",
|
|
30
|
-
"@ai-sdk/provider-utils": "5.0.
|
|
31
|
-
"ai": "7.0.
|
|
35
|
+
"@ai-sdk/provider-utils": "5.0.32",
|
|
36
|
+
"ai": "7.0.82",
|
|
32
37
|
"ajv": "^8.20.0"
|
|
33
38
|
},
|
|
34
39
|
"devDependencies": {
|
|
@@ -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
|
+
}
|
|
@@ -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
|
|
42
|
-
* serializable record of tool definitions.
|
|
43
|
-
*
|
|
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
|
+
}
|