/** * Fallback-ladder scene renderer — the third resumable scene driver, alongside * `runAutoChain` (`execute-autochain.ts`, SEQUENTIAL + chained) and * `runScenePool` (`execute-pool.ts`, PARALLEL + independent). Where those two * each render a scene on the project's single resolved route, this driver * renders scenes SEQUENTIALLY and — per scene — walks a FALLBACK ROUTE LADDER: * try route A; if the provider rejects it (the runner returns status:'failed' or * throws), escalate to route B, then C, and so on. The first route that * succeeds wins and the ladder stops for that scene. * * This productizes the hand-written `voice-render.mjs` / `chain.mjs` loops * operators write to render scenes one at a time and, on a provider rejection, * escalate to a fallback method — resumable across crashes. Mirrors the * auto-chain / pool shape: a PURE scheduler (`runRenderScenes`) plus an * injectable per-scene runner (`RenderSceneRunner`), so the scheduler is fully * offline-testable with a simulated runner. The real runner + the CLI handler * live in `src/cli/handlers/execution.ts`. */ export interface RenderSceneRunner { /** * Render one scene on ONE specific route. Resolves with status:'done' (or * simply resolves without throwing) when that route produced a usable * candidate; status:'failed' (or a throw) when the route rejected it (e.g. a * Seedance RejectFace / moderation rejection) so the ladder should escalate. */ (sceneIndex: number, route: string): Promise<{ status: 'done' | 'failed'; error?: string; }>; } export interface RenderSceneResult { sceneIndex: number; status: 'done' | 'failed' | 'skipped'; /** The route that produced the scene (set on 'done'). */ routeUsed?: string; /** How many ladder rungs were tried (skips report 0). */ attempts: number; /** The last error when every rung failed. */ error?: string; } export interface RenderScenesResult { results: RenderSceneResult[]; } export interface RunRenderScenesOptions { /** Scene indices to consider, in any order (processed ascending). */ scenes: number[]; /** * The fallback route ladder, in escalation order. A single-entry ladder = no * fallback (plain sequential render on that one route). An empty ladder throws * — there would be nothing to try. */ routeLadder: string[]; /** Injectable per-scene-per-route runner — submit + poll + select for one (scene, route). */ runner: RenderSceneRunner; /** * Resume hook: when it returns true for a scene, that scene is recorded * 'skipped' and never handed to the runner (it is already done/selected). */ isAlreadyDone?: (sceneIndex: number) => boolean; /** * Resume cursor: scenes with index < continueFrom are recorded 'skipped' and * never run, so an interrupted run can pick up where it stopped. */ continueFrom?: number; /** Optional progress sink (a started/escalated/settled message per scene). */ onProgress?: (msg: string) => void; } /** * Render `scenes` SEQUENTIALLY in ascending order, walking the `routeLadder` * per scene until one route succeeds. * * THE LADDER-ESCALATION MECHANISM (the inner loop): for each scene that must * run, iterate the routes of `routeLadder` IN ORDER. Call `runner(i, route)`. * - If it resolves with status:'done' (success), record * `status:'done', routeUsed:route, attempts:` and BREAK * the ladder — later rungs are never tried. * - If it resolves with status:'failed' OR THROWS, record the error and * continue to the NEXT rung (escalate). * If every rung is exhausted without a success, record * `status:'failed', attempts:routeLadder.length, error:` and CONTINUE * to the next scene — one bad scene never aborts the whole run (but it IS * recorded so the operator sees it). * * Resumable: a scene with `i < continueFrom` OR `isAlreadyDone(i) === true` is * recorded 'skipped' (attempts:0) and never handed to the runner. Results are * returned deterministically ordered by sceneIndex. * * PURE: no fs / provider / timer access beyond awaiting the injected runner. */ export declare function runRenderScenes(opts: RunRenderScenesOptions): Promise; //# sourceMappingURL=execute-render-scenes.d.ts.map