@koda-sl/baker-cli 0.296.0-dev.f25aa60dd → 0.296.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.
Files changed (28) hide show
  1. package/README.md +41 -87
  2. package/canvas/tiktok-captions-composition/index.html +2 -23
  3. package/dist/{chunk-2IUN3S3E.js → chunk-2IB3IL4K.js} +2 -2
  4. package/dist/{chunk-4YF56EGK.js → chunk-D3HHUBIL.js} +4 -4
  5. package/dist/{chunk-WFWU3CHS.js → chunk-DZUVUGEP.js} +1 -9
  6. package/dist/{chunk-WFWU3CHS.js.map → chunk-DZUVUGEP.js.map} +1 -1
  7. package/dist/{chunk-A2VZOTCV.js → chunk-EX2OIOVL.js} +3 -3
  8. package/dist/{chunk-KDTHRRAC.js → chunk-GU7IWEBC.js} +3 -3
  9. package/dist/{chunk-YMHERSTK.js → chunk-YFQWCJX4.js} +123 -315
  10. package/dist/chunk-YFQWCJX4.js.map +1 -0
  11. package/dist/cli.js +1476 -2976
  12. package/dist/cli.js.map +1 -1
  13. package/dist/{client-6KQHCXS2.js → client-VDCCDEHE.js} +4 -4
  14. package/dist/engine/index.d.ts +0 -13
  15. package/dist/engine/index.js +3 -3
  16. package/dist/{env-C7YXL6C6.js → env-FWMZXMQK.js} +2 -6
  17. package/dist/{output-RBM32FKJ.js → output-4H2RNBXL.js} +5 -5
  18. package/dist/{shared-WJIJTWST.js → shared-UKL36AXT.js} +6 -6
  19. package/package.json +2 -5
  20. package/dist/chunk-YMHERSTK.js.map +0 -1
  21. /package/dist/{chunk-2IUN3S3E.js.map → chunk-2IB3IL4K.js.map} +0 -0
  22. /package/dist/{chunk-4YF56EGK.js.map → chunk-D3HHUBIL.js.map} +0 -0
  23. /package/dist/{chunk-A2VZOTCV.js.map → chunk-EX2OIOVL.js.map} +0 -0
  24. /package/dist/{chunk-KDTHRRAC.js.map → chunk-GU7IWEBC.js.map} +0 -0
  25. /package/dist/{client-6KQHCXS2.js.map → client-VDCCDEHE.js.map} +0 -0
  26. /package/dist/{env-C7YXL6C6.js.map → env-FWMZXMQK.js.map} +0 -0
  27. /package/dist/{output-RBM32FKJ.js.map → output-4H2RNBXL.js.map} +0 -0
  28. /package/dist/{shared-WJIJTWST.js.map → shared-UKL36AXT.js.map} +0 -0
@@ -1,25 +1,24 @@
1
1
  import {
2
2
  debugLogHttp,
3
3
  readBodyForLog
4
- } from "./chunk-2IUN3S3E.js";
4
+ } from "./chunk-2IB3IL4K.js";
5
5
  import {
6
6
  DIRECT_ROUTE,
7
7
  __commonJS,
8
8
  __toESM,
9
9
  captureProxyCredentials,
10
10
  childEnvWith,
11
- hasFrameVisionKey,
12
11
  isChallengeBody,
13
12
  isPrivateAddress,
14
13
  isProxyFailure,
15
14
  plannedRoutes,
16
15
  refuseNonPublicUrl,
17
16
  shouldEscalate
18
- } from "./chunk-WFWU3CHS.js";
17
+ } from "./chunk-DZUVUGEP.js";
19
18
 
20
- // ../../.pnpm-store/v10/links/@/safe-stable-stringify/2.5.0/88b6d0c76c4dff408de4044be85791896193f2435af7c280bc59312c3fb9649c/node_modules/safe-stable-stringify/index.js
19
+ // ../../node_modules/.pnpm/safe-stable-stringify@2.5.0/node_modules/safe-stable-stringify/index.js
21
20
  var require_safe_stable_stringify = __commonJS({
22
- "../../.pnpm-store/v10/links/@/safe-stable-stringify/2.5.0/88b6d0c76c4dff408de4044be85791896193f2435af7c280bc59312c3fb9649c/node_modules/safe-stable-stringify/index.js"(exports, module) {
21
+ "../../node_modules/.pnpm/safe-stable-stringify@2.5.0/node_modules/safe-stable-stringify/index.js"(exports, module) {
23
22
  "use strict";
24
23
  var { hasOwnProperty } = Object.prototype;
25
24
  var stringify = configure2();
@@ -758,6 +757,19 @@ async function parseErrorBody(res) {
758
757
  }
759
758
  return classifyHttpError(res.status, errObj, message2);
760
759
  }
760
+ function providerVerdict(status, errObj, message2) {
761
+ if (errObj.provider === void 0 && errObj.code !== "provider_error") return null;
762
+ return {
763
+ kind: "provider",
764
+ status,
765
+ provider: errObj.provider,
766
+ code: errObj.code ?? "provider_error",
767
+ message: message2,
768
+ // A 4xx is terminal unless the backend says otherwise — the opposite
769
+ // default from the 502 branch, where the status itself means "try again".
770
+ retryable: errObj.retryable ?? false
771
+ };
772
+ }
761
773
  function classifyHttpError(status, errObj, message2) {
762
774
  if (errObj.code === CONTENT_POLICY_CODE) {
763
775
  return { kind: "content_policy", status, provider: errObj.provider, message: message2 };
@@ -766,7 +778,7 @@ function classifyHttpError(status, errObj, message2) {
766
778
  return { kind: "unauthorized", status, message: message2 };
767
779
  }
768
780
  if (status === 400 || status === 422) {
769
- return { kind: "validation", status, message: message2, details: errObj.details };
781
+ return providerVerdict(status, errObj, message2) ?? { kind: "validation", status, message: message2, details: errObj.details };
770
782
  }
771
783
  if (status === 502 || status === 504) {
772
784
  if (errObj.code === "provider_timeout" || status === 504) {
@@ -1034,17 +1046,12 @@ function failureDetail(reason) {
1034
1046
  }
1035
1047
  return { message: describeFailureReason(reason) };
1036
1048
  }
1037
- function retryVerdict(retryable) {
1038
- if (retryable === true) return "transient \u2014 retry the run";
1039
- if (retryable === false) return "not retryable \u2014 retrying will not help, fix the input";
1040
- return "retryability unknown";
1041
- }
1042
1049
  function describeCause(c) {
1043
1050
  switch (c.kind) {
1044
1051
  case "local":
1045
1052
  return c.cause instanceof Error ? c.cause.message : String(c.cause);
1046
1053
  case "remote":
1047
- return `[${c.code}] ${c.message}${c.provider ? ` (${c.provider})` : ""} \u2014 ${retryVerdict(c.retryable)}`;
1054
+ return `[${c.code}] ${c.message}${c.provider ? ` (${c.provider})` : ""}`;
1048
1055
  case "timeout":
1049
1056
  return `timeout${c.provider ? ` (${c.provider})` : ""}`;
1050
1057
  case "network":
@@ -1098,7 +1105,7 @@ function resolveAdaptFormats(params) {
1098
1105
  return params.formats ?? [];
1099
1106
  }
1100
1107
 
1101
- // ../../.pnpm-store/v10/links/@/safe-stable-stringify/2.5.0/88b6d0c76c4dff408de4044be85791896193f2435af7c280bc59312c3fb9649c/node_modules/safe-stable-stringify/esm/wrapper.js
1108
+ // ../../node_modules/.pnpm/safe-stable-stringify@2.5.0/node_modules/safe-stable-stringify/esm/wrapper.js
1102
1109
  var import__ = __toESM(require_safe_stable_stringify(), 1);
1103
1110
  var configure = import__.default.configure;
1104
1111
  var wrapper_default = import__.default;
@@ -1139,14 +1146,6 @@ function normalizeForCanonical(value) {
1139
1146
  return void 0;
1140
1147
  }
1141
1148
 
1142
- // ../canvas-contract/src/frameRealism.ts
1143
- function frameRealismDirection(opts = {}) {
1144
- return " Everything obeys real-world physics: paper, card and screens are OPAQUE with nothing showing through from behind, every object is at believable real-world scale next to the people handling it, and every object has its real-world form and construction \u2014 a phone has ONE screen and it is on the front. NO readable text or numbers anywhere in frame \u2014 phone screens, documents and signage stay illegible or out of focus, because any figure the model invents will contradict the script. Hands are kept simple: no close-up of fingers manipulating small parts, no hand gripping the edge of an object, and each person has exactly TWO arms and TWO legs, all attached and all visible or all out of frame. Anyone working does so the way the trade actually does it: nobody stands or kneels on the equipment being installed, nothing is fitted overhanging an edge or floating unsupported, and every part rests on the structure that would really carry it." + // The newest clause, and the one no route had. A testimonial came back with the customer
1145
- // repairing the panel herself: nothing said she was not the installer, so the model cast
1146
- // her as one. Who someone IS in the picture has to be stated, or it is guessed.
1147
- (opts.role ? ` The person on camera is ${opts.role} \u2014 they are shown as that and never doing somebody else's job.` : "") + (opts.currency ? ` If a currency is unavoidably visible it is ${opts.currency}.` : "");
1148
- }
1149
-
1150
1149
  // ../canvas-contract/src/registry.ts
1151
1150
  var OPENROUTER_IMAGE_AR = ["1:1", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4", "9:16", "16:9", "21:9"];
1152
1151
  var OPENROUTER_IMAGE_AR_EXTREME = [...OPENROUTER_IMAGE_AR, "1:4", "4:1", "1:8", "8:1"];
@@ -1166,7 +1165,6 @@ var OPENROUTER_IMAGE_SIZES = ["0.5K", ...OPENROUTER_IMAGE_SIZE];
1166
1165
  var OPENROUTER_IMAGE_SIZE_EXTENDED = OPENROUTER_IMAGE_SIZES;
1167
1166
  var GEMINI_LITE_IMAGE_SIZE = ["1K"];
1168
1167
  var OPENROUTER_IMAGE_QUALITY = ["auto", "low", "medium", "high"];
1169
- var OPENROUTER_IMAGE_QUALITY_25 = ["auto", "low", "medium", "high", "xhigh", "max"];
1170
1168
  var RECRAFT_IMAGE_AR = ["1:1", "4:3", "3:4", "16:9", "9:16"];
1171
1169
  var SEEDANCE_DURATIONS = [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
1172
1170
  var SEEDANCE_25_DURATIONS = [
@@ -1229,7 +1227,6 @@ var REPLICATE_VIDEO_MIMES = ["video/mp4", "video/webm", "video/quicktime"];
1229
1227
  var DECONSTRUCT_VIDEO_MIMES = ["video/mp4", "video/webm", "video/quicktime"];
1230
1228
  var REPLICATE_AUDIO_MIMES = ["audio/wav", "audio/mpeg", "audio/mp3"];
1231
1229
  var IMAGE_GENERATE_MODELS = [
1232
- "openai/gpt-image-2.5-sunburst",
1233
1230
  "openai/gpt-image-2",
1234
1231
  "openai/gpt-5.4-image-2",
1235
1232
  "google/gemini-3.1-flash-image-preview",
@@ -1375,20 +1372,6 @@ var MODEL_REGISTRY = {
1375
1372
  // images as a side effect. Notable capability gaps vs the Gemini entries:
1376
1373
  // no `image_size` (OpenAI picks the pixel dimensions from the ratio, and a
1377
1374
  // `resolution` is silently ignored) and the narrower `..._AR_GPT` ratio set.
1378
- "openai/gpt-image-2.5-sunburst": {
1379
- // Identical to the gpt-image-2 entry below except for the quality ladder — the
1380
- // ratio set, the 16-reference ceiling, the missing `image_size` and the reasons
1381
- // `background` / `output_compression` stay undeclared all carry over unchanged.
1382
- label: "OpenAI GPT Image 2.5",
1383
- inputs: [],
1384
- optional_inputs: [{ kind: "image", mimes: OPENROUTER_IMAGE_MIMES, max: GPT_IMAGE_MAX_REFERENCES }],
1385
- required: ["prompt"],
1386
- params: {
1387
- prompt: { kind: "string", maxLength: GPT_IMAGE_PROMPT_MAX },
1388
- aspect_ratio: { kind: "string", enum: OPENROUTER_IMAGE_AR_GPT },
1389
- quality: { kind: "string", enum: OPENROUTER_IMAGE_QUALITY_25 }
1390
- }
1391
- },
1392
1375
  "openai/gpt-image-2": {
1393
1376
  // Its live endpoint also advertises `background` (auto|opaque) and
1394
1377
  // `output_compression` (0-100), which we deliberately do not declare. Not an
@@ -2043,34 +2026,12 @@ function supportsParam(kind, model, param) {
2043
2026
  return MODEL_REGISTRY[kind]?.[model]?.params[param] !== void 0;
2044
2027
  }
2045
2028
  var DEFAULT_CLIP_DURATION_S = 5;
2046
- var SPOKEN_WORDS_PER_SECOND = 2.5;
2047
- function spokenWordsIn(prompt) {
2048
- if (!prompt) return 0;
2049
- const quoted = [
2050
- ...prompt.matchAll(/['"\u201c\u201d\u2018\u2019]([^'"\u201c\u201d\u2018\u2019]{8,})['"\u201c\u201d\u2018\u2019]/g)
2051
- ].map((m) => m[1] ?? "");
2052
- const text = quoted.join(" ").trim();
2053
- return text ? text.split(/\s+/).filter(Boolean).length : 0;
2054
- }
2055
2029
  function nearestClipDuration(model, preferred) {
2056
2030
  const schema = MODEL_REGISTRY.video_generate[model]?.params.duration;
2057
2031
  const allowed = schema?.kind === "number" ? schema.enum : void 0;
2058
2032
  if (!allowed?.length || allowed.includes(preferred)) return preferred;
2059
2033
  return [...allowed].sort((a, b) => Math.abs(a - preferred) - Math.abs(b - preferred) || a - b)[0];
2060
2034
  }
2061
- function maxClipSeconds(model) {
2062
- const schema = MODEL_REGISTRY.video_generate[model]?.params.duration;
2063
- const allowed = schema?.kind === "number" ? schema.enum : void 0;
2064
- return allowed?.length ? Math.max(...allowed) : void 0;
2065
- }
2066
- function splitScriptFor(words, model) {
2067
- const maxSeconds = maxClipSeconds(model);
2068
- if (!maxSeconds) return null;
2069
- const perClip = Math.floor(maxSeconds * SPOKEN_WORDS_PER_SECOND);
2070
- if (words <= perClip) return null;
2071
- const clips = Math.ceil(words / perClip);
2072
- return { clips, wordsPerClip: Math.ceil(words / clips), maxSeconds };
2073
- }
2074
2035
  function promptMaxLength(kind, model) {
2075
2036
  const schema = MODEL_REGISTRY[kind]?.[model]?.params.prompt;
2076
2037
  return schema?.kind === "string" ? schema.maxLength : void 0;
@@ -2085,19 +2046,6 @@ function maxInputSlot(kind, model, inputKind) {
2085
2046
  function maxInputReferences(kind, model) {
2086
2047
  return maxInputSlot(kind, model, "image");
2087
2048
  }
2088
- function supportedQualities(kind, model) {
2089
- const schema = MODEL_REGISTRY[kind]?.[model]?.params.quality;
2090
- return schema?.kind === "string" ? schema.enum : void 0;
2091
- }
2092
- function bestSupportedQuality(kind, model, want) {
2093
- const supported = supportedQualities(kind, model);
2094
- if (!supported) return void 0;
2095
- if (supported.includes(want)) return want;
2096
- const ladder = supported.filter((step) => step !== "auto");
2097
- const ceiling = ladder.indexOf(want);
2098
- const reachable = ceiling === -1 ? ladder : ladder.slice(0, ceiling);
2099
- return reachable[reachable.length - 1];
2100
- }
2101
2049
  function supportedAspectRatios(kind, model) {
2102
2050
  const schema = MODEL_REGISTRY[kind]?.[model]?.params.aspect_ratio;
2103
2051
  return schema?.kind === "string" ? schema.enum : void 0;
@@ -3182,16 +3130,6 @@ function dfsCycle(u, color, stack, reverseAdj) {
3182
3130
  stack.pop();
3183
3131
  return null;
3184
3132
  }
3185
- function nodesBeforeCheckpoint(graph, types, stopKinds) {
3186
- const all = new Set(graph.keys());
3187
- if (!stopKinds?.size) return all;
3188
- const running = /* @__PURE__ */ new Set();
3189
- for (const layer of topologicalLayers(graph)) {
3190
- if (layer.some((id) => stopKinds.has(types.get(id) ?? ""))) return running;
3191
- for (const id of layer) running.add(id);
3192
- }
3193
- return running;
3194
- }
3195
3133
 
3196
3134
  // src/engine/engine/validator.ts
3197
3135
  import { readFile as readFile2 } from "fs/promises";
@@ -3210,7 +3148,7 @@ var VEO_DURATIONS = [4, 6, 8];
3210
3148
  var KLING_DURATIONS2 = [5, 10];
3211
3149
  var KLING_NEGATIVE_PROMPT = "warped face, distorted hands, extra fingers, morphing, flicker, on-screen text, watermark, low quality";
3212
3150
  var KLING_CFG_SCALE = 0.7;
3213
- var SPEAKS_PROSE = (line, accent) => `The person speaks to camera; lip-sync follows the dialogue verbatim, with delivery and emotion carried in the wording itself (no bracketed cues).${accent ? ` The speech is in ${accent}.` : ""} Dialogue: "${line}"`;
3151
+ var SPEAKS_PROSE = (line) => `The person speaks to camera; lip-sync follows the dialogue verbatim, with delivery and emotion carried in the wording itself (no bracketed cues). Dialogue: "${line}"`;
3214
3152
  var SEEDANCE_PROFILE = {
3215
3153
  id: "seedance",
3216
3154
  dialogueDirective: SPEAKS_PROSE,
@@ -3311,14 +3249,9 @@ var GPT_IMAGE_PROFILE = {
3311
3249
  id: "gpt-image",
3312
3250
  constraintPlacement: "last",
3313
3251
  photorealCue: true,
3314
- // OpenRouter forwards `quality`; gpt-image already processes inputs at high fidelity
3315
- // automatically, so we deliberately do NOT send `input_fidelity`.
3316
- //
3317
- // No `quality` here any more: it is the one default that depends on WHICH gpt-image is
3318
- // pinned. 2.5 added `xhigh` and `max` above `high`, and the older entries would refuse
3319
- // them at validate — so callers ask for the step they want through
3320
- // `bestSupportedQuality` and get the best the chosen model actually has.
3321
- paramDefaults: {}
3252
+ // OpenRouter forwards `quality`; gpt-image-2 already processes inputs at high
3253
+ // fidelity automatically, so we deliberately do NOT send `input_fidelity`.
3254
+ paramDefaults: { quality: "high" }
3322
3255
  };
3323
3256
  var GEMINI_IMAGE_PROFILE = {
3324
3257
  id: "gemini",
@@ -3829,19 +3762,6 @@ function checkSlotsForNode(ctx, n, _i) {
3829
3762
  });
3830
3763
  }
3831
3764
  }
3832
- function estimateCreditsFor(canvas, registry, ids) {
3833
- let total = 0;
3834
- for (const n of canvas.nodes) {
3835
- if (!ids.has(n.id)) continue;
3836
- const def = registry.get(n.type);
3837
- if (!def?.cost) continue;
3838
- try {
3839
- total += def.cost({ params: def.params.parse(n.params ?? {}) }).credits;
3840
- } catch {
3841
- }
3842
- }
3843
- return total;
3844
- }
3845
3765
  function estimateCredits(ctx) {
3846
3766
  let total = 0;
3847
3767
  for (const n of ctx.canvas.nodes) {
@@ -4148,7 +4068,7 @@ function checkAudioTimelineTotals(ctx, audioMixNode, expected) {
4148
4068
  if (audioMixNode) mustBeFullLength.add(audioMixNode);
4149
4069
  ctx.canvas.nodes.forEach((n) => {
4150
4070
  if (n.type !== "audio_voice_convert") return;
4151
- const track = refNodeOf(ctx, n.inputs?.audio);
4071
+ const track = refNodeOf(ctx, (n.inputs ?? {}).audio);
4152
4072
  if (track?.type === "audio_timeline") mustBeFullLength.add(track.id);
4153
4073
  });
4154
4074
  for (const id of mustBeFullLength) {
@@ -4169,11 +4089,11 @@ function checkAudioTimelineTotals(ctx, audioMixNode, expected) {
4169
4089
  function checkNativeSegOverlap(ctx) {
4170
4090
  for (const conv of ctx.canvas.nodes) {
4171
4091
  if (conv.type !== "audio_voice_convert") continue;
4172
- const track = refNodeOf(ctx, conv.inputs?.audio);
4092
+ const track = refNodeOf(ctx, (conv.inputs ?? {}).audio);
4173
4093
  if (track?.type !== "audio_timeline") continue;
4174
4094
  const params = track.params;
4175
4095
  const windows = (params.tracks ?? []).map((t) => {
4176
- const extract = refNodeOf(ctx, track.inputs?.[t.slot]);
4096
+ const extract = refNodeOf(ctx, (track.inputs ?? {})[t.slot]);
4177
4097
  const len = t.duration_s ?? (extract ? ffmpegTrimSeconds(extract) : null);
4178
4098
  return len === null ? null : { slot: t.slot, start: t.start_s, end: t.start_s + len };
4179
4099
  }).filter((w) => w !== null).sort((a, b) => a.start - b.start);
@@ -4666,13 +4586,6 @@ function unwrap(schema) {
4666
4586
  }
4667
4587
 
4668
4588
  // src/engine/engine/executor.ts
4669
- function heldByCheckpoint(canvas, layer, kinds) {
4670
- if (!kinds?.size) return [];
4671
- return layer.filter((id) => {
4672
- const type = canvas.nodes.find((n) => n.id === id)?.type;
4673
- return type !== void 0 && kinds.has(type);
4674
- });
4675
- }
4676
4589
  var Engine = class {
4677
4590
  registry;
4678
4591
  client;
@@ -4700,7 +4613,7 @@ var Engine = class {
4700
4613
  async run(input, opts = {}) {
4701
4614
  const validation = await this.validateDeep(input);
4702
4615
  if (!validation.ok) throw new ValidationError(validation.issues);
4703
- if (!opts.stop_before_kinds?.size && opts.max_credits !== void 0 && validation.estimatedCredits > opts.max_credits) {
4616
+ if (opts.max_credits !== void 0 && validation.estimatedCredits > opts.max_credits) {
4704
4617
  throw new RunAbortedError(
4705
4618
  "cost_cap",
4706
4619
  `estimated ${validation.estimatedCredits} credits exceeds the ${opts.max_credits}-credit cap \u2014 nothing was billed; raise --max-credits or shrink the canvas`
@@ -4719,20 +4632,6 @@ var Engine = class {
4719
4632
  const counters = { cachedNodes: 0, totalCredits: 0 };
4720
4633
  const nodeRuns = [];
4721
4634
  const graph = this.pruneToOutput(canvas, buildGraph(canvas));
4722
- if (opts.max_credits !== void 0 && opts.stop_before_kinds?.size) {
4723
- const willRun = nodesBeforeCheckpoint(
4724
- graph,
4725
- new Map(canvas.nodes.map((n) => [n.id, n.type])),
4726
- opts.stop_before_kinds
4727
- );
4728
- const estimate = estimateCreditsFor(canvas, this.registry, willRun);
4729
- if (estimate > opts.max_credits) {
4730
- throw new RunAbortedError(
4731
- "cost_cap",
4732
- `estimated ${estimate} credits exceeds the ${opts.max_credits}-credit cap \u2014 nothing was billed; raise --max-credits or shrink the canvas`
4733
- );
4734
- }
4735
- }
4736
4635
  const needsBytes = computeNeedsLocalBytes(canvas, graph, this.registry);
4737
4636
  this.emitProgress(opts, {
4738
4637
  kind: "plan",
@@ -4777,13 +4676,6 @@ var Engine = class {
4777
4676
  `spent ${counters.totalCredits} credits, over the ${opts.max_credits}-credit cap \u2014 completed nodes are cached; raise --max-credits to continue where this stopped`
4778
4677
  );
4779
4678
  }
4780
- const held = heldByCheckpoint(canvas, layer, opts.stop_before_kinds);
4781
- if (held.length > 0) {
4782
- throw new RunAbortedError(
4783
- "checkpoint",
4784
- `stopped before ${held.join(", ")} \u2014 everything up to here is done and cached, so continuing this run id pays for none of it again`
4785
- );
4786
- }
4787
4679
  const settled = await mapWithConcurrency(layer, limit, (nodeId) => {
4788
4680
  if (opts.signal?.aborted) {
4789
4681
  return Promise.reject(new RunAbortedError("signal", "run aborted before node dispatch"));
@@ -6057,7 +5949,7 @@ function resolveStrategy(params) {
6057
5949
  case "text": {
6058
5950
  const p = safePathname(params.url);
6059
5951
  const isRawText = RAW_TEXT_EXTENSIONS.some((ext) => p.endsWith(ext));
6060
- return isRawText ? "direct_fetch" : "handinger";
5952
+ return isRawText ? "direct_fetch" : "firecrawl";
6061
5953
  }
6062
5954
  default: {
6063
5955
  params.expect;
@@ -6074,10 +5966,10 @@ function safePathname(rawUrl) {
6074
5966
  }
6075
5967
  var ingestNode = defineNode({
6076
5968
  id: "ingest",
6077
- version: "1.2.0",
5969
+ version: "1.3.0",
6078
5970
  category: "io",
6079
5971
  location: "local",
6080
- summary: "Ingest an external URL or a local file into the asset store. Declare the kind you expect (image/video/audio/text/json/font); the node picks the strategy. For source=url: yt-dlp for video/audio (YouTube/TikTok/Vimeo/etc. and direct file URLs), Handinger for HTML/PDF pages \u2192 markdown, direct HTTP fetch for binary URLs (images, fonts) and raw .txt/.md. For source=path: read from the local filesystem and upload to R2.",
5972
+ summary: "Ingest an external URL or a local file into the asset store. Declare the kind you expect (image/video/audio/text/json/font); the node picks the strategy. For source=url: yt-dlp for video/audio (YouTube/TikTok/Vimeo/etc. and direct file URLs), Firecrawl for HTML/PDF pages \u2192 markdown, direct HTTP fetch for binary URLs (images, fonts) and raw .txt/.md. For source=path: read from the local filesystem and upload to R2.",
6081
5973
  when_to_use: 'Use as the on-ramp for any external asset a canvas needs. `expect` makes the output port statically typed so downstream wiring is checked before any byte is fetched. Pick `source: "url"` for portable canvas; pick `source: "path"` for local files (canvas is not portable across machines without the file). Compose with other nodes for richer pipelines (e.g. `ingest expect=video` \u2192 `video_transcribe`).',
6082
5974
  inputs: IngestInputs,
6083
5975
  params: IngestParams,
@@ -6104,8 +5996,8 @@ function runStrategy(strategy, params, ctx) {
6104
5996
  switch (strategy) {
6105
5997
  case "direct_fetch":
6106
5998
  return execDirectFetch(params, ctx);
6107
- case "handinger":
6108
- return execHandinger(params, ctx);
5999
+ case "firecrawl":
6000
+ return execFirecrawl(params, ctx);
6109
6001
  case "yt_dlp":
6110
6002
  return execYtDlp(params, ctx);
6111
6003
  case "local_file":
@@ -6143,9 +6035,8 @@ async function ingestImageUrl(url, ctx) {
6143
6035
  } catch (e) {
6144
6036
  throw localExecError(ctx, `${url}: ${e.message}`);
6145
6037
  }
6146
- if (normalized.rasterizedFrom) {
6147
- ctx.log(`ingest: normalized ${normalized.rasterizedFrom} URL -> PNG (${normalized.bytes.length}B)`);
6148
- }
6038
+ const note = normalizationNote(normalized);
6039
+ if (note) ctx.log(`ingest: ${url} ${note}`);
6149
6040
  return uploadAndIngest({
6150
6041
  bytes: normalized.bytes,
6151
6042
  kind: "image",
@@ -6159,11 +6050,11 @@ async function ingestImageUrl(url, ctx) {
6159
6050
  ctx
6160
6051
  });
6161
6052
  }
6162
- async function execHandinger(params, ctx) {
6053
+ async function execFirecrawl(params, ctx) {
6163
6054
  const result = await callBackendExec({
6164
6055
  nodeType: "ingest",
6165
6056
  nodeVersion: ingestNode.version,
6166
- params: { strategy: "handinger", url: params.url },
6057
+ params: { strategy: "firecrawl", url: params.url },
6167
6058
  inputs: {},
6168
6059
  outputKinds: { asset: "text" },
6169
6060
  ctx
@@ -6255,23 +6146,69 @@ async function rasterizeSvgToPng(bytes) {
6255
6146
  return await sharp(bytes, { density }).png({ force: true, palette: false }).toBuffer();
6256
6147
  }
6257
6148
  var MODEL_SAFE_IMAGE_MIMES = /* @__PURE__ */ new Set(["image/jpeg", "image/png", "image/gif", "image/webp"]);
6258
- async function toModelSafeImage(bytes) {
6149
+ var MAX_MODEL_REFERENCE_BYTES = 30 * 1024 * 1024;
6150
+ async function fitWithinReferenceLimit(bytes, mime, maxBytes) {
6151
+ if (bytes.byteLength <= maxBytes) return { bytes, mime };
6152
+ const { default: sharp } = await import("sharp");
6153
+ const read = () => sharp(bytes, { animated: true });
6154
+ const meta = await read().metadata();
6155
+ const animated = (meta.pages ?? 1) > 1;
6156
+ const keepAlpha = meta.hasAlpha === true;
6157
+ const width = meta.width ?? 0;
6158
+ const encode = async (scale2) => {
6159
+ let pipeline2 = read();
6160
+ if (scale2 < 1 && width > 0) pipeline2 = pipeline2.resize({ width: Math.max(256, Math.round(width * scale2)) });
6161
+ if (animated && mime === "image/gif") return { bytes: await pipeline2.gif().toBuffer(), mime: "image/gif" };
6162
+ if (animated || keepAlpha) return { bytes: await pipeline2.webp({ quality: 90 }).toBuffer(), mime: "image/webp" };
6163
+ return { bytes: await pipeline2.jpeg({ quality: 90, mozjpeg: true }).toBuffer(), mime: "image/jpeg" };
6164
+ };
6165
+ let out = await encode(1);
6166
+ let scale = 1;
6167
+ for (let pass = 0; pass < 4 && out.bytes.byteLength > maxBytes; pass++) {
6168
+ scale *= Math.min(0.9, Math.sqrt(maxBytes / out.bytes.byteLength));
6169
+ out = await encode(scale);
6170
+ }
6171
+ return out;
6172
+ }
6173
+ async function toModelSafeImage(bytes, opts) {
6174
+ const maxBytes = opts?.maxBytes ?? MAX_MODEL_REFERENCE_BYTES;
6175
+ const fit = async (candidate, mime, rasterizedFrom) => {
6176
+ const fitted = await fitWithinReferenceLimit(candidate, mime, maxBytes);
6177
+ return {
6178
+ bytes: fitted.bytes,
6179
+ mime: fitted.mime,
6180
+ ...rasterizedFrom ? { rasterizedFrom } : {},
6181
+ ...fitted.bytes === candidate ? {} : { shrunkFromBytes: candidate.byteLength }
6182
+ };
6183
+ };
6259
6184
  const safe = sniffImageMime(bytes);
6260
6185
  if (safe && MODEL_SAFE_IMAGE_MIMES.has(safe)) {
6261
- return { bytes, mime: safe };
6186
+ return await fit(bytes, safe);
6262
6187
  }
6263
6188
  if (sniffSvg(bytes)) {
6264
- return { bytes: await rasterizeSvgToPng(bytes), mime: "image/png", rasterizedFrom: "svg" };
6189
+ return await fit(await rasterizeSvgToPng(bytes), "image/png", "svg");
6265
6190
  }
6266
6191
  const { default: sharp } = await import("sharp");
6192
+ let png;
6193
+ let format;
6267
6194
  try {
6268
6195
  const img = sharp(bytes);
6269
- const format = (await img.metadata()).format;
6270
- const png = await img.png({ force: true }).toBuffer();
6271
- return { bytes: png, mime: "image/png", rasterizedFrom: format ?? "unknown" };
6196
+ format = (await img.metadata()).format ?? "unknown";
6197
+ png = await img.png({ force: true }).toBuffer();
6272
6198
  } catch (e) {
6273
6199
  throw new Error(`bytes are not a decodable image (${e.message})`);
6274
6200
  }
6201
+ return await fit(png, "image/png", format);
6202
+ }
6203
+ function normalizationNote(image) {
6204
+ const parts = [];
6205
+ if (image.rasterizedFrom) parts.push(`normalized ${image.rasterizedFrom} -> ${image.mime}`);
6206
+ if (image.shrunkFromBytes !== void 0) {
6207
+ parts.push(
6208
+ `fitted ${image.shrunkFromBytes}B -> ${image.bytes.length}B as ${image.mime} (providers refuse a reference over ${MAX_MODEL_REFERENCE_BYTES}B)`
6209
+ );
6210
+ }
6211
+ return parts.length > 0 ? parts.join("; ") : null;
6275
6212
  }
6276
6213
  function hasAscii(buf, offset, sig) {
6277
6214
  return buf.length >= offset + sig.length && buf.toString("ascii", offset, offset + sig.length) === sig;
@@ -6401,7 +6338,8 @@ async function execLocalFile(params, ctx) {
6401
6338
  outBytes = normalized.bytes;
6402
6339
  outMime = normalized.mime;
6403
6340
  rasterizedFrom = normalized.rasterizedFrom;
6404
- if (rasterizedFrom) ctx.log(`ingest: normalized ${rasterizedFrom} -> PNG (${outBytes.length}B)`);
6341
+ const note = normalizationNote(normalized);
6342
+ if (note) ctx.log(`ingest: ${note}`);
6405
6343
  }
6406
6344
  const durationMs = probeVideoDurationMs(params.expect, outBytes, ctx);
6407
6345
  const ref = await uploadAndIngest({
@@ -7373,24 +7311,6 @@ import { execFile as execFile3 } from "child_process";
7373
7311
  import { readFile as readFile9 } from "fs/promises";
7374
7312
  import path12 from "path";
7375
7313
  import { promisify as promisify3 } from "util";
7376
-
7377
- // src/engine/nodes/local/lib/caption-style.ts
7378
- var TERMINAL = /[.,;:!?…]$/;
7379
- function captionTextsFrom(html) {
7380
- const cards = html.match(/<div[^>]*class="[^"]*\bcaption\b[^"]*"[\s\S]*?<\/div>/g) ?? [];
7381
- return cards.map(
7382
- (card) => card.replace(/<[^>]+>/g, "").replace(/\s+/g, " ").trim()
7383
- ).filter((text) => text.length > 0);
7384
- }
7385
- function fragmentedCaptions(texts) {
7386
- if (texts.length < 2) return null;
7387
- const fragments = texts.slice(0, -1).filter((t) => !TERMINAL.test(t));
7388
- if (fragments.length === 0) return null;
7389
- const example = fragments[0];
7390
- return `${fragments.length} of ${texts.length} caption cards end mid-clause, e.g. "${example}". Split captions where the script punctuates, not on a word count \u2014 a card that ends bare is a sentence cut in half by a timing decision, and it reads as one.`;
7391
- }
7392
-
7393
- // src/engine/nodes/local/lib/hyperframe-check.ts
7394
7314
  var execFileAsync = promisify3(execFile3);
7395
7315
  var NEVER_BLOCK = [
7396
7316
  /contrast/i,
@@ -7459,74 +7379,6 @@ function classifyCheckOutput(lintRaw, inspectRaw) {
7459
7379
  warnings: findings.filter((f) => f.severity === "warning")
7460
7380
  };
7461
7381
  }
7462
- var GATE_SECTIONS = ["lint", "runtime", "layout", "motion", "contrast"];
7463
- function buildCheckArgs(dir, samples) {
7464
- return ["hyperframes", "check", dir, "--json", "--samples", String(samples), "--at-transitions"];
7465
- }
7466
- var PROMOTE_TO_BLOCKING = /GSAP target [^ ]+ not found|no deterministic font mapping/i;
7467
- function toGateFinding(section, entry) {
7468
- const f = entry;
7469
- const code = typeof f.code === "string" ? f.code : "unknown";
7470
- const message2 = typeof f.message === "string" ? f.message : "";
7471
- const isError = f.severity === "error" || PROMOTE_TO_BLOCKING.test(message2);
7472
- const fatal = PROMOTE_TO_BLOCKING.test(message2);
7473
- return {
7474
- source: section,
7475
- code,
7476
- message: message2,
7477
- severity: fatal || isError && !isAdvisory(code, message2) ? "blocking" : "warning"
7478
- };
7479
- }
7480
- function classifyGateOutput(raw) {
7481
- const parsed = parseCheckJson(raw);
7482
- const findings = GATE_SECTIONS.flatMap((section) => {
7483
- const block = parsed?.[section];
7484
- const entries = Array.isArray(block?.findings) ? block.findings : [];
7485
- return entries.map((entry) => toGateFinding(section, entry));
7486
- });
7487
- return {
7488
- blocking: findings.filter((f) => f.severity === "blocking"),
7489
- warnings: findings.filter((f) => f.severity === "warning")
7490
- };
7491
- }
7492
- function summariseWarnings(warnings) {
7493
- const groups = /* @__PURE__ */ new Map();
7494
- for (const w of warnings) {
7495
- const key = `${w.source}/${w.code}`;
7496
- const seen = groups.get(key);
7497
- if (seen) seen.count += 1;
7498
- else groups.set(key, { count: 1, message: w.message });
7499
- }
7500
- return [...groups.entries()].sort((a, b) => b[1].count - a[1].count).map(([key, g]) => `${g.count}\xD7 [${key}] ${g.message}`);
7501
- }
7502
- var FINDING_ADVICE = {
7503
- sweep_static: "the timeline never advanced, so this renders as a STILL IMAGE while billing like a video \u2014 and every other green verdict in this run is unreliable. Check the composition registers a paused timeline on `window.__timelines[<composition-id>]` and that the tweens target elements that exist.",
7504
- console_error: "the composition threw in the browser, so whatever that script was driving did not happen.",
7505
- page_error: "a script failed to evaluate \u2014 animations and any JS-driven layout in this composition did not run.",
7506
- http_error: "an asset 404ed at render time; it will be missing from the frame, not substituted.",
7507
- console_warning: "if this names a GSAP target, the element it animates does not exist, so that tween is a no-op and whatever it was meant to reveal never appears. Fix the selector or add the element before rendering."
7508
- };
7509
- function explainGateFinding(finding) {
7510
- const advice = FINDING_ADVICE[finding.code];
7511
- return advice ? `${finding.message} \u2014 ${advice}` : finding.message;
7512
- }
7513
- function condenseFrameDescriptions(markdown) {
7514
- const lines = [];
7515
- let frame = null;
7516
- for (const line of markdown.split("\n")) {
7517
- const heading = line.match(/^## (.+)$/);
7518
- if (heading) {
7519
- frame = heading[1] ?? null;
7520
- continue;
7521
- }
7522
- const text = line.trim();
7523
- if (frame && text) {
7524
- lines.push(`${frame}: ${text}`);
7525
- frame = null;
7526
- }
7527
- }
7528
- return lines;
7529
- }
7530
7382
  function buildLintArgs(dir) {
7531
7383
  return ["hyperframes", "lint", dir, "--json"];
7532
7384
  }
@@ -7558,13 +7410,8 @@ async function lintStructuralIssues(dir, timeoutMs) {
7558
7410
  function buildInspectArgs(dir, samples) {
7559
7411
  return ["hyperframes", "inspect", dir, "--json", "--samples", String(samples)];
7560
7412
  }
7561
- function buildSnapshotArgs(dir, frames, vision) {
7562
- const base = ["hyperframes", "snapshot", dir, "--frames", String(frames)];
7563
- return vision ? [
7564
- ...base,
7565
- "--describe",
7566
- "Answer four things about this frame. (1) Is it empty or near-empty? Name every element actually visible. (2) Could what is shown physically happen \u2014 object sizes, human scale, and whether every object has its real-world form (a phone has ONE screen, on its front). Say so plainly if something is impossible. (3) Read out every number, currency symbol and word visible INSIDE the picture \u2014 phone screens, documents, signage \u2014 and say whether any of it contradicts the caption on this frame. (4) Is the caption legible against what is behind it?"
7567
- ] : [...base, "--describe", "false"];
7413
+ function buildSnapshotArgs(dir, frames) {
7414
+ return ["hyperframes", "snapshot", dir, "--frames", String(frames), "--describe", "false"];
7568
7415
  }
7569
7416
  function usesNestedCompositions(indexHtml) {
7570
7417
  const withoutComments = indexHtml.replace(/<!--[\s\S]*?-->/g, "");
@@ -7593,66 +7440,44 @@ async function runSnapshotSmoke(args, timeoutMs) {
7593
7440
  return { ok: false, unavailable: false, message: (err.stderr || err.message || "snapshot failed").slice(0, 800) };
7594
7441
  }
7595
7442
  }
7596
- async function runNestedCompositionSmoke(opts) {
7597
- const { dir, nodeId, ctx, timeoutMs, samples } = opts;
7598
- const indexHtml = await readFile9(path12.join(dir, "index.html"), "utf-8").catch(() => "");
7599
- if (!indexHtml || !usesNestedCompositions(indexHtml)) return;
7600
- const snap = await runSnapshotSmoke(
7601
- buildSnapshotArgs(dir, Math.min(samples, 3), hasFrameVisionKey()),
7602
- Math.max(timeoutMs, 12e4)
7603
- );
7604
- if (snap.unavailable) {
7605
- ctx.log(`${nodeId}: hyperframes snapshot unavailable \u2014 skipping nested-composition smoke test`);
7606
- return;
7607
- }
7608
- if (!snap.ok) {
7609
- throw new Error(
7610
- `${nodeId}: nested-composition smoke test failed \u2014 an embedded block did not render. Check the host\u2194block id match, that the block's <style>/<script> live inside its <template>, and that it styles #root (not a class).
7611
- ${snap.message}`
7612
- );
7613
- }
7614
- const described = await readFile9(path12.join(dir, "snapshots", "descriptions.md"), "utf-8").catch(() => "");
7615
- for (const line of condenseFrameDescriptions(described)) {
7616
- ctx.log(`${nodeId}: frame check \u2014 ${line}`);
7617
- }
7618
- ctx.log(`${nodeId}: nested-composition smoke test passed`);
7619
- }
7620
- async function runGate(dir, timeoutMs, samples) {
7621
- const checkRaw = await runOne(buildCheckArgs(dir, samples), timeoutMs);
7622
- if (checkRaw !== null) return classifyGateOutput(checkRaw);
7443
+ async function runHyperframesCheck(opts) {
7444
+ const { dir, nodeId, ctx, timeoutMs, samples = 5 } = opts;
7623
7445
  const [lintRaw, inspectRaw] = await Promise.all([
7624
7446
  runOne(buildLintArgs(dir), timeoutMs),
7625
7447
  runOne(buildInspectArgs(dir, samples), timeoutMs)
7626
7448
  ]);
7627
- if (lintRaw === null && inspectRaw === null) return null;
7628
- return classifyCheckOutput(lintRaw ?? "", inspectRaw ?? "");
7629
- }
7630
- async function runHyperframesCheck(opts) {
7631
- const { dir, nodeId, ctx, timeoutMs, samples = 5 } = opts;
7632
- const gate = await runGate(dir, timeoutMs, samples);
7633
- if (gate === null) {
7634
- ctx.log(`${nodeId}: hyperframes check/lint/inspect unavailable \u2014 skipping pre-render check`);
7449
+ if (lintRaw === null && inspectRaw === null) {
7450
+ ctx.log(`${nodeId}: hyperframes lint/inspect unavailable \u2014 skipping pre-render check`);
7635
7451
  return;
7636
7452
  }
7637
- const { blocking, warnings } = gate;
7638
- for (const line of summariseWarnings(warnings)) {
7639
- ctx.log(`${nodeId}: hyperframe check warning ${line}`);
7453
+ const { blocking, warnings } = classifyCheckOutput(lintRaw ?? "", inspectRaw ?? "");
7454
+ for (const w of warnings) {
7455
+ ctx.log(`${nodeId}: hyperframe check warning [${w.source}/${w.code}] ${w.message}`);
7640
7456
  }
7641
7457
  if (blocking.length > 0) {
7642
- const seen = /* @__PURE__ */ new Map();
7643
- for (const b of blocking) seen.set(`${b.source}/${b.code}/${b.message}`, b);
7644
- const detail = [...seen.values()].map((b) => `\u2022 [${b.source}/${b.code}] ${explainGateFinding(b)}`).join("\n");
7645
- throw new Error(
7646
- `${nodeId}: pre-render check failed (${blocking.length} blocking, ${seen.size} distinct)
7647
- ${detail}`
7648
- );
7458
+ const detail = blocking.map((b) => `\u2022 [${b.source}/${b.code}] ${b.message}`).join("\n");
7459
+ throw new Error(`${nodeId}: pre-render check failed (${blocking.length} blocking)
7460
+ ${detail}`);
7649
7461
  }
7650
- const composition = await readFile9(path12.join(dir, "index.html"), "utf-8").catch(() => "");
7651
- const captionComplaint = fragmentedCaptions(captionTextsFrom(composition));
7652
- if (captionComplaint) {
7653
- ctx.log(`${nodeId}: caption style \u2014 ${captionComplaint}`);
7462
+ let indexHtml = "";
7463
+ try {
7464
+ indexHtml = await readFile9(path12.join(dir, "index.html"), "utf-8");
7465
+ } catch {
7466
+ indexHtml = "";
7467
+ }
7468
+ if (indexHtml && usesNestedCompositions(indexHtml)) {
7469
+ const snap = await runSnapshotSmoke(buildSnapshotArgs(dir, Math.min(samples, 3)), Math.max(timeoutMs, 12e4));
7470
+ if (snap.unavailable) {
7471
+ ctx.log(`${nodeId}: hyperframes snapshot unavailable \u2014 skipping nested-composition smoke test`);
7472
+ } else if (!snap.ok) {
7473
+ throw new Error(
7474
+ `${nodeId}: nested-composition smoke test failed \u2014 an embedded block did not render. Check the host\u2194block id match, that the block's <style>/<script> live inside its <template>, and that it styles #root (not a class).
7475
+ ${snap.message}`
7476
+ );
7477
+ } else {
7478
+ ctx.log(`${nodeId}: nested-composition smoke test passed`);
7479
+ }
7654
7480
  }
7655
- await runNestedCompositionSmoke({ dir, nodeId, ctx, timeoutMs, samples });
7656
7481
  ctx.log(`${nodeId}: pre-render check passed (${warnings.length} warning${warnings.length === 1 ? "" : "s"})`);
7657
7482
  }
7658
7483
 
@@ -9159,14 +8984,7 @@ async function tryExtractAudio(inputs, ctx) {
9159
8984
  import { z as z34 } from "zod";
9160
8985
  var voiceSelectNode = delegated({
9161
8986
  id: "voice_select",
9162
- // 1.1.0: a pinned voice used to come back as an inline `{ kind, text }` with no sha256
9163
- // and no mime, which every consumer taking the id as an INPUT rejected —
9164
- // `audio_voice_convert` died on `voice_ref.sha256: expected string, received undefined`.
9165
- // The backend now uploads it as a real asset like the ranked branch, and the version has
9166
- // to move with it: the cache key is built from this string, so entries written under
9167
- // 1.0.0 kept replaying the broken shape long after the fix was deployed. A node whose
9168
- // OUTPUT shape changes has to bump, not only one whose behaviour does.
9169
- version: "1.1.0",
8987
+ version: "1.0.0",
9170
8988
  category: "audio",
9171
8989
  summary: 'Cast an ElevenLabs voice from a natural-language description (e.g. "warm, authoritative female narrator, American accent"). Lists the account\'s voices and ranks them against the brief, emitting the best `voice_id` as a bare-string text asset plus a ranked `candidates` JSON.',
9172
8990
  when_to_use: 'Use to turn a voice description (e.g. from a `video_deconstruct` blueprint\'s `voice_description`) into a usable ElevenLabs voice id, then feed it into a `tts` node by wiring `inputs.voice_ref: $ref:<this>.voice_id` and setting `params.voice: "{{voice_ref}}"` \u2014 the engine splices the id in at run time. Review `candidates` (json) to pick a different voice. Optional `gender`/`age`/`accent`/`language` hints sharpen the ranking.',
@@ -9177,11 +8995,6 @@ var voiceSelectNode = delegated({
9177
8995
  age: z34.string().optional(),
9178
8996
  accent: z34.string().optional(),
9179
8997
  language: z34.string().optional(),
9180
- /**
9181
- * A voice already chosen — an Avatar's pinned one. Given, nothing is cast: the
9182
- * ranking is skipped and this id is emitted as-is.
9183
- */
9184
- voice_id: z34.string().min(1).max(120).optional(),
9185
8998
  limit: z34.number().int().min(1).max(20).optional()
9186
8999
  }).strict(),
9187
9000
  outputs: z34.object({ voice_id: TextRef, candidates: JsonRef }).strict(),
@@ -9344,7 +9157,6 @@ export {
9344
9157
  describeFailureReason,
9345
9158
  AD_FORMAT_PLATFORMS,
9346
9159
  platformFormats,
9347
- frameRealismDirection,
9348
9160
  SEEDANCE_DURATIONS,
9349
9161
  ELEVENLABS_MAX_MUSIC_LENGTH_MS,
9350
9162
  IMAGE_GENERATE_MODELS,
@@ -9356,14 +9168,10 @@ export {
9356
9168
  MODEL_REGISTRY,
9357
9169
  supportsParam,
9358
9170
  DEFAULT_CLIP_DURATION_S,
9359
- SPOKEN_WORDS_PER_SECOND,
9360
- spokenWordsIn,
9361
9171
  nearestClipDuration,
9362
- splitScriptFor,
9363
9172
  promptMaxLength,
9364
9173
  maxInputSlot,
9365
9174
  maxInputReferences,
9366
- bestSupportedQuality,
9367
9175
  nearestSupportedAspectRatio,
9368
9176
  nearestSupportedImageSize,
9369
9177
  estimateVideoCredits,
@@ -9404,4 +9212,4 @@ export {
9404
9212
  defaultRegistry,
9405
9213
  createEngineFromEnv
9406
9214
  };
9407
- //# sourceMappingURL=chunk-YMHERSTK.js.map
9215
+ //# sourceMappingURL=chunk-YFQWCJX4.js.map