Summary
The typed-duration contract (TModelDurationByName generic + availableDurations() / snapDuration() introspection, plus the shared snapToDurationOption util) landed on main via #624 (commit 8fa6cc56, 2026-06-17). But only Gemini Veo actually adopted it. The fal video adapter still sits on the base-class defaults (availableDurations() → { kind: 'none' }, snapDuration() → undefined, duration?: number), so fal callers get no per-model duration typing and the introspection helpers are inert.
This issue tracks migrating falVideo onto the contract.
Current state on main
| Adapter |
On the typed-duration contract? |
geminiVideo |
✅ Yes (overrides availableDurations/snapDuration) |
falVideo |
❌ No — base defaults |
openaiVideo (Sora) |
❌ No — base defaults (descoped from #641 at the time) |
openRouterVideo |
✅ Yes (added on the #707 branch, matching the Veo pattern) |
What to do
- Add
FalVideoModelDurationByName (per-model duration unions) and a getFalVideoDurationOptions(model) returning DurationOptions, following packages/ai-gemini/src/video/video-provider-options.ts and packages/ai-openrouter/src/video/video-provider-options.ts.
- Wire the sixth
BaseVideoAdapter generic in packages/ai-fal/src/adapters/video.ts, narrow createVideoJob's duration, and override availableDurations() / snapDuration().
- fal durations are heterogeneous (discrete enums,
'8s'-style keyword-with-unit strings, ranges like Wan 2…15, and kind: 'none' for Minimax/Hunyuan), so the DurationOptions mapping must cover discrete / range / mixed / none — snapToDurationOption already handles all of those.
- Unit tests for the duration table + snap behavior; update docs (
docs/media/video-generation.md provider table) and the ai-core/media-generation SKILL.
Prior art / context
Refs: #534, #538, #624, #641, #707
Summary
The typed-duration contract (
TModelDurationByNamegeneric +availableDurations()/snapDuration()introspection, plus the sharedsnapToDurationOptionutil) landed onmainvia #624 (commit8fa6cc56, 2026-06-17). But only Gemini Veo actually adopted it. The fal video adapter still sits on the base-class defaults (availableDurations() → { kind: 'none' },snapDuration() → undefined,duration?: number), so fal callers get no per-model duration typing and the introspection helpers are inert.This issue tracks migrating
falVideoonto the contract.Current state on
maingeminiVideoavailableDurations/snapDuration)falVideoopenaiVideo(Sora)openRouterVideoWhat to do
FalVideoModelDurationByName(per-model duration unions) and agetFalVideoDurationOptions(model)returningDurationOptions, followingpackages/ai-gemini/src/video/video-provider-options.tsandpackages/ai-openrouter/src/video/video-provider-options.ts.BaseVideoAdaptergeneric inpackages/ai-fal/src/adapters/video.ts, narrowcreateVideoJob'sduration, and overrideavailableDurations()/snapDuration().'8s'-style keyword-with-unit strings, ranges like Wan2…15, andkind: 'none'for Minimax/Hunyuan), so theDurationOptionsmapping must coverdiscrete/range/mixed/none—snapToDurationOptionalready handles all of those.docs/media/video-generation.mdprovider table) and theai-core/media-generationSKILL.Prior art / context
534-video-duration-support), but it targets the#622schemas branch and never rebased tomain, which is why fal regressed to defaults when the contract merged via feat: multimodal prompt for generateImage/generateVideo (image-to-image, image-to-video) #624. This issue can either rebase/retarget feat(ai,ai-fal): per-model typed durations for video generation #641 tomainor reimplement the fal half directly.main/ the feat(ai-openrouter): video generation adapter (/api/v1/videos) + image activity follow-ups #707 branch:packages/ai-gemini/src/{video/video-provider-options.ts,adapters/video.ts}andpackages/ai-openrouter/src/{video/video-provider-options.ts,adapters/video.ts}.Refs: #534, #538, #624, #641, #707