@koda-sl/baker-cli 0.246.0 → 0.247.0

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/README.md CHANGED
@@ -3485,7 +3485,7 @@ baker studio animate "handheld drift right, steam rising from the cup" \
3485
3485
  baker studio animate "product rotates once on a turntable" --image j57abc…,j57def… --from references
3486
3486
  ```
3487
3487
 
3488
- The image fixes the look, so the prompt describes **movement**. Models: `google/gemini-omni-flash` (default), `bytedance/seedance-2.0`, `bytedance/seedance-2.5`, `google/veo-3.1`, `google/veo-3.1-fast`, `kwaivgi/kling-v3.0-pro`.
3488
+ The image fixes the look, so the prompt describes **movement**. Models: `google/gemini-omni-1.1-flash` (default), `google/gemini-omni-flash` (legacy preview), `bytedance/seedance-2.0`, `bytedance/seedance-2.5`, `google/veo-3.1`, `google/veo-3.1-fast`, `kwaivgi/kling-v3.0-pro`.
3489
3489
 
3490
3490
  **`bytedance/seedance-2.5` is the long-form, multimodal tier**, and the only model that does either of the two things below. Reach for it when the beat cannot be five seconds, or when the source is footage rather than a still.
3491
3491
 
@@ -3512,7 +3512,7 @@ baker studio animate "she keeps walking, camera stays with her, then she stops a
3512
3512
  | `--from` | `frame` (default — animate the first image) \| `references` (use the assets as visual guidance) \| `text` (no image; render the prompt). The first two are mutually exclusive at every provider |
3513
3513
  | `--from-clip` | Studio takes to build on, `batchId:slot` comma-separated (Seedance 2.5, needs `--from references`) |
3514
3514
  | `--from-video` | Library video ids to build on — same 10-clip budget as `--from-clip` |
3515
- | `--model` | Video model id (default `google/gemini-omni-flash`) |
3515
+ | `--model` | Video model id (default `google/gemini-omni-1.1-flash`) |
3516
3516
  | `--aspect-ratio` | Default `9:16` |
3517
3517
  | `--duration` | Seconds; per-model set (default 5, snapped onto what the model renders) |
3518
3518
  | `--quality` | Resolution, e.g. `720p` (default) \| `1080p` |
@@ -4316,7 +4316,7 @@ Fail-fast: an invalid model selection (wrong count, duplicate or out-of-range pi
4316
4316
 
4317
4317
  ##### `video_generate`
4318
4318
 
4319
- Generate video. Curated model roster (per-model params below). Async with polling, except `google/gemini-omni-flash`, which returns its clip inline.
4319
+ Generate video. Curated model roster (per-model params below). Async with polling, except `google/gemini-omni-1.1-flash`, which returns its clip inline.
4320
4320
 
4321
4321
  **Inputs**
4322
4322
 
@@ -4339,20 +4339,23 @@ Accepted ref-image MIMEs vary by model — see per-model sections below.
4339
4339
 
4340
4340
  ---
4341
4341
 
4342
- ###### Model: `google/gemini-omni-flash` (default)
4342
+ ###### Model: `google/gemini-omni-1.1-flash` (default)
4343
4343
 
4344
- The default `video_generate` model (`DEFAULT_VIDEO_GENERATE_MODEL`). Natively multimodal — one call returns picture **and** synchronized audio. **Not on OpenRouter** (its `GET /api/v1/videos/models` catalogue of 17 video models does not include it): routed direct to Google's **Interactions API**, `POST https://generativelanguage.googleapis.com/v1beta/interactions`, wire model `gemini-omni-flash-preview`. Its own `generateContent` endpoint refuses the model ("This model only supports Interactions API"), and it does not use Veo's `predictLongRunning` shape. The call is synchronous (~30–40s) and returns the MP4 inline as base64 — no polling.
4344
+ The default `video_generate` model (`DEFAULT_VIDEO_GENERATE_MODEL`). Natively multimodal — one call returns picture **and** synchronized audio. **Not on OpenRouter** (its `GET /api/v1/videos/models` catalogue of 17 video models does not include it): routed direct to Google's **Interactions API**, `POST https://generativelanguage.googleapis.com/v1beta/interactions`, wire model `gemini-omni-1.1-flash`. Its own `generateContent` endpoint refuses the model ("This model only supports Interactions API"), and it does not use Veo's `predictLongRunning` shape. The call is synchronous (~30–40s) and returns the MP4 inline as base64 — no polling.
4345
4345
 
4346
4346
  Ref-image MIMEs: `image/png`, `image/jpeg`, `image/webp`. Takes **one** conditioning image — there is no `last_frame`, and wiring one raises `VIDEO_MODEL_IGNORES_INPUT`. Tasks: `text_to_video`, `image_to_video`, `reference_to_video`, `edit`, `extend` — the only curated model besides Seedance that accepts `references`.
4347
4347
 
4348
4348
  | Name | Type | Required | Notes |
4349
4349
  |---|---|---|---|
4350
- | `model` | literal | yes | `"google/gemini-omni-flash"` |
4350
+ | `model` | literal | yes | `"google/gemini-omni-1.1-flash"` |
4351
4351
  | `prompt` | string | yes | non-empty |
4352
4352
  | `aspect_ratio` | enum | no | `16:9 \| 9:16` (`1:1` is rejected) |
4353
+ | `resolution` | enum | no | `360p \| 720p \| 1080p \| 4k`. Omitted ⇒ **720p**. Note the lowercase `4k` — `4K` is Veo's spelling and is rejected here. |
4353
4354
  | `duration` | enum | no | `3, 4, 5, 6, 7, 8, 9, 10` seconds. Omitted ⇒ **10s** — the model's own default *and* its ceiling. |
4354
4355
 
4355
- > Those are the **only** accepted params. `resolution`, `seed`, `negative_prompt`, `generate_audio`, `person_generation`, `enhance_prompt` and `conditioning_scale` each fail pre-dispatch with a 400 `Unknown parameter`. Output is fixed: **720p** (1280×720 or 720×1280), 24fps, h264 + native stereo AAC — audio is always on.
4356
+ > Those are the **only** accepted params. `seed`, `negative_prompt`, `generate_audio`, `person_generation`, `enhance_prompt` and `conditioning_scale` each fail pre-dispatch with a 400 `Unknown parameter`. Output is 24fps, h264 + native stereo AAC — audio is always on and has no toggle. Measured frame sizes: 640×360, 1280×720, 1920×1080, 3840×2160 (the last two are upscales of the same render).
4357
+
4358
+ > **`resolution` is new in 1.1** — the preview model had no such knob and 400'd the field, which is why older notes say Omni is 720p-only. **Video input is a different story: it does not work on our key.** 1.1 advertises video references, `edit` and `extend`, and every request carrying a video input part comes back 400 `content_blocked`, whether the clip is inlined as base64 or uploaded to the Files API and passed by `uri` — including a clip Omni itself had just rendered. An ordinary `https://` URL is refused separately with "HTTP video input is not supported by the model". Image references on the same key and request shape render fine. Until that clears, a beat that must build on existing footage belongs on `bytedance/seedance-2.5`.
4356
4359
 
4357
4360
  > `duration` is the exception. Omni has **no duration field** — every spelling at every nesting level (`duration`, `duration_seconds`, `seconds`, `length`, `video_length`, `num_frames`, at top level, inside `response_format`, inside `generation_config.video_config`) comes back `Unknown parameter`. But it **honours a length asked for in the prompt**, so the backend adapter (`convex/lib/geminiOmni.ts`) translates the canonical `duration` param into a prompt directive. Measured: "exactly 3 seconds" → 3.008s, "exactly 6 seconds" → 6.016s, no length named → 10.005s.
4358
4361
 
@@ -4361,13 +4364,30 @@ Ref-image MIMEs: `image/png`, `image/jpeg`, `image/webp`. Takes **one** conditio
4361
4364
  ```json
4362
4365
  { "id": "clip", "type": "video_generate",
4363
4366
  "inputs": { "first_frame": "$ref:start.images#0" },
4364
- "params": { "model": "google/gemini-omni-flash", "prompt": "Same person, talking head, …",
4367
+ "params": { "model": "google/gemini-omni-1.1-flash", "prompt": "Same person, talking head, …",
4365
4368
  "aspect_ratio": "9:16", "duration": 6 } }
4366
4369
  ```
4367
4370
 
4368
- > **Billed per token, which resolves to a clean per-second rate** — $17.50 per 1M video output tokens ($1.50 per 1M input, noise), and 720p video is a flat **5,792 tokens per second at every length** (3.008s 17,376 tokens; 6.016s 34,752; 10.005s → 57,920). So **$0.10136 per second**: a 10s clip ~$1.01 (102 credits), a 4s clip ~$0.41 (41 credits), a 3s clip ~$0.30 (31 credits). Cutting a clip short is a real saving. A 5s 720p Seedance clip is $2.50.
4371
+ > **Billed per token, which resolves to a clean per-second rate at each tier** — $17.50 per 1M video output tokens ($1.50 per 1M input, noise). Video output is flat per second of footage and linear in both length and tier, measured: 720p returned 17,376 tokens for 3.008s and 34,752 for 6.016s, and at a fixed 3s the four tiers returned 5,793 / 17,376 / 26,064 / 52,128 exactly ⅓, 1, 1.5 and 3 times the 720p rate.
4372
+ >
4373
+ > | Tier | Tokens/s | USD/s | 3s clip | 10s clip |
4374
+ > |---|---|---|---|---|
4375
+ > | `360p` | 1,931 | $0.0338 | ~$0.10 (11 cr) | ~$0.34 (35 cr) |
4376
+ > | `720p` | 5,792 | $0.1014 | ~$0.30 (31 cr) | ~$1.01 (102 cr) |
4377
+ > | `1080p` | 8,688 | $0.1520 | ~$0.46 (46 cr) | ~$1.52 (153 cr) |
4378
+ > | `4k` | 17,376 | $0.3041 | ~$0.91 (92 cr) | ~$3.04 (305 cr) |
4379
+ >
4380
+ > Cutting a clip short is a real saving, and so is drafting at `360p`: five 360p takes cost less than two at 720p. (The **preview** model billed its whole 10s window whatever length it returned — a flat ~$1.03 — so anything quoting Omni at a flat rate predates 1.1.) A 5s 720p Seedance clip is $2.50.
4381
+
4382
+ > **Move off the default** when a beat needs a length outside 3–10s, a `1:1` frame, existing footage as an input, or a photoreal human face on camera (that still routes to Veo, unchanged). 1080p no longer forces a move.
4383
+
4384
+ ###### Model: `google/gemini-omni-flash` (legacy preview)
4385
+
4386
+ The Omni **preview** (wire model `gemini-omni-flash-preview`), superseded by `google/gemini-omni-1.1-flash`. Kept in the roster so canvases authored before 1.1 still validate and re-run verbatim — **don't pick it for new work.** It is 1.1 minus the quality dial: same per-second rate, `prompt` / `aspect_ratio` / `duration` and nothing else.
4387
+
4388
+ > **It does not reject a `resolution` — it ignores one.** Asked for `360p` it returns HTTP 200, a **1280×720** clip, and a bill of **17,376 video tokens** (the 720p rate, 3× the 5,793 that tier costs on 1.1). Accepted, ignored, charged for. That is why the registry declares no `resolution` here and the studio refuses one outright rather than passing it through: this is the one model where asking for a cheaper tier silently costs full price.
4369
4389
 
4370
- > **Move off the default** when a beat needs 1080p, a length outside 3–10s, a `1:1` frame, or a photoreal human face on camera (that still routes to Veo, unchanged).
4390
+ > Historical note: this model used to bill its **whole 10s window** whatever length it rendered (a 3s and a 4s clip both ~$1.034). Re-measured, that is gone 3s bills 17,376 tokens and 6s 34,752, the same per-second line as 1.1.
4371
4391
 
4372
4392
  ###### Model: `bytedance/seedance-2.0`
4373
4393
 
@@ -5050,7 +5070,7 @@ baker canvas run ./reference-ad.video.canvas.json
5050
5070
  | `--deconstruct-model <id>` | `~google/gemini-pro-latest` | Override the `video_deconstruct` model. |
5051
5071
  | `--select-model <id>` | `~google/gemini-flash-latest` | Override the element-selection `text_generate` model. |
5052
5072
  | `--image-model <id>` | `openai/gpt-image-2` | Override the per-frame `image_generate` model (defaults to the strongest, matching `scaffold-static-ad`). |
5053
- | `--video-model <id>` | scored router | Override the `video_generate` model **and skip the router**. Curated roster: `google/gemini-omni-flash` (**the default video model** — native audio + reference images, ~$0.101 per second of clip, 720p/`16:9`\|`9:16`, `duration` 3–10s and 10s when unset), `bytedance/seedance-2.0` (workhorse), `google/veo-3.1` (cine ceiling + real-face), `google/veo-3.1-fast` (cheap Veo), `kwaivgi/kling-v3.0-pro` (motion-transfer). |
5073
+ | `--video-model <id>` | scored router | Override the `video_generate` model **and skip the router**. Curated roster: `google/gemini-omni-1.1-flash` (**the default video model** — native audio + reference images, `360p`\|`720p`\|`1080p`\|`4k` at ~$0.034\|$0.101\|$0.152\|$0.304 per second, `16:9`\|`9:16`, `duration` 3–10s and 10s when unset), `bytedance/seedance-2.0` (workhorse), `google/veo-3.1` (cine ceiling + real-face), `google/veo-3.1-fast` (cheap Veo), `kwaivgi/kling-v3.0-pro` (motion-transfer). |
5054
5074
  | `--real-face` | auto-detected | Force the Veo route for a photoreal human presenter (dodges the ByteDance real-person filter). **Usually unnecessary** — the scaffold auto-detects a photoreal on-camera person/animal cast from the deconstruct and routes it to Veo on its own; set this only to force it when the cast isn't detected. Covers AI-generated photoreal faces too, not just real ones. |
5055
5075
  | `--motion-transfer` | off | Motion driven from a reference / hyper-dynamic → the router picks Kling. |
5056
5076
  | `--identity` | off | Same character/product across clips → the router picks the Seedance workhorse. |
@@ -1191,6 +1191,7 @@ var SEEDANCE_25_MAX_AUDIO_REFERENCES = 10;
1191
1191
  var KLING_DURATIONS = [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
1192
1192
  var GEMINI_OMNI_DURATIONS = [3, 4, 5, 6, 7, 8, 9, 10];
1193
1193
  var GEMINI_OMNI_ASPECT_RATIOS = ["16:9", "9:16"];
1194
+ var GEMINI_OMNI_RESOLUTIONS = ["360p", "720p", "1080p", "4k"];
1194
1195
  var GEMINI_OMNI_IMAGE_MIMES = ["image/png", "image/jpeg", "image/webp"];
1195
1196
  var GROK_IMAGINE_DURATIONS = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
1196
1197
  var WAN_27_DURATIONS = [2, 3, 4, 5, 6, 7, 8, 9, 10];
@@ -1224,6 +1225,7 @@ var DEFAULT_IMAGE_GENERATE_MODEL = "google/gemini-3.1-flash-image-preview";
1224
1225
  var VIDEO_GENERATE_MODELS = [
1225
1226
  "bytedance/seedance-2.0",
1226
1227
  "bytedance/seedance-2.5",
1228
+ "google/gemini-omni-1.1-flash",
1227
1229
  "google/gemini-omni-flash",
1228
1230
  "google/veo-3.1",
1229
1231
  "google/veo-3.1-fast",
@@ -1233,10 +1235,11 @@ var VIDEO_GENERATE_MODELS = [
1233
1235
  "alibaba/wan-2.7",
1234
1236
  "alibaba/happyhorse-1.1"
1235
1237
  ];
1236
- var DEFAULT_VIDEO_GENERATE_MODEL = "google/gemini-omni-flash";
1238
+ var DEFAULT_VIDEO_GENERATE_MODEL = "google/gemini-omni-1.1-flash";
1237
1239
  var REFERENCE_TO_VIDEO_MODELS = [
1238
1240
  "bytedance/seedance-2.0",
1239
1241
  "bytedance/seedance-2.5",
1242
+ "google/gemini-omni-1.1-flash",
1240
1243
  "google/gemini-omni-flash",
1241
1244
  "x-ai/grok-imagine-video",
1242
1245
  "alibaba/wan-2.7",
@@ -1248,6 +1251,10 @@ function supportsReferenceToVideo(model) {
1248
1251
  function isGeminiOmniModel(model) {
1249
1252
  return model.startsWith("google/gemini-omni");
1250
1253
  }
1254
+ var GEMINI_OMNI_PREVIEW_MODEL = "google/gemini-omni-flash";
1255
+ function isGeminiOmniPreviewModel(model) {
1256
+ return model === GEMINI_OMNI_PREVIEW_MODEL;
1257
+ }
1251
1258
  function isSeedance25Model(model) {
1252
1259
  return model === "bytedance/seedance-2.5";
1253
1260
  }
@@ -1603,32 +1610,87 @@ var MODEL_REGISTRY = {
1603
1610
  watermark: { kind: "boolean" }
1604
1611
  }
1605
1612
  },
1606
- "google/gemini-omni-flash": {
1607
- // Google Gemini Omni Flash — the DEFAULT video model. Natively multimodal:
1608
- // it reasons over text + images and renders video WITH synchronized audio in
1609
- // one call, and it is the only curated model that takes reference images
1610
- // through its own first-party API (task `reference_to_video`).
1613
+ "google/gemini-omni-1.1-flash": {
1614
+ // Google Gemini Omni 1.1 Flash — the DEFAULT video model. Natively
1615
+ // multimodal: it reasons over text + images and renders video WITH
1616
+ // synchronized audio in one call, and it is the only curated model that
1617
+ // takes reference images through its own first-party API (task
1618
+ // `reference_to_video`).
1619
+ //
1620
+ // It is a SEPARATE entry from `google/gemini-omni-flash` (the preview),
1621
+ // not a rolling upgrade of it, because the two do not render the same
1622
+ // things: 1.1 takes a `resolution` and the preview does not, and 1.1 bills
1623
+ // the seconds it renders where the preview bills its whole 10s window. One
1624
+ // shared key would have to promise the union of those, which means a canvas
1625
+ // could ask the preview for 360p and be quoted a third of what it charges.
1611
1626
  //
1612
1627
  // NOT on OpenRouter. `GET /api/v1/videos/models` lists 17 video models and
1613
- // Omni is not among them, so this model is the sanctioned direct-provider
1628
+ // no Gemini Omni at either version, so this is the sanctioned direct-provider
1614
1629
  // exception (see `convex/lib/geminiOmni.ts`): Google's Interactions API,
1615
1630
  // `POST /v1beta/interactions`. Its own `generateContent` endpoint refuses it
1616
1631
  // ("This model only supports Interactions API"), so the Veo `predictLongRunning`
1617
1632
  // shape does not apply either.
1618
1633
  //
1619
- // The param set below is DELIBERATELY tiny and was read off the live API, not
1620
- // off the docs — every knob the other video models take is rejected with a
1621
- // pre-dispatch 400 (`Unknown parameter '<name>'`): no `resolution`, no `seed`,
1622
- // no `negative_prompt`, no `generate_audio`, no `person_generation` /
1623
- // `enhance_prompt` / `conditioning_scale`. Resolution is fixed at 720p/24fps
1624
- // and audio is always on. Widening this list does not widen the model; it just
1625
- // moves a free validation error into a billed one.
1634
+ // The param set below is deliberately short and was read off the live API,
1635
+ // not off the docs — the knobs absent here are rejected with a pre-dispatch
1636
+ // 400 (`Unknown parameter '<name>'`): no `seed`, no `negative_prompt`, no
1637
+ // `generate_audio`, no `person_generation` / `enhance_prompt` /
1638
+ // `conditioning_scale`. Audio is always on and cannot be turned off.
1639
+ // Widening this list does not widen the model; it just moves a free
1640
+ // validation error into a billed one.
1641
+ //
1642
+ // `duration` is the odd one out: Omni has no duration FIELD at any nesting
1643
+ // level, but it honours a length named in the prompt (3-10s), so the adapter
1644
+ // turns this param into a prompt directive. It is a real, billable knob.
1645
+ //
1646
+ // NO VIDEO INPUT SLOT, and that is a gate on our project rather than a gap
1647
+ // in the model or a mistake in how we ask. 1.1 advertises video references,
1648
+ // `edit` and `extend`, and every request carrying a video comes back 400
1649
+ // `content_blocked`.
1650
+ //
1651
+ // The controlled version, run through the shape Google's own docs use
1652
+ // (`{"type":"document","uri":<Files API uri>}`, no generation_config),
1653
+ // changing only the uploaded file: an IMAGE returns 200 and renders a clip;
1654
+ // a VIDEO returns `content_blocked`. Same route, same structure. So the
1655
+ // request shape is right and video input specifically is refused. Also
1656
+ // measured across inline base64, all three tasks, video AND text output,
1657
+ // synthetic clips, Omni's own output, real camera footage, and both our
1658
+ // keys. Full probe log: `.context/omni-1.1-measurements.md`.
1626
1659
  //
1627
- // `duration` is the exception, and the reason it looks odd: Omni has no
1628
- // duration FIELD, but it honours a length named in the prompt (3-10s), so the
1629
- // adapter turns this param into a prompt directive. It is a real, billable
1630
- // knob cost scales exactly with the seconds rendered.
1631
- label: "Google Gemini Omni Flash",
1660
+ // Adding `{ kind: "video", mimes: }` below is the ONE line that turns the
1661
+ // whole feature on the "Build on" control, the reference picker taking an
1662
+ // MP4, the drop target and the source-clip cost premium are all driven off
1663
+ // this slot. Add it the day the 400 stops, not before: until then it offers
1664
+ // a control whose every use is refused.
1665
+ label: "Google Gemini Omni 1.1 Flash",
1666
+ inputs: [],
1667
+ optional_inputs: [{ kind: "image", mimes: GEMINI_OMNI_IMAGE_MIMES }],
1668
+ required: ["prompt"],
1669
+ params: {
1670
+ prompt: { kind: "string" },
1671
+ aspect_ratio: { kind: "string", enum: GEMINI_OMNI_ASPECT_RATIOS },
1672
+ resolution: { kind: "string", enum: GEMINI_OMNI_RESOLUTIONS },
1673
+ duration: { kind: "number", enum: GEMINI_OMNI_DURATIONS }
1674
+ }
1675
+ },
1676
+ "google/gemini-omni-flash": {
1677
+ // LEGACY — the Omni PREVIEW (`gemini-omni-flash-preview`), superseded by
1678
+ // `google/gemini-omni-1.1-flash` above. Kept so canvases authored before 1.1
1679
+ // still validate and re-run unchanged (`baker canvas rerun` restores a
1680
+ // recorded canvas verbatim, so dropping this model would break every stored
1681
+ // creative that used it). Don't reach for it in new work.
1682
+ //
1683
+ // Its param surface is the ORIGINAL one on purpose, and the omission that
1684
+ // matters is `resolution`. This model renders 720p / 24fps and nothing else.
1685
+ //
1686
+ // It does NOT reject the field, which is the trap and the reason this is
1687
+ // enforced here rather than left to the provider: asked for `360p` it
1688
+ // returns HTTP 200, a 1280x720 clip, and a bill of 17,376 video tokens —
1689
+ // the 720p rate, three times the 5,793 that tier costs on 1.1. Accepted,
1690
+ // ignored, and charged for. Copying 1.1's enum across to make the two
1691
+ // entries match would hand a canvas a quality dial that does nothing and a
1692
+ // quote a third of the real charge.
1693
+ label: "Google Gemini Omni Flash (legacy preview)",
1632
1694
  inputs: [],
1633
1695
  optional_inputs: [{ kind: "image", mimes: GEMINI_OMNI_IMAGE_MIMES }],
1634
1696
  required: ["prompt"],
@@ -2218,9 +2280,20 @@ var USD_PER_SECOND = {
2218
2280
  };
2219
2281
  var GEMINI_OMNI_USD_PER_1M_VIDEO_TOKENS = 17.5;
2220
2282
  var GEMINI_OMNI_VIDEO_TOKENS_PER_SECOND = 5792;
2283
+ var GEMINI_OMNI_RESOLUTION_MULTIPLIER = {
2284
+ "360p": 1 / 3,
2285
+ "720p": 1,
2286
+ "1080p": 1.5,
2287
+ "4k": 3
2288
+ };
2289
+ var GEMINI_OMNI_DEFAULT_RESOLUTION = "720p";
2290
+ var GEMINI_OMNI_OVERHEAD_TOKENS = 600;
2221
2291
  var GEMINI_OMNI_WINDOW_SECONDS = 10;
2222
- var GEMINI_OMNI_WINDOW_MARGIN = 1.05;
2223
2292
  var GEMINI_OMNI_USD_PER_SECOND = GEMINI_OMNI_VIDEO_TOKENS_PER_SECOND * GEMINI_OMNI_USD_PER_1M_VIDEO_TOKENS / 1e6;
2293
+ function geminiOmniUsdPerSecond(resolution) {
2294
+ const multiplier = GEMINI_OMNI_RESOLUTION_MULTIPLIER[resolution ?? GEMINI_OMNI_DEFAULT_RESOLUTION] ?? 1;
2295
+ return GEMINI_OMNI_USD_PER_SECOND * multiplier;
2296
+ }
2224
2297
  var VIDEO_SOURCE_COST_MULTIPLIER = 2.5;
2225
2298
  var FAL_SEEDANCE_USD_PER_1K_TOKENS = 0.0214;
2226
2299
  var SEEDANCE_SOURCE_CLIP_DISCOUNT = 0.6;
@@ -2234,13 +2307,16 @@ function falSeedanceUsdPerSecond(resolution, buildsOnSourceClip = false) {
2234
2307
  const rate = tokensPerSecond * FAL_SEEDANCE_USD_PER_1K_TOKENS / 1e3;
2235
2308
  return buildsOnSourceClip ? rate * SEEDANCE_SOURCE_CLIP_DISCOUNT : rate;
2236
2309
  }
2310
+ function geminiOmniCostUsd(model, duration, resolution) {
2311
+ const tier = isGeminiOmniPreviewModel(model) ? GEMINI_OMNI_DEFAULT_RESOLUTION : resolution;
2312
+ const footage = geminiOmniUsdPerSecond(tier) * (duration ?? GEMINI_OMNI_WINDOW_SECONDS);
2313
+ return footage + GEMINI_OMNI_OVERHEAD_TOKENS * GEMINI_OMNI_USD_PER_1M_VIDEO_TOKENS / 1e6;
2314
+ }
2237
2315
  function estimateVideoCostUsd(input) {
2238
2316
  const { model, duration, resolution, generateAudio, buildsOnSourceClip } = input;
2239
2317
  const seconds = billedSeconds(model, duration ?? DEFAULT_VIDEO_DURATION_S);
2240
2318
  const sourceClipPremium = buildsOnSourceClip ? VIDEO_SOURCE_COST_MULTIPLIER : 1;
2241
- if (isGeminiOmniModel(model)) {
2242
- return GEMINI_OMNI_WINDOW_SECONDS * GEMINI_OMNI_USD_PER_SECOND * GEMINI_OMNI_WINDOW_MARGIN;
2243
- }
2319
+ if (isGeminiOmniModel(model)) return geminiOmniCostUsd(model, duration, resolution);
2244
2320
  if (isSeedance25Model(model)) {
2245
2321
  const viaOpenRouter = seedance25UsdPerSecond(resolution) * seconds * sourceClipPremium;
2246
2322
  if (!input.mayRouteToFal) return viaOpenRouter;
@@ -3137,9 +3213,9 @@ function clipProfileFor(modelId) {
3137
3213
  if (/^kwaivgi\/kling|^kling\//.test(modelId)) return KLING_PROFILE;
3138
3214
  return void 0;
3139
3215
  }
3140
- function clipParamRecipe(profile, intent) {
3216
+ function clipParamRecipe(model, profile, intent) {
3141
3217
  const out = {};
3142
- if (intent === "hero" && profile.id !== "omni") {
3218
+ if (intent === "hero" && videoModelRenders(model, "1080p")) {
3143
3219
  out.resolution = "1080p";
3144
3220
  }
3145
3221
  if (intent === "hook" && profile.id === "kling") {
@@ -3147,6 +3223,10 @@ function clipParamRecipe(profile, intent) {
3147
3223
  }
3148
3224
  return out;
3149
3225
  }
3226
+ function videoModelRenders(model, resolution) {
3227
+ const schema = MODEL_REGISTRY.video_generate[model]?.params.resolution;
3228
+ return schema?.kind === "string" && (schema.enum ?? []).includes(resolution);
3229
+ }
3150
3230
  function nativeDialogueOf(prompt) {
3151
3231
  if (typeof prompt !== "string") return void 0;
3152
3232
  const m = prompt.match(/Dialogue: "(.*)"/);
@@ -8537,8 +8617,8 @@ var videoGenerateNode = delegated({
8537
8617
  id: "video_generate",
8538
8618
  version: "2.0.0",
8539
8619
  category: "video",
8540
- summary: "Generate video for ad creatives. Curated roster: `google/gemini-omni-flash` (DEFAULT \u2014 native audio + reference images in one call, 720p, 3-10s), `bytedance/seedance-2.0` (identity/product workhorse, NO photoreal human faces), `google/veo-3.1` (photoreal cine ceiling + the human-face model), `google/veo-3.1-fast` (cheap Veo iteration), `kwaivgi/kling-3.0` (motion-transfer/dynamic). Async with polling.",
8541
- when_to_use: "`google/gemini-omni-flash` is the DEFAULT: it renders picture and synchronized audio in one call, and is the only model here that takes reference images alongside a prompt. SET `duration` (3-10s) to the length the beat actually needs \u2014 it bills ~$0.101 PER SECOND, so leaving it out renders the 10s default and charges ~$1.01 for a beat that may need 3s (~$0.30). Its resolution is fixed at 720p and it accepts only `16:9` or `9:16`; it takes NO `resolution`, `seed`, `negative_prompt` or `generate_audio` param \u2014 sending one fails validation. Keep the default for ordinary beats; move off it when a beat needs 1080p, a length outside 3-10s, or a 1:1 frame. Use `bytedance/seedance-2.0` for identity/product output WITHOUT a photoreal human face on camera. Any clip whose frame shows a photoreal human face \u2014 a UGC creator, presenter, or testimonial speaker, REAL OR AI-GENERATED \u2014 must use `google/veo-3.1`: ByteDance's filter rejects photoreal human faces on Seedance (content_policy_blocked/E005), and a synthetic AI face does NOT clear it. Use `google/veo-3.1-fast` while iterating to keep cost low; `kwaivgi/kling-3.0` for motion-transfer/hyper-dynamic beats. `baker canvas scaffold-video` auto-routes a photoreal cast to Veo; a Seedance clip blocked at runtime also auto-recovers on Veo. Each model gates its own durations/resolutions/aspect ratios in the registry \u2014 see the README per-model section.",
8620
+ summary: "Generate video for ad creatives. Curated roster: `google/gemini-omni-1.1-flash` (DEFAULT \u2014 native audio + reference images in one call, 360p-4k, 3-10s), `bytedance/seedance-2.0` (identity/product workhorse, NO photoreal human faces), `google/veo-3.1` (photoreal cine ceiling + the human-face model), `google/veo-3.1-fast` (cheap Veo iteration), `kwaivgi/kling-3.0` (motion-transfer/dynamic). Async with polling.",
8621
+ when_to_use: "`google/gemini-omni-1.1-flash` is the DEFAULT: it renders picture and synchronized audio in one call, and is the only model here that takes reference images alongside a prompt. SET `duration` (3-10s) to the length the beat actually needs \u2014 it bills PER SECOND, so leaving it out renders the 10s default and charges for ten seconds of a beat that may need three. SET `resolution` too: `360p` bills a THIRD of `720p` ($0.034 vs $0.101 per second) and is the right tier while you are still choosing between takes \u2014 render the drafts at 360p, then re-render the keeper at `720p` (default), `1080p` ($0.152/s) or `4k` ($0.304/s). It accepts only `16:9` or `9:16`, and takes NO `seed`, `negative_prompt` or `generate_audio` param \u2014 sending one fails validation, and it always renders audio. Keep the default for ordinary beats; move off it only when a beat needs a length outside 3-10s or a 1:1 frame. Use `bytedance/seedance-2.0` for identity/product output WITHOUT a photoreal human face on camera. Any clip whose frame shows a photoreal human face \u2014 a UGC creator, presenter, or testimonial speaker, REAL OR AI-GENERATED \u2014 must use `google/veo-3.1`: ByteDance's filter rejects photoreal human faces on Seedance (content_policy_blocked/E005), and a synthetic AI face does NOT clear it. Use `google/veo-3.1-fast` while iterating to keep cost low; `kwaivgi/kling-3.0` for motion-transfer/hyper-dynamic beats. `baker canvas scaffold-video` auto-routes a photoreal cast to Veo; a Seedance clip blocked at runtime also auto-recovers on Veo. Each model gates its own durations/resolutions/aspect ratios in the registry \u2014 see the README per-model section.",
8542
8622
  inputs: z29.object({
8543
8623
  first_frame: ImageRef.optional(),
8544
8624
  last_frame: ImageRef.optional(),
@@ -9074,4 +9154,4 @@ export {
9074
9154
  defaultRegistry,
9075
9155
  createEngineFromEnv
9076
9156
  };
9077
- //# sourceMappingURL=chunk-EKLAHWSF.js.map
9157
+ //# sourceMappingURL=chunk-SJPRTSGY.js.map