You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(ai-openrouter): typed per-model durations for video adapter
Wire openRouterVideo onto the shared typed-duration contract (the same one
geminiVideo uses): add the sixth BaseVideoAdapter generic
(OpenRouterVideoModelDurationByName), narrow `duration` per model from the
published `/api/v1/videos/models` metadata, and override availableDurations()
/ snapDuration() (backed by snapToDurationOption). `duration` is now a
compile-time per-model union; the runtime validateVideoDuration backstop stays
for JS callers and unknown-meta models.
- video-provider-options.ts: OpenRouterVideoModelDurationByName +
getVideoDurationOptions (discrete from meta, none when unknown/empty)
- adapter: 6th generic, createVideoJob narrowed to per-model size/duration,
availableDurations()/snapDuration() overrides
- export OpenRouterVideoModelDurationByName from index
- tests: 4 introspection cases; existing negative size/duration tests now use
@ts-expect-error (proves the union rejects them) while still asserting the
runtime throw
- docs/media/video-generation.md, docs/adapters/openrouter.md, media-generation
SKILL.md: document snapDuration/availableDurations for OpenRouter; bump
updatedAt; changeset
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: .changeset/openrouter-video-adapter.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,6 +2,6 @@
2
2
'@tanstack/ai-openrouter': minor
3
3
---
4
4
5
-
Add `openRouterVideo`, a video generation adapter for OpenRouter's dedicated async API (`POST /api/v1/videos`) — Seedance, Veo 3.1, Wan, Kling, and Sora 2 Pro through one API key. Follows the jobs/polling architecture (`generateVideo()` → `getVideoJobStatus()`), with per-model `size` / `duration` / provider-option types generated from OpenRouter's `GET /api/v1/videos/models` metadata and validated before submit. Image-conditioned prompts map `metadata.role` onto the wire: `start_frame` / `end_frame` → `frame_images[]` (`first_frame` / `last_frame`), `reference` / `character` → `input_references[]`; frame roles are validated against each model's `supported_frame_images`. Completed videos are downloaded server-side and returned as `data:` URLs (OpenRouter's download URLs require the API key), and the gateway-reported cost is surfaced as `usage.cost`.
5
+
Add `openRouterVideo`, a video generation adapter for OpenRouter's dedicated async API (`POST /api/v1/videos`) — Seedance, Veo 3.1, Wan, Kling, and Sora 2 Pro through one API key. Follows the jobs/polling architecture (`generateVideo()` → `getVideoJobStatus()`), with per-model `size` / `duration` / provider-option types generated from OpenRouter's `GET /api/v1/videos/models` metadata and validated before submit. `duration` is typed per model on the shared typed-duration contract — the adapter implements `availableDurations()` and `snapDuration(seconds)` (matching the Veo adapter) to enumerate the valid set and coerce raw UI seconds to the closest supported value. Image-conditioned prompts map `metadata.role` onto the wire: `start_frame` / `end_frame` → `frame_images[]` (`first_frame` / `last_frame`), `reference` / `character` → `input_references[]`; frame roles are validated against each model's `supported_frame_images`. Completed videos are downloaded server-side and returned as `data:` URLs (OpenRouter's download URLs require the API key), and the gateway-reported cost is surfaced as `usage.cost`.
6
6
7
7
Image adapter fixes from the #624 review: requested `size` is now validated (the `WIDTHxHEIGHT` union previously used a Unicode `×`, so every size except `1024x1024` silently dropped its aspect ratio; unsupported sizes now throw with the supported list), `numberOfImages > 1` throws instead of silently returning one image (verified live: the gateway ignores all count keys in `image_config`), and `image_config.strength` (0.0–1.0 image-to-image influence) is exposed via `modelOptions.strength`.
0 commit comments