varg.ai-sdk 0.1.1 → 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 +43 -10
- 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} +58 -68
- 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 -169
- package/action/edit/SKILL.md +0 -235
- package/action/edit/index.ts +0 -437
- package/action/image/SKILL.md +0 -140
- package/action/image/index.ts +0 -105
- package/action/sync/SKILL.md +0 -136
- package/action/sync/index.ts +0 -145
- package/action/transcribe/SKILL.md +0 -179
- package/action/video/SKILL.md +0 -116
- package/action/video/index.ts +0 -125
- package/action/voice/SKILL.md +0 -125
- package/action/voice/index.ts +0 -136
- package/cli/commands/find.ts +0 -58
- package/cli/commands/help.ts +0 -70
- package/cli/commands/list.ts +0 -49
- package/cli/commands/run.ts +0 -237
- package/cli/commands/which.ts +0 -66
- package/cli/discover.ts +0 -66
- package/cli/index.ts +0 -33
- package/cli/runner.ts +0 -65
- package/cli/types.ts +0 -49
- package/cli/ui.ts +0 -185
- package/index.ts +0 -75
- 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 -467
- 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,403 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Unit tests for varg SDK (no API calls required)
|
|
5
|
+
* Run with: bun run src/tests/unit.test.ts
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
import { registry } from "../core/registry";
|
|
10
|
+
import { findSimilar, resolve, suggest } from "../core/registry/resolver";
|
|
11
|
+
import { getCliSchemaInfo } from "../core/schema/helpers";
|
|
12
|
+
import {
|
|
13
|
+
applyDefaults,
|
|
14
|
+
validateAndPrepare,
|
|
15
|
+
validateInputs,
|
|
16
|
+
} from "../core/schema/validator";
|
|
17
|
+
import { allDefinitions } from "../definitions";
|
|
18
|
+
import { allActions } from "../definitions/actions";
|
|
19
|
+
import { allModels } from "../definitions/models";
|
|
20
|
+
import { allSkills } from "../definitions/skills";
|
|
21
|
+
import { providers } from "../providers";
|
|
22
|
+
|
|
23
|
+
// Colors for output
|
|
24
|
+
const green = (s: string) => `\x1b[32m${s}\x1b[0m`;
|
|
25
|
+
const red = (s: string) => `\x1b[31m${s}\x1b[0m`;
|
|
26
|
+
const cyan = (s: string) => `\x1b[36m${s}\x1b[0m`;
|
|
27
|
+
const dim = (s: string) => `\x1b[2m${s}\x1b[0m`;
|
|
28
|
+
|
|
29
|
+
let passed = 0;
|
|
30
|
+
let failed = 0;
|
|
31
|
+
|
|
32
|
+
function test(name: string, fn: () => void): void {
|
|
33
|
+
try {
|
|
34
|
+
fn();
|
|
35
|
+
passed++;
|
|
36
|
+
console.log(`${green("✓")} ${name}`);
|
|
37
|
+
} catch (error) {
|
|
38
|
+
failed++;
|
|
39
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
40
|
+
console.log(`${red("✗")} ${name}`);
|
|
41
|
+
console.log(` ${red(msg)}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function assert(condition: boolean, message: string): void {
|
|
46
|
+
if (!condition) throw new Error(message);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function assertEqual<T>(actual: T, expected: T, message?: string): void {
|
|
50
|
+
if (actual !== expected) {
|
|
51
|
+
throw new Error(message || `Expected ${expected}, got ${actual}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Register all definitions first
|
|
56
|
+
for (const definition of allDefinitions) {
|
|
57
|
+
registry.register(definition);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
console.log(`\n${cyan("═".repeat(60))}`);
|
|
61
|
+
console.log(cyan(" VARG SDK UNIT TESTS"));
|
|
62
|
+
console.log(`${cyan("═".repeat(60))}\n`);
|
|
63
|
+
|
|
64
|
+
// ============================================================================
|
|
65
|
+
// Definition Count Tests
|
|
66
|
+
// ============================================================================
|
|
67
|
+
|
|
68
|
+
console.log(dim("─ Definition Counts ─\n"));
|
|
69
|
+
|
|
70
|
+
test("all models are exported", () => {
|
|
71
|
+
assert(
|
|
72
|
+
allModels.length >= 8,
|
|
73
|
+
`Expected at least 8 models, got ${allModels.length}`,
|
|
74
|
+
);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test("all actions are exported", () => {
|
|
78
|
+
assert(
|
|
79
|
+
allActions.length >= 14,
|
|
80
|
+
`Expected at least 14 actions, got ${allActions.length}`,
|
|
81
|
+
);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test("all skills are exported", () => {
|
|
85
|
+
assert(
|
|
86
|
+
allSkills.length >= 2,
|
|
87
|
+
`Expected at least 2 skills, got ${allSkills.length}`,
|
|
88
|
+
);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test("allDefinitions contains all definitions", () => {
|
|
92
|
+
const expected = allModels.length + allActions.length + allSkills.length;
|
|
93
|
+
assertEqual(
|
|
94
|
+
allDefinitions.length,
|
|
95
|
+
expected,
|
|
96
|
+
`Expected ${expected} total definitions`,
|
|
97
|
+
);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// ============================================================================
|
|
101
|
+
// Registry Tests
|
|
102
|
+
// ============================================================================
|
|
103
|
+
|
|
104
|
+
console.log(`\n${dim("─ Registry ─\n")}`);
|
|
105
|
+
|
|
106
|
+
test("registry.list() returns all definitions", () => {
|
|
107
|
+
const all = registry.list();
|
|
108
|
+
assert(all.length > 0, "Registry is empty");
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
test("registry.list('model') filters correctly", () => {
|
|
112
|
+
const models = registry.list("model");
|
|
113
|
+
assert(
|
|
114
|
+
models.every((d) => d.type === "model"),
|
|
115
|
+
"Non-model in model list",
|
|
116
|
+
);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test("registry.list('action') filters correctly", () => {
|
|
120
|
+
const actions = registry.list("action");
|
|
121
|
+
assert(
|
|
122
|
+
actions.every((d) => d.type === "action"),
|
|
123
|
+
"Non-action in action list",
|
|
124
|
+
);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
test("registry.list('skill') filters correctly", () => {
|
|
128
|
+
const skills = registry.list("skill");
|
|
129
|
+
assert(
|
|
130
|
+
skills.every((d) => d.type === "skill"),
|
|
131
|
+
"Non-skill in skill list",
|
|
132
|
+
);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test("registry.resolve() finds models", () => {
|
|
136
|
+
const kling = registry.resolve("kling");
|
|
137
|
+
assert(kling !== null, "Could not resolve kling");
|
|
138
|
+
assertEqual(kling?.type, "model");
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
test("registry.resolve() finds actions", () => {
|
|
142
|
+
const video = registry.resolve("video");
|
|
143
|
+
assert(video !== null, "Could not resolve video");
|
|
144
|
+
assertEqual(video?.type, "action");
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
test("registry.resolve() finds skills", () => {
|
|
148
|
+
const skill = registry.resolve("talking-character");
|
|
149
|
+
assert(skill !== null, "Could not resolve talking-character");
|
|
150
|
+
assertEqual(skill?.type, "skill");
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
test("registry.resolve() returns null for unknown", () => {
|
|
154
|
+
const unknown = registry.resolve("nonexistent-thing");
|
|
155
|
+
assert(unknown === null, "Should return null for unknown");
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
test("registry.has() works correctly", () => {
|
|
159
|
+
assert(registry.has("video"), "Should have video");
|
|
160
|
+
assert(!registry.has("nonexistent"), "Should not have nonexistent");
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
test("registry.search() finds matching definitions", () => {
|
|
164
|
+
const results = registry.search("video");
|
|
165
|
+
assert(results.length > 0, "Should find video-related definitions");
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
test("registry.getModel() returns only models", () => {
|
|
169
|
+
const kling = registry.getModel("kling");
|
|
170
|
+
assert(kling !== undefined, "Should find kling model");
|
|
171
|
+
assert(
|
|
172
|
+
registry.getModel("video") === undefined,
|
|
173
|
+
"Should not find video as model",
|
|
174
|
+
);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
test("registry.getAction() returns only actions", () => {
|
|
178
|
+
const video = registry.getAction("video");
|
|
179
|
+
assert(video !== undefined, "Should find video action");
|
|
180
|
+
assert(
|
|
181
|
+
registry.getAction("kling") === undefined,
|
|
182
|
+
"Should not find kling as action",
|
|
183
|
+
);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
test("registry.stats returns correct counts", () => {
|
|
187
|
+
const stats = registry.stats;
|
|
188
|
+
assert(stats.models > 0, "Should have models");
|
|
189
|
+
assert(stats.actions > 0, "Should have actions");
|
|
190
|
+
assert(stats.skills > 0, "Should have skills");
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// ============================================================================
|
|
194
|
+
// Resolver Tests
|
|
195
|
+
// ============================================================================
|
|
196
|
+
|
|
197
|
+
console.log(`\n${dim("─ Resolver ─\n")}`);
|
|
198
|
+
|
|
199
|
+
test("resolve() returns exact matches", () => {
|
|
200
|
+
const result = resolve("video");
|
|
201
|
+
assertEqual(result.matchType, "exact");
|
|
202
|
+
assert(result.definition !== null, "Should find definition");
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
test("resolve() handles fuzzy matching", () => {
|
|
206
|
+
const result = resolve("vid", { fuzzy: true });
|
|
207
|
+
assert(result.suggestions !== undefined, "Should have suggestions");
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
test("resolve() throws on required not found", () => {
|
|
211
|
+
let threw = false;
|
|
212
|
+
try {
|
|
213
|
+
resolve("nonexistent", { required: true });
|
|
214
|
+
} catch {
|
|
215
|
+
threw = true;
|
|
216
|
+
}
|
|
217
|
+
assert(threw, "Should throw for required not found");
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
test("findSimilar() returns suggestions", () => {
|
|
221
|
+
const similar = findSimilar("vide");
|
|
222
|
+
assert(similar.length > 0, "Should find similar names");
|
|
223
|
+
assert(similar.includes("video"), "Should suggest 'video'");
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
test("suggest() returns prefix matches", () => {
|
|
227
|
+
const suggestions = suggest("vi");
|
|
228
|
+
assert(
|
|
229
|
+
suggestions.some((s) => s.startsWith("vi")),
|
|
230
|
+
"Should return prefix matches",
|
|
231
|
+
);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
// ============================================================================
|
|
235
|
+
// Schema Validation Tests (Zod-based)
|
|
236
|
+
// ============================================================================
|
|
237
|
+
|
|
238
|
+
console.log(`\n${dim("─ Schema Validation (Zod) ─\n")}`);
|
|
239
|
+
|
|
240
|
+
// Create a test Zod schema
|
|
241
|
+
const testSchema = z.object({
|
|
242
|
+
prompt: z.string().describe("Test prompt"),
|
|
243
|
+
count: z.number().int().default(1).describe("Count"),
|
|
244
|
+
mode: z.enum(["fast", "slow"]).default("fast").describe("Mode"),
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
test("validateInputs accepts valid inputs", () => {
|
|
248
|
+
const result = validateInputs({ prompt: "test" }, testSchema);
|
|
249
|
+
assert(
|
|
250
|
+
result.valid,
|
|
251
|
+
`Should be valid: ${result.errors.map((e) => e.message).join(", ")}`,
|
|
252
|
+
);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
test("validateInputs rejects missing required", () => {
|
|
256
|
+
const result = validateInputs({}, testSchema);
|
|
257
|
+
assert(!result.valid, "Should be invalid");
|
|
258
|
+
assert(
|
|
259
|
+
result.errors.some((e) => e.path === "prompt"),
|
|
260
|
+
"Should report missing prompt",
|
|
261
|
+
);
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
test("validateInputs validates enum values", () => {
|
|
265
|
+
const result = validateInputs(
|
|
266
|
+
{ prompt: "test", mode: "invalid" },
|
|
267
|
+
testSchema,
|
|
268
|
+
);
|
|
269
|
+
assert(!result.valid, "Should reject invalid enum");
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
test("applyDefaults adds default values", () => {
|
|
273
|
+
const inputs = applyDefaults({ prompt: "test" }, testSchema);
|
|
274
|
+
assertEqual(inputs.count, 1, "Should apply count default");
|
|
275
|
+
assertEqual(inputs.mode, "fast", "Should apply mode default");
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
test("validateAndPrepare combines validation and defaults", () => {
|
|
279
|
+
const result = validateAndPrepare({ prompt: "test" }, testSchema);
|
|
280
|
+
assert(result.valid, "Should be valid");
|
|
281
|
+
assertEqual(result.data?.count, 1, "Should have default count");
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
// ============================================================================
|
|
285
|
+
// Model Definition Tests
|
|
286
|
+
// ============================================================================
|
|
287
|
+
|
|
288
|
+
console.log(`\n${dim("─ Model Definitions ─\n")}`);
|
|
289
|
+
|
|
290
|
+
for (const model of allModels) {
|
|
291
|
+
test(`model '${model.name}' has required fields`, () => {
|
|
292
|
+
assert(model.type === "model", "Type should be 'model'");
|
|
293
|
+
assert(model.name.length > 0, "Name should not be empty");
|
|
294
|
+
assert(model.description.length > 0, "Description should not be empty");
|
|
295
|
+
assert(model.providers.length > 0, "Should have providers");
|
|
296
|
+
assert(model.defaultProvider.length > 0, "Should have default provider");
|
|
297
|
+
assert(
|
|
298
|
+
model.providers.includes(model.defaultProvider),
|
|
299
|
+
"Default provider should be in providers",
|
|
300
|
+
);
|
|
301
|
+
assert(model.schema !== undefined, "Should have schema");
|
|
302
|
+
// Use getCliSchemaInfo to check properties
|
|
303
|
+
const { properties } = getCliSchemaInfo(model.schema.input);
|
|
304
|
+
assert(Object.keys(properties).length > 0, "Should have input properties");
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// ============================================================================
|
|
309
|
+
// Action Definition Tests
|
|
310
|
+
// ============================================================================
|
|
311
|
+
|
|
312
|
+
console.log(`\n${dim("─ Action Definitions ─\n")}`);
|
|
313
|
+
|
|
314
|
+
for (const action of allActions) {
|
|
315
|
+
test(`action '${action.name}' has required fields`, () => {
|
|
316
|
+
assert(action.type === "action", "Type should be 'action'");
|
|
317
|
+
assert(action.name.length > 0, "Name should not be empty");
|
|
318
|
+
assert(action.description.length > 0, "Description should not be empty");
|
|
319
|
+
assert(action.schema !== undefined, "Should have schema");
|
|
320
|
+
assert(
|
|
321
|
+
action.routes !== undefined || action.execute !== undefined,
|
|
322
|
+
"Should have routes or execute function",
|
|
323
|
+
);
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// ============================================================================
|
|
328
|
+
// Skill Definition Tests
|
|
329
|
+
// ============================================================================
|
|
330
|
+
|
|
331
|
+
console.log(`\n${dim("─ Skill Definitions ─\n")}`);
|
|
332
|
+
|
|
333
|
+
for (const skill of allSkills) {
|
|
334
|
+
test(`skill '${skill.name}' has required fields`, () => {
|
|
335
|
+
assert(skill.type === "skill", "Type should be 'skill'");
|
|
336
|
+
assert(skill.name.length > 0, "Name should not be empty");
|
|
337
|
+
assert(skill.description.length > 0, "Description should not be empty");
|
|
338
|
+
assert(skill.schema !== undefined, "Should have schema");
|
|
339
|
+
assert(skill.steps.length > 0, "Should have steps");
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
test(`skill '${skill.name}' steps reference valid targets`, () => {
|
|
343
|
+
for (const step of skill.steps) {
|
|
344
|
+
assert(step.name.length > 0, `Step should have name`);
|
|
345
|
+
assert(step.run.length > 0, `Step '${step.name}' should have run target`);
|
|
346
|
+
// Note: We don't validate if target exists as it might be another action/model
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// ============================================================================
|
|
352
|
+
// Provider Registration Tests
|
|
353
|
+
// ============================================================================
|
|
354
|
+
|
|
355
|
+
console.log(`\n${dim("─ Provider Registration ─\n")}`);
|
|
356
|
+
|
|
357
|
+
const expectedProviders = [
|
|
358
|
+
"fal",
|
|
359
|
+
"replicate",
|
|
360
|
+
"elevenlabs",
|
|
361
|
+
"groq",
|
|
362
|
+
"fireworks",
|
|
363
|
+
"higgsfield",
|
|
364
|
+
"ffmpeg",
|
|
365
|
+
"storage",
|
|
366
|
+
];
|
|
367
|
+
|
|
368
|
+
for (const name of expectedProviders) {
|
|
369
|
+
test(`provider '${name}' is registered`, () => {
|
|
370
|
+
const provider = providers.get(name);
|
|
371
|
+
assert(provider !== undefined, `Provider '${name}' not found`);
|
|
372
|
+
assertEqual(provider?.name, name, "Provider name should match");
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
test(`providers.all() returns all providers`, () => {
|
|
377
|
+
const list = providers.all();
|
|
378
|
+
assert(
|
|
379
|
+
list.length >= expectedProviders.length,
|
|
380
|
+
`Expected at least ${expectedProviders.length} providers`,
|
|
381
|
+
);
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
// ============================================================================
|
|
385
|
+
// Summary
|
|
386
|
+
// ============================================================================
|
|
387
|
+
|
|
388
|
+
console.log(`\n${cyan("═".repeat(60))}`);
|
|
389
|
+
console.log(cyan(" SUMMARY"));
|
|
390
|
+
console.log(`${cyan("═".repeat(60))}\n`);
|
|
391
|
+
|
|
392
|
+
const total = passed + failed;
|
|
393
|
+
console.log(`Total: ${total}`);
|
|
394
|
+
console.log(`Passed: ${green(String(passed))}`);
|
|
395
|
+
console.log(`Failed: ${failed > 0 ? red(String(failed)) : "0"}`);
|
|
396
|
+
console.log("");
|
|
397
|
+
|
|
398
|
+
if (failed > 0) {
|
|
399
|
+
console.log(red(`${failed} test(s) failed!`));
|
|
400
|
+
process.exit(1);
|
|
401
|
+
} else {
|
|
402
|
+
console.log(green("All tests passed! ✨"));
|
|
403
|
+
}
|
package/tsconfig.json
CHANGED
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
// Environment setup & latest features
|
|
4
4
|
"lib": ["ESNext"],
|
|
5
5
|
"target": "ESNext",
|
|
6
|
-
"module": "
|
|
6
|
+
"module": "ESNext",
|
|
7
7
|
"moduleDetection": "force",
|
|
8
8
|
"jsx": "react-jsx",
|
|
9
|
+
"jsxImportSource": "@/react/runtime",
|
|
9
10
|
"allowJs": true,
|
|
10
11
|
|
|
11
12
|
// Bundler mode
|
|
@@ -24,6 +25,23 @@
|
|
|
24
25
|
// Some stricter flags (disabled by default)
|
|
25
26
|
"noUnusedLocals": false,
|
|
26
27
|
"noUnusedParameters": false,
|
|
27
|
-
"noPropertyAccessFromIndexSignature": false
|
|
28
|
-
|
|
28
|
+
"noPropertyAccessFromIndexSignature": false,
|
|
29
|
+
|
|
30
|
+
// Base URL for imports
|
|
31
|
+
"baseUrl": ".",
|
|
32
|
+
"paths": {
|
|
33
|
+
"@/*": ["./src/*"]
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"include": ["src/**/*"],
|
|
37
|
+
"exclude": [
|
|
38
|
+
"node_modules",
|
|
39
|
+
"action",
|
|
40
|
+
"lib",
|
|
41
|
+
"cli",
|
|
42
|
+
"service",
|
|
43
|
+
"utilities",
|
|
44
|
+
"pipeline",
|
|
45
|
+
"src/cli"
|
|
46
|
+
]
|
|
29
47
|
}
|
package/TEST_RESULTS.md
DELETED
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
# test results
|
|
2
|
-
|
|
3
|
-
## ✅ both fal approaches working
|
|
4
|
-
|
|
5
|
-
### approach 1: lib/ai-sdk/fal.ts (vercel ai sdk)
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
$ bun run lib/ai-sdk/fal.ts generate_image "futuristic spaceship" "fal-ai/flux/dev" "16:9"
|
|
9
|
-
|
|
10
|
-
[ai-sdk/fal] generating image with fal-ai/flux/dev
|
|
11
|
-
[ai-sdk/fal] prompt: futuristic spaceship interior
|
|
12
|
-
[ai-sdk/fal] aspect ratio: 16:9
|
|
13
|
-
[ai-sdk/fal] completed!
|
|
14
|
-
|
|
15
|
-
image saved to: /tmp/fal-ai-sdk-1763772836608.png
|
|
16
|
-
|
|
17
|
-
metadata:
|
|
18
|
-
{
|
|
19
|
-
"images": [
|
|
20
|
-
{
|
|
21
|
-
"width": 1024,
|
|
22
|
-
"height": 576,
|
|
23
|
-
"contentType": "image/jpeg",
|
|
24
|
-
"nsfw": false
|
|
25
|
-
}
|
|
26
|
-
]
|
|
27
|
-
}
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
✅ benefits:
|
|
31
|
-
- clean typed api
|
|
32
|
-
- auto image save + open
|
|
33
|
-
- aspect ratio support
|
|
34
|
-
- consistent with other ai-sdk providers
|
|
35
|
-
|
|
36
|
-
### approach 2: lib/fal.ts (fal client direct)
|
|
37
|
-
|
|
38
|
-
```bash
|
|
39
|
-
$ bun run lib/fal.ts generate_image "ancient temple ruins"
|
|
40
|
-
|
|
41
|
-
[fal] generating image with fal-ai/flux-pro/v1.1
|
|
42
|
-
[fal] prompt: ancient temple ruins at sunset
|
|
43
|
-
[fal] processing...
|
|
44
|
-
[fal] completed!
|
|
45
|
-
|
|
46
|
-
{
|
|
47
|
-
"data": {
|
|
48
|
-
"images": [
|
|
49
|
-
{
|
|
50
|
-
"url": "https://v3b.fal.media/files/b/koala/L5LYGCHZ4aZ_CKZsmPbUe.jpg",
|
|
51
|
-
"width": 1024,
|
|
52
|
-
"height": 768,
|
|
53
|
-
"content_type": "image/jpeg"
|
|
54
|
-
}
|
|
55
|
-
],
|
|
56
|
-
"seed": 2946158106
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
✅ benefits:
|
|
62
|
-
- full api access
|
|
63
|
-
- queue updates
|
|
64
|
-
- video support
|
|
65
|
-
- custom parameters
|
|
66
|
-
|
|
67
|
-
## cli tests ✅
|
|
68
|
-
|
|
69
|
-
all help menus working:
|
|
70
|
-
|
|
71
|
-
```bash
|
|
72
|
-
bun run lib/ai-sdk/fal.ts # ✓
|
|
73
|
-
bun run lib/fal.ts # ✓
|
|
74
|
-
bun run lib/higgsfield.ts # ✓
|
|
75
|
-
bun run service/image.ts # ✓
|
|
76
|
-
bun run service/video.ts # ✓
|
|
77
|
-
bun run utilities/s3.ts # ✓
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
## library imports ✅
|
|
81
|
-
|
|
82
|
-
```typescript
|
|
83
|
-
import { generateImage } from "./index"
|
|
84
|
-
import * as aiSdkFal from "./index"
|
|
85
|
-
|
|
86
|
-
// both approaches available
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
## actual generation tests ✅
|
|
90
|
-
|
|
91
|
-
successfully generated and opened:
|
|
92
|
-
- cyberpunk city (16:9, ai-sdk)
|
|
93
|
-
- spaceship interior (16:9, ai-sdk)
|
|
94
|
-
- temple ruins (4:3, fal client)
|
|
95
|
-
- aurora borealis (4:3, fal client)
|
|
96
|
-
|
|
97
|
-
all images ~15-20 seconds generation time
|
|
98
|
-
|
|
99
|
-
## what works
|
|
100
|
-
|
|
101
|
-
1. **dual fal implementations** - ai-sdk for simplicity, client for power ✓
|
|
102
|
-
2. **all cli scripts executable** with proper help menus ✓
|
|
103
|
-
3. **library imports functional** ✓
|
|
104
|
-
4. **actual image generation working** ✓
|
|
105
|
-
5. **automatic image opening** (ai-sdk version) ✓
|
|
106
|
-
6. **queue progress updates** (fal client) ✓
|
|
107
|
-
|
|
108
|
-
## file structure
|
|
109
|
-
|
|
110
|
-
```
|
|
111
|
-
lib/
|
|
112
|
-
├── ai-sdk/
|
|
113
|
-
│ └── fal.ts # vercel ai sdk approach
|
|
114
|
-
├── fal.ts # fal client approach
|
|
115
|
-
└── higgsfield.ts # soul character generation
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
## recommendations
|
|
119
|
-
|
|
120
|
-
- **use lib/ai-sdk/fal.ts** for standard image generation
|
|
121
|
-
- **use lib/fal.ts** for video or advanced features
|
|
122
|
-
- **use service/**.ts for high-level operations with s3 upload
|