import type { VideoExecutionCancelResult, VideoExecutionPayload, VideoExecutionPollResult } from './types.js'; import { type ModelArkClientContext, type ModelArkFetchLike, type ModelArkModelId } from './providers/modelark.js'; import { type ModelArkReferenceDeps } from './providers/modelark-references.js'; export declare const SEEDANCE_MODELARK_ROUTE_ID: "seedance-modelark"; export interface ModelArkJobSceneState { sceneIndex: number; prompt: string; /** The vendor's task id. Absent while a create is in flight or its answer was lost. */ taskId?: string; outputPath: string; /** * `submitting`: the intent is on file and the POST is in flight (a file * still saying so after the process died means the answer was lost). * `submit-unknown`: the create's answer was lost; the task may exist. */ status: 'submitting' | 'submit-unknown' | 'submitted' | 'completed' | 'failed'; error?: string; /** * When THIS scene's poll wrote `outputPath` (ISO). A file at that path this * job did not download belongs to something else — another job in the same * output dir renders to the same `scene-N.mp4` — so the poll may only skip * the download when it knows it made that file. */ downloadedAt?: string; /** When the create was attempted (ISO); the anchor for finding a lost task. */ intentAt?: string; /** What went wrong with the create whose answer was lost. */ submitError?: string; lastFrameUrl?: string; /** * What was asked for, kept so the cost can be read off the vendor's usage * later. Optional only because a file written before cost accounting has * neither; every submit since writes both. */ resolution?: '480p' | '720p' | '1080p'; /** Whether the request carried a reference video (the vendor prices that differently). */ videoInput?: boolean; /** The vendor's output token count on the succeeded task, when it sent one. */ usageTokens?: number; /** `usageTokens` × the list rate, USD, unrounded. Absent when the cost is unknown. */ costUsd?: number; /** Why `costUsd` is absent on a completed scene; repeated as an issue on every poll. */ costUnknownReason?: string; } export interface ModelArkNativeJobState { externalJobId: string; routeId: typeof SEEDANCE_MODELARK_ROUTE_ID; model: ModelArkModelId; outputDir: string; createdAt: string; scenes: ModelArkJobSceneState[]; /** How `costUsd` is derived; the acceptance audit prints it. Absent on a file written before cost accounting. */ costSource?: typeof MODELARK_COST_SOURCE; /** * The job's list-price total, USD, once every completed scene has a cost — * on the file's top level because the acceptance audit reads it there * (as native-veo writes its own). */ actualCost?: { currency: 'USD'; amount: number; }; } export declare const MODELARK_COST_SOURCE: "vendor-usage-tokens-at-list-price"; /** `.env.local` sits UNDER the process environment, as on every other native route. */ export declare function loadModelArkWorkspaceEnv(workspaceRoot: string, env: NodeJS.ProcessEnv): Promise; /** * True when a chained seedance-modelark scene should keep the previous clip as * a VIDEO (extend mode) instead of reducing it to its last frame. Read from the * same merged env as the transport (.env.local under the process env), so the * payload build and the submit agree; an invalid value keeps the default here * and is refused, loudly, by the planner. */ export declare function modelArkChainKeepsVideo(workspaceRoot: string, env: NodeJS.ProcessEnv): Promise; export declare function modelArkJobStatePath(outputDir: string, externalJobId: string): string; /** * Every way `value` is not a job-state file this transport can act on, as * sentences (empty when it is one). Only this module writes the file, so a * problem means a bug or a hand edit, and acting on it anyway would poll a * task id that is not a string, download to a path that is not one, sum a * bill that is not a number, or write the job back under another id. * * It checks each field's type, and beyond that only what the poll relies on: * the file names its own job, the route and scene statuses are known values, * and each scene index is used once. A refusal strands whatever task the file * holds, so the states the poll handles on purpose stay valid (a lost create * with no task id, an intent time that does not parse), every field later * versions added is optional, because older files lack them (#610 cost, #611 * intent), and values a later table edit could retire (the model, the * resolution) are only required to be text: the poll prices an unknown one as * "cost unknown". Fields this version does not know are ignored. Submit runs * the same check on the file it is about to write, before any upload or create. */ export declare function modelArkJobStateProblems(value: unknown, externalJobId: string): string[]; export declare function readModelArkJobState(outputDir: string, externalJobId: string): Promise; export interface ModelArkTransportOptions { env?: NodeJS.ProcessEnv; fetchImpl?: ModelArkFetchLike; referenceDeps?: ModelArkReferenceDeps; /** Retry policy for GET / DELETE; tests inject `{ retries: 0 }` so a 5xx does not sleep. */ retry?: ModelArkClientContext['retry']; /** The clock; tests inject one so a lost-create window can be walked. */ now?: () => Date; } /** * How long after the intent a task created by a lost create can appear in the * vendor's list. The create is one POST with the vendor's own timeout in front * of it; two minutes covers a slow accept, and a window this narrow is what * keeps a bind by creation time honest. */ export declare const MODELARK_LOST_CREATE_WINDOW_SECONDS = 120; /** * Clock skew allowed between this machine and the vendor's `created_at`, * applied BEFORE the intent. Generous on purpose: a task the vendor stamped * earlier than our intent (their clock behind ours) missed by a tight bound * would be declared "never created", the one wrong answer that costs money. */ export declare const MODELARK_LOST_CREATE_SKEW_SECONDS = 60; /** The vendor's maximum list page; a full page is the signal the window may lie beyond it. */ export declare const MODELARK_LIST_PAGE_SIZE = 500; export declare function submitSeedanceModelArkNative(payload: VideoExecutionPayload, options?: ModelArkTransportOptions): Promise<{ externalJobId: string; rawResult: unknown; }>; export declare function pollSeedanceModelArkNative(input: { outputDir: string; externalJobId: string; workspaceRoot: string; }, options?: ModelArkTransportOptions): Promise; /** * Cancel what CAN be cancelled: a queued task. ModelArk cannot stop a running * task, so a scene the vendor refuses to cancel keeps its `submitted` status * (it is still billing and its clip will still arrive), and the answer says so * rather than reporting it stopped. Finished scenes are never touched. */ export declare function cancelSeedanceModelArkNative(input: { outputDir: string; externalJobId: string; workspaceRoot: string; }, options?: ModelArkTransportOptions): Promise; /** * Stop WAITING for scenes still in flight without touching the provider: the * remote task keeps running and keeps billing, and the recorded reason says so. * Mirrors `abandonDreaminaUseApiNativeJob` for `execute-abandon`. */ export declare function abandonSeedanceModelArkNativeJob(input: { outputDir: string; externalJobId: string; dryRun?: boolean; }): Promise<{ abandonedScenes: number[]; untouchedScenes: Array<{ sceneIndex: number; status: string; }>; }>; export interface ModelArkBindResult { externalJobId: string; sceneIndex: number; taskId: string; /** false = the plan only; nothing was written. */ applied: boolean; /** What ModelArk says about the task, read before anything is written. */ task: { status: string; model: string; createdAt: string | null; resolution: string | null; }; /** Whether the task was created in the lost create's window; null when either time is unknown. Reported, not enforced: the operator is overriding the window on purpose. */ createdInsideWindow: boolean | null; issues: string[]; } /** * Bind a lost create to the task the operator names — the exit for the cases * the poll will not decide: several unbound tasks in the window, a window it * could not search, or no intent time to search by. Nothing is submitted: the * task is read with one GET, and only a task that exists, is on this job's * model and is not already some job's is bound. The scene then polls as an * ordinary submitted one. `dryRun` reports the plan and writes nothing. */ export declare function bindSeedanceModelArkLostCreate(input: { outputDir: string; externalJobId: string; workspaceRoot: string; taskId: string; sceneIndex?: number; dryRun?: boolean; }, options?: ModelArkTransportOptions): Promise; //# sourceMappingURL=native-modelark.d.ts.map