varg.ai-sdk 0.1.0 ā 0.4.0-alpha.1
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/.claude/settings.local.json +1 -1
- package/.env.example +3 -0
- package/.github/workflows/ci.yml +23 -0
- package/.husky/README.md +102 -0
- package/.husky/commit-msg +6 -0
- package/.husky/pre-commit +9 -0
- package/.husky/pre-push +6 -0
- package/.size-limit.json +8 -0
- package/.test-hooks.ts +5 -0
- package/CLAUDE.md +10 -3
- package/CONTRIBUTING.md +150 -0
- package/LICENSE.md +53 -0
- package/README.md +56 -209
- package/SKILLS.md +26 -10
- package/biome.json +7 -1
- package/bun.lock +1286 -0
- package/commitlint.config.js +22 -0
- package/docs/index.html +1130 -0
- package/docs/prompting.md +326 -0
- package/docs/react.md +834 -0
- package/docs/sdk.md +812 -0
- package/ffmpeg/CLAUDE.md +68 -0
- package/package.json +48 -8
- package/pipeline/cookbooks/scripts/animate-frames-parallel.ts +84 -0
- package/pipeline/cookbooks/scripts/combine-scenes.sh +53 -0
- package/pipeline/cookbooks/scripts/generate-frames-parallel.ts +99 -0
- package/pipeline/cookbooks/scripts/still-to-video.sh +37 -0
- package/pipeline/cookbooks/text-to-tiktok.md +669 -0
- package/pipeline/cookbooks/trendwatching.md +156 -0
- package/plan.md +281 -0
- package/scripts/.gitkeep +0 -0
- package/src/ai-sdk/cache.ts +142 -0
- package/src/ai-sdk/examples/cached-generation.ts +53 -0
- package/src/ai-sdk/examples/duet-scene-4.ts +53 -0
- package/src/ai-sdk/examples/duet-scene-5-audio.ts +32 -0
- package/src/ai-sdk/examples/duet-video.ts +56 -0
- package/src/ai-sdk/examples/editly-composition.ts +63 -0
- package/src/ai-sdk/examples/editly-test.ts +57 -0
- package/src/ai-sdk/examples/editly-video-test.ts +52 -0
- package/src/ai-sdk/examples/fal-lipsync.ts +43 -0
- package/src/ai-sdk/examples/higgsfield-image.ts +61 -0
- package/src/ai-sdk/examples/music-generation.ts +19 -0
- package/src/ai-sdk/examples/openai-sora.ts +34 -0
- package/src/ai-sdk/examples/replicate-bg-removal.ts +52 -0
- package/src/ai-sdk/examples/simpsons-scene.ts +61 -0
- package/src/ai-sdk/examples/talking-lion.ts +55 -0
- package/src/ai-sdk/examples/video-generation.ts +39 -0
- package/src/ai-sdk/examples/workflow-animated-girl.ts +104 -0
- package/src/ai-sdk/examples/workflow-before-after.ts +114 -0
- package/src/ai-sdk/examples/workflow-character-grid.ts +112 -0
- package/src/ai-sdk/examples/workflow-slideshow.ts +161 -0
- package/src/ai-sdk/file-cache.ts +112 -0
- package/src/ai-sdk/file.ts +238 -0
- package/src/ai-sdk/generate-element.ts +92 -0
- package/src/ai-sdk/generate-music.ts +46 -0
- package/src/ai-sdk/generate-video.ts +165 -0
- package/src/ai-sdk/index.ts +72 -0
- package/src/ai-sdk/music-model.ts +110 -0
- package/src/ai-sdk/providers/editly/editly.test.ts +1108 -0
- package/src/ai-sdk/providers/editly/ffmpeg.ts +60 -0
- package/src/ai-sdk/providers/editly/index.ts +817 -0
- package/src/ai-sdk/providers/editly/layers.ts +776 -0
- package/src/ai-sdk/providers/editly/plan.md +144 -0
- package/src/ai-sdk/providers/editly/types.ts +328 -0
- package/src/ai-sdk/providers/elevenlabs-provider.ts +255 -0
- package/src/ai-sdk/providers/fal-provider.ts +512 -0
- package/src/ai-sdk/providers/higgsfield.ts +379 -0
- package/src/ai-sdk/providers/openai.ts +251 -0
- package/src/ai-sdk/providers/replicate.ts +16 -0
- package/src/ai-sdk/video-model.ts +185 -0
- package/src/cli/commands/find.tsx +137 -0
- package/src/cli/commands/help.tsx +85 -0
- package/src/cli/commands/index.ts +6 -0
- package/src/cli/commands/list.tsx +238 -0
- package/src/cli/commands/render.tsx +71 -0
- package/src/cli/commands/run.tsx +511 -0
- package/src/cli/commands/which.tsx +253 -0
- package/src/cli/index.ts +114 -0
- package/src/cli/quiet.ts +44 -0
- package/src/cli/types.ts +32 -0
- package/src/cli/ui/components/Badge.tsx +29 -0
- package/src/cli/ui/components/DataTable.tsx +51 -0
- package/src/cli/ui/components/Header.tsx +23 -0
- package/src/cli/ui/components/HelpBlock.tsx +44 -0
- package/src/cli/ui/components/KeyValue.tsx +33 -0
- package/src/cli/ui/components/OptionRow.tsx +81 -0
- package/src/cli/ui/components/Separator.tsx +23 -0
- package/src/cli/ui/components/StatusBox.tsx +108 -0
- package/src/cli/ui/components/VargBox.tsx +51 -0
- package/src/cli/ui/components/VargProgress.tsx +36 -0
- package/src/cli/ui/components/VargSpinner.tsx +34 -0
- package/src/cli/ui/components/VargText.tsx +56 -0
- package/src/cli/ui/components/index.ts +19 -0
- package/src/cli/ui/index.ts +12 -0
- package/src/cli/ui/render.ts +35 -0
- package/src/cli/ui/theme.ts +63 -0
- package/src/cli/utils.ts +78 -0
- package/src/core/executor/executor.ts +201 -0
- package/src/core/executor/index.ts +13 -0
- package/src/core/executor/job.ts +214 -0
- package/src/core/executor/pipeline.ts +222 -0
- package/src/core/index.ts +11 -0
- package/src/core/registry/index.ts +9 -0
- package/src/core/registry/loader.ts +149 -0
- package/src/core/registry/registry.ts +221 -0
- package/src/core/registry/resolver.ts +206 -0
- package/src/core/schema/helpers.ts +134 -0
- package/src/core/schema/index.ts +8 -0
- package/src/core/schema/shared.ts +102 -0
- package/src/core/schema/types.ts +279 -0
- package/src/core/schema/validator.ts +92 -0
- package/src/definitions/actions/captions.ts +261 -0
- package/src/definitions/actions/edit.ts +298 -0
- package/src/definitions/actions/image.ts +125 -0
- package/src/definitions/actions/index.ts +114 -0
- package/src/definitions/actions/music.ts +205 -0
- package/src/definitions/actions/sync.ts +128 -0
- package/{action/transcribe/index.ts ā src/definitions/actions/transcribe.ts} +63 -90
- package/src/definitions/actions/upload.ts +111 -0
- package/src/definitions/actions/video.ts +163 -0
- package/src/definitions/actions/voice.ts +119 -0
- package/src/definitions/index.ts +23 -0
- package/src/definitions/models/elevenlabs.ts +50 -0
- package/src/definitions/models/flux.ts +56 -0
- package/src/definitions/models/index.ts +36 -0
- package/src/definitions/models/kling.ts +56 -0
- package/src/definitions/models/llama.ts +54 -0
- package/src/definitions/models/nano-banana-pro.ts +102 -0
- package/src/definitions/models/sonauto.ts +68 -0
- package/src/definitions/models/soul.ts +65 -0
- package/src/definitions/models/wan.ts +54 -0
- package/src/definitions/models/whisper.ts +44 -0
- package/src/definitions/skills/index.ts +12 -0
- package/src/definitions/skills/talking-character.ts +87 -0
- package/src/definitions/skills/text-to-tiktok.ts +97 -0
- package/src/index.ts +118 -0
- package/src/providers/apify.ts +269 -0
- package/src/providers/base.ts +264 -0
- package/src/providers/elevenlabs.ts +217 -0
- package/src/providers/fal.ts +392 -0
- package/src/providers/ffmpeg.ts +544 -0
- package/src/providers/fireworks.ts +193 -0
- package/src/providers/groq.ts +149 -0
- package/src/providers/higgsfield.ts +145 -0
- package/src/providers/index.ts +143 -0
- package/src/providers/replicate.ts +147 -0
- package/src/providers/storage.ts +206 -0
- package/src/react/cli.ts +52 -0
- package/src/react/elements.ts +146 -0
- package/src/react/examples/branching.tsx +66 -0
- package/src/react/examples/captions-demo.tsx +37 -0
- package/src/react/examples/character-video.tsx +84 -0
- package/src/react/examples/grid.tsx +53 -0
- package/src/react/examples/layouts-demo.tsx +57 -0
- package/src/react/examples/madi.tsx +60 -0
- package/src/react/examples/music-test.tsx +35 -0
- package/src/react/examples/onlyfans-1m/workflow.tsx +88 -0
- package/src/react/examples/orange-portrait.tsx +41 -0
- package/src/react/examples/split-element-demo.tsx +60 -0
- package/src/react/examples/split-layout-demo.tsx +60 -0
- package/src/react/examples/split.tsx +41 -0
- package/src/react/examples/video-grid.tsx +46 -0
- package/src/react/index.ts +43 -0
- package/src/react/layouts/grid.tsx +28 -0
- package/src/react/layouts/index.ts +2 -0
- package/src/react/layouts/split.tsx +20 -0
- package/src/react/react.test.ts +309 -0
- package/src/react/render.ts +21 -0
- package/src/react/renderers/animate.ts +59 -0
- package/src/react/renderers/captions.ts +297 -0
- package/src/react/renderers/clip.ts +248 -0
- package/src/react/renderers/context.ts +17 -0
- package/src/react/renderers/image.ts +109 -0
- package/src/react/renderers/index.ts +22 -0
- package/src/react/renderers/music.ts +60 -0
- package/src/react/renderers/packshot.ts +84 -0
- package/src/react/renderers/progress.ts +173 -0
- package/src/react/renderers/render.ts +243 -0
- package/src/react/renderers/slider.ts +69 -0
- package/src/react/renderers/speech.ts +53 -0
- package/src/react/renderers/split.ts +91 -0
- package/src/react/renderers/subtitle.ts +16 -0
- package/src/react/renderers/swipe.ts +75 -0
- package/src/react/renderers/title.ts +17 -0
- package/src/react/renderers/utils.ts +124 -0
- package/src/react/renderers/video.ts +127 -0
- package/src/react/runtime/jsx-dev-runtime.ts +43 -0
- package/src/react/runtime/jsx-runtime.ts +35 -0
- package/src/react/types.ts +232 -0
- package/src/studio/index.ts +26 -0
- package/src/studio/scanner.ts +102 -0
- package/src/studio/server.ts +554 -0
- package/src/studio/stages.ts +251 -0
- package/src/studio/step-renderer.ts +279 -0
- package/src/studio/types.ts +60 -0
- package/src/studio/ui/cache.html +303 -0
- package/src/studio/ui/index.html +1820 -0
- package/src/tests/all.test.ts +509 -0
- package/src/tests/index.ts +33 -0
- package/src/tests/unit.test.ts +403 -0
- package/tsconfig.cli.json +8 -0
- package/tsconfig.json +21 -3
- package/TEST_RESULTS.md +0 -122
- package/action/captions/SKILL.md +0 -170
- package/action/captions/index.ts +0 -227
- package/action/edit/SKILL.md +0 -235
- package/action/edit/index.ts +0 -493
- package/action/image/SKILL.md +0 -140
- package/action/image/index.ts +0 -112
- package/action/sync/SKILL.md +0 -136
- package/action/sync/index.ts +0 -187
- package/action/transcribe/SKILL.md +0 -179
- package/action/video/SKILL.md +0 -116
- package/action/video/index.ts +0 -135
- package/action/voice/SKILL.md +0 -125
- package/action/voice/index.ts +0 -201
- package/index.ts +0 -38
- package/lib/README.md +0 -144
- package/lib/ai-sdk/fal.ts +0 -106
- package/lib/ai-sdk/replicate.ts +0 -107
- package/lib/elevenlabs.ts +0 -382
- package/lib/fal.ts +0 -478
- package/lib/ffmpeg.ts +0 -467
- package/lib/fireworks.ts +0 -235
- package/lib/groq.ts +0 -246
- package/lib/higgsfield.ts +0 -176
- package/lib/remotion/SKILL.md +0 -823
- package/lib/remotion/cli.ts +0 -115
- package/lib/remotion/functions.ts +0 -283
- package/lib/remotion/index.ts +0 -19
- package/lib/remotion/templates.ts +0 -73
- package/lib/replicate.ts +0 -304
- package/output.txt +0 -1
- package/test-import.ts +0 -7
- package/test-services.ts +0 -97
- package/utilities/s3.ts +0 -147
|
@@ -0,0 +1,509 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Comprehensive tests for all varg SDK actions and models
|
|
5
|
+
* Run with: bun run src/tests/all.test.ts
|
|
6
|
+
*
|
|
7
|
+
* Note: Most tests require API keys to be set in environment variables:
|
|
8
|
+
* - FAL_KEY
|
|
9
|
+
* - REPLICATE_API_TOKEN
|
|
10
|
+
* - ELEVENLABS_API_KEY
|
|
11
|
+
* - GROQ_API_KEY
|
|
12
|
+
* - FIREWORKS_API_KEY
|
|
13
|
+
* - HIGGSFIELD_API_KEY / HF_API_KEY
|
|
14
|
+
* - CLOUDFLARE_R2_API_URL, CLOUDFLARE_ACCESS_KEY_ID, CLOUDFLARE_ACCESS_SECRET
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { executor } from "../core/executor";
|
|
18
|
+
import { registry } from "../core/registry";
|
|
19
|
+
import { getCliSchemaInfo } from "../core/schema/helpers";
|
|
20
|
+
import { applyDefaults, validateInputs } from "../core/schema/validator";
|
|
21
|
+
import { allDefinitions } from "../definitions";
|
|
22
|
+
import { providers } from "../providers";
|
|
23
|
+
|
|
24
|
+
// Register all definitions
|
|
25
|
+
for (const definition of allDefinitions) {
|
|
26
|
+
registry.register(definition);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Test results tracking
|
|
30
|
+
interface TestResult {
|
|
31
|
+
name: string;
|
|
32
|
+
passed: boolean;
|
|
33
|
+
error?: string;
|
|
34
|
+
duration: number;
|
|
35
|
+
skipped?: boolean;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const results: TestResult[] = [];
|
|
39
|
+
|
|
40
|
+
// Helper to run a test
|
|
41
|
+
async function test(
|
|
42
|
+
name: string,
|
|
43
|
+
fn: () => Promise<void>,
|
|
44
|
+
skip = false,
|
|
45
|
+
): Promise<void> {
|
|
46
|
+
if (skip) {
|
|
47
|
+
results.push({ name, passed: true, duration: 0, skipped: true });
|
|
48
|
+
console.log(`āļø SKIP: ${name}`);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const start = Date.now();
|
|
53
|
+
try {
|
|
54
|
+
await fn();
|
|
55
|
+
const duration = Date.now() - start;
|
|
56
|
+
results.push({ name, passed: true, duration });
|
|
57
|
+
console.log(`ā
PASS: ${name} (${duration}ms)`);
|
|
58
|
+
} catch (error) {
|
|
59
|
+
const duration = Date.now() - start;
|
|
60
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
61
|
+
results.push({ name, passed: false, error: errorMsg, duration });
|
|
62
|
+
console.log(`ā FAIL: ${name} (${duration}ms)`);
|
|
63
|
+
console.log(` Error: ${errorMsg}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Check if an API key is available
|
|
68
|
+
function hasApiKey(envVar: string | string[]): boolean {
|
|
69
|
+
const vars = Array.isArray(envVar) ? envVar : [envVar];
|
|
70
|
+
return vars.some((v) => !!process.env[v]);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// ============================================================================
|
|
74
|
+
// Registry Tests
|
|
75
|
+
// ============================================================================
|
|
76
|
+
|
|
77
|
+
console.log("\nš REGISTRY TESTS\n");
|
|
78
|
+
|
|
79
|
+
await test("registry has models registered", async () => {
|
|
80
|
+
const models = registry.list("model");
|
|
81
|
+
if (models.length === 0) throw new Error("No models registered");
|
|
82
|
+
console.log(` Found ${models.length} models`);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
await test("registry has actions registered", async () => {
|
|
86
|
+
const actions = registry.list("action");
|
|
87
|
+
if (actions.length === 0) throw new Error("No actions registered");
|
|
88
|
+
console.log(` Found ${actions.length} actions`);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
await test("registry has skills registered", async () => {
|
|
92
|
+
const skills = registry.list("skill");
|
|
93
|
+
if (skills.length === 0) throw new Error("No skills registered");
|
|
94
|
+
console.log(` Found ${skills.length} skills`);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
await test("registry has providers registered", async () => {
|
|
98
|
+
const providerList = providers.all();
|
|
99
|
+
if (providerList.length === 0) throw new Error("No providers registered");
|
|
100
|
+
console.log(` Found ${providerList.length} providers`);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
await test("registry resolves 'video' action", async () => {
|
|
104
|
+
const video = registry.resolve("video");
|
|
105
|
+
if (!video) throw new Error("Could not resolve 'video'");
|
|
106
|
+
if (video.type !== "action") throw new Error("Expected action type");
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
await test("registry resolves 'kling' model", async () => {
|
|
110
|
+
const kling = registry.resolve("kling");
|
|
111
|
+
if (!kling) throw new Error("Could not resolve 'kling'");
|
|
112
|
+
if (kling.type !== "model") throw new Error("Expected model type");
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
await test("registry resolves 'talking-character' skill", async () => {
|
|
116
|
+
const skill = registry.resolve("talking-character");
|
|
117
|
+
if (!skill) throw new Error("Could not resolve 'talking-character'");
|
|
118
|
+
if (skill.type !== "skill") throw new Error("Expected skill type");
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
await test("registry search works", async () => {
|
|
122
|
+
const searchResults = registry.search("video");
|
|
123
|
+
if (searchResults.length === 0) throw new Error("No search results");
|
|
124
|
+
console.log(` Found ${searchResults.length} results for 'video'`);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// ============================================================================
|
|
128
|
+
// Provider Tests
|
|
129
|
+
// ============================================================================
|
|
130
|
+
|
|
131
|
+
console.log("\nš PROVIDER TESTS\n");
|
|
132
|
+
|
|
133
|
+
await test("fal provider is registered", async () => {
|
|
134
|
+
const fal = providers.get("fal");
|
|
135
|
+
if (!fal) throw new Error("Fal provider not found");
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
await test("replicate provider is registered", async () => {
|
|
139
|
+
const replicate = providers.get("replicate");
|
|
140
|
+
if (!replicate) throw new Error("Replicate provider not found");
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
await test("elevenlabs provider is registered", async () => {
|
|
144
|
+
const el = providers.get("elevenlabs");
|
|
145
|
+
if (!el) throw new Error("ElevenLabs provider not found");
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
await test("groq provider is registered", async () => {
|
|
149
|
+
const groq = providers.get("groq");
|
|
150
|
+
if (!groq) throw new Error("Groq provider not found");
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
await test("ffmpeg provider is registered", async () => {
|
|
154
|
+
const ffmpeg = providers.get("ffmpeg");
|
|
155
|
+
if (!ffmpeg) throw new Error("FFmpeg provider not found");
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
await test("storage provider is registered", async () => {
|
|
159
|
+
const storage = providers.get("storage");
|
|
160
|
+
if (!storage) throw new Error("Storage provider not found");
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// ============================================================================
|
|
164
|
+
// Schema Validation Tests
|
|
165
|
+
// ============================================================================
|
|
166
|
+
|
|
167
|
+
console.log("\nš SCHEMA VALIDATION TESTS\n");
|
|
168
|
+
|
|
169
|
+
await test("validator accepts valid inputs", async () => {
|
|
170
|
+
const def = registry.resolve("video");
|
|
171
|
+
if (!def) throw new Error("No definition");
|
|
172
|
+
|
|
173
|
+
// Use the input schema directly
|
|
174
|
+
const result = validateInputs({ prompt: "test video" }, def.schema.input);
|
|
175
|
+
if (!result.valid)
|
|
176
|
+
throw new Error(
|
|
177
|
+
`Validation failed: ${result.errors.map((e) => e.message).join(", ")}`,
|
|
178
|
+
);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
await test("validator rejects missing required fields", async () => {
|
|
182
|
+
const def = registry.resolve("video");
|
|
183
|
+
if (!def) throw new Error("No definition");
|
|
184
|
+
|
|
185
|
+
const result = validateInputs({}, def.schema.input);
|
|
186
|
+
if (result.valid) throw new Error("Should have failed validation");
|
|
187
|
+
if (!result.errors.some((e) => e.path === "prompt")) {
|
|
188
|
+
throw new Error("Should report missing 'prompt' field");
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
await test("validator applies defaults", async () => {
|
|
193
|
+
const def = registry.resolve("video");
|
|
194
|
+
if (!def) throw new Error("No definition");
|
|
195
|
+
|
|
196
|
+
const inputs = applyDefaults({ prompt: "test" }, def.schema.input);
|
|
197
|
+
// Check that duration and aspectRatio have defaults applied
|
|
198
|
+
const { properties } = getCliSchemaInfo(def.schema.input);
|
|
199
|
+
if (properties.duration?.default !== undefined) {
|
|
200
|
+
console.log(` Defaults applied: duration=${inputs.duration}`);
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
// ============================================================================
|
|
205
|
+
// Model Definition Tests
|
|
206
|
+
// ============================================================================
|
|
207
|
+
|
|
208
|
+
console.log("\nš¤ MODEL DEFINITION TESTS\n");
|
|
209
|
+
|
|
210
|
+
const modelNames = [
|
|
211
|
+
"kling",
|
|
212
|
+
"flux",
|
|
213
|
+
"wan",
|
|
214
|
+
"whisper",
|
|
215
|
+
"elevenlabs-tts",
|
|
216
|
+
"soul",
|
|
217
|
+
"sonauto",
|
|
218
|
+
"llama",
|
|
219
|
+
];
|
|
220
|
+
|
|
221
|
+
for (const name of modelNames) {
|
|
222
|
+
await test(`model '${name}' is properly defined`, async () => {
|
|
223
|
+
const model = registry.getModel(name);
|
|
224
|
+
if (!model) throw new Error(`Model '${name}' not found`);
|
|
225
|
+
if (!model.providers || model.providers.length === 0) {
|
|
226
|
+
throw new Error("Model has no providers");
|
|
227
|
+
}
|
|
228
|
+
if (!model.defaultProvider) {
|
|
229
|
+
throw new Error("Model has no default provider");
|
|
230
|
+
}
|
|
231
|
+
if (!model.schema) {
|
|
232
|
+
throw new Error("Model has no schema");
|
|
233
|
+
}
|
|
234
|
+
console.log(
|
|
235
|
+
` Providers: ${model.providers.join(", ")}, default: ${model.defaultProvider}`,
|
|
236
|
+
);
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// ============================================================================
|
|
241
|
+
// Action Definition Tests
|
|
242
|
+
// ============================================================================
|
|
243
|
+
|
|
244
|
+
console.log("\nā” ACTION DEFINITION TESTS\n");
|
|
245
|
+
|
|
246
|
+
const actionNames = [
|
|
247
|
+
"video",
|
|
248
|
+
"image",
|
|
249
|
+
"voice",
|
|
250
|
+
"transcribe",
|
|
251
|
+
"music",
|
|
252
|
+
"sync",
|
|
253
|
+
"captions",
|
|
254
|
+
"trim",
|
|
255
|
+
"cut",
|
|
256
|
+
"merge",
|
|
257
|
+
"split",
|
|
258
|
+
"fade",
|
|
259
|
+
"transition",
|
|
260
|
+
"remove",
|
|
261
|
+
];
|
|
262
|
+
|
|
263
|
+
for (const name of actionNames) {
|
|
264
|
+
await test(`action '${name}' is properly defined`, async () => {
|
|
265
|
+
const action = registry.getAction(name);
|
|
266
|
+
if (!action) throw new Error(`Action '${name}' not found`);
|
|
267
|
+
if (!action.schema) {
|
|
268
|
+
throw new Error("Action has no schema");
|
|
269
|
+
}
|
|
270
|
+
if (!action.routes && !action.execute) {
|
|
271
|
+
throw new Error("Action has no routes or execute function");
|
|
272
|
+
}
|
|
273
|
+
const hasRoutes = action.routes && action.routes.length > 0;
|
|
274
|
+
const hasExecute = !!action.execute;
|
|
275
|
+
console.log(` Routes: ${hasRoutes}, Execute: ${hasExecute}`);
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// ============================================================================
|
|
280
|
+
// Skill Definition Tests
|
|
281
|
+
// ============================================================================
|
|
282
|
+
|
|
283
|
+
console.log("\nšÆ SKILL DEFINITION TESTS\n");
|
|
284
|
+
|
|
285
|
+
const skillNames = ["talking-character", "text-to-tiktok"];
|
|
286
|
+
|
|
287
|
+
for (const name of skillNames) {
|
|
288
|
+
await test(`skill '${name}' is properly defined`, async () => {
|
|
289
|
+
const skill = registry.getSkill(name);
|
|
290
|
+
if (!skill) throw new Error(`Skill '${name}' not found`);
|
|
291
|
+
if (!skill.steps || skill.steps.length === 0) {
|
|
292
|
+
throw new Error("Skill has no steps");
|
|
293
|
+
}
|
|
294
|
+
console.log(` Steps: ${skill.steps.length}`);
|
|
295
|
+
for (const step of skill.steps) {
|
|
296
|
+
console.log(` - ${step.name} ā ${step.run}`);
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// ============================================================================
|
|
302
|
+
// Live API Tests (require API keys)
|
|
303
|
+
// ============================================================================
|
|
304
|
+
|
|
305
|
+
console.log("\nš LIVE API TESTS (requires API keys)\n");
|
|
306
|
+
|
|
307
|
+
// Fal.ai tests
|
|
308
|
+
await test(
|
|
309
|
+
"fal: generate image with flux",
|
|
310
|
+
async () => {
|
|
311
|
+
const { falProvider } = await import("../providers/fal");
|
|
312
|
+
const result = await falProvider.generateImage({
|
|
313
|
+
prompt: "a cute cat sitting on a rainbow",
|
|
314
|
+
imageSize: "square",
|
|
315
|
+
});
|
|
316
|
+
if (!result?.data?.images?.[0]?.url) {
|
|
317
|
+
throw new Error("No image URL in result");
|
|
318
|
+
}
|
|
319
|
+
console.log(` Generated: ${result.data.images[0].url}`);
|
|
320
|
+
},
|
|
321
|
+
!hasApiKey("FAL_KEY"),
|
|
322
|
+
);
|
|
323
|
+
|
|
324
|
+
await test(
|
|
325
|
+
"fal: text-to-video with kling",
|
|
326
|
+
async () => {
|
|
327
|
+
const { falProvider } = await import("../providers/fal");
|
|
328
|
+
const result = await falProvider.textToVideo({
|
|
329
|
+
prompt: "ocean waves crashing on beach",
|
|
330
|
+
duration: 5,
|
|
331
|
+
});
|
|
332
|
+
if (!result?.data?.video?.url) {
|
|
333
|
+
throw new Error("No video URL in result");
|
|
334
|
+
}
|
|
335
|
+
console.log(` Generated: ${result.data.video.url}`);
|
|
336
|
+
},
|
|
337
|
+
!hasApiKey("FAL_KEY"),
|
|
338
|
+
);
|
|
339
|
+
|
|
340
|
+
// Replicate tests
|
|
341
|
+
await test(
|
|
342
|
+
"replicate: run flux image generation",
|
|
343
|
+
async () => {
|
|
344
|
+
const { replicateProvider, MODELS } = await import(
|
|
345
|
+
"../providers/replicate"
|
|
346
|
+
);
|
|
347
|
+
const result = await replicateProvider.runImage({
|
|
348
|
+
model: MODELS.IMAGE.FLUX_SCHNELL,
|
|
349
|
+
input: { prompt: "a mountain landscape at sunset" },
|
|
350
|
+
});
|
|
351
|
+
console.log(` Generated: ${JSON.stringify(result).slice(0, 100)}...`);
|
|
352
|
+
},
|
|
353
|
+
!hasApiKey("REPLICATE_API_TOKEN"),
|
|
354
|
+
);
|
|
355
|
+
|
|
356
|
+
// ElevenLabs tests
|
|
357
|
+
await test(
|
|
358
|
+
"elevenlabs: text-to-speech",
|
|
359
|
+
async () => {
|
|
360
|
+
const { elevenlabsProvider } = await import("../providers/elevenlabs");
|
|
361
|
+
const buffer = await elevenlabsProvider.textToSpeech({
|
|
362
|
+
text: "Hello, this is a test of the varg SDK.",
|
|
363
|
+
});
|
|
364
|
+
if (buffer.length === 0) {
|
|
365
|
+
throw new Error("Empty audio buffer");
|
|
366
|
+
}
|
|
367
|
+
console.log(` Generated: ${buffer.length} bytes of audio`);
|
|
368
|
+
},
|
|
369
|
+
!hasApiKey("ELEVENLABS_API_KEY"),
|
|
370
|
+
);
|
|
371
|
+
|
|
372
|
+
await test(
|
|
373
|
+
"elevenlabs: list voices",
|
|
374
|
+
async () => {
|
|
375
|
+
const { elevenlabsProvider } = await import("../providers/elevenlabs");
|
|
376
|
+
const voices = await elevenlabsProvider.listVoices();
|
|
377
|
+
if (voices.length === 0) {
|
|
378
|
+
throw new Error("No voices found");
|
|
379
|
+
}
|
|
380
|
+
console.log(` Found ${voices.length} voices`);
|
|
381
|
+
},
|
|
382
|
+
!hasApiKey("ELEVENLABS_API_KEY"),
|
|
383
|
+
);
|
|
384
|
+
|
|
385
|
+
// Groq tests
|
|
386
|
+
await test(
|
|
387
|
+
"groq: chat completion",
|
|
388
|
+
async () => {
|
|
389
|
+
const { groqProvider } = await import("../providers/groq");
|
|
390
|
+
const result = await groqProvider.chatCompletion({
|
|
391
|
+
messages: [{ role: "user", content: "Say hello in one word" }],
|
|
392
|
+
maxTokens: 10,
|
|
393
|
+
});
|
|
394
|
+
if (!result) {
|
|
395
|
+
throw new Error("No response");
|
|
396
|
+
}
|
|
397
|
+
console.log(` Response: ${result}`);
|
|
398
|
+
},
|
|
399
|
+
!hasApiKey("GROQ_API_KEY"),
|
|
400
|
+
);
|
|
401
|
+
|
|
402
|
+
await test(
|
|
403
|
+
"groq: list models",
|
|
404
|
+
async () => {
|
|
405
|
+
const { groqProvider } = await import("../providers/groq");
|
|
406
|
+
const models = await groqProvider.listModels();
|
|
407
|
+
if (models.length === 0) {
|
|
408
|
+
throw new Error("No models found");
|
|
409
|
+
}
|
|
410
|
+
console.log(` Found ${models.length} models`);
|
|
411
|
+
},
|
|
412
|
+
!hasApiKey("GROQ_API_KEY"),
|
|
413
|
+
);
|
|
414
|
+
|
|
415
|
+
// Higgsfield tests
|
|
416
|
+
await test(
|
|
417
|
+
"higgsfield: list soul styles",
|
|
418
|
+
async () => {
|
|
419
|
+
const { higgsfieldProvider } = await import("../providers/higgsfield");
|
|
420
|
+
const styles = await higgsfieldProvider.listSoulStyles();
|
|
421
|
+
console.log(` Found styles: ${JSON.stringify(styles).slice(0, 100)}...`);
|
|
422
|
+
},
|
|
423
|
+
!hasApiKey(["HIGGSFIELD_API_KEY", "HF_API_KEY"]),
|
|
424
|
+
);
|
|
425
|
+
|
|
426
|
+
// FFmpeg tests (local, no API needed)
|
|
427
|
+
await test("ffmpeg: probe video info", async () => {
|
|
428
|
+
const { ffmpegProvider } = await import("../providers/ffmpeg");
|
|
429
|
+
// This test requires a local video file - skip if not available
|
|
430
|
+
const testVideo = "./media/test.mp4";
|
|
431
|
+
const file = Bun.file(testVideo);
|
|
432
|
+
if (!(await file.exists())) {
|
|
433
|
+
console.log(` Skipped: No test video at ${testVideo}`);
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
const info = await ffmpegProvider.probe(testVideo);
|
|
437
|
+
console.log(` Video: ${info.width}x${info.height}, ${info.duration}s`);
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
// ============================================================================
|
|
441
|
+
// Executor Tests
|
|
442
|
+
// ============================================================================
|
|
443
|
+
|
|
444
|
+
console.log("\nš EXECUTOR TESTS\n");
|
|
445
|
+
|
|
446
|
+
await test(
|
|
447
|
+
"executor: run image action",
|
|
448
|
+
async () => {
|
|
449
|
+
const result = await executor.run("image", {
|
|
450
|
+
prompt: "a beautiful sunset over mountains",
|
|
451
|
+
size: "landscape_4_3",
|
|
452
|
+
});
|
|
453
|
+
if (!result.output) {
|
|
454
|
+
throw new Error("No output");
|
|
455
|
+
}
|
|
456
|
+
console.log(` Output: ${JSON.stringify(result.output).slice(0, 100)}...`);
|
|
457
|
+
},
|
|
458
|
+
!hasApiKey("FAL_KEY"),
|
|
459
|
+
);
|
|
460
|
+
|
|
461
|
+
await test(
|
|
462
|
+
"executor: run voice action",
|
|
463
|
+
async () => {
|
|
464
|
+
const result = await executor.run("voice", {
|
|
465
|
+
text: "Hello from the varg SDK executor test.",
|
|
466
|
+
});
|
|
467
|
+
if (!result.output) {
|
|
468
|
+
throw new Error("No output");
|
|
469
|
+
}
|
|
470
|
+
console.log(` Duration: ${result.duration}ms`);
|
|
471
|
+
},
|
|
472
|
+
!hasApiKey("ELEVENLABS_API_KEY"),
|
|
473
|
+
);
|
|
474
|
+
|
|
475
|
+
// ============================================================================
|
|
476
|
+
// Summary
|
|
477
|
+
// ============================================================================
|
|
478
|
+
|
|
479
|
+
console.log(`\n${"=".repeat(60)}`);
|
|
480
|
+
console.log("TEST SUMMARY");
|
|
481
|
+
console.log(`${"=".repeat(60)}\n`);
|
|
482
|
+
|
|
483
|
+
const passed = results.filter((r) => r.passed && !r.skipped).length;
|
|
484
|
+
const failed = results.filter((r) => !r.passed).length;
|
|
485
|
+
const skipped = results.filter((r) => r.skipped).length;
|
|
486
|
+
const total = results.length;
|
|
487
|
+
|
|
488
|
+
console.log(`Total: ${total}`);
|
|
489
|
+
console.log(`Passed: ${passed} ā
`);
|
|
490
|
+
console.log(`Failed: ${failed} ā`);
|
|
491
|
+
console.log(`Skipped: ${skipped} āļø`);
|
|
492
|
+
console.log("");
|
|
493
|
+
|
|
494
|
+
if (failed > 0) {
|
|
495
|
+
console.log("Failed tests:");
|
|
496
|
+
for (const r of results.filter((r) => !r.passed)) {
|
|
497
|
+
console.log(` - ${r.name}: ${r.error}`);
|
|
498
|
+
}
|
|
499
|
+
console.log("");
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
const totalDuration = results.reduce((sum, r) => sum + r.duration, 0);
|
|
503
|
+
console.log(`Total time: ${totalDuration}ms`);
|
|
504
|
+
console.log("");
|
|
505
|
+
|
|
506
|
+
// Exit with error code if any tests failed
|
|
507
|
+
if (failed > 0) {
|
|
508
|
+
process.exit(1);
|
|
509
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* Test runner index
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* bun run src/tests/unit.test.ts - Run unit tests (no API needed)
|
|
7
|
+
* bun run src/tests/all.test.ts - Run all tests (requires API keys)
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
console.log(`
|
|
11
|
+
varg SDK Tests
|
|
12
|
+
==============
|
|
13
|
+
|
|
14
|
+
Available test files:
|
|
15
|
+
|
|
16
|
+
bun run src/tests/unit.test.ts
|
|
17
|
+
Unit tests that don't require API keys.
|
|
18
|
+
Tests registry, resolver, validation, and definition structure.
|
|
19
|
+
|
|
20
|
+
bun run src/tests/all.test.ts
|
|
21
|
+
Comprehensive tests including live API calls.
|
|
22
|
+
Requires API keys set in environment variables:
|
|
23
|
+
- FAL_KEY
|
|
24
|
+
- REPLICATE_API_TOKEN
|
|
25
|
+
- ELEVENLABS_API_KEY
|
|
26
|
+
- GROQ_API_KEY
|
|
27
|
+
- FIREWORKS_API_KEY
|
|
28
|
+
- HIGGSFIELD_API_KEY / HF_API_KEY
|
|
29
|
+
|
|
30
|
+
Run specific test file with:
|
|
31
|
+
bun run <test-file>
|
|
32
|
+
|
|
33
|
+
`);
|