venice-video-harness 2.19.0 → 2.20.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/.agents/skills/venice-agent-guide/SKILL.md +8 -0
- package/.agents/skills/venice-video-model-routing/SKILL.md +9 -0
- package/AGENTS.md +8 -1
- package/CHANGELOG.md +44 -0
- package/README.md +21 -0
- package/capabilities.json +2 -2
- package/dist/agent/guide.d.ts.map +1 -1
- package/dist/agent/guide.js +11 -0
- package/dist/agent/guide.js.map +1 -1
- package/dist/agent/pipeline.d.ts +23 -0
- package/dist/agent/pipeline.d.ts.map +1 -1
- package/dist/agent/pipeline.js +26 -2
- package/dist/agent/pipeline.js.map +1 -1
- package/dist/mini-drama/cli.d.ts.map +1 -1
- package/dist/mini-drama/cli.js +3 -0
- package/dist/mini-drama/cli.js.map +1 -1
- package/dist/mini-drama/loop-engine.d.ts +29 -0
- package/dist/mini-drama/loop-engine.d.ts.map +1 -1
- package/dist/mini-drama/loop-engine.js +94 -17
- package/dist/mini-drama/loop-engine.js.map +1 -1
- package/dist/mini-drama/video-generator.d.ts.map +1 -1
- package/dist/mini-drama/video-generator.js +42 -16
- package/dist/mini-drama/video-generator.js.map +1 -1
- package/dist/session/status.d.ts +12 -0
- package/dist/session/status.d.ts.map +1 -1
- package/dist/session/status.js +11 -0
- package/dist/session/status.js.map +1 -1
- package/dist/venice/models.d.ts +13 -0
- package/dist/venice/models.d.ts.map +1 -1
- package/dist/venice/models.js +15 -0
- package/dist/venice/models.js.map +1 -1
- package/package.json +1 -1
|
@@ -38,6 +38,14 @@ in the other.
|
|
|
38
38
|
- State placement explicitly in every prompt: lock each location's landmark geography (`spatialAnchors`) and give every character shot a `blocking` field (position vs named anchors, screen side, depth, facing/eyeline). Keep screen sides and eyelines constant across a scene unless a movement is scripted.
|
|
39
39
|
- Prefer native model dialogue (Seedance 2.0, HappyHorse 1.1 with voice-donor references) over exact TTS lip-sync.
|
|
40
40
|
|
|
41
|
+
## Modes of operation — the linear pipeline is not the only path
|
|
42
|
+
- Default path: the gated pipeline (`venice-video pipeline`) — aesthetic → cast → episode → script → approve → storyboard → QA → render → assemble. Use it for a finished, identity-locked cut.
|
|
43
|
+
- Loop mode (`venice-video loop -p <project> -e <n> --mode <looping|production>`): once a shot script exists, render the whole plan continuously and watch it as a live browser loop that hot-swaps fresh takes. It SKIPS the storyboard/QA gates and writes only under `episodes/episode-NNN/loop/`, so it never touches the canonical cut. `looping` = creative flow, lower quality (Turbo 480P, disposable); `production` = gather usable, identity-locked takes (Max R2V @768P). `--mode` is REQUIRED non-interactively; `--budget` caps spend (default $2). This is NOT in the `pipeline` stage list — it is under `branches` in `pipeline --json`.
|
|
44
|
+
- **Loop mode plays AND renders at the same time — it does NOT pre-generate everything.** The browser loops the takes that already exist while the worker keeps generating new ones, swapping each shot's newer take in on the loop's **next pass** (never mid-clip). Two things make a running loop *look* pre-generated when it isn't: (a) it **pauses** when it hits `--budget` or you click Pause, then just replays what's on disk — raise `--budget` or pass `--unbounded` to keep it generating; (b) `--max-takes` is a per-shot ring buffer (default 3, older takes pruned), not a total.
|
|
45
|
+
- **Which mode evolves while you watch:** `looping` (Turbo, 480P) renders faster than it plays, so it visibly changes as you watch. `production`/create renders each shot slowly on Max R2V — it's for **gathering keeper takes**, not a continuously-evolving watch, and on a short/few-shot plan it can look static even while running (one take takes longer to render than a full loop cycle takes to play). Want "watch it keep changing"? Use `looping` with a higher/unbounded budget.
|
|
46
|
+
- Three video lanes, chosen per shot by the router (see the `venice-video-model-routing` skill): **t2v** (prompt only), **i2v** (animate a supplied START image via `image_url` — establishing/atmosphere shots, or chaining off a previous last frame), **R2V** (identity anchored to a reference stack — the default for character shots). "i2v" means a supplied first frame; "R2V" means `reference_image_urls`, not a start frame — do not conflate them.
|
|
47
|
+
- To animate a single image you already have (plain i2v, no project), the routing skill's bundled `scripts/venice-video.py --image <file> --model <...-image-to-video>` is the standalone path; the project pipeline is for multi-shot, consistency-first work.
|
|
48
|
+
|
|
41
49
|
## Where the full knowledge lives
|
|
42
50
|
- `AGENTS.md` — 49 rules and 28 production anti-patterns, shipped in the package.
|
|
43
51
|
- `.agents/skills/` — `venice-api`, `venice-video-model-routing`, `character-consistency`, `shot-composition`, `burn-in-subtitles`, `video-editing`, and more.
|
|
@@ -372,6 +372,15 @@ Both skip the storyboard/QA gates and write only under `loop/`. See `LoopEngine`
|
|
|
372
372
|
(`src/mini-drama/loop-engine.ts`) and AGENTS.md rule 58. Watch is a preview, not a production
|
|
373
373
|
path; create is the "keep the good takes" path.
|
|
374
374
|
|
|
375
|
+
**The loop plays AND renders concurrently — it does not pre-generate.** The browser loops the
|
|
376
|
+
takes that already exist while the worker keeps generating new ones, swapping each shot's newer
|
|
377
|
+
take in on the loop's NEXT pass (never mid-clip). It only *looks* pre-generated when (a) it is
|
|
378
|
+
PAUSED — budget hit or Pause clicked — and just replays what is on disk (raise `--budget` or
|
|
379
|
+
pass `--unbounded` to keep it going), or (b) it is in `create` mode, whose slow Max R2V renders
|
|
380
|
+
can't keep up with a short loop cycle, so evolution lags. `watch` (looping/Turbo) renders faster
|
|
381
|
+
than it plays and visibly evolves as you watch; `create` (production) is for gathering keeper
|
|
382
|
+
takes, not a live-evolving watch. `--max-takes` is a per-shot ring buffer, not a total/stop.
|
|
383
|
+
|
|
375
384
|
The Creator app mirrors this: `VideoModelCapabilities.wantsSimplePrompt(id:)` gates the
|
|
376
385
|
same trimming in `ShotPromptBuilder`, and relaxes the `produce_shots` motion/length gate
|
|
377
386
|
so a correctly short H3 Max prompt isn't rejected as thin.
|
package/AGENTS.md
CHANGED
|
@@ -478,7 +478,7 @@ Use `POST /video/quote` (via `quoteVideo()`) to estimate costs before committing
|
|
|
478
478
|
|
|
479
479
|
57. **The browser UI is the built-in node web app — default to `venice-video web`.** When the operator asks for a browser UI, a dashboard, or to "open the harness in a browser," start the bundled local web app: `venice-video web` (browser dashboard + a whitelisted command runner over the workspace; binds localhost only, `http://127.0.0.1:3000` by default). Do NOT scaffold a separate/ad-hoc UI or point them at anything else. Per the workspace dev-server rule, kill existing node processes first and run on port 3000. The compiled front-end ships inside the npm package (`dist/web/ui/dist`); `npm run web:build` rebuilds it. Command lives in `src/mini-drama/cli.ts` (`web`), server in `src/web/server.ts`.
|
|
480
480
|
|
|
481
|
-
58. **Loop mode has two modes — a disposable Turbo draft (watch) and an identity-locked Max R2V create — both gate-skipping and money-capped (2026-09-04).** `venice-video loop -p <project> -e <n> [--mode watch|create]` boots the web UI (Loop tab) plus an in-process `LoopEngine` (`src/mini-drama/loop-engine.ts`) that renders every shot into `episodes/episode-NNN/loop/` and keeps regenerating fresh takes so the browser can watch the whole plan on repeat while it evolves. Both modes **bypass the references(only for watch) / storyboard / QA gates** — the only hard precondition is a shot script with ≥1 shot — and write ONLY under `loop/` (`shot-NNN--takeK.mp4` + `loop-manifest.json`), never touching canonical `scene-001/` renders or `series.json`, so a loop can run alongside real production. **The mode is the session's first, REQUIRED decision** — the `loop` command asks "is this for LOOPING (creative flow, lower quality) or PRODUCTION (gather usable shots, higher quality)?" It is a deliberate quality-vs-flow tradeoff, never a silent default: interactive `promptChoice` in a TTY, and a **hard error** in a non-interactive run with no `--mode` (agents MUST pass it). `--mode` accepts natural words — `looping`/`loop`/`fun`/`creative` → watch, `production`/`prod`/`gather` → create (`normalizeLoopMode`). Internally the modes are still `watch`/`create`. **The two modes are the point:** (a) **watch** (enjoyment / creative flow) = MiniMax H3 Max **Turbo** at 480P (~$0.012/s): the first generation is **t2v**, every shot after it **chains i2v off the previous last frame**, and it **NEVER uses R2V** (R2V renders are too slow for a loop, and Turbo has none anyway). It ignores panels and the reference stack — identity is NOT locked; it is a fast fun loop, never production-fidelity. (b) **create** (gather good shots for a project) = the real reference-first routing on the **non-Turbo** H3 Max family at 768P (~$0.024/s): character shots render on `minimax-h3-max-reference-to-video` with the full `@Image` reference stack + voice-donor audio (identity **locked**, takes usable), atmosphere shots on Max i2v/t2v, **each shot rendered independently (chaining OFF by default** — R2V and a start frame can't combine on MiniMax). Create degrades a character shot to i2v/t2v only when its references are missing on disk — so for create, generate character/location references first (rule 54). Both share the render primitive: create mode reuses `resolveShotReferenceInputs` + `ensureVoiceReferenceForShot` (exported from `video-generator.ts`, the SAME resolution `renderSingleShotUnit` uses), so its reference stack can't drift from the real pipeline. Other invariants: (c) **chaining default follows the mode:** watch chains (shot 1 t2v, every later shot i2v off the previous shot's current-take LAST frame via `extractLastFrame`, so the loop plays as one piece); create does NOT chain (each shot is independent R2V — chaining and R2V are mutually exclusive on MiniMax). `--no-chain` forces it off. Chaining uses a lean prompt because the start frame, not a reference stack, drives the render. (d) **Every take renders the model's full length (15s default)** — not the shot's scripted duration — for maximum footage/playback per render; override with `--duration`. (e) **The loop regenerates continuously** and does NOT settle after a fixed number of takes: `--max-takes` is a **ring buffer** (candidate takes kept per shot; older non-current takes are pruned and their files deleted so an infinite run can't fill the disk), NOT a stop condition. It stops only on Pause, `--once` (one pass), or the budget. (f) **Money:** billed at queue time; `--budget` (default $2) pauses the loop, and the UI **Resume** button (or a per-shot regenerate) authorizes another budget's worth via `engine.start()` — so "Start/Resume" always does something. `--unbounded` removes the budget cap (spends until stopped) but keeps the ring buffer. (g) Resolution is reachable because `renderVideoFile` honors an optional `resolution` override validated against the model's `resolutions` (it otherwise force-pins `768P` for every `minimax-h3-max*` id); **watch defaults 480P (the infinite-loop tier), create 768P**. (h) The engine shares the web server's `EventHub` and broadcasts `loop-updated` for instant hot-swap; the manifest (with `mode` + `chain`) also feeds `collectEpisodeState` so a plain `venice-video web` shows the last loop state. When changing loop behavior, keep `loop-engine.ts`, the `loop` command in `cli.ts`, the `/api/projects/:slug/loop/*` endpoints + `WebServerOptions.loop` in `src/web/server.ts`, `resolveShotReferenceInputs`/`extractLastFrame` in `video-generator.ts`, and the `LoopView` UI in sync.
|
|
481
|
+
58. **Loop mode has two modes — a disposable Turbo draft (watch) and an identity-locked Max R2V create — both gate-skipping and money-capped (2026-09-04).** `venice-video loop -p <project> -e <n> [--mode watch|create]` boots the web UI (Loop tab) plus an in-process `LoopEngine` (`src/mini-drama/loop-engine.ts`) that renders every shot into `episodes/episode-NNN/loop/` and keeps regenerating fresh takes so the browser can watch the whole plan on repeat while it evolves. Both modes **bypass the references(only for watch) / storyboard / QA gates** — the only hard precondition is a shot script with ≥1 shot — and write ONLY under `loop/` (`shot-NNN--takeK.mp4` + `loop-manifest.json`), never touching canonical `scene-001/` renders or `series.json`, so a loop can run alongside real production. **The mode is the session's first, REQUIRED decision** — the `loop` command asks "is this for LOOPING (creative flow, lower quality) or PRODUCTION (gather usable shots, higher quality)?" It is a deliberate quality-vs-flow tradeoff, never a silent default: interactive `promptChoice` in a TTY, and a **hard error** in a non-interactive run with no `--mode` (agents MUST pass it). `--mode` accepts natural words — `looping`/`loop`/`fun`/`creative` → watch, `production`/`prod`/`gather` → create (`normalizeLoopMode`). Internally the modes are still `watch`/`create`. **The two modes are the point:** (a) **watch** (enjoyment / creative flow) = MiniMax H3 Max **Turbo** at 480P (~$0.012/s): the first generation is **t2v**, every shot after it **chains i2v off the previous last frame**, and it **NEVER uses R2V** (R2V renders are too slow for a loop, and Turbo has none anyway). It ignores panels and the reference stack — identity is NOT locked; it is a fast fun loop, never production-fidelity. (b) **create** (gather good shots for a project) = the real reference-first routing on the **non-Turbo** H3 Max family at 768P (~$0.024/s): character shots render on `minimax-h3-max-reference-to-video` with the full `@Image` reference stack + voice-donor audio (identity **locked**, takes usable), atmosphere shots on Max i2v/t2v, **each shot rendered independently (chaining OFF by default** — R2V and a start frame can't combine on MiniMax). Create degrades a character shot to i2v/t2v only when its references are missing on disk — so for create, generate character/location references first (rule 54). Both share the render primitive: create mode reuses `resolveShotReferenceInputs` + `ensureVoiceReferenceForShot` (exported from `video-generator.ts`, the SAME resolution `renderSingleShotUnit` uses), so its reference stack can't drift from the real pipeline. Other invariants: (c) **chaining default follows the mode:** watch chains (shot 1 t2v, every later shot i2v off the previous shot's current-take LAST frame via `extractLastFrame`, so the loop plays as one piece); create does NOT chain (each shot is independent R2V — chaining and R2V are mutually exclusive on MiniMax). `--no-chain` forces it off. Chaining uses a lean prompt because the start frame, not a reference stack, drives the render. (d) **Every take renders the model's full length (15s default)** — not the shot's scripted duration — for maximum footage/playback per render; override with `--duration`. (e) **The loop regenerates continuously** and does NOT settle after a fixed number of takes: `--max-takes` is a **ring buffer** (candidate takes kept per shot; older non-current takes are pruned and their files deleted so an infinite run can't fill the disk), NOT a stop condition. It stops only on Pause, `--once` (one pass), or the budget. (f) **Money:** billed at queue time; `--budget` (default $2) pauses the loop, and the UI **Resume** button (or a per-shot regenerate) authorizes another budget's worth via `engine.start()` — so "Start/Resume" always does something. `--unbounded` removes the budget cap (spends until stopped) but keeps the ring buffer. (g) Resolution is reachable because `renderVideoFile` honors an optional `resolution` override validated against the model's `resolutions` (it otherwise force-pins `768P` for every `minimax-h3-max*` id); **watch defaults 480P (the infinite-loop tier), create 768P**. (h) The engine shares the web server's `EventHub` and broadcasts `loop-updated` for instant hot-swap; the manifest (with `mode` + `chain`) also feeds `collectEpisodeState` so a plain `venice-video web` shows the last loop state. (i) **A shot that fails `MAX_CONSECUTIVE_SHOT_ERRORS` (3) times in a row is given up on** — marked `failed`, dropped from `pickNext`, no longer re-queued/re-billed (a manual `regenerate` clears it). This caps the money leak where a server-side-doomed shot (a MiniMax i2v face start frame — billed at queue time, then `/video/retrieve` 500s) is otherwise re-selected fewest-takes-first and re-billed every cycle. (j) **Face-continuity prompting (`--face-continuity`, default on):** prompts each chained character shot to END on the character's face so the next i2v continuation is smoother — but it is **auto-suppressed** when the chain i2v model rejects face start frames (`i2vRejectsFaceStartFrame`, i.e. all MiniMax i2v lanes; a face-ending frame becomes the next start frame and would trip the death in anti-pattern 31). So it is dormant on both current loop lanes and activates on a face-accepting i2v lane; for face loops today use create/R2V. When changing loop behavior, keep `loop-engine.ts`, the `loop` command in `cli.ts`, the `/api/projects/:slug/loop/*` endpoints + `WebServerOptions.loop` in `src/web/server.ts`, `resolveShotReferenceInputs`/`extractLastFrame`/`i2vRejectsFaceStartFrame` in `video-generator.ts`/`models.ts`, and the `LoopView` UI in sync.
|
|
482
482
|
|
|
483
483
|
59. **MiniMax H3 Max (simple-prompt) models IMPROVISE dialogue — the scripted line is intent, not a script (2026-09-04).** Unlike Seedance/Wan, which render the exact line you give them, the H3 Max family (`promptStyle: 'simple'`) performs markedly better carrying natural, continuous speech across a whole generation than reciting a verbatim quote — a fixed line fights the model the same way the directorial blocks do. So in **native-dialogue mode** the prompt builders render a speaker's line as INTENT — `[@ImageN, voice, delivery] conveys: "…"` plus a one-line "improvise naturally in character, keep the meaning and tone, don't recite word for word" note — instead of the directorial `[…]: "exact line"` quote. This is automatic via `shouldImproviseDialogue(modelId, series)` in `prompt-builder.ts` (`modelWantsSimplePrompt(modelId)` AND `videoDefaults.audioStrategy !== 'lip-sync'`), applied in both `buildVideoPrompt` (singles) and `buildMontagePrompt` (montage) — the two paths the H3 Max family renders through. Directorial models keep the exact quote; the legacy Seedance-native / Kling multi-shot builders (`buildMultiShotPrompt`) are untouched because those lanes are never simple-prompt. **The exception is exact-lip-sync**: there the `audio_url` drives the exact spoken words, so the line stays verbatim (the improv gate excludes `audioStrategy === 'lip-sync'`). **Consequence:** when a simple-prompt model improvises, burned/exported captions must be derived by transcribing the rendered audio (the editing pipeline's `silencedetect`/whisper path), NOT from `script.json` — the model will not say it word for word. When changing this, keep `shouldImproviseDialogue` / `formatDialogueLine` / `IMPROV_DIALOGUE_NOTE` in `prompt-builder.ts` and this rule in sync.
|
|
484
484
|
|
|
@@ -674,6 +674,13 @@ Issues discovered during production and their fixes. The agent should internaliz
|
|
|
674
674
|
**Root cause:** Seedance montage generations front-load transition frames so the beats can be cut apart; the per-beat cutter slices at the planned timestamps, so when the model's actual transition lands a few frames off the boundary, junk frames survive at a cut's head — most visibly on the first beat of unit 1, which becomes the film's opening frames.
|
|
675
675
|
**Fix:** `qa-videos` detects it programmatically (per-frame luma scan over each unit's first second; a spike that reverts within 3 frames is a flash, not a scene change — ffmpeg `signalstats`, zero API cost). Fix by re-rendering the unit or trimming the flagged frames off the head of that beat's cut before assembly; for the film's first shot, always eyeball frames 0-10 of the final master before delivery.
|
|
676
676
|
|
|
677
|
+
### 31. Loop Watch Mode: t2v Aspect 400, Chain Frame Past Stream End, Face Frames Die Server-Side (2026-09-04)
|
|
678
|
+
**Symptom:** First watch-mode loop run failed at three successive layers. (a) Every t2v queue 400'd with `aspect_ratio: Required`. (b) After that was fixed, chained i2v takes 400'd with `image_url is required` because the extracted last-frame PNG did not exist — yet `extractLastFrame` had not thrown. (c) Once chaining produced real frames, every chained render whose start frame contained a recognizable human face queued successfully, then died server-side: `/video/retrieve` 500s ("An unknown error occurred") forever. The engine's give-up-after-6-polls path cleared the pending record and re-queued fresh, billing ~$0.18 per attempt (4 attempts on one shot).
|
|
679
|
+
**Root cause:** (a) `renderVideoFile` set `aspect_ratio` only for `reference-to-video` and non-i2v Seedance; MiniMax H3 Max (Turbo) t2v REQUIRES it. (b) `extractLastFrame` probed the CONTAINER duration and sought to `duration - 0.05`; MiniMax writes an audio track slightly longer than the video stream, so the seek landed past the last decodable frame — and ffmpeg exits 0 having written no file. (c) MiniMax i2v accepts a face-bearing start frame at queue time (billed) but the render fails server-side, surfacing only as a retrieve 500. Faceless start frames (the robot) render fine; t2v (no input image) renders fine. There is no MiniMax equivalent of the Seedance 409 `needs_consent` handshake.
|
|
680
|
+
**Fix:** (a) `video-generator.ts` now sets `body.aspect_ratio` for every `text-to-video` model as well. (b) `extractLastFrame` probes the `v:0` stream duration and steps back in widening offsets (0.1/0.3/0.6/1.0s) until the PNG actually exists on disk, throwing otherwise. (c) The face-death is Venice-side, but the fallout is now capped: `LoopEngine` counts consecutive render failures per shot and **gives up on a shot after `MAX_CONSECUTIVE_SHOT_ERRORS` (3)** — it is marked `failed`, dropped from `pickNext`, and no longer re-queued/re-billed (a manual `regenerate` revives it). This is the real fix for the money leak — note the re-queue was NOT `isQueueGoneError` (400/404/410, not 500): the loop force-requeues, so a doomed shot was re-selected fewest-takes-first by the *scheduler* every cycle. Watch mode with human faces still hits the death per chained take, so `--no-chain` remains the clean workaround; create mode routes character shots to R2V (face **references**, not a start frame) and, when refs are missing, now degrades to **t2v** instead of a face-bearing i2v (`i2vRejectsFaceStartFrame` in `models.ts`). **Verified 2026-09-04:** MiniMax **R2V** accepts face-bearing reference sheets — a 5s render off a character `front.png` succeeded in ~13s (`scripts/probe-minimax-r2v-face.ts`). So only i2v *start frames* die on a face, not R2V *references*: create-mode character loops are viable, and create/R2V is the working path for smooth character-face loops.
|
|
681
|
+
**Related — face-continuity prompting:** the loop can prompt each chained shot to END on the character's face for smoother i2v continuations (`--face-continuity`, on by default), but it is **auto-suppressed on any i2v model that rejects face start frames** (all MiniMax i2v lanes), because a face-ending frame is the next shot's start frame and would trip exactly this death. So today it is dormant on both loop lanes; it activates on a non-MiniMax i2v lane or once Venice fixes MiniMax i2v. For face continuity now, use create mode (R2V locks the face from the sheets, no i2v chaining).
|
|
682
|
+
**Files:** `src/mini-drama/video-generator.ts`, `src/mini-drama/loop-engine.ts`, `src/venice/models.ts`, `scripts/probe-minimax-r2v-face.ts`
|
|
683
|
+
|
|
677
684
|
## Output
|
|
678
685
|
|
|
679
686
|
Generated project output belongs in:
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,49 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.20.0 — 2026-09-04
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- **Loop watch mode: t2v `aspect_ratio` 400 + chain-frame past stream end (#25).**
|
|
8
|
+
`renderVideoFile` now sends `aspect_ratio` for every `text-to-video` model
|
|
9
|
+
(MiniMax H3 / H3 Max t2v **require** it — every opening watch take 400'd
|
|
10
|
+
without it). `extractLastFrame` now probes the `v:0` **stream** duration (not
|
|
11
|
+
the container, whose longer audio track pushed the seek past the last
|
|
12
|
+
decodable frame, making ffmpeg exit 0 with no file) and steps back in widening
|
|
13
|
+
offsets until the PNG lands, throwing otherwise so callers fall back to an
|
|
14
|
+
unchained render instead of queueing an `image_url`-less i2v.
|
|
15
|
+
- **Loop money leak: a persistently-failing shot is now given up on.**
|
|
16
|
+
`LoopEngine` tracks consecutive render failures per shot and, after
|
|
17
|
+
`MAX_CONSECUTIVE_SHOT_ERRORS` (3), marks the shot `failed`, drops it from the
|
|
18
|
+
scheduler, and stops re-queueing it. Previously a server-side-doomed shot (a
|
|
19
|
+
MiniMax i2v start frame with a human face — billed at queue time, then
|
|
20
|
+
`/video/retrieve` 500s forever) was re-selected fewest-takes-first and
|
|
21
|
+
re-billed every cycle until the budget paused the loop. A manual `regenerate`
|
|
22
|
+
revives a given-up-on shot. `failed`/`lastError` are surfaced on the manifest
|
|
23
|
+
and `loop-updated` events.
|
|
24
|
+
- **Create mode no longer degrades a character shot to a face-killing i2v.**
|
|
25
|
+
When a create-mode character shot has no R2V references on disk it now degrades
|
|
26
|
+
to **t2v** rather than i2v-off-a-panel on models that reject face start frames
|
|
27
|
+
(MiniMax) — a character panel almost always shows a face, which would 500.
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
|
|
31
|
+
- **`venice-video loop --face-continuity` (on by default).** Prompts each chained
|
|
32
|
+
character shot to end on the character's face so the next clip's i2v
|
|
33
|
+
continuation is smoother. **Auto-suppressed** on i2v models that reject face
|
|
34
|
+
start frames (all MiniMax i2v lanes — a face-ending frame is the next start
|
|
35
|
+
frame and would trip the server-side death), so it can't break the watch loop;
|
|
36
|
+
it activates on a face-accepting i2v lane. `--no-face-continuity` to disable.
|
|
37
|
+
New `i2vRejectsFaceStartFrame()` capability in `models.ts`.
|
|
38
|
+
- **`scripts/probe-minimax-r2v-face.ts`** — one paid 5s probe to settle whether
|
|
39
|
+
MiniMax H3 Max **R2V** accepts face-bearing reference sheets (the open question
|
|
40
|
+
behind create-mode character loops). **Verified 2026-09-04: it does** (render
|
|
41
|
+
succeeded in ~13s) — only i2v *start frames* die on a face, so create-mode
|
|
42
|
+
character loops are viable.
|
|
43
|
+
- Injectable `errorBackoffMs` on `LoopEngine` (test seam).
|
|
44
|
+
|
|
45
|
+
See AGENTS.md rule 58 and anti-pattern 31.
|
|
46
|
+
|
|
3
47
|
## 2.19.0 — 2026-09-04
|
|
4
48
|
|
|
5
49
|
### Added
|
package/README.md
CHANGED
|
@@ -1012,6 +1012,7 @@ venice-video loop -p <dir> -e 1 \
|
|
|
1012
1012
|
--budget 2 \ # pause after ~$2; Resume/regenerate authorizes another budget
|
|
1013
1013
|
--max-takes 3 \ # candidate takes kept per shot (ring buffer, not a stop)
|
|
1014
1014
|
--no-chain \ # render shots independently instead of i2v last-frame chaining
|
|
1015
|
+
--no-face-continuity \ # don't prompt chained shots to end on the character's face (see below)
|
|
1015
1016
|
--once # or: render one take per shot, then stop
|
|
1016
1017
|
# --unbounded # remove the budget cap (spends until you Ctrl-C)
|
|
1017
1018
|
```
|
|
@@ -1020,6 +1021,26 @@ The loop is resumable: takes, pins, and spend are recorded in
|
|
|
1020
1021
|
`loop/loop-manifest.json`, so re-running `loop` picks up where it left off.
|
|
1021
1022
|
`Ctrl-C` stops the engine and the server.
|
|
1022
1023
|
|
|
1024
|
+
**A shot that keeps failing is given up on, not re-billed forever.** After 3
|
|
1025
|
+
consecutive render failures the engine marks the shot `failed`, stops scheduling
|
|
1026
|
+
it, and moves on — so a server-side-doomed shot (e.g. a MiniMax i2v start frame
|
|
1027
|
+
with a human face, which Venice bills at queue time then 500s on retrieve) can't
|
|
1028
|
+
burn the whole budget one failed take at a time. A manual **regenerate** in the
|
|
1029
|
+
UI revives it.
|
|
1030
|
+
|
|
1031
|
+
**Face continuity (on by default, for smoother i2v transitions).** In a chained
|
|
1032
|
+
loop each shot's last frame becomes the next shot's i2v start frame, so
|
|
1033
|
+
`--face-continuity` (default on) prompts each character shot to **end on the
|
|
1034
|
+
character's face**, giving the next clip a clean anchor to continue from
|
|
1035
|
+
(`--no-face-continuity` turns it off). One important caveat: MiniMax i2v renders
|
|
1036
|
+
**die server-side when the start frame shows a face** (AGENTS.md anti-pattern
|
|
1037
|
+
31), so on the MiniMax loop lanes this prompting is **auto-suppressed** — a
|
|
1038
|
+
face-ending frame would kill the next chained render. It activates on any i2v
|
|
1039
|
+
model that accepts face start frames. For smooth character-face loops **today**,
|
|
1040
|
+
use **production** mode: R2V locks the face from the reference sheets across every
|
|
1041
|
+
shot, with no i2v chaining involved (verified — MiniMax R2V accepts face-bearing
|
|
1042
|
+
reference sheets; only i2v *start frames* die).
|
|
1043
|
+
|
|
1023
1044
|
### Interrupted renders are resumable
|
|
1024
1045
|
|
|
1025
1046
|
The harness records each Venice `queue_id` to disk *before* it starts polling, so
|
package/capabilities.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guide.d.ts","sourceRoot":"","sources":["../../src/agent/guide.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,eAAO,MAAM,WAAW,EAAE,SAAS,YAAY,
|
|
1
|
+
{"version":3,"file":"guide.d.ts","sourceRoot":"","sources":["../../src/agent/guide.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,eAAO,MAAM,WAAW,EAAE,SAAS,YAAY,EA0E9C,CAAC;AAEF,wBAAgB,WAAW,IAAI;IAAE,OAAO,EAAE,CAAC,CAAC;IAAC,QAAQ,EAAE,SAAS,YAAY,EAAE,CAAA;CAAE,CAE/E;AAED,wBAAgB,WAAW,IAAI,MAAM,CAWpC"}
|
package/dist/agent/guide.js
CHANGED
|
@@ -69,6 +69,17 @@ export const AGENT_GUIDE = [
|
|
|
69
69
|
'Prefer native model dialogue (Seedance 2.0, HappyHorse 1.1 with voice-donor references) over exact TTS lip-sync.',
|
|
70
70
|
],
|
|
71
71
|
},
|
|
72
|
+
{
|
|
73
|
+
title: 'Modes of operation — the linear pipeline is not the only path',
|
|
74
|
+
points: [
|
|
75
|
+
'Default path: the gated pipeline (`venice-video pipeline`) — aesthetic → cast → episode → script → approve → storyboard → QA → render → assemble. Use it for a finished, identity-locked cut.',
|
|
76
|
+
'Loop mode (`venice-video loop -p <project> -e <n> --mode <looping|production>`): once a shot script exists, render the whole plan continuously and watch it as a live browser loop that hot-swaps fresh takes. It SKIPS the storyboard/QA gates and writes only under episodes/episode-NNN/loop/, so it never touches the canonical cut. LOOPING = creative flow, lower quality (Turbo 480P, disposable); PRODUCTION = gather usable, identity-locked takes (Max R2V @768P). --mode is REQUIRED non-interactively; --budget caps spend (default $2). This is not in the `pipeline` stage list — it is under `branches`.',
|
|
77
|
+
'Loop mode plays AND renders at the same time — it does NOT pre-generate everything. The browser loops the takes that already exist while the worker keeps generating new ones, swapping each shot\'s newer take in on the loop\'s NEXT pass (never mid-clip). Two things make a running loop LOOK pre-generated when it is not: (a) it PAUSES when it hits --budget or you click Pause in the UI, and then just replays what is on disk — raise --budget or pass --unbounded to keep it generating; (b) --max-takes is a per-shot ring buffer (default 3, older takes pruned), not a total, so once every shot has its cap the change per cycle is subtle.',
|
|
78
|
+
'Which mode evolves while you watch: LOOPING (Turbo, 480P) renders faster than it plays, so the video visibly changes as you watch. PRODUCTION/create renders each shot slowly on Max R2V — it is for GATHERING keeper takes, not a continuously-evolving watch, and on a short or few-shot plan it can look static even while running because one take takes longer to render than a full loop cycle takes to play. If the user wants to "watch it keep changing", pick LOOPING and a higher/unbounded budget.',
|
|
79
|
+
'Three video lanes, chosen per shot by the router (see the venice-video-model-routing skill): t2v (prompt only), i2v (animate a supplied START image via image_url — establishing/atmosphere shots, or chaining off a previous last frame), R2V (identity anchored to a reference stack — the default for character shots). "i2v" means a supplied first frame; "R2V" means reference_image_urls, not a start frame — do not conflate them.',
|
|
80
|
+
'To animate a single image you already have (plain i2v, no project), the routing skill\'s bundled `scripts/venice-video.py --image <file> --model <...-image-to-video>` is the standalone path; the project pipeline is for multi-shot, consistency-first work.',
|
|
81
|
+
],
|
|
82
|
+
},
|
|
72
83
|
{
|
|
73
84
|
title: 'Where the full knowledge lives',
|
|
74
85
|
points: [
|
package/dist/agent/guide.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guide.js","sourceRoot":"","sources":["../../src/agent/guide.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,uDAAuD;AACvD,EAAE;AACF,2EAA2E;AAC3E,8EAA8E;AAC9E,sEAAsE;AACtE,8EAA8E;AAC9E,sDAAsD;AACtD,EAAE;AACF,6EAA6E;AAC7E,8EAA8E;AAC9E,8EAA8E;AAC9E,4EAA4E;AAC5E,EAAE;AACF,gFAAgF;AAChF,8DAA8D;AAC9D,8EAA8E;AAO9E,MAAM,CAAC,MAAM,WAAW,GAA4B;IAClD;QACE,KAAK,EAAE,kCAAkC;QACzC,MAAM,EAAE;YACN,2GAA2G;YAC3G,sGAAsG;YACtG,0GAA0G;SAC3G;KACF;IACD;QACE,KAAK,EAAE,8BAA8B;QACrC,MAAM,EAAE;YACN,sGAAsG;YACtG,wNAAwN;YACxN,kJAAkJ;YAClJ,wGAAwG;SACzG;KACF;IACD;QACE,KAAK,EAAE,yCAAyC;QAChD,MAAM,EAAE;YACN,2FAA2F;YAC3F,4JAA4J;YAC5J,6FAA6F;SAC9F;KACF;IACD;QACE,KAAK,EAAE,2BAA2B;QAClC,MAAM,EAAE;YACN,mGAAmG;YACnG,8JAA8J;YAC9J,kJAAkJ;SACnJ;KACF;IACD;QACE,KAAK,EAAE,4CAA4C;QACnD,MAAM,EAAE;YACN,4PAA4P;YAC5P,kNAAkN;YAClN,kKAAkK;YAClK,6MAA6M;SAC9M;KACF;IACD;QACE,KAAK,EAAE,8BAA8B;QACrC,MAAM,EAAE;YACN,oHAAoH;YACpH,+JAA+J;YAC/J,gKAAgK;YAChK,8JAA8J;YAC9J,6SAA6S;YAC7S,kHAAkH;SACnH;KACF;IACD;QACE,KAAK,EAAE,gCAAgC;QACvC,MAAM,EAAE;YACN,+EAA+E;YAC/E,gJAAgJ;YAChJ,sFAAsF;YACtF,oIAAoI;SACrI;KACF;CACF,CAAC;AAEF,MAAM,UAAU,WAAW;IACzB,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CAAC,sEAAsE,CAAC,CAAC;IACnF,KAAK,CAAC,IAAI,CAAC,mFAAmF,CAAC,CAAC;IAChG,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,MAAM,OAAO,IAAI,WAAW,EAAE,CAAC;QAClC,KAAK,CAAC,IAAI,CAAC,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;QAClC,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,MAAM;YAAE,KAAK,CAAC,IAAI,CAAC,OAAO,KAAK,EAAE,CAAC,CAAC;QAC/D,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;AACpC,CAAC"}
|
|
1
|
+
{"version":3,"file":"guide.js","sourceRoot":"","sources":["../../src/agent/guide.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,uDAAuD;AACvD,EAAE;AACF,2EAA2E;AAC3E,8EAA8E;AAC9E,sEAAsE;AACtE,8EAA8E;AAC9E,sDAAsD;AACtD,EAAE;AACF,6EAA6E;AAC7E,8EAA8E;AAC9E,8EAA8E;AAC9E,4EAA4E;AAC5E,EAAE;AACF,gFAAgF;AAChF,8DAA8D;AAC9D,8EAA8E;AAO9E,MAAM,CAAC,MAAM,WAAW,GAA4B;IAClD;QACE,KAAK,EAAE,kCAAkC;QACzC,MAAM,EAAE;YACN,2GAA2G;YAC3G,sGAAsG;YACtG,0GAA0G;SAC3G;KACF;IACD;QACE,KAAK,EAAE,8BAA8B;QACrC,MAAM,EAAE;YACN,sGAAsG;YACtG,wNAAwN;YACxN,kJAAkJ;YAClJ,wGAAwG;SACzG;KACF;IACD;QACE,KAAK,EAAE,yCAAyC;QAChD,MAAM,EAAE;YACN,2FAA2F;YAC3F,4JAA4J;YAC5J,6FAA6F;SAC9F;KACF;IACD;QACE,KAAK,EAAE,2BAA2B;QAClC,MAAM,EAAE;YACN,mGAAmG;YACnG,8JAA8J;YAC9J,kJAAkJ;SACnJ;KACF;IACD;QACE,KAAK,EAAE,4CAA4C;QACnD,MAAM,EAAE;YACN,4PAA4P;YAC5P,kNAAkN;YAClN,kKAAkK;YAClK,6MAA6M;SAC9M;KACF;IACD;QACE,KAAK,EAAE,8BAA8B;QACrC,MAAM,EAAE;YACN,oHAAoH;YACpH,+JAA+J;YAC/J,gKAAgK;YAChK,8JAA8J;YAC9J,6SAA6S;YAC7S,kHAAkH;SACnH;KACF;IACD;QACE,KAAK,EAAE,+DAA+D;QACtE,MAAM,EAAE;YACN,+LAA+L;YAC/L,ylBAAylB;YACzlB,4nBAA4nB;YAC5nB,gfAAgf;YAChf,4aAA4a;YAC5a,gQAAgQ;SACjQ;KACF;IACD;QACE,KAAK,EAAE,gCAAgC;QACvC,MAAM,EAAE;YACN,+EAA+E;YAC/E,gJAAgJ;YAChJ,sFAAsF;YACtF,oIAAoI;SACrI;KACF;CACF,CAAC;AAEF,MAAM,UAAU,WAAW;IACzB,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CAAC,sEAAsE,CAAC,CAAC;IACnF,KAAK,CAAC,IAAI,CAAC,mFAAmF,CAAC,CAAC;IAChG,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,MAAM,OAAO,IAAI,WAAW,EAAE,CAAC;QAClC,KAAK,CAAC,IAAI,CAAC,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;QAClC,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,MAAM;YAAE,KAAK,CAAC,IAAI,CAAC,OAAO,KAAK,EAAE,CAAC,CAAC;QAC/D,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;AACpC,CAAC"}
|
package/dist/agent/pipeline.d.ts
CHANGED
|
@@ -23,9 +23,32 @@ export interface PipelineStage {
|
|
|
23
23
|
* `qa-approve` — are explicit human sign-offs.
|
|
24
24
|
*/
|
|
25
25
|
export declare const PIPELINE_STAGES: readonly PipelineStage[];
|
|
26
|
+
/**
|
|
27
|
+
* An alternate entry point that is NOT part of the linear order above. Branches
|
|
28
|
+
* are reachable once their `availableAfter` stage is done, run OUTSIDE the gate
|
|
29
|
+
* sequence, and an agent walking `PIPELINE_STAGES` will never be told they
|
|
30
|
+
* exist — which is exactly why they are stated here as data too. `pipeline`
|
|
31
|
+
* prints them and `pipeline --json` emits them under `branches`.
|
|
32
|
+
*/
|
|
33
|
+
export interface PipelineBranch {
|
|
34
|
+
/** Stable id an agent can branch on. */
|
|
35
|
+
id: string;
|
|
36
|
+
/** One-line human name. */
|
|
37
|
+
name: string;
|
|
38
|
+
/** The stage id after which this branch becomes available. */
|
|
39
|
+
availableAfter: string;
|
|
40
|
+
/** What it does and how it differs from the linear path. */
|
|
41
|
+
summary: string;
|
|
42
|
+
/** Any gate it skips or precondition it needs. */
|
|
43
|
+
note?: string;
|
|
44
|
+
/** Literal command that runs it. `<...>` marks a value to fill. */
|
|
45
|
+
command: string;
|
|
46
|
+
}
|
|
47
|
+
export declare const PIPELINE_BRANCHES: readonly PipelineBranch[];
|
|
26
48
|
export declare function pipelineAsJson(): {
|
|
27
49
|
version: 1;
|
|
28
50
|
stages: readonly PipelineStage[];
|
|
51
|
+
branches: readonly PipelineBranch[];
|
|
29
52
|
};
|
|
30
53
|
export declare function formatPipeline(): string;
|
|
31
54
|
//# sourceMappingURL=pipeline.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/agent/pipeline.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,aAAa;IAC5B,wCAAwC;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,kEAAkE;IAClE,KAAK,EAAE,SAAS,GAAG,SAAS,CAAC;IAC7B,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,eAAO,MAAM,eAAe,EAAE,SAAS,aAAa,EAiFnD,CAAC;AAEF,wBAAgB,cAAc,IAAI;
|
|
1
|
+
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/agent/pipeline.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,aAAa;IAC5B,wCAAwC;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,kEAAkE;IAClE,KAAK,EAAE,SAAS,GAAG,SAAS,CAAC;IAC7B,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,eAAO,MAAM,eAAe,EAAE,SAAS,aAAa,EAiFnD,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC7B,wCAAwC;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,8DAA8D;IAC9D,cAAc,EAAE,MAAM,CAAC;IACvB,4DAA4D;IAC5D,OAAO,EAAE,MAAM,CAAC;IAChB,kDAAkD;IAClD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,mEAAmE;IACnE,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,eAAO,MAAM,iBAAiB,EAAE,SAAS,cAAc,EAWtD,CAAC;AAEF,wBAAgB,cAAc,IAAI;IAChC,OAAO,EAAE,CAAC,CAAC;IACX,MAAM,EAAE,SAAS,aAAa,EAAE,CAAC;IACjC,QAAQ,EAAE,SAAS,cAAc,EAAE,CAAC;CACrC,CAEA;AAED,wBAAgB,cAAc,IAAI,MAAM,CA+BvC"}
|
package/dist/agent/pipeline.js
CHANGED
|
@@ -102,8 +102,18 @@ export const PIPELINE_STAGES = [
|
|
|
102
102
|
command: 'assemble-episode -p <project> -e <n>',
|
|
103
103
|
},
|
|
104
104
|
];
|
|
105
|
+
export const PIPELINE_BRANCHES = [
|
|
106
|
+
{
|
|
107
|
+
id: 'loop',
|
|
108
|
+
name: 'Loop mode — watch the plan render, or gather usable takes',
|
|
109
|
+
availableAfter: 'script',
|
|
110
|
+
summary: 'Continuously renders the whole shot script and plays it as a live browser loop, hot-swapping each shot in as its take finishes and regenerating fresh takes while it plays. Requires ONE decision up front: LOOPING (creative flow, lower quality — MiniMax H3 Max Turbo 480P, t2v then i2v last-frame chaining, identity not locked) or PRODUCTION (gather usable shots, higher quality — Max R2V + the full reference stack @768P, identity locked).',
|
|
111
|
+
note: 'Skips the storyboard/QA gates and writes ONLY under episodes/episode-NNN/loop/ — canonical scene-001 renders and series.json are never touched, so it can run alongside production. Only precondition: a shot script with >=1 shot. Money-capped by --budget (default $2); --mode is REQUIRED in a non-interactive run.',
|
|
112
|
+
command: 'loop -p <project> -e <n> --mode <looping|production>',
|
|
113
|
+
},
|
|
114
|
+
];
|
|
105
115
|
export function pipelineAsJson() {
|
|
106
|
-
return { version: 1, stages: PIPELINE_STAGES };
|
|
116
|
+
return { version: 1, stages: PIPELINE_STAGES, branches: PIPELINE_BRANCHES };
|
|
107
117
|
}
|
|
108
118
|
export function formatPipeline() {
|
|
109
119
|
const lines = [];
|
|
@@ -121,6 +131,20 @@ export function formatPipeline() {
|
|
|
121
131
|
});
|
|
122
132
|
lines.push('`venice-video status -p <project>` reports where a project stands and the next command.');
|
|
123
133
|
lines.push('Gates are human decisions. Never use --skip-approval / --skip-qa to get past them.');
|
|
124
|
-
|
|
134
|
+
if (PIPELINE_BRANCHES.length > 0) {
|
|
135
|
+
lines.push('');
|
|
136
|
+
lines.push('Alternate paths (not steps in the order above — a shot script is the only prerequisite):');
|
|
137
|
+
lines.push('');
|
|
138
|
+
for (const branch of PIPELINE_BRANCHES) {
|
|
139
|
+
lines.push(`• ${branch.name}`);
|
|
140
|
+
lines.push(` available once the "${branch.availableAfter}" stage is done`);
|
|
141
|
+
lines.push(` does ${branch.summary}`);
|
|
142
|
+
if (branch.note)
|
|
143
|
+
lines.push(` note ${branch.note}`);
|
|
144
|
+
lines.push(` run ${branch.command}`);
|
|
145
|
+
lines.push('');
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return lines.join('\n').trimEnd();
|
|
125
149
|
}
|
|
126
150
|
//# sourceMappingURL=pipeline.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../../src/agent/pipeline.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,4BAA4B;AAC5B,EAAE;AACF,4EAA4E;AAC5E,6EAA6E;AAC7E,6EAA6E;AAC7E,4DAA4D;AAC5D,EAAE;AACF,6EAA6E;AAC7E,6EAA6E;AAC7E,6EAA6E;AAC7E,2EAA2E;AAC3E,EAAE;AACF,kEAAkE;AAClE,2EAA2E;AAC3E,+EAA+E;AAC/E,8EAA8E;AAsB9E;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAA6B;IACvD;QACE,EAAE,EAAE,WAAW;QACf,IAAI,EAAE,wBAAwB;QAC9B,KAAK,EAAE,SAAS;QAChB,QAAQ,EAAE,2CAA2C;QACrD,OAAO,EAAE,iFAAiF;KAC3F;IACD;QACE,EAAE,EAAE,MAAM;QACV,IAAI,EAAE,yBAAyB;QAC/B,KAAK,EAAE,SAAS;QAChB,QAAQ,EAAE,qCAAqC;QAC/C,OAAO,EAAE,2DAA2D;KACrE;IACD;QACE,EAAE,EAAE,SAAS;QACb,IAAI,EAAE,mBAAmB;QACzB,KAAK,EAAE,SAAS;QAChB,QAAQ,EAAE,iCAAiC;QAC3C,OAAO,EAAE,uCAAuC;KACjD;IACD;QACE,EAAE,EAAE,QAAQ;QACZ,IAAI,EAAE,kBAAkB;QACxB,KAAK,EAAE,SAAS;QAChB,QAAQ,EAAE,0CAA0C;QACpD,OAAO,EAAE,iEAAiE;KAC3E;IACD;QACE,EAAE,EAAE,gBAAgB;QACpB,IAAI,EAAE,oBAAoB;QAC1B,KAAK,EAAE,SAAS;QAChB,QAAQ,EAAE,sBAAsB;QAChC,IAAI,EAAE,uEAAuE;QAC7E,OAAO,EAAE,oCAAoC;KAC9C;IACD;QACE,EAAE,EAAE,YAAY;QAChB,IAAI,EAAE,4BAA4B;QAClC,KAAK,EAAE,SAAS;QAChB,QAAQ,EAAE,wBAAwB;QAClC,OAAO,EAAE,wCAAwC;KAClD;IACD;QACE,EAAE,EAAE,eAAe;QACnB,IAAI,EAAE,eAAe;QACrB,KAAK,EAAE,SAAS;QAChB,QAAQ,EAAE,gBAAgB;QAC1B,OAAO,EAAE,mCAAmC;KAC7C;IACD;QACE,EAAE,EAAE,YAAY;QAChB,IAAI,EAAE,YAAY;QAClB,KAAK,EAAE,SAAS;QAChB,QAAQ,EAAE,kBAAkB;QAC5B,IAAI,EAAE,8DAA8D;QACpE,OAAO,EAAE,gCAAgC;KAC1C;IACD;QACE,EAAE,EAAE,QAAQ;QACZ,IAAI,EAAE,yCAAyC;QAC/C,KAAK,EAAE,SAAS;QAChB,QAAQ,EAAE,wBAAwB;QAClC,OAAO,EAAE,qCAAqC;KAC/C;IACD;QACE,EAAE,EAAE,WAAW;QACf,IAAI,EAAE,4DAA4D;QAClE,KAAK,EAAE,SAAS;QAChB,QAAQ,EAAE,sBAAsB;QAChC,OAAO,EAAE,+BAA+B;KACzC;IACD;QACE,EAAE,EAAE,UAAU;QACd,IAAI,EAAE,wBAAwB;QAC9B,KAAK,EAAE,SAAS;QAChB,QAAQ,EAAE,uBAAuB;QACjC,IAAI,EAAE,yFAAyF;QAC/F,OAAO,EAAE,sCAAsC;KAChD;CACF,CAAC;AAEF,MAAM,UAAU,cAAc;
|
|
1
|
+
{"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../../src/agent/pipeline.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/mini-drama/cli.ts"],"names":[],"mappings":";AAEA,OAAO,eAAe,CAAC;AACvB,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA0JpC,QAAA,MAAM,OAAO,SAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/mini-drama/cli.ts"],"names":[],"mappings":";AAEA,OAAO,eAAe,CAAC;AACvB,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA0JpC,QAAA,MAAM,OAAO,SAAgB,CAAC;AAmwJ9B,OAAO,EAAE,OAAO,EAAE,CAAC"}
|
package/dist/mini-drama/cli.js
CHANGED
|
@@ -4414,6 +4414,7 @@ program
|
|
|
4414
4414
|
.option('--budget <usd>', 'Pause rendering after this much estimated spend (each Start / regenerate authorizes another budget)', '2')
|
|
4415
4415
|
.option('--max-takes <n>', 'Candidate takes kept per shot (ring buffer; the loop regenerates forever until stopped/budget)', '3')
|
|
4416
4416
|
.option('--no-chain', 'Render each shot independently instead of chaining i2v off the previous shot\'s last frame')
|
|
4417
|
+
.option('--no-face-continuity', 'Do not prompt chained shots to end on the character\'s face (on by default for smoother i2v transitions; auto-suppressed on MiniMax i2v, which rejects face start frames)')
|
|
4417
4418
|
.option('--once', 'Render one take per shot, then stop (no regeneration)', false)
|
|
4418
4419
|
.option('--unbounded', 'Regenerate forever with NO budget cap (spends until stopped)', false)
|
|
4419
4420
|
.option('--no-open', 'Do not open the browser automatically')
|
|
@@ -4491,6 +4492,7 @@ program
|
|
|
4491
4492
|
slug,
|
|
4492
4493
|
mode,
|
|
4493
4494
|
chain,
|
|
4495
|
+
faceContinuity: opts.faceContinuity,
|
|
4494
4496
|
resolution: opts.resolution,
|
|
4495
4497
|
duration: opts.duration,
|
|
4496
4498
|
budgetUsd: Number.isFinite(budgetUsd) ? budgetUsd : undefined,
|
|
@@ -4517,6 +4519,7 @@ program
|
|
|
4517
4519
|
episode: opts.episode,
|
|
4518
4520
|
mode: status.mode,
|
|
4519
4521
|
chain: status.chain,
|
|
4522
|
+
faceContinuity: status.faceContinuity,
|
|
4520
4523
|
model: status.model,
|
|
4521
4524
|
resolution: status.resolution,
|
|
4522
4525
|
duration: status.duration,
|