@koda-sl/baker-cli 0.186.0-dev.6d88981c0 → 0.186.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/README.md CHANGED
@@ -491,7 +491,7 @@ baker ads google keywords metrics --customer-id 1234567890 --keywords "running s
491
491
 
492
492
  ### Staged writes (`baker ads google budgets|campaigns|...`)
493
493
 
494
- Write commands **never touch the Google Ads API at stage time**. Each command stages a create/update/pause/resume/remove op against the current chat's draft (`BAKER_CHAT_ID`); the dashboard shows it as a pending "Google Ads" change, and the whole draft applies as one atomic `GoogleAdsService.Mutate` when the chat is published. Feature-flagged per company (`companies.googleAdsWriteEnabled`) — off by default = a fully simulated publish with zero real API calls.
494
+ Write commands **never touch the Google Ads API at stage time**. Each command stages a create/update/pause/resume/remove op against the current chat's draft (`BAKER_CHAT_ID`); the dashboard shows it as a pending "Google Ads" change, and the whole draft applies as one atomic `GoogleAdsService.Mutate` when the chat is published. **That publish reaches the real account for every company**Google Ads writes are generally available, with no per-company flag to turn them on or off. Discarding the chat before it completes is what undoes a staged change.
495
495
 
496
496
  Reference not-yet-created resources with `g_temp_*` refs returned by earlier `create` commands (they map to Google's temporary negative-ID resource names inside one atomic batch).
497
497
 
@@ -602,7 +602,7 @@ Command groups: `budgets`, `campaigns`, `ad-groups`, `keywords` (add/update/remo
602
602
 
603
603
  **Retiring a conversion action** — `status` accepts `ENABLED` and `REMOVED` only. Google denies `HIDDEN` on every conversion-action write, so to stop bidding toward an action while it keeps measuring use `--no-primary`, and to stop it counting at all use `"status": "REMOVED"`. Conversion actions **Google owns** cannot be changed at all — Smart campaign call/directions actions, the in-ad lead form's submit, YouTube subscriptions and follow-on views, Floodlight and Search Ads 360 imports, store visits, codeless webpage actions. Staging any edit to one, a rename included, is refused up front; there is no manual route either, since the Google Ads interface will not change them.
604
604
 
605
- **Reviewing the draft** — `baker ads google draft list` renders everything you've staged as a grouped campaign ▸ ad group ▸ ad tree (with the simulated/live mode banner and non-blocking completeness advisories), the CLI counterpart to the dashboard's Google Ads tab. Pass `--json` for the raw envelope. Aim for a fully built campaign — 2–4 ad groups, ≥5 keywords each, 2–4 RSAs with 8–12 headlines, ≥4 sitelinks / ≥3 callouts / ≥1 structured snippet, and ≥1 shared negative list; the advisories flag what's still thin.
605
+ **Reviewing the draft** — `baker ads google draft list` renders everything you've staged as a grouped campaign ▸ ad group ▸ ad tree (with non-blocking completeness advisories), the CLI counterpart to the dashboard's Google Ads tab. Pass `--json` for the raw envelope. Aim for a fully built campaign — 2–4 ad groups, ≥5 keywords each, 2–4 RSAs with 8–12 headlines, ≥4 sitelinks / ≥3 callouts / ≥1 structured snippet, and ≥1 shared negative list; the advisories flag what's still thin.
606
606
 
607
607
  **Amending a staged op** — `draft amend <ref> (--file patch.json | --patch '<json>')` merges a JSON patch into an already-staged op's payload (objects deep-merge, `null` deletes a key, arrays/scalars replace) and re-validates it in full. Always prefer this over removing and re-staging — it preserves the op's ref (so dependents don't break) and its position in the draft. `draft show <ref>` prints the full staged payload (including warnings/annotations) so you can verify a change looks right before publish.
608
608
 
@@ -2890,7 +2890,7 @@ The generation lane. `baker images` **sources** what already exists; `baker stud
2890
2890
  | `baker studio skills` | Craft directions accepted by `generate --skill <id>` |
2891
2891
  | `baker studio improve <prompt>` | Sharpen a rough brief — the same rewrite the client's prompt-bar wand performs. Returns the rewrite and the original; generates nothing |
2892
2892
 
2893
- **Every per-model limit is enforced before anything is billed.** Prompt character caps (Kling 2,500 · Seedance 4,000 · Recraft 10,000 · gpt-image 32,000), reference-image counts (Recraft 1 · Gemini 14 · gpt-image 16 · Seedance 9 in reference mode), the uint32 seed range, RGB channel bounds, and `width:height` shapes are all checked against the chosen model up front — the request is refused with the number to fix rather than opening a batch that fails a take at a time. A knob the model does not have is refused too; only the *shape* snaps to the nearest it renders. `baker studio models` reads all of this from the same contract table the backend validates against, so it cannot drift.
2893
+ **Every per-model limit is enforced before anything is billed.** Prompt character caps (Kling 2,500 · Seedance 2.0 4,000 · Recraft 10,000 · gpt-image 32,000 · Seedance 2.5 uncapped), reference counts (Recraft 1 · Gemini 14 · gpt-image 16 · Seedance 2.0 9 · Seedance 2.5 30 images plus 10 source clips), the uint32 seed range, RGB channel bounds, and `width:height` shapes are all checked against the chosen model up front — the request is refused with the number to fix rather than opening a batch that fails a take at a time. A knob the model does not have is refused too; only the *shape* snaps to the nearest it renders. `baker studio models` reads all of this from the same contract table the backend validates against, so it cannot drift.
2894
2894
 
2895
2895
  Two of those checks run in the CLI itself, before the request is even sent. The **reference-image count** is one: `--reference` / `--image` accept file paths and URLs, which are uploaded to the media library first, so checking the count only at the backend means paying to ingest and describe every image in a set that was always going to be refused. The **first-frame rule** is the other — a clip started from one exact frame takes exactly one image whatever the model's reference slot allows, and reference mode is refused outright on Veo and Kling, which cannot read references at all.
2896
2896
 
@@ -2980,19 +2980,40 @@ baker studio animate "handheld drift right, steam rising from the cup" \
2980
2980
  baker studio animate "product rotates once on a turntable" --image j57abc…,j57def… --from references
2981
2981
  ```
2982
2982
 
2983
- The image fixes the look, so the prompt describes **movement**. Models: `bytedance/seedance-2.0` (default), `google/veo-3.1`, `google/veo-3.1-fast`, `kwaivgi/kling-v3.0-pro`.
2983
+ 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`.
2984
+
2985
+ **`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.
2986
+
2987
+ ```bash
2988
+ baker studio animate "she keeps walking, camera stays with her, then she stops and looks up" \
2989
+ --image j57abc… --from references --from-clip j57batch…:0 \
2990
+ --model bytedance/seedance-2.5 --duration 20
2991
+ ```
2992
+
2993
+ - **4–30 seconds** in one render; everything else in the roster stops at 15, and Veo at 8.
2994
+ - **`--from-clip batchId:slot`** builds on takes already rendered, and **`--from-video <videoId>`** on anything in the video library (client footage, synced ads). Together up to 10 — this is how a clip is extended, edited, or has its motion carried into a new shot. Both need `--from references`. A library video's first use spends ~1 minute encoding a reusable copy and is refused with "try again shortly"; every use after is instant.
2995
+ - **No soundtrack input.** The model reads MP3/WAV reference audio; the only audio Baker stores is Mux's M4A, which it refuses. Nothing to pass it today.
2996
+ - **The output shape follows the source clip** — `--aspect-ratio` does not apply when building on one, and building on one **costs about double** the per-second rate (measured; the estimate accounts for it).
2997
+ - **`--from text`** renders with no image at all. Every model does text-to-video; this is the only mode where `--image` may be omitted.
2998
+ - **Up to 30 reference images**, against 9 on Seedance 2.0.
2999
+ - **480p / 720p only** — 1080p and 4K are real Seedance tiers but not on this route.
3000
+ - **Sound costs nothing extra** here, unlike every other model that offers it.
3001
+ - **No watermark** unless `--watermark` asks for one; it cannot be removed after the render.
3002
+ - **No people from an uploaded picture.** A privacy pre-check refuses any recognisable face in the input image — invented characters included, and images from ByteDance's own image model included. Clips that hit it are re-rendered automatically on Gemini Omni (reference mode) or Veo (frame mode).
2984
3003
 
2985
3004
  | Flag | Description |
2986
3005
  |---|---|
2987
- | `--image` | **Required.** Comma-separated library image ids / local paths / image URLs; the first is the opening frame |
2988
- | `--from` | `frame` (default — animate the first image) \| `references` (use the images as visual reference). Mutually exclusive at every provider |
2989
- | `--model` | Video model id (default `bytedance/seedance-2.0`) |
3006
+ | `--image` | Comma-separated library image ids / local paths / image URLs; the first is the opening frame. **Required unless `--from text`** |
3007
+ | `--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 |
3008
+ | `--from-clip` | Studio takes to build on, `batchId:slot` comma-separated (Seedance 2.5, needs `--from references`) |
3009
+ | `--from-video` | Library video ids to build on — same 10-clip budget as `--from-clip` |
3010
+ | `--model` | Video model id (default `google/gemini-omni-flash`) |
2990
3011
  | `--aspect-ratio` | Default `9:16` |
2991
3012
  | `--duration` | Seconds; per-model set (default 5, snapped onto what the model renders) |
2992
3013
  | `--quality` | Resolution, e.g. `720p` (default) \| `1080p` |
2993
3014
  | `--count` | Takes, 1–3 (default 1). A clip costs ~45x an image |
2994
3015
  | `--sound` | Let the model generate audio. Off by default (billed on top) |
2995
- | `--negative` / `--seed` / `--people` / `--enhance-prompt` / `--conditioning-scale` / `--cfg-scale` | Per-model knobs; refused when the chosen model doesn't advertise them |
3016
+ | `--negative` / `--seed` / `--people` / `--enhance-prompt` / `--conditioning-scale` / `--cfg-scale` / `--watermark` | Per-model knobs; refused when the chosen model doesn't advertise them |
2996
3017
  | `--wait` / `--max-wait` | Wait for the takes (default on, 600000 ms) |
2997
3018
  | `--full` | Include settings, references, chat attribution, `createdAt` |
2998
3019
 
@@ -5080,32 +5101,6 @@ Without `--slug` the command behaves as before (one creative record per publishe
5080
5101
 
5081
5102
  ## Landing Quality (`baker landing`)
5082
5103
 
5083
- Two tools that bracket a landing build: **`inspiration`** before you design (what does good look like here?) and **`critique`** after you build (did this settle into generic defaults?).
5084
-
5085
- ### `baker landing inspiration`
5086
-
5087
- A searchable library of real landing-page sections. Each entry is one section of a real page: a screenshot, a standalone HTML+CSS reproduction with a measured fidelity score, a description of how it moves, and the transferable idea behind it — classified in the same vocabulary the landing skill teaches, so a hit is directly buildable.
5088
-
5089
- ```bash
5090
- baker landing inspiration search "pricing with a monthly/annual toggle" --scope all
5091
- baker landing inspiration view <section id> # full DNA + screenshots + motion filmstrip
5092
- baker landing inspiration code <section id> # the standalone bundle
5093
- baker landing inspiration page <source id> # a whole page as a section sequence
5094
- baker landing inspiration add https://linear.app --note "client likes this density"
5095
- baker landing inspiration favorites # what this company has saved
5096
- baker landing inspiration scrape <url> --out <dir> # capture any page now, synchronously
5097
- ```
5098
-
5099
- - **Hybrid search over three signals** — keywords, meaning, and *appearance* (the screenshot is embedded, so a query like "dark developer hero with a terminal" can match a section whose text never says "terminal"). Filters: `--type --composition --register --interaction --motion --media --device --theme --max-rank --min-craft --min-fidelity --domain --similar-to --scope --limit`.
5100
- - **Screenshots are downloaded to `.baker/inspiration/`** so an agent can actually look at a result rather than read a description of it.
5101
- - **`fidelity` says how much to trust the code.** A measured 0–1 match between the live section and our standalone re-render, always reported. Above ~0.95 the markup renders like the original; below ~0.75 the section is scroll- or JS-driven and it does not.
5102
- - **`used_on_pages`** appears when a section shows up on more than one of that site's pages — a nav or footer they ship everywhere, which is a stronger reference than a one-off.
5103
- - **The corpus is shared across companies; favorites are per-company**, and search defaults to this company's saved sections.
5104
- - **`add` studies in the background; `scrape` returns with the page on disk.** `add` grows the shared library and takes minutes, so it can never answer "build our page like this one" within the same turn. `scrape` runs the identical capture locally and blocks until it finishes, writing section screenshots, standalone markup, a whole-page reproduction and `report.html`. `--no-motion` roughly halves the runtime; `--no-mobile`, `--no-code` and `--no-report` skip further passes.
5105
- - **Inspiration, never a clipboard.** Both `code` and `scrape` record what was consulted, and `critique`'s `originality` family blocks a publish that reuses a reference's copy verbatim.
5106
-
5107
- ### `baker landing critique`
5108
-
5109
5104
  Deterministic design-quality critic for landing pages — an offline, no-LLM detector for the well-known "AI slop" tells (gradient text, overused fonts like Inter, side-tab colored borders, cream/parchment grounds, purple-on-heading palettes, buzzword copy, broken images, and more). It scores a landing's `.astro` source and returns findings tiered **block / warn / advisory**.
5110
5105
 
5111
5106
  ```bash
@@ -5123,9 +5118,7 @@ baker landing critique spring-offer summer-offer claude # score three landings
5123
5118
 
5124
5119
  - **Agent washing is a copy tell.** A page that claims autonomy ("fully autonomous", "while you sleep", "no human intervention") and never says anywhere what the buyer approves, overrides, or audits scores an `agent-washing` warn. One signal about oversight of the agent's actions — approval, review, override, undo/rollback, audit log, escalation — anywhere on the page clears it; the rule is page-scope precisely because the hero can defer the trust story to a section below it. Generic privacy boilerplate ("GDPR", "encrypted", "your data") deliberately does **not** clear it, since it appears in most footers and says nothing about who is in charge of the agent.
5125
5120
 
5126
- - **The `originality` family compares your copy against inspiration sections you actually consulted.** It fires only on sections opened with `baker landing inspiration code`, so it flags facts rather than resemblances. Reusing a reference's headline, subhead, or CTA verbatim is block-tier.
5127
-
5128
- Output is the standard envelope `{ ok, data, hints }` with `data = { advisory, slug, overall, counts, dimensions, findings }`. `dimensions` scores eight design families (typography, color, borders_depth, motion, spacing, copy, integrity, originality) 0–1 (higher is better); `counts` is the block/warn/advisory tally.
5121
+ Output is the standard envelope `{ ok, data, hints }` with `data = { advisory, slug, overall, counts, dimensions, findings }`. `dimensions` scores seven design families (typography, color, borders_depth, motion, spacing, copy, integrity) 0–1 (higher is better); `counts` is the block/warn/advisory tally.
5129
5122
 
5130
5123
  ## Brand Fonts (`baker brand fonts`)
5131
5124
 
@@ -7,9 +7,9 @@ import {
7
7
  __toESM
8
8
  } from "./chunk-YL3HDEIJ.js";
9
9
 
10
- // ../../.pnpm-store/v10/links/@/safe-stable-stringify/2.5.0/810146e81bae4e3a061fe487864f2fde80c4b03b886877dc0f1fffbc6480b67e/node_modules/safe-stable-stringify/index.js
10
+ // ../../node_modules/.pnpm/safe-stable-stringify@2.5.0/node_modules/safe-stable-stringify/index.js
11
11
  var require_safe_stable_stringify = __commonJS({
12
- "../../.pnpm-store/v10/links/@/safe-stable-stringify/2.5.0/810146e81bae4e3a061fe487864f2fde80c4b03b886877dc0f1fffbc6480b67e/node_modules/safe-stable-stringify/index.js"(exports, module) {
12
+ "../../node_modules/.pnpm/safe-stable-stringify@2.5.0/node_modules/safe-stable-stringify/index.js"(exports, module) {
13
13
  "use strict";
14
14
  var { hasOwnProperty } = Object.prototype;
15
15
  var stringify = configure2();
@@ -1075,7 +1075,7 @@ function resolveAdaptFormats(params) {
1075
1075
  return params.formats ?? [];
1076
1076
  }
1077
1077
 
1078
- // ../../.pnpm-store/v10/links/@/safe-stable-stringify/2.5.0/810146e81bae4e3a061fe487864f2fde80c4b03b886877dc0f1fffbc6480b67e/node_modules/safe-stable-stringify/esm/wrapper.js
1078
+ // ../../node_modules/.pnpm/safe-stable-stringify@2.5.0/node_modules/safe-stable-stringify/esm/wrapper.js
1079
1079
  var import__ = __toESM(require_safe_stable_stringify(), 1);
1080
1080
  var configure = import__.default.configure;
1081
1081
  var wrapper_default = import__.default;
@@ -1124,7 +1124,8 @@ var GPT_IMAGE_PROMPT_MAX = 32e3;
1124
1124
  var RECRAFT_PROMPT_MAX = 1e4;
1125
1125
  var SEEDANCE_PROMPT_MAX = 4e3;
1126
1126
  var KLING_PROMPT_MAX = 2500;
1127
- var VEO_SEED_MAX = 4294967295;
1127
+ var UINT32_MAX = 4294967295;
1128
+ var VEO_SEED_MAX = UINT32_MAX;
1128
1129
  var GPT_IMAGE_MAX_REFERENCES = 16;
1129
1130
  var GEMINI_IMAGE_MAX_REFERENCES = 14;
1130
1131
  var RECRAFT_MAX_REFERENCES = 1;
@@ -1136,9 +1137,42 @@ var GEMINI_LITE_IMAGE_SIZE = ["1K"];
1136
1137
  var OPENROUTER_IMAGE_QUALITY = ["auto", "low", "medium", "high"];
1137
1138
  var RECRAFT_IMAGE_AR = ["1:1", "4:3", "3:4", "16:9", "9:16"];
1138
1139
  var SEEDANCE_DURATIONS = [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
1140
+ var SEEDANCE_25_DURATIONS = [
1141
+ 4,
1142
+ 5,
1143
+ 6,
1144
+ 7,
1145
+ 8,
1146
+ 9,
1147
+ 10,
1148
+ 11,
1149
+ 12,
1150
+ 13,
1151
+ 14,
1152
+ 15,
1153
+ 16,
1154
+ 17,
1155
+ 18,
1156
+ 19,
1157
+ 20,
1158
+ 21,
1159
+ 22,
1160
+ 23,
1161
+ 24,
1162
+ 25,
1163
+ 26,
1164
+ 27,
1165
+ 28,
1166
+ 29,
1167
+ 30
1168
+ ];
1169
+ var SEEDANCE_25_ASPECT_RATIOS = ["1:1", "3:4", "9:16", "4:3", "16:9", "21:9"];
1170
+ var SEEDANCE_25_RESOLUTIONS = ["480p", "720p"];
1171
+ var SEEDANCE_25_MAX_IMAGE_REFERENCES = 30;
1172
+ var SEEDANCE_25_MAX_VIDEO_REFERENCES = 10;
1173
+ var SEEDANCE_25_MAX_AUDIO_REFERENCES = 10;
1139
1174
  var KLING_DURATIONS = [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
1140
1175
  var GEMINI_OMNI_DURATIONS = [3, 4, 5, 6, 7, 8, 9, 10];
1141
- var GEMINI_OMNI_DEFAULT_SECONDS = 10;
1142
1176
  var GEMINI_OMNI_ASPECT_RATIOS = ["16:9", "9:16"];
1143
1177
  var GEMINI_OMNI_IMAGE_MIMES = ["image/png", "image/jpeg", "image/webp"];
1144
1178
  var ELEVENLABS_OUTPUT_FORMATS = [
@@ -1152,6 +1186,8 @@ var ELEVENLABS_OUTPUT_FORMATS = [
1152
1186
  var ELEVENLABS_MAX_TEXT_CHARS = 45454;
1153
1187
  var ELEVENLABS_MAX_MUSIC_LENGTH_MS = 454545;
1154
1188
  var OPENROUTER_IMAGE_MIMES = ["image/png", "image/jpeg", "image/webp", "image/gif"];
1189
+ var OPENROUTER_VIDEO_REFERENCE_MIMES = ["video/mp4", "video/quicktime", "video/webm"];
1190
+ var OPENROUTER_AUDIO_REFERENCE_MIMES = ["audio/mpeg", "audio/mp3", "audio/wav"];
1155
1191
  var REPLICATE_IMAGE_MIMES = ["image/png", "image/jpeg", "image/webp"];
1156
1192
  var REPLICATE_VIDEO_MIMES = ["video/mp4", "video/webm", "video/quicktime"];
1157
1193
  var DECONSTRUCT_VIDEO_MIMES = ["video/mp4", "video/webm", "video/quicktime"];
@@ -1167,21 +1203,30 @@ var IMAGE_GENERATE_MODELS = [
1167
1203
  var DEFAULT_IMAGE_GENERATE_MODEL = "google/gemini-3.1-flash-image-preview";
1168
1204
  var VIDEO_GENERATE_MODELS = [
1169
1205
  "bytedance/seedance-2.0",
1206
+ "bytedance/seedance-2.5",
1170
1207
  "google/gemini-omni-flash",
1171
1208
  "google/veo-3.1",
1172
1209
  "google/veo-3.1-fast",
1173
1210
  "kwaivgi/kling-v3.0-pro"
1174
1211
  ];
1175
1212
  var DEFAULT_VIDEO_GENERATE_MODEL = "google/gemini-omni-flash";
1176
- var REFERENCE_TO_VIDEO_MODELS = ["bytedance/seedance-2.0", "google/gemini-omni-flash"];
1213
+ var REFERENCE_TO_VIDEO_MODELS = [
1214
+ "bytedance/seedance-2.0",
1215
+ "bytedance/seedance-2.5",
1216
+ "google/gemini-omni-flash"
1217
+ ];
1177
1218
  function supportsReferenceToVideo(model) {
1178
1219
  return REFERENCE_TO_VIDEO_MODELS.includes(model);
1179
1220
  }
1180
1221
  function isGeminiOmniModel(model) {
1181
1222
  return model.startsWith("google/gemini-omni");
1182
1223
  }
1224
+ function isSeedance25Model(model) {
1225
+ return model === "bytedance/seedance-2.5";
1226
+ }
1183
1227
  var LAST_FRAME_TO_VIDEO_MODELS = [
1184
1228
  "bytedance/seedance-2.0",
1229
+ "bytedance/seedance-2.5",
1185
1230
  "google/veo-3.1",
1186
1231
  "google/veo-3.1-fast",
1187
1232
  "kwaivgi/kling-v3.0-pro"
@@ -1488,6 +1533,49 @@ var MODEL_REGISTRY = {
1488
1533
  generate_audio: { kind: "boolean" }
1489
1534
  }
1490
1535
  },
1536
+ "bytedance/seedance-2.5": {
1537
+ // Seedance 2.5 — the LONG-FORM, MULTIMODAL tier, and the only curated video
1538
+ // model reached through OpenRouter that is not frame-only.
1539
+ //
1540
+ // Routed through OpenRouter's video gateway (provider `seed`), NOT through
1541
+ // Replicate like 2.0 — the gateway carries the multimodal reference surface
1542
+ // 2.5 exists for, and Replicate's 2.0 wrapper only has `reference_images`.
1543
+ // The backend branches on the exact 2.0 id for the Replicate path, so this
1544
+ // model must never be folded into a `startsWith("bytedance/seedance")`
1545
+ // routing test: that is one character away from sending 2.5 to a wrapper
1546
+ // that cannot express half of what it is being asked to do.
1547
+ //
1548
+ // Same upstream likeness filter as 2.0 — ByteDance classifies PIXELS, so an
1549
+ // AI-generated face that reads photographic is refused exactly like a
1550
+ // photograph (content_policy_blocked). The workflow's automatic Veo recovery
1551
+ // therefore covers this model too.
1552
+ //
1553
+ // No published prompt cap on this route, so none is invented: OpenRouter's
1554
+ // request schema declares no `maxLength` and the model is sold on long,
1555
+ // multi-shot briefs. A ceiling we made up would refuse the exact prompts
1556
+ // this tier exists to render.
1557
+ label: "ByteDance Seedance 2.5",
1558
+ inputs: [],
1559
+ optional_inputs: [
1560
+ { kind: "image", mimes: OPENROUTER_IMAGE_MIMES, max: SEEDANCE_25_MAX_IMAGE_REFERENCES },
1561
+ { kind: "video", mimes: OPENROUTER_VIDEO_REFERENCE_MIMES, max: SEEDANCE_25_MAX_VIDEO_REFERENCES },
1562
+ { kind: "audio", mimes: OPENROUTER_AUDIO_REFERENCE_MIMES, max: SEEDANCE_25_MAX_AUDIO_REFERENCES }
1563
+ ],
1564
+ required: ["prompt"],
1565
+ params: {
1566
+ prompt: { kind: "string" },
1567
+ aspect_ratio: { kind: "string", enum: SEEDANCE_25_ASPECT_RATIOS },
1568
+ resolution: { kind: "string", enum: SEEDANCE_25_RESOLUTIONS },
1569
+ duration: { kind: "number", enum: SEEDANCE_25_DURATIONS },
1570
+ seed: { kind: "number", integer: true, min: 0, max: UINT32_MAX },
1571
+ generate_audio: { kind: "boolean" },
1572
+ // A visible AI watermark on an ad creative is a defect, and this is the
1573
+ // only curated model that lets us turn one off: `watermark` is named in
1574
+ // the model's own `allowed_passthrough_parameters`, so it rides as a
1575
+ // top-level body field exactly like Kling's `cfg_scale` does.
1576
+ watermark: { kind: "boolean" }
1577
+ }
1578
+ },
1491
1579
  "google/gemini-omni-flash": {
1492
1580
  // Google Gemini Omni Flash — the DEFAULT video model. Natively multimodal:
1493
1581
  // it reasons over text + images and renders video WITH synchronized audio in
@@ -1763,10 +1851,15 @@ function promptMaxLength(kind, model) {
1763
1851
  const schema = MODEL_REGISTRY[kind]?.[model]?.params.prompt;
1764
1852
  return schema?.kind === "string" ? schema.maxLength : void 0;
1765
1853
  }
1766
- function maxInputReferences(kind, model) {
1854
+ function inputSlot(kind, model, inputKind) {
1767
1855
  const spec = MODEL_REGISTRY[kind]?.[model];
1768
- const slot = spec?.optional_inputs?.find((input) => input.kind === "image") ?? spec?.inputs.find((input) => input.kind === "image");
1769
- return slot?.max;
1856
+ return spec?.optional_inputs?.find((input) => input.kind === inputKind) ?? spec?.inputs.find((input) => input.kind === inputKind);
1857
+ }
1858
+ function maxInputSlot(kind, model, inputKind) {
1859
+ return inputSlot(kind, model, inputKind)?.max;
1860
+ }
1861
+ function maxInputReferences(kind, model) {
1862
+ return maxInputSlot(kind, model, "image");
1770
1863
  }
1771
1864
  function supportedAspectRatios(kind, model) {
1772
1865
  const schema = MODEL_REGISTRY[kind]?.[model]?.params.aspect_ratio;
@@ -1956,6 +2049,14 @@ var DEFAULT_VIDEO_DURATION_S = 5;
1956
2049
  function isSeedanceModel(model) {
1957
2050
  return model.startsWith("bytedance/seedance");
1958
2051
  }
2052
+ var SEEDANCE_25_USD_PER_SECOND = {
2053
+ "480p": 0.1075,
2054
+ "720p": 0.2326
2055
+ };
2056
+ var SEEDANCE_25_FALLBACK_USD_PER_SECOND = 0.2326;
2057
+ function seedance25UsdPerSecond(resolution) {
2058
+ return SEEDANCE_25_USD_PER_SECOND[resolution ?? DEFAULT_VIDEO_RESOLUTION] ?? SEEDANCE_25_FALLBACK_USD_PER_SECOND;
2059
+ }
1959
2060
  var FALLBACK_USD_PER_SECOND = 0.5;
1960
2061
  function seedanceUsdPerSecond(resolution) {
1961
2062
  return SEEDANCE_USD_PER_SECOND[resolution ?? DEFAULT_VIDEO_RESOLUTION] ?? FALLBACK_USD_PER_SECOND;
@@ -1981,11 +2082,33 @@ var USD_PER_SECOND = {
1981
2082
  };
1982
2083
  var GEMINI_OMNI_USD_PER_1M_VIDEO_TOKENS = 17.5;
1983
2084
  var GEMINI_OMNI_VIDEO_TOKENS_PER_SECOND = 5792;
2085
+ var GEMINI_OMNI_WINDOW_SECONDS = 10;
2086
+ var GEMINI_OMNI_WINDOW_MARGIN = 1.05;
1984
2087
  var GEMINI_OMNI_USD_PER_SECOND = GEMINI_OMNI_VIDEO_TOKENS_PER_SECOND * GEMINI_OMNI_USD_PER_1M_VIDEO_TOKENS / 1e6;
1985
- function estimateVideoCostUsd({ model, duration, resolution, generateAudio }) {
2088
+ var VIDEO_SOURCE_COST_MULTIPLIER = 2.5;
2089
+ var FAL_SEEDANCE_USD_PER_1K_TOKENS = 0.0214;
2090
+ var SEEDANCE_SOURCE_CLIP_DISCOUNT = 0.6;
2091
+ var SEEDANCE_DEAREST_FRAME = {
2092
+ "480p": { width: 992, height: 432 },
2093
+ "720p": { width: 1112, height: 834 }
2094
+ };
2095
+ function falSeedanceUsdPerSecond(resolution, buildsOnSourceClip = false) {
2096
+ const frame = SEEDANCE_DEAREST_FRAME[resolution ?? DEFAULT_VIDEO_RESOLUTION] ?? SEEDANCE_DEAREST_FRAME["720p"];
2097
+ const tokensPerSecond = (frame?.width ?? 1112) * (frame?.height ?? 834) * 24 / 1024;
2098
+ const rate = tokensPerSecond * FAL_SEEDANCE_USD_PER_1K_TOKENS / 1e3;
2099
+ return buildsOnSourceClip ? rate * SEEDANCE_SOURCE_CLIP_DISCOUNT : rate;
2100
+ }
2101
+ function estimateVideoCostUsd(input) {
2102
+ const { model, duration, resolution, generateAudio, buildsOnSourceClip } = input;
1986
2103
  const seconds = duration ?? DEFAULT_VIDEO_DURATION_S;
2104
+ const sourceClipPremium = buildsOnSourceClip ? VIDEO_SOURCE_COST_MULTIPLIER : 1;
1987
2105
  if (isGeminiOmniModel(model)) {
1988
- return (duration ?? GEMINI_OMNI_DEFAULT_SECONDS) * GEMINI_OMNI_USD_PER_SECOND;
2106
+ return GEMINI_OMNI_WINDOW_SECONDS * GEMINI_OMNI_USD_PER_SECOND * GEMINI_OMNI_WINDOW_MARGIN;
2107
+ }
2108
+ if (isSeedance25Model(model)) {
2109
+ const viaOpenRouter = seedance25UsdPerSecond(resolution) * seconds * sourceClipPremium;
2110
+ if (!input.mayRouteToFal) return viaOpenRouter;
2111
+ return Math.max(viaOpenRouter, falSeedanceUsdPerSecond(resolution, buildsOnSourceClip) * seconds);
1989
2112
  }
1990
2113
  if (isSeedanceModel(model)) return seedanceUsdPerSecond(resolution) * seconds;
1991
2114
  const published = USD_PER_SECOND[model];
@@ -8214,6 +8337,7 @@ export {
8214
8337
  DEFAULT_CLIP_DURATION_S,
8215
8338
  nearestClipDuration,
8216
8339
  promptMaxLength,
8340
+ maxInputSlot,
8217
8341
  maxInputReferences,
8218
8342
  nearestSupportedAspectRatio,
8219
8343
  nearestSupportedImageSize,
@@ -8244,4 +8368,4 @@ export {
8244
8368
  defaultRegistry,
8245
8369
  createEngineFromEnv
8246
8370
  };
8247
- //# sourceMappingURL=chunk-PJ5KH27L.js.map
8371
+ //# sourceMappingURL=chunk-OWDTSPY4.js.map