fix: normalize video duration per model rules via Zod schemas#194
fix: normalize video duration per model rules via Zod schemas#194SecurityQQ merged 1 commit intomainfrom
Conversation
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 Walkthroughwalkthroughrefactored fal provider by extracting duration normalization into a new changes
sequence diagram(s)(skip — changes are modular and don't introduce a new multi-component flow) estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/ai-sdk/providers/model-rules.ts`:
- Around line 68-100: ModelInputSchemas is missing entries for several Falcon
video model variants so those IDs will bypass validation; add explicit schema
rules for "grok-imagine-edit", "grok-imagine-image", "grok-imagine-image/edit",
"kling-v2.6-motion", "kling-v2.6-motion-standard", and "sora-2-remix" into the
ModelInputSchemas map (or implement a clear fallback rule at the top of the map)
using the same helper validators used elsewhere (stringIntDuration,
enumDuration, rangeDuration, intDuration) to mirror the appropriate existing
variants (e.g., match "grok-imagine" rules for grok-imagine-* variants, match
"kling-v2.6" for kling-v2.6-motion*, and match "sora-2" for sora-2-remix) so
these IDs are validated consistently by the lookup.
- Around line 116-127: normalizeProviderInput currently silently applies schema
coercions via ModelInputSchemas and schema.safeParse, losing the previous
warning behavior; update normalizeProviderInput to detect when the
parsed/normalized value differs from the original (e.g., compare input.duration
to result.data.duration) and return the normalized input together with a
warnings array (or attach a warnings property) describing adjustments (for
example: "Duration Xs not supported. Using Ys"); ensure the function signature
and callers that consume normalizeProviderInput are updated to accept { input:
Record<string, unknown>, warnings?: string[] } (or similar) and emit a warning
only when the schema clamps or coerces values so callers regain observability of
changes.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 38e54a08-c86b-4122-8723-1b53b644d8f6
📒 Files selected for processing (2)
src/ai-sdk/providers/fal.tssrc/ai-sdk/providers/model-rules.ts
src/ai-sdk/providers/model-rules.ts
Outdated
| const ModelInputSchemas: Record<string, z.ZodType> = { | ||
| // Kling O3 (v3): fal expects string integer "3"–"15" | ||
| "kling-v3": z.object({ duration: stringIntDuration(3, 15, 5) }), | ||
| "kling-v3-standard": z.object({ duration: stringIntDuration(3, 15, 5) }), | ||
|
|
||
| // Kling v2.6: same rules as v3 | ||
| "kling-v2.6": z.object({ duration: stringIntDuration(3, 15, 5) }), | ||
|
|
||
| // Kling legacy: exactly 5 or 10 | ||
| "kling-v2.5": z.object({ duration: enumDuration([5, 10], 5) }), | ||
| "kling-v2.1": z.object({ duration: enumDuration([5, 10], 5) }), | ||
| "kling-v2": z.object({ duration: enumDuration([5, 10], 5) }), | ||
|
|
||
| // Wan: 5 or 10 | ||
| "wan-2.5": z.object({ duration: enumDuration([5, 10], 5) }), | ||
| "wan-2.5-preview": z.object({ duration: enumDuration([5, 10], 5) }), | ||
|
|
||
| // Minimax: round to integer | ||
| minimax: z.object({ duration: intDuration(5) }), | ||
|
|
||
| // Grok Imagine: integer 1–15 | ||
| "grok-imagine": z.object({ duration: rangeDuration(1, 15, 6) }), | ||
|
|
||
| // Sora 2: only 4, 8, 12, 16, 20 | ||
| "sora-2": z.object({ duration: enumDuration([4, 8, 12, 16, 20], 4) }), | ||
| "sora-2-pro": z.object({ duration: enumDuration([4, 8, 12, 16, 20], 4) }), | ||
|
|
||
| // Seedance (piapi): 5, 10, or 15 | ||
| "seedance-2-preview": z.object({ duration: enumDuration([5, 10, 15], 5) }), | ||
| "seedance-2-fast-preview": z.object({ | ||
| duration: enumDuration([5, 10, 15], 5), | ||
| }), | ||
| }; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# check if VIDEO_MODELS keys in fal.ts are all covered in ModelInputSchemas
# extract model ids from both files and compare
echo "=== VIDEO_MODELS in fal.ts ==="
rg -o '"[^"]+":' src/ai-sdk/providers/fal.ts | head -50 | grep -E 'kling|wan|minimax|grok|sora|seedance' | sort -u
echo ""
echo "=== ModelInputSchemas keys ==="
rg -o '"[^"]+":|^ [a-z].*:' src/ai-sdk/providers/model-rules.ts | grep -v '//' | sort -uRepository: vargHQ/sdk
Length of output: 712
add schema definitions for missing model variants - the lookup doesn't cover all video models from fal.ts. these ids are missing from ModelInputSchemas and will skip validation:
- grok-imagine-edit
- grok-imagine-image
- grok-imagine-image/edit
- kling-v2.6-motion
- kling-v2.6-motion-standard
- sora-2-remix
add explicit schema rules for each or define a fallback strategy meow
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/ai-sdk/providers/model-rules.ts` around lines 68 - 100, ModelInputSchemas
is missing entries for several Falcon video model variants so those IDs will
bypass validation; add explicit schema rules for "grok-imagine-edit",
"grok-imagine-image", "grok-imagine-image/edit", "kling-v2.6-motion",
"kling-v2.6-motion-standard", and "sora-2-remix" into the ModelInputSchemas map
(or implement a clear fallback rule at the top of the map) using the same helper
validators used elsewhere (stringIntDuration, enumDuration, rangeDuration,
intDuration) to mirror the appropriate existing variants (e.g., match
"grok-imagine" rules for grok-imagine-* variants, match "kling-v2.6" for
kling-v2.6-motion*, and match "sora-2" for sora-2-remix) so these IDs are
validated consistently by the lookup.
| export function normalizeProviderInput( | ||
| model: string, | ||
| input: Record<string, unknown>, | ||
| ): Record<string, unknown> { | ||
| const schema = ModelInputSchemas[model]; | ||
| if (!schema) return input; | ||
|
|
||
| const result = schema.safeParse({ duration: input.duration }); | ||
| if (!result.success) return input; | ||
|
|
||
| return { ...input, ...(result.data as Record<string, unknown>) }; | ||
| } |
There was a problem hiding this comment.
silent normalization loses observability from previous implementation
the old openai.ts and fal.ts code pushed warnings when duration was invalid or clamped (e.g., "Duration ${duration}s not supported. Using ${validSeconds}s"). this new approach silently transforms values without any indication to the caller.
if someone passes duration: 2.5 to kling-v3, it silently becomes "3" with no warning. might want to consider returning warnings alongside the normalized input for cases where values were adjusted.
💡 possible approach to add observability
+interface NormalizeResult {
+ input: Record<string, unknown>;
+ warnings: string[];
+}
+
export function normalizeProviderInput(
model: string,
input: Record<string, unknown>,
-): Record<string, unknown> {
+): NormalizeResult {
const schema = ModelInputSchemas[model];
- if (!schema) return input;
+ if (!schema) return { input, warnings: [] };
const result = schema.safeParse({ duration: input.duration });
- if (!result.success) return input;
+ if (!result.success) return { input, warnings: [] };
- return { ...input, ...(result.data as Record<string, unknown>) };
+ const normalized = { ...input, ...(result.data as Record<string, unknown>) };
+ const warnings: string[] = [];
+ if (input.duration !== undefined && normalized.duration !== input.duration) {
+ warnings.push(`Duration ${input.duration} normalized to ${normalized.duration} for ${model}`);
+ }
+ return { input: normalized, warnings };
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/ai-sdk/providers/model-rules.ts` around lines 116 - 127,
normalizeProviderInput currently silently applies schema coercions via
ModelInputSchemas and schema.safeParse, losing the previous warning behavior;
update normalizeProviderInput to detect when the parsed/normalized value differs
from the original (e.g., compare input.duration to result.data.duration) and
return the normalized input together with a warnings array (or attach a warnings
property) describing adjustments (for example: "Duration Xs not supported. Using
Ys"); ensure the function signature and callers that consume
normalizeProviderInput are updated to accept { input: Record<string, unknown>,
warnings?: string[] } (or similar) and emit a warning only when the schema
clamps or coerces values so callers regain observability of changes.
Replace the scattered duration if/else chain in fal.ts with a centralised normalizeProviderInput() backed by per-model Zod schemas. Each model gets a .transform() schema that clamps, rounds, and type-converts duration values automatically. Fixes kling-v3/v2.6 failures when duration is a float (from speech segments) or outside the [3,15] range.
94fc438 to
0bea8a1
Compare
Summary
model-rules.tswith per-model Zod schemas that validate and transformdurationvalues via.transform()— rounding floats, clamping to valid ranges, and converting typesif/elsechain infal.tswith a singlenormalizeProviderInput()callresolution, Soradelete_video) preserved alongside the new normalizationProblem
All 6 clips failed with:
Input should be '3', '4', '5', ... '15'onfal-ai/kling-video/o3/pro/image-to-video.The SDK was doing
String(duration ?? 5)but never clamping range or rounding — floats like2.34from speech segments became"2.34"(rejected), and values outside [3,15] passed through.Model rules defined
kling-v3,kling-v3-standard,kling-v2.6stringkling-v2.5,kling-v2.1,kling-v2numberwan-2.5,wan-2.5-previewnumberminimaxnumbergrok-imaginenumbersora-2,sora-2-pronumberseedance-2-*numberCompanion gateway PR: https://github.com/vargHQ/gateway/pull/new/fix/normalize-provider-duration