@starreel/mcp 0.1.224 → 0.1.230

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/SKILL.md CHANGED
@@ -95,7 +95,8 @@ announces a condensed version as MCP `instructions` at connect time.
95
95
  | Their own **footage** for a shot (screen recording, product b-roll, an existing clip) | `upload_shot_footage` → that shot is no longer AI-generated (frames/video skipped, final cut uses the clip as-is, duration written back from the clip); **it overwrites whatever AI video that shot already had**, and afterwards every AI video call on it (including `edit_video_shot`) is refused with **409** until you `clear_shot_footage` or pass `replace_user_footage: true` | pasting an externally AI-generated clip to "fix" a shot — it carries none of this film's identity / style anchors; use `regenerate_shot_video` instead |
96
96
  | A clip that should **drive the motion** of an AI shot (a blocking/previz pass, a dance or action reference) | `edit_video_shot` with `reference_video_urls` — the shot keeps its AI video and borrows the clip's movement. To make the clip itself the source and restyle it in place, `upload_shot_footage` it first, then `edit_video_shot` with `replace_user_footage: true` | `upload_shot_footage` alone — that registers the clip as the finished shot, so nothing gets restyled and every later AI call on it returns 409 |
97
97
  | A clip whose **motion should be kept while the people / outfits are redrawn** (video repaint) — their own footage or a shot already generated here | `get_repaint_capabilities` (is it enabled for this drama; `relayMaxSegments`) → for their own clip, `upload_shot_footage` it onto a shot first → `quote_repaint_shot_video` → `repaint_shot_video` (prompt + reference image; with no `reference_image_url` the shot's character portrait is used — without any reference the person is redrawn too) **or** `quote_reskin_shot_video` → `reskin_shot_video` (`first_frame_url` = an already-reskinned first frame that matches the original first frame's composition, pose and props exactly) → `get_repaint_status` with the returned id until `completed` → `restore_repaint_original` to switch back (free). Motion, lip timing and camera move follow the source and its audio is carried over. ≤5 s is one charge (billed as 5 s); with long-shot relay enabled, 5–~14 s is split into ≤3 relayed segments, one charge each, and the quote is the total and the charge cap. A quote is tied to the shot's current video — if that video changes, generating returns 409; re-quote (free) | `edit_video_shot` to swap the whole cast or wardrobe (it edits by instruction); clips longer than ~14 s (`split_shot` first) |
98
- | `review_storyboards` reports `forbidden_term` (light / color-temperature / BGM wording in the shot text) | every hit is listed at once in the finding's `hits` (`shot`, `field`, `term`) → `get_shot_prompts` to read that field (`description` is returned there too) → `update_shot` to remove the term from that field; if the intent is lighting, move it to `update_shot`'s `lighting` field (not scanned, and video / image generation read it) → `review_storyboards` again | rewriting the whole shot blind, or putting the lighting back into `description` / prompts in other words |
98
+ | `review_storyboards` reports `forbidden_term` (light / color-temperature / BGM wording in the shot text) | every hit is listed at once in the finding's `hits` (`shot`, `field`, `term`) → `get_shot_prompts` to read that field (`description` is returned there too) → `update_shot` to remove the term from that field; if the intent is lighting, move it to `update_shot`'s `lighting` field (not scanned, and video / image generation read it); a hit with `field=sound_effect` is fixed with `update_shot`'s `sound_effect` field (its current value is in `get_shot_prompts` too) → `review_storyboards` again | rewriting the whole shot blind, or putting the lighting back into `description` / prompts in other words |
99
+ | A shot/reverse-shot or over-the-shoulder pair (camera over A's shoulder onto B, then over B's shoulder onto A) | `update_shot` the second shot with `continuity_intent: "shot_change"` — it keeps the frame chain (re-framed first frame) but never takes the video-extension path, so the shot is rendered from its own first/last frames | `continuous_action` on a reverse shot: extension continues the previous clip's camera and the model invents the turned-around view |
99
100
  | A scene plate that came out wrong (backdrop, era, light, layout) | `get_scene_prompt` → `update_scene` (`image_prompt`) → `quote_regenerate_scene_image` (tell the customer the points — it includes the lighting reference the platform auto-derives after a plate change when no wide-shot frame exists) → `regenerate_scene_image` with that `quote_id` (after `upload_scene_image` the platform does **not** auto-create the lighting reference — if the reply says `lighting_ref.needed`, quote it with `quote_scene_lighting_ref` and, once the customer agrees, `generate_scene_lighting_ref`); already-rendered shot frames still anchor on the old plate, so regenerate those shots too | re-running `generate_scene_images` (it only fills scenes that have **no** plate — it will not touch this one) |
100
101
  | A voice sample / a required voice | `clone_voice` → `speak_with_voice` → `set_character_voice` / `assign_voices` | cloning without the rights-holder's consent |
101
102
  | No sample, but a character already speaks in a rendered shot | `set_voice_anchor_from_shot` (free; native-audio dramas: locks the voice for later videos) → regenerate `stale_shots` | picking the voice after the whole episode is rendered |
@@ -523,7 +524,12 @@ content that will be rejected.
523
524
  shot's first frame the previous shot's last frame (free, but the shot inherits the
524
525
  previous shot's framing); *reframe* regenerates the first frame anchored on that last
525
526
  frame (one image per seam, keeps the shot's own framing). Tell the customer, then run
526
- it without `dry_run`. **Reframes render asynchronously** — the call returns as soon as
527
+ it without `dry_run`. Drama-wide switch: `update_project_settings` `frame_chain_mode`
528
+ — `off` turns all cross-shot chaining off (the automatic join after frames settle,
529
+ `chain_frames` and bookends; quotes stop counting them), `reframe` is the default,
530
+ `strict` only copies across adjacent seams (bookends still regenerate and are
531
+ still quoted — use `off` for no images at all). Switch back to `reframe`/`strict` before using `chain_frames`;
532
+ changing the mode never regenerates existing frames. **Reframes render asynchronously** — the call returns as soon as
527
533
  they are dispatched. Before `review_frames`, watch `get_jobs` until those shots'
528
534
  `first_frame` jobs are no longer pending/processing (a failed one carries `error_msg`;
529
535
  re-join that seam with `chain_shot_from`), then re-check `seam_state` in
@@ -753,6 +759,22 @@ content that will be rejected.
753
759
  lets it through). Relay your QC findings to the user verbatim. Listing a
754
760
  `ref` you never opened is signing off on the user's money.
755
761
 
762
+ **Check action and camera movement against the user's own script, not
763
+ against the platform's description.** Shot materials carry `shot_spec`
764
+ (shot type, `movement`, `action` with `action_in` / `action_out`, first and
765
+ last frame prompts). At the storyboard layer compare every shot with the
766
+ "picture" and "camera / movement" columns of the user's original
767
+ (`get_script` → `original_content`, or the storyboard table they gave you)
768
+ — `shot_action`, `camera_movement`. At the frame layer check that each first
769
+ frame is the *start* of the action and camera move and each last frame its
770
+ end (`frame_is_start_state`: a first frame that already shows the end state
771
+ leaves the video with no action), and compare left/right position, facing
772
+ and eyeline with the neighbouring shots (`screen_direction`). At the video
773
+ layer sample the start, middle and end of every clip: the action is played
774
+ out to the end, no extra limbs or objects appear, and the sound matches the
775
+ script (`action_complete`). Say in each note what you compared against — a
776
+ one-line summary is not a check.
777
+
756
778
  **The user's specific requirements are not covered by "the review passed".**
757
779
  When the user asks for something specific about a shot or the whole episode
758
780
  (identity, wardrobe, prop color, lip sync, visual artifacts…), register it in
@@ -983,7 +1005,9 @@ what? which shots are key moments? where is the emotional valley?),
983
1005
  (`{speaker, text}` per line — parsed by the same parser subtitles and voice-over
984
1006
  use, so the speaker you see is the one that will be voiced), `is_key_moment` and
985
1007
  `emotion_intensity`. One call covers the whole episode; the prompt bodies stay
986
- per shot via `get_shot_prompts`.
1008
+ per shot via `get_shot_prompts`, which is also where you read back `shot_type`,
1009
+ `angle`, `camera_movement` and `continuity_intent` after changing them with
1010
+ `update_shot`.
987
1011
 
988
1012
  When the frame or the motion is off in a way the business text cannot express,
989
1013
  edit the shot's prompt bodies directly: `get_shot_prompts` reads the current
@@ -1310,7 +1334,10 @@ from an internal measured run (one character, 3 shots, 18 s, `hailuo-3`):
1310
1334
  generating frames.
1311
1335
  - **Adjacent continuous-action shots are generated as one group**, and their
1312
1336
  durations get re-split by content (6 s + 5 s came back as ~8 s + 3.7 s). Check
1313
- `get_scene_group_plan` before generating videos.
1337
+ `get_scene_group_plan` before generating videos. This only applies while
1338
+ long-take mode is on: if the plan's top-level `active` is `false`
1339
+ (`scene_group_mode` off), its `groups` are a preview only — every shot is
1340
+ generated and billed on its own.
1314
1341
  - **Tail frames only help shots generated on their own.** Check
1315
1342
  `get_scene_group_plan` first: a grouped shot's tail frame is never sent to
1316
1343
  the video model (only the group head's first frame is, except Seedance 2.5
@@ -27,7 +27,7 @@
27
27
  "get_frame_retry_diagnosis": "Free read-only query for image-task losing-streak diagnosis, evidence task IDs, and next action. When diagnosis_required, call this tool first: audit failures should re-review existing candidates; unknown causes should be rechecked first; do not redraw with identical input or change the script without authorization. ★Returned recovery_options are the three choices after image generation failure (ordered free→free→paid, no need to disturb customer when needs_attention=false): ① adopt_rejected select an audit-misjudged candidate from rejected/unselected candidates (get_frame_candidates→adopt_frame_candidate, candidates is adoptable count); ② upload_fixed locally patch this shot’s platform candidate then upload_shot_frame; ③ regenerate modify content per diagnosis then quote_shot_frame→generate_shot_frame. When ask_customer=true, present all three to the customer and let them choose; do not approve on their behalf or pay for regeneration without authorization. failure_class=transient is incidental failure; wait and retry same input. not_self_healable is overdue account/insufficient credits/quota full/model unavailable; regeneration is useless (regenerate.available=false); handle account or change model first.",
28
28
  "get_image_dispatch": "Free read-only query of a shot frame’s dispatch ledger: which reference images were actually used, each image’s purpose and character ownership, whether it reached the model, at which step and why any missing or pre-dispatch removed image was removed (e.g. conflicting object named by era precheck), and the final prompt actually sent to the image model. Use to answer “which image was used and why the result does not look like it”; check facts before deciding to regenerate, do not repeatedly pay for redraws by guessing. ledger=partial/none means the image was generated before ledger launch; missing fields are honestly null.",
29
29
  "get_frame_candidates": "Free read-only: **all candidates** for a shot’s first frame/last frame (same data as the image acceptance workbench). Each candidate includes original image URL (rejected ones too; can open directly at original size), status, whether currently in use (adopted), rejection reason reject (main primary code / code specific cause / details / class routing: needs_content_fix=content must change, content_retryable=content issue but reroll succeeds about 1/3, transient=audit did not complete or incidental—not image disqualification), audit evidence audit (warnings Chinese conclusion, expected design requirements, derived_shot_type inferred shot size with rationale, boxes positions of subjects/body parts in frame; candidates before 2026-10-07 have no archived evidence and are null, not proof they were audited), and which reference images were actually used (references: purpose/character ownership/whether delivered). storyboard.tail_endstate is the “last frame≈first frame” check conclusion (current=false means the conclusion is not for the current two images). ★When a shot is repeatedly rejected, or the customer asks “what did those rejected images look like / why not adopt them”, call this first: inspect each original image and evidence, then decide whether to change storyboard, references, or reroll—do not blindly pay to regenerate. To see a specific image’s final prompt use get_image_dispatch(generation_id). If the customer has seen the original image and confirms the image is fine and the audit was wrong, use adopt_frame_candidate for manual adoption (free); manual_adoption non-empty = this candidate was manually approved. recovery_options gives the three choices after failure by frame position (pick false rejection / patch and upload / regenerate), same criteria as get_frame_retry_diagnosis.",
30
- "adopt_frame_candidate": "Free: manually adopt a completed first-frame/last-frame candidate (rejected by audit rejected, unselected dismissed, or completed but previously in use then replaced) as the active frame for this shot—manual fallback for audit misjudgment (e.g. setting explicitly specified by author contract was judged conflicting), and can switch back to a previous one at any time. ★You must first use get_frame_candidates so the customer has seen the original image and rejection reason, and only call after explicit customer consent (adopting a rejected candidate requires explicit customer consent in every execution mode, autopilot included); do not self-approve just to move the process along. Can only adopt this shot’s same frame position, completed, has image, and not currently active. Manual approval is recorded on the candidate (who/when/original rejection reason); original rejection reason is retained for statistics. If this shot already has video, it will be marked pending regeneration (video was generated from old frames; need regenerate_shot_video). If this frame is customer-uploaded or finalized, pass replace_user_frame:true to replace it (and unfinalize). If same frame position has image generation in progress or this shot has video in progress, returns 409; wait for it to finish before adopting.",
30
+ "adopt_frame_candidate": "Free: manually adopt a completed first-frame/last-frame candidate (rejected by audit rejected, unselected dismissed, or completed but previously in use then replaced) as the active frame for this shot—manual fallback for audit misjudgment (e.g. setting explicitly specified by author contract was judged conflicting), and can switch back to a previous one at any time. ★You must first use get_frame_candidates so the customer has seen the original image and rejection reason, and only call after explicit customer consent (adopting a rejected candidate requires explicit customer consent in every execution mode, autopilot included); do not self-approve just to move the process along. ★Before adopting, check the shot (get_storyboards first_frame_prompt / last_frame_prompt / action_in / action_out / movement): an adopted first frame must be the start of the action, an adopted last frame its end—if a first-frame candidate already shows the end state (the person has already arrived, the action is already done) or draws the camera move's end point into its start, the video will have no action in it; pick another candidate or fix the prompt and regenerate. Can only adopt this shot’s same frame position, completed, has image, and not currently active. Manual approval is recorded on the candidate (who/when/original rejection reason); original rejection reason is retained for statistics. If this shot already has video, it will be marked pending regeneration (video was generated from old frames; need regenerate_shot_video). If this frame is customer-uploaded or finalized, pass replace_user_frame:true to replace it (and unfinalize). If same frame position has image generation in progress or this shot has video in progress, returns 409; wait for it to finish before adopting.",
31
31
  "get_stale_portrait_frames": "Free read-only query for which active first frames/last frames in an episode were drawn using old assets for characters that have since been replaced (old character sheet, old turnaround, old body/hair image). Use after changing a character sheet to confirm impact scope, then let the customer decide which shots to regenerate (regeneration costs credits; this tool changes no data). verdict=stale must include evidence: ledger-old-asset (dispatch ledger directly recorded use of old image) / references-previous-asset (references include that character’s previous old asset) / portrait-born-after-frame (current character sheet was created after this frame). If not provable, mark unknown with reason; do not treat as stale. has_video=true means this shot’s video is also based on old frame; after regenerating frames, video must be regenerated.",
32
32
  "get_asset_versions": "Read-only query for all image/video versions of a shot, historical view links, dependency IDs and version hashes, plus four independent facts: generated → consistent with current input → audit valid → adopted. If historical dependency records are missing, show unknown; do not fabricate snapshots. Free. video_lock is the customer-accepted video lock (lock_shot_video): when locked=true that video counts as current by choice; frames_changed_since_lock=true means frames changed after the lock but no regeneration is needed.",
33
33
  "lock_shot_video": "Lock a shot's current video as the customer-accepted version (free; generates nothing, changes no asset). Use it when the customer has explicitly said \"keep this take\" and the shot's frames / scene / character were changed afterwards. While locked, asset changes no longer mark the shot stale: review_videos stops reporting video_stale (a warning video_locked_frames_changed instead), get_asset_versions shows acceptance_locked=true with the drift listed in drift_while_locked, native-voice stale_shots skip it, and the compose preflight does not flag it; regenerate_shot_video / edit_video_shot / repaint / reskin / footage upload or clear / a whole-episode generate_videos that would replace it all return 409 VIDEO_LOCKED. The lock freezes the video generation id and the inputs it was made from (first/last frame URLs, prompt, reference list). Only the video currently in use can be locked (a generation_id that is not it returns 409 NOT_CURRENT_VIDEO; no video returns 409 NO_VIDEO). If the video is swapped by another path, the lock lapses (video_lock.broken=true in get_asset_versions). Lock only after the customer explicitly confirms; never treat generation finishing or a model judgement as acceptance. To regenerate, get the customer's OK and call unlock_shot_video first.",
@@ -51,11 +51,11 @@
51
51
  "autofill_storyboards": "(Recommended) AI one-click fills missing storyboard fields across the episode (or only the shots in storyboard_ids); by default it **only fills blanks and does not overwrite existing values** (only overwrites when overwrite=true). Improves storyboard completeness; do before image generation. Async in background, postpaid text step (billed per shot that actually calls AI). ★Before running, confirm character/scene/prop bindings (check get_storyboards character_ids / scene_id / prop_ids shot by shot against the customer's original). If a missing binding turns up after auto-completion, just fix it with update_shot; **do not re-import the episode**—re-import replaces the storyboards, discards the auto-completion and charges again. ★**Quote first with quote_autofill** (same overwrite / storyboard_ids), tell the customer shots_to_fill and estimated_points / typical_points, and **run this tool only after the customer agrees**. ★When done, read the receipt from get_autofill_status (which fields were written on how many shots, how many skipped, how many still lack contracts) and tell the customer—the internal fields written here are not readable via get_storyboards, so don’t let the customer think they were charged for nothing. ★The platform already completed one round when storyboards were saved: in fill-empty mode, shots with no gaps left (all six narrative text fields present, vocal direction present on shots with dialogue, and contract present when contract auto-fill is on) are skipped with no AI call and no charge; only overwrite:true reruns the whole episode and bills every shot. ★Completion writes narrative/rhythm internal fields and composition contracts; get_storyboards / get_shot_prompts do not return these fields, so no visible change on read-back is normal—check the counts in the get_autofill_status receipt; it **does not change** image/video prompt text. ★When platform contract auto-fill is enabled, it also tries to add contracts to shots **without composition contracts** (whether enabled is indicated by the note in the import receipt contract_coverage; visible headcount / subject range / shot size are judged by it for both image generation and review; with default overwrite:false, existing contracts are untouched; **overwrite:true also rewrites existing contracts**)—if auto_complete was off during import and the contract_coverage note points to this tool, call it once before image generation. If this episode already has autofill running, this run **will not queue** (prevents duplicate-click duplicate charges); newly imported shots must wait until get_autofill_status is done before calling again. ★To trial a small range first: pass storyboard_ids (1–50 shot ids of this episode, from get_storyboards); only those shots are filled, others make no AI call and are not charged; omit = whole episode. If a completion is already running in this episode, the subset does not start: the receipt returns started=false, reason=fill batch already running; call again after get_autofill_status reaches done.",
52
52
  "enhance_shot_prompts": "(Optional enhancement · ★not required · has side effects) AI batch-enhances the whole episode's image_prompt. ★It **rewrites existing prompts** (including manually edited ones); and **must be done before generate_frames**—changing prompts after image generation makes images stale and requires paid regeneration. Not required to get a film through the pipeline; do only if the customer explicitly requests it. Async in background, postpaid text step.",
53
53
  "complete_ending_motifs": "(Optional enhancement·★not required·conditional) Complete missing visual motifs in the ending segment (graft visual echoes onto ending shots). ★Prerequisite: this drama already has motifs (none = no-op); this will **modify ending shot action/descriptions**, so do it before generating images (otherwise already-generated ending shots become stale). Backend async, billed after the text step.",
54
- "tail_frame_plan": "★Free read-only: which shots in this episode **need independent last frames** (shots whose terminal state ≠ initial state—large camera move/object released/state change). It uses the same criteria the platform uses for video generation; you cannot guess this yourself, so call it once after first frames are done. Returns shots_needing_last_frame(total), ready(shots with first frames already available and can get last frames now), pending_first_frame(shots that need last frames but whose first frames are not ready yet—call this tool again after first frames finish). After getting the ready list: use quote_frames + generate_frames with frame_type=last_frame to batch-fill. ★After last frames are filled (or this tool reports 0), the next step is seams: chain_frames(dry_run:true) to view plan and estimate, execute after customer confirmation, then review_frames. ★Skipping last frames will not error, but those shots have only one first-frame anchor during video generation, so the model improvises the terminal state—bad action completion, large camera moves ending back at the starting composition, etc. usually come from this. Zero cost, callable anytime.",
54
+ "tail_frame_plan": "★Free read-only: which shots in this episode **need independent last frames** (shots whose terminal state ≠ initial state—large camera move/object released/state change). Camera-move shots (pan/push/pull/track/crane, start and end compositions differ) are counted per drama rollout; write the camera move into the shot's movement or action (e.g. “the camera slowly tilts down to …”) — a shot whose prompt only says “fixed camera” is treated as static. It uses the same criteria the platform uses for video generation; you cannot guess this yourself, so call it once after first frames are done. Returns shots_needing_last_frame(total), ready(shots with first frames already available and can get last frames now), pending_first_frame(shots that need last frames but whose first frames are not ready yet—call this tool again after first frames finish). After getting the ready list: use quote_frames + generate_frames with frame_type=last_frame to batch-fill. ★After last frames are filled (or this tool reports 0), the next step is seams: chain_frames(dry_run:true) to view plan and estimate, execute after customer confirmation, then review_frames. ★Skipping last frames will not error, but those shots have only one first-frame anchor during video generation, so the model improvises the terminal state—bad action completion, large camera moves ending back at the starting composition, etc. usually come from this. Zero cost, callable anytime.",
55
55
  "quote_frames": "Quote: how many credits to batch-generate frames for an episode. Returns frames_to_generate, estimated_points, quote_id. Zero cost. frame_type defaults to first_frame(only shots missing first frames); last_frame only generates shots that have first frames and lack last frames; both fills both. ★Quote is tiered by the **actual model and resolution that will be used**; response includes price_breakdown(count and unit price per tier). If you plan to temporarily switch models in generate_frames, pass the same image_model when quoting, otherwise prices differ. ★Both sides must pass the same image_model — mismatch is rejected directly (400 IMAGE_MODEL_MISMATCH), because the model determines the billing tier; different sources mean \"estimate ≠ charge\". Passing neither on both sides also counts as consistent (uses the drama setting). Deprecated models (all FLUX series) are always rejected; do not pass them. ★Returns two numbers: estimated_points is the **upper bound** (estimated by maximum reference-image count; prepare this balance to avoid mid-run 402), typical_points is the **usual cost**. Tell the customer both; quoting only the upper bound makes it look much more expensive. For fixed-price models (e.g. Nano Banana series), they are equal.",
56
56
  "generate_frames": "Batch-generate frames after confirmation: backend async. Poll with get_storyboards; done when first_frame_image/last_frame_image is filled shot by shot. ★Image generation is slow—tens of seconds to minutes per image (especially HD models); a full episode may take 10+ minutes. When polling, check frame_status: **pending=still generating (keep waiting patiently; do not treat as failure; do not call generate_frames again; duplicate triggers=wasted credits)**, ready=done, failed=only this is real failure. Do not decide generation failed or retry just because “it still has not appeared after waiting a while”. Frames must be generated before video, otherwise video degrades into images with no consistency anchors. ★**Before generating frames, prepare both anchors**: character sheets (generate_portraits_and_sheets, anchors people) and empty scene baseplates (generate_scene_images, anchors scenes). Missing baseplates will not block you, but the first shot of each scene will have no background anchor (the platform fallback fill only benefits later shots in the same scene), so the background starts drifting from the first shot. Use the generate_scene_images step in get_pipeline_status to verify completed/total. frame_type must match what quote_frames used (default first_frame). ★This is **batch fill-missing-frames**: it only generates images for shots “missing that frame”; shots that already have first frames are skipped—this is normal design, not “the system refusing to regenerate”. To **regenerate/redraw an existing frame for one shot** (e.g. after changing a character sheet and wanting the new image to take effect), use generate_shot_frame (single-shot regeneration with platform identity anchor), not this tool, and definitely not a self-made image via upload_shot_frame. ★**This tool generates only first frames by default; framing is a two-pass process**: after first frames finish, you must call the free tail_frame_plan once—it tells you, using the platform’s own criteria, which shots need independent tail frames (end state ≠ start state: large camera move/object released/state change, about 30%; you cannot guess this yourself), then batch-fill with frame_type=last_frame. Production data: in 32 episodes, 30 generated only first frames for the whole episode, and 23 proceeded all the way to video: those shots had only one first-frame anchor when generating video, so the model freely invented the end state. shots_needing_last_frame in this tool’s response is this count; if it is not 0, do not go straight to review_frames. ★frames_planned in the response is **planned count, not successful count**—this endpoint returns before the backend dispatch loop starts. Real progress is only in get_storyboards first_frame_image / get_jobs per-item generation records; insufficient balance (402) aborts the whole batch, and polling forever will not produce results—check balance instead of continuing to wait. ★★**If a few shots repeatedly fail while all others are ready**: that is not “not enough waiting”; those shots are being repeatedly rejected by content gates. Check fail_reason in get_storyboards (repeat_rejected / diagnosis_required / needs_content_fix / contract_rejected). If diagnosis_required, first diagnose existing candidates per fail_hint; if audit is wrong, re-audit first; if evidence is insufficient, re-check first; do not redraw unchanged or rewrite the script on your own. Then **run run_precheck** (can be run after the fact; it will tell you what contradiction it is), follow its hints to use update_shot to change shot size/description/bound characters, then regenerate. Do not keep spinning generate_frames, and do not send the customer to external tools to make images—external images bypass identity anchors and frame audit, so faces/costumes/style will drift.\n★【Storyboard review hard gate · free】Before this step you must call review_storyboards first: relay every returned finding to the customer verbatim (each with code=issue type, shots=hit shot numbers, action=which tool to use to fix), then pass review_token into this tool. Without review it is rejected with 400. If content changes after review → token auto-invalidates; just review again (still free). error findings block by default; only if the customer is informed and insists on continuing as-is may you pass acknowledge_review:true—pushing ahead with issues is likely to produce a junk video and still charges normally (acknowledge_review only means the customer personally agreed; any execution mode requires explicit customer consent, including autopilot). In autopilot steps, only whitelisted heuristic errors can pass with auto_acknowledge:true (platform decides; if not whitelisted returns 400 AUTOPILOT_MUST_ASK: must_ask_customer=true means pause and ask customer; false = self-fix per action and re-review). ★Gray-release dramas also require you (agent) to personally QC: inspect materials item by item per agent_qc returned by review_storyboards, answer every checklist item, and submit via submit_qc_report before this token can be used (not submitted → 400 agent_qc_required; report has issues → blocked by default just like error).\n★【Asset-layer hard gate · free】You must also run review_assets first (character appearance images/scene images/prop images) and pass its review_token as asset_review_token here (coexists with storyboard-layer review_token; both are required; gray-release dramas missing it will 400 and name review_assets). Generating frames does not invalidate the asset token. ⚠️ Batch quote confirmation flow: first call the corresponding quote_* tool to get estimated_points and quote_id, then call this tool with quote_id (quote confirmation depends on execution mode: professional mode / unconfirmed plan / this step controlled by customer → explain to customer and proceed only after customer agrees; do not decide for them; this step in autopilot → do not ask customer, follow get_production_plan autopilot.default_decisions, platform records it in get_autopilot_log). Autopilot-step quotes must be within the hard budget cap; if blocked by 402 BUDGET_WOULD_EXCEED, stop and ask the customer. ★**Image-generation quotes (character sheets/scene images/frame generation) provide two numbers**: estimated_points is the **upper bound** (estimated using the maximum reference-image count for that model, ensuring you do not start with an underbudget and hit 402 midway); typical_points in the same response is the **typical cost**. Tell the customer both—only saying the upper bound makes it seem much more expensive (the full-reference upper bound can exceed typical by 2x+), while only saying the typical value may leave insufficient balance. For fixed-price models they are equal; then one number is enough. Video-generation quote and charge use the same function; this range does not exist.",
57
- "quote_shot_frame": "Quote: how many credits to redraw/fill **one frame of one shot** (one frame = one image). Returns estimated_points, quote_id. Zero cost. Use this when the customer says \"shot N is wrong/needs changes\", instead of using another image platform and then upload_shot_frame. ★Response includes billing_kind/unit_points(actual billing tier and unit price); if you will switch models in generate_shot_frame, pass the same image_model when quoting. ★Both sides must pass the same image_model — mismatch is rejected directly (400 IMAGE_MODEL_MISMATCH), because the model determines the billing tier; different sources mean \"estimate ≠ charge\". Passing neither on both sides also counts as consistent (uses the drama setting). Deprecated models (all FLUX series) are always rejected; do not pass them. ★Returns two numbers: estimated_points is the **upper bound** (estimated by maximum reference-image count; prepare this balance to avoid mid-run 402), typical_points is the **usual cost**. Tell the customer both; quoting only the upper bound makes it look much more expensive. For fixed-price models (e.g. Nano Banana series), they are equal.",
58
- "generate_shot_frame": "After confirmation, generate or regenerate the frame for **one shot** (async). This is the proper path to fix a shot image: the platform will carry this shot’s character identity anchors, scene/prop reference images, style anchor, and frame audit; regenerated images stay consistent with the whole film. Using external tools to generate then upload bypasses this entire chain, so character/clothing/style will inevitably drift. Regeneration overwrites the shot’s existing frame image (including prior uploads) and marks this shot’s video as needing regeneration. A last frame requires this shot’s first frame to be ready (otherwise use first_frame or both first). Completion criterion: poll get_storyboards and watch this shot’s first_frame_image/last_frame_image change.\n★Inherited reopen (reopen_pair_id): if get_storyboards returns this field on a shot, pass it through unchanged to reroll only the actually problematic side among first/last frames—the other previously generated candidate is preserved as-is, not regenerated and not charged again. When passing it, you no longer need frame_type (it will be ignored; the platform decides which side to regenerate); quote_id still must come from quote_shot_frame (frame_type may be first_frame or last_frame; single-frame price is the same). If the shot has no reopen_pair_id field (inheritance conditions not met), do not pass this parameter; use normal frame_type retry.\n★★If generating a last frame is blocked with “this shot is marked as state changed, but nowhere says what it looks like at the end”: the correct fix is to use update_shot to write the ending state into last_frame_prompt, then generate—**do not simply add allow_missing_terminal and force it**. For this type of shot, generating a last frame as-is historically succeeds only 9.4% of the time (40.2% when an end-state description exists), so forcing it will mostly waste one charge. Only pass that parameter when you confirm this shot is intended to look “almost unchanged”.\n★One-click final cut hosted flow: the same shot may regenerate frames at most 3 rounds (one call counts as one round; both also counts as one round). At the limit, returns **409 AUTOPILOT_SHOT_REGEN_LIMIT** (not dispatched, not charged, quote not consumed)—do not bypass with another tool. Stop and ask the customer: if the customer agrees to more regeneration, quote and generate normally with customer_approved_more_regens:true (grants another limit); if the customer accepts the current state, proceed downward, and the next paid call must include acknowledge_review:true to record confirmation. Professional mode and customer-controlled stages are not subject to this limit.\n★【Storyboard review hard gate · free】Before this step you must call review_storyboards: tell the customer every returned finding verbatim (each with code=issue type, shots=hit shot numbers, action=which tool to use for fixing), then pass review_token into this tool. If not reviewed, it will be rejected with 400. If content changes after review → token auto-invalidates; just re-review once (still free). error findings block by default; only when the customer is informed and insists on continuing as-is may you pass acknowledge_review:true—pushing ahead with known issues is likely to produce unusable footage and still charges normally (acknowledge_review only means the customer personally agreed; every execution mode requires explicit customer consent, hosted included). In hosted stages, only allowlisted heuristic errors may pass with auto_acknowledge:true (platform decides; if not allowlisted, returns 400 AUTOPILOT_MUST_ASK: must_ask_customer=true means pause and ask the customer, false = self-fix according to action and re-review). ★Grayscale dramas also require you (agent) to personally QC: inspect assets item by item per agent_qc returned by review_storyboards, answer the checklist line by line, and submit via submit_qc_report before this token can be used (not submitted → 400 agent_qc_required; problematic report → blocks by default just like error).\n★【Asset-layer hard gate · free】You must also run review_assets first (character sheet images / scene images / prop images), and pass its review_token as asset_review_token (coexists with the storyboard-layer review_token; both are required; grayscale dramas missing it get 400 naming review_assets). Generating frames does not invalidate the asset token. ⚠️ Batch quote confirmation flow: first call the corresponding quote_* tool to get estimated_points and quote_id, then call this tool with quote_id (quote confirmation depends on execution mode: professional mode / unconfirmed plan / customer-controlled stage → explain to the customer and proceed only after customer approval; hosted stage → do not ask the customer, follow get_production_plan autopilot.default_decisions, and the platform records it in get_autopilot_log). Hosted-stage quotes must stay within the hard budget cap; if blocked by 402 BUDGET_WOULD_EXCEED, stop and ask the customer. ★**Image-generation quotes (character sheet / scene image / frame generation) return two numbers**: estimated_points is the **upper bound** (estimated using that model’s maximum reference-image count, ensuring you do not start with an underbudgeted run that hits 402 midway); typical_points in the same response is the **typical cost**. Tell the customer both—only saying the upper bound makes it look much more expensive (the max-reference upper bound can exceed 2× the typical value), while only saying the typical value may leave insufficient balance. For fixed-price models they are equal, so one number is enough. Video-generation quote and charge use the same function; no such range exists.",
57
+ "quote_shot_frame": "Quote: how many credits to redraw/fill **one frame of one shot** (one frame = one image). Returns estimated_points, quote_id. Zero cost. Use this when the customer says \"shot N is wrong/needs changes\", instead of using another image platform and then upload_shot_frame. ★Response includes billing_kind/unit_points(actual billing tier and unit price); if you will switch models in generate_shot_frame, pass the same image_model when quoting. ★Both sides must pass the same image_model — mismatch is rejected directly (400 IMAGE_MODEL_MISMATCH), because the model determines the billing tier; different sources mean \"estimate ≠ charge\". Passing neither on both sides also counts as consistent (uses the drama setting). Deprecated models (all FLUX series) are always rejected; do not pass them. ★Returns two numbers: estimated_points is the **upper bound** (estimated by maximum reference-image count; prepare this balance to avoid mid-run 402), typical_points is the **usual cost**. Tell the customer both; quoting only the upper bound makes it look much more expensive. For fixed-price models (e.g. Nano Banana series), they are equal. ★With frame_type=both, if the platform judges this shot needs no independent last frame (end ≈ start, no camera move) it generates only the first frame: the quote returns frames_to_generate=1, charges only the first frame, and includes last_frame_skipped explaining why — **tell the customer verbatim that no last frame will be made**. If the customer really wants a last frame (e.g. a camera move whose start and end differ), pass force_independent_last_frame:true on both the quote and the generate call.",
58
+ "generate_shot_frame": "After confirmation, generate or regenerate the frame for **one shot** (async). This is the proper path to fix a shot image: the platform will carry this shot’s character identity anchors, scene/prop reference images, style anchor, and frame audit; regenerated images stay consistent with the whole film. Using external tools to generate then upload bypasses this entire chain, so character/clothing/style will inevitably drift. Regeneration overwrites the shot’s existing frame image (including prior uploads) and marks this shot’s video as needing regeneration. A last frame requires this shot’s first frame to be ready (otherwise use first_frame or both first). Completion criterion: poll get_storyboards and watch this shot’s first_frame_image/last_frame_image change.\n★Inherited reopen (reopen_pair_id): if get_storyboards returns this field on a shot, pass it through unchanged to reroll only the actually problematic side among first/last frames—the other previously generated candidate is preserved as-is, not regenerated and not charged again. When passing it, you no longer need frame_type (it will be ignored; the platform decides which side to regenerate); quote_id still must come from quote_shot_frame (frame_type may be first_frame or last_frame; single-frame price is the same). If the shot has no reopen_pair_id field (inheritance conditions not met), do not pass this parameter; use normal frame_type retry.\n★★If generating a last frame is blocked with “this shot is marked as state changed, but nowhere says what it looks like at the end”: the correct fix is to use update_shot to write the ending state into last_frame_prompt, then generate—**do not simply add allow_missing_terminal and force it**. For this type of shot, generating a last frame as-is historically succeeds only 9.4% of the time (40.2% when an end-state description exists), so forcing it will mostly waste one charge. Only pass that parameter when you confirm this shot is intended to look “almost unchanged”.\n★One-click final cut hosted flow: the same shot may regenerate frames at most 3 rounds (one call counts as one round; both also counts as one round). At the limit, returns **409 AUTOPILOT_SHOT_REGEN_LIMIT** (not dispatched, not charged, quote not consumed)—do not bypass with another tool. Stop and ask the customer: if the customer agrees to more regeneration, quote and generate normally with customer_approved_more_regens:true (grants another limit); if the customer accepts the current state, proceed downward, and the next paid call must include acknowledge_review:true to record confirmation. Professional mode and customer-controlled stages are not subject to this limit.\n★【Storyboard review hard gate · free】Before this step you must call review_storyboards: tell the customer every returned finding verbatim (each with code=issue type, shots=hit shot numbers, action=which tool to use for fixing), then pass review_token into this tool. If not reviewed, it will be rejected with 400. If content changes after review → token auto-invalidates; just re-review once (still free). error findings block by default; only when the customer is informed and insists on continuing as-is may you pass acknowledge_review:true—pushing ahead with known issues is likely to produce unusable footage and still charges normally (acknowledge_review only means the customer personally agreed; every execution mode requires explicit customer consent, hosted included). In hosted stages, only allowlisted heuristic errors may pass with auto_acknowledge:true (platform decides; if not allowlisted, returns 400 AUTOPILOT_MUST_ASK: must_ask_customer=true means pause and ask the customer, false = self-fix according to action and re-review). ★Grayscale dramas also require you (agent) to personally QC: inspect assets item by item per agent_qc returned by review_storyboards, answer the checklist line by line, and submit via submit_qc_report before this token can be used (not submitted → 400 agent_qc_required; problematic report → blocks by default just like error).\n★【Asset-layer hard gate · free】You must also run review_assets first (character sheet images / scene images / prop images), and pass its review_token as asset_review_token (coexists with the storyboard-layer review_token; both are required; grayscale dramas missing it get 400 naming review_assets). Generating frames does not invalidate the asset token. ⚠️ Batch quote confirmation flow: first call the corresponding quote_* tool to get estimated_points and quote_id, then call this tool with quote_id (quote confirmation depends on execution mode: professional mode / unconfirmed plan / customer-controlled stage → explain to the customer and proceed only after customer approval; hosted stage → do not ask the customer, follow get_production_plan autopilot.default_decisions, and the platform records it in get_autopilot_log). Hosted-stage quotes must stay within the hard budget cap; if blocked by 402 BUDGET_WOULD_EXCEED, stop and ask the customer. ★**Image-generation quotes (character sheet / scene image / frame generation) return two numbers**: estimated_points is the **upper bound** (estimated using that model’s maximum reference-image count, ensuring you do not start with an underbudgeted run that hits 402 midway); typical_points in the same response is the **typical cost**. Tell the customer both—only saying the upper bound makes it look much more expensive (the max-reference upper bound can exceed 2× the typical value), while only saying the typical value may leave insufficient balance. For fixed-price models they are equal, so one number is enough. Video-generation quote and charge use the same function; no such range exists. ★frames_dispatched in the receipt is the number of images actually dispatched; when the last frame of a both request is judged unnecessary the receipt includes skipped_frames (not generated, not charged) — relay it to the customer verbatim.",
59
59
  "quote_videos": "Quote: how many credits to batch-generate videos for an episode (same function as actual charge, relatively accurate). Returns estimated_points, quote_id. Zero cost. ⚠️ Video is a large expense; clearly tell the user the credits and wait for confirmation.\n★**Only counts shots actually dispatched this time**: shots that already have video are skipped during whole-episode resume, not regenerated and not priced—shots_total = shots priced this time (not total shots in episode), shots_already_done = shots with video skipped this time. Exception: if any shot in a scene group lacks video, the **entire group is regenerated**, and already-generated shots inside the group are also priced. All shots already have video ⇒ 400(no dispatchable shots; use regenerate_shot_video to regenerate a shot). If any shot's video is cleared after quoting (becomes pending video), generate_videos returns 409 requiring a new quote; it will not charge for shots outside the quote.\n★**Specify video engine per shot**: pass shot_engines={storyboard id: engine} to switch engines only for those shots and only for this whole-episode generation (does not change drama-level video_engine; other shots unchanged). Quote prices per shot accordingly; quote_id pins the engines, and generate_videos dispatches exactly them—changing engine requires a new quote. Receipt shot_engines = actual applied mapping; shot_engines_ungrouped = scene groups **split into per-shot generation** because they include specified shots (scene-group duration and multi-keyframes are planned for the drama engine; generating the whole group with a changed engine would lose shots/keyframes; after splitting, other shots in the group still generate per-shot with the drama engine, losing group-level one-pass continuity, so do not split a good group for one shot—check get_scene_group_plan first). Selected engine must support this drama's resolution (seedance-2.5 only 480p/720p; hailuo-3 only 720p/1080p; wan3.0/wan3.0-prime 480p~1080p), and shot duration must not exceed that engine's single-shot limit (seedance-2.5/wan3.0 30s, hailuo-3 15s), otherwise 400 (vendors truncate overlong shots; either switch engine or split_shot). Shots with specified engines must be generated this time: whole-episode generation will not regenerate shots already having video, so specifying an engine for one ⇒ 400; a split per-shot scene group only counts group members without video. If you only want to regenerate a few shots that already have video, using quote_regenerate_shot_video with model is cheaper. ★The response may carry an **unchained-seam hint** (does not affect review_token / quote / status codes): review_frames and generate_videos return unchained_seam_advisory; quote_videos returns an advisories entry with code=unchained_seams. seams lists adjacent seams (from_shot→to_shot) that chain_frames would chain but that are not chained yet: status=no_stamp (never chained) / pending (a chaining was dispatched but has not landed, or its audit has no verdict yet) / stale_anchor (the previous chaining anchor is no longer valid: the upstream shot's last frame was regenerated after chaining, so the seam must be re-chained) / join_failed (the last chaining regeneration was rejected / failed / superseded and never landed) / audit_failed (the chaining landed but the continuity audit judged it discontinuous — see seam_failed_dims in get_storyboards) / first_frame_regenerated (the downstream first frame was regenerated after the seam was reviewed, bypassing the chaining path, so the old chaining no longer counts) / not_linked (the planner judges the seam unchained but the cause is not evidenced); re-chain all of them per the plan; video_locked lists the same kind of seam where the downstream shot already has a video — chain_frames will not touch those, so fix them per shot with chain_shot_from_prev / chain_shot_from and then regenerate_shot_video (quote first). If seams is non-empty before generating videos, run chain_frames(dry_run:true) first, tell the customer the plan and price, execute after they agree, then re-run review_frames.",
60
60
  "generate_videos": "After confirmation, batch-generate videos: one backend chain runs the full episode; if balance is insufficient it auto-aborts the whole chain (prevents duplicate charging). Requires first frames already generated for this episode (otherwise rejected). Poll get_storyboards; completion = video_url filled shot by shot.\n★【Hard gate: shot image review · free】Before this step you must call review_frames first: report the returned findings to the customer verbatim, item by item (each with code=issue type, shots=hit shot numbers, action=which tool to use to fix), then pass review_token into this tool. No review → 400 rejection. If content changes after review → token auto-invalidates; review once again (still free). If there is error, block by default; only if the customer is informed and insists on continuing as-is, pass acknowledge_review:true—pushing ahead with issues will very likely produce unusable footage and still charges normally (acknowledge_review only means the customer personally agreed; every execution mode requires explicit customer consent, including autopilot). In autopilot steps, only whitelisted heuristic errors may be released with auto_acknowledge:true (platform decides; if not whitelisted, returns 400 AUTOPILOT_MUST_ASK: must_ask_customer=true means pause and ask customer, false = self-fix per action then re-review). ★ Gray-release dramas also require you (agent) to personally QC: per review_frames returned agent_qc, inspect assets item by item, answer every checklist item, and submit via submit_qc_report before this token can be used (not submitted → 400 agent_qc_required; report has problems → blocked by default same as error). ⚠️ Batch quote confirmation flow: first call the corresponding quote_* tool to get estimated_points and quote_id, then call this tool with quote_id (quote confirmation follows execution mode: professional mode / unconfirmed plan / this step controlled by customer → explain to customer and proceed only after customer agrees; do not decide for customer; this step autopilot → do not ask customer, execute per get_production_plan autopilot.default_decisions, platform records it in get_autopilot_log). Autopilot-step quotes must stay within the hard budget cap; if blocked by 402 BUDGET_WOULD_EXCEED, stop and ask customer. ★ **Image-generation quotes (character sheet / scene image / frame generation) give two numbers**: estimated_points is the **upper bound** (estimated using that model's max reference-image count, ensuring you do not start with too-low budget and hit 402 mid-run); typical_points in the same response is the **usual cost**. Tell the customer both—only stating the upper bound makes it look much more expensive (with max reference images, the upper bound can exceed 2x the typical value); only stating the typical value may leave balance insufficient. For fixed-price models the two are equal; then one number is enough. Video-generation quote and charge use the same function; no range exists.\n★【Post-completion QC · free】After generation, wait for it to persist (check video_status in get_storyboards / get_pipeline_status), then call review_videos to review video and dubbing layers (missing video / video made from old frames / hard cut at ending / unexpected human voice / missing dubbing / voice timbre unassigned / original voice line expired); fix and re-review; then personally inspect each shot and listen to dubbing per agent_qc (action correct, face stable, lines complete, voice right), submit via submit_qc_report; compose_episode must carry its review_token. ★The response may carry an **unchained-seam hint** (does not affect review_token / quote / status codes): review_frames and generate_videos return unchained_seam_advisory; quote_videos returns an advisories entry with code=unchained_seams. seams lists adjacent seams (from_shot→to_shot) that chain_frames would chain but that are not chained yet: status=no_stamp (never chained) / pending (a chaining was dispatched but has not landed, or its audit has no verdict yet) / stale_anchor (the previous chaining anchor is no longer valid: the upstream shot's last frame was regenerated after chaining, so the seam must be re-chained) / join_failed (the last chaining regeneration was rejected / failed / superseded and never landed) / audit_failed (the chaining landed but the continuity audit judged it discontinuous — see seam_failed_dims in get_storyboards) / first_frame_regenerated (the downstream first frame was regenerated after the seam was reviewed, bypassing the chaining path, so the old chaining no longer counts) / not_linked (the planner judges the seam unchained but the cause is not evidenced); re-chain all of them per the plan; video_locked lists the same kind of seam where the downstream shot already has a video — chain_frames will not touch those, so fix them per shot with chain_shot_from_prev / chain_shot_from and then regenerate_shot_video (quote first). If seams is non-empty before generating videos, run chain_frames(dry_run:true) first, tell the customer the plan and price, execute after they agree, then re-run review_frames.",
61
61
  "compose_episode": "Stitch all shot videos of one episode into one final cut (final stitching). **Free** (pure stitching, no quote confirmation required), async in backend. Before starting, a final-stitch precheck runs: shots missing video or video tasks still generating will hard-block with 400 and list the problem shots (blockers); fix them and retry. If you really want a partial final cut, pass force=true (shots missing video are skipped, final cut lacks shots, logged). advisories in the response (duration drift/orphan tasks/missing TTS/post_production_pending unfinished post-production effects) are warnings only, not blockers; handle them one by one before stitching. After starting, poll with get_final_cut.\n★【Video and dubbing review hard gate · Free】Before this step you must call review_videos: relay the returned findings to the customer verbatim one by one (each with code=issue type, shots=hit shot numbers, action=which tool to use to fix), then pass the review_token into this tool. If not reviewed, 400 rejection. If content changed after review → token auto-invalidates; just review again (still free). error blocks by default; only if the customer is informed and insists on proceeding as-is may you pass acknowledge_review:true — proceeding with known issues will likely produce unusable video and still charge credits as usual (acknowledge_review only means the customer personally agreed; every execution mode requires explicit customer consent, autopilot included). In autopilot, only whitelisted heuristic errors may pass with auto_acknowledge:true (platform decides; if not whitelisted, returns 400 AUTOPILOT_MUST_ASK: must_ask_customer=true means pause to ask customer, false = self-fix per action and re-review). ★ For gray rollout dramas, you (agent) must personally QC: inspect materials item by item per agent_qc from review_videos, answer every checklist item, and submit via submit_qc_report before this token can be used (not submitted → 400 agent_qc_required; report has issues → blocked by default like error).\n★★【Pre-compose checks · after review_videos passes, before compose_episode】Don't hunt for problems by repeatedly exporting the whole cut and trying transitions by hand — per-shot and seam problems have dedicated tools; run them in order before stitching: ① portraits / turnarounds / scene images / shot frames were changed in this episode → first get_stale_portrait_frames(episode_id, free) to see which shots' in-use frames are still based on old assets; for shots where it is unclear which version to use, get_asset_versions(storyboard_id, free) shows each shot's versions and dependencies (unknown means insufficient evidence, not stale; regenerating is paid, so give the list to the customer and let them decide); ② scan_intra_shot_cuts(episode_id, free) finds shots where the vendor hard-cut inside a single shot; ③ per shot, recommend_trim_window(storyboard_id, free) shows a frozen tail and the effective action window (shots inside a scene group return applicable=false — skip them); apply a recommendation with trim_shot (free); ④ audit_seams(episode_id) checks editing continuity at seams between adjacent shots: by default dry_run only lists what would be audited (free); actually running it is billed by real text-token usage — tell the customer, and only after they explicitly accept pass dry_run:false + confirm_usage_billing:true; read the result from seam_review in get_storyboards; ⑤ then compose_episode. If the final cut shows jump cuts / dragging tails / seams that don't match, go back to these tools to locate the shots and fix only those — don't keep re-exporting the whole cut by trial and error. These checks are advisory, not gates; trimming and seam audits don't invalidate the review_videos token.\n★【Post-completion QC · Free】After the final cut is ready, run review_final_cut (missing shots/subtitles not fitting/identity anchors/axis jumps/typos; proofread=false means no credits charged), tell the customer the conclusion; call confirm_delivery_acceptance only after customer confirmation (delivery acceptance requires explicit customer consent in every execution mode, autopilot included). force only bypasses the final-stitch precheck, not the review gate.",
@@ -88,7 +88,7 @@
88
88
  "apply_extend_final": "Set an extension output as this episode's **final cut** (free, pure pointer switch).\n★This step **overwrites** the episode's current final cut link: the previous final cut is no longer the public version. First use get_extend_final to inspect final_url and confirm the customer is satisfied before calling.\n★If compose_episode (final assembly) is run again later, the final cut will be overwritten by the final assembly result, and applied automatically becomes false.",
89
89
  "export_sheet_compare": "Export **character sheet comparison version** (side-by-side composite of character sheets and final cut frames, for marketing/delivery). Triggers backend compositing; poll with get_sheet_compare.\n★This capability is **off by default**: it is a drama-level switch (not every title is allowed to export this externally). When off it returns **403**. If you see 403, do not retry and do not treat it as failure—tell the customer to enable it in **Drama Settings** on the official site.\nIf character_id is omitted, export the whole episode; if provided, export only that character.",
90
90
  "get_sheet_compare": "Poll export status for the character sheet comparison version. Free. Returns enabled (whether the drama switch is on)/processing/result/error.\n★enabled=false means the drama switch is not enabled—not an error. Enable it in Drama Settings on the official site, then export again.",
91
- "update_project_settings": "Modify project settings after creating the drama. Besides aspect ratio/resolution/worldview Brief/ethnicity/genre/director style, now also covers ★whole-drama visual consistency anchors (cinematography DNA cinematography_prompt/art bible art_bible/visual lock visual_lock/video style positive and negative prompts/visual motifs motifs), audio (bgm_source own vs native/bgm_volume_preset volume/use_clip_audio use original video audio), subtitles (show_subtitles/bilingual subtitle_secondary_lang/position/margins/animation), transitions—i.e. all common settings on the project settings page. Free. ⚠️ After changing worldview Brief/ethnicity/aspect ratio/consistency anchors, already generated content will not update automatically; regenerate the corresponding content.",
91
+ "update_project_settings": "Modify project settings after creating the drama. Besides aspect ratio/resolution/worldview Brief/ethnicity/genre/director style, now also covers ★whole-drama visual consistency anchors (cinematography DNA cinematography_prompt/art bible art_bible/visual lock visual_lock/video style positive and negative prompts/visual motifs motifs), audio (bgm_source own vs native/bgm_volume_preset volume/use_clip_audio use original video audio), subtitles (show_subtitles/bilingual subtitle_secondary_lang/position/margins/animation), transitions—i.e. all common settings on the project settings page. Free. ⚠️ After changing worldview Brief/ethnicity/aspect ratio/consistency anchors, already generated content will not update automatically; regenerate the corresponding content. ★frame_chain_mode controls cross-shot frame chaining for the whole drama: off = none at all (the auto-chain after frames settle, chain_frames and bookends dispatch no images and change no frames, and quotes no longer include them); reframe = default; strict = adjacent seams only copy the previous shot's last frame, no regeneration (bookends already set still regenerate as reframes and are still quoted; use off for no images at all). To use chain_frames after turning it off, switch back to reframe/strict first; changing the mode does not regenerate existing frames.",
92
92
  "generate_world_concept": "(★Default required·many third-party platforms miss this step·still uses quote confirmation) Generate worldview concept images (fixed 4 panels: panorama/era/main location/color) to improve whole-drama visual consistency. ★Call this by default after storyboard; do not skip. But still tell the customer the estimated credits (whether to run depends on execution mode: Professional mode / unconfirmed plan / this step is customer-controlled → explain to the customer and run only after customer approval; do not decide for them. This step in autopilot → do not ask the customer; follow get_production_plan autopilot.default_decisions, and the platform records it in get_autopilot_log). Before dispatch, the platform prechecks budget by missing slots × single-image upper bound; if it exceeds the hard cap, returns 402, with no charge. Requires setting_brief ≥30 characters. Image step, fixed-cost postpaid, no arrears.",
93
93
  "generate_art_bible": "Generate the art bible (palette/materials/atmosphere, reads characters + metadata). Text step, postpaid, no arrears.",
94
94
  "extract_visual_lock": "Extract \"visual lock\" rules from worldview Brief + characters (writes visual_lock, unifies image style/ethnicity). Text step, postpaid, no arrears.",
@@ -138,9 +138,9 @@
138
138
  "scan_voice_consistency": "★For original-voice dramas (video has built-in human speech), run this when the customer reports \"the same character's voice differs across shots / voice drifted\". Free (local inference, no vendor call). For each shot with dialogue, listens to vendor-generated human speech: whether the dialogue was fully spoken, and whether the voice resembles the timbre anchor bound to that character. **Async**: returns immediately; background full-episode scan takes about 10 minutes. Only one scan per episode can run at the same time (repeat calls return started=false). By default skips shots already scanned for the current video; rescan=true rescans all. Use get_voice_consistency to check progress and per-shot results.",
139
139
  "get_voice_consistency": "Check progress and per-shot results of the voice consistency scan (started by scan_voice_consistency). Free. summary.voice_mismatch = shot numbers whose voice does not resemble the character timbre anchor (focus on these); dialogue_issues = shots where dialogue was incomplete/wrong/extra speech appeared; not_scanned_or_stale = not scanned yet or video changed and needs rescan. speaker_verdict=uncertain means the human speech is too short to judge; it is not an issue. For shots with inconsistent voice: first use get_pipeline_status native_voice_anchor to confirm the character has a bound voice, then regenerate_shot_video.",
140
140
  "scan_dialogue_coverage": "★When the customer reports \"cut before the line finished / only half the dialogue was spoken\", run this first. Default **free, zero charge** (read-only access to persisted transcription audit results). Compares each original-voice shot's video audio track against the dialogue at word level, and reports conclusions by family: truncated (stops halfway through the line) / off_script (most spoken content is not the dialogue: improvising, repeating previous shot, only ambience) / extra_speech (dialogue is fully spoken but extra speech is added) / minor_gap (sporadic missing words, transcription error, ignore) / ok. ★Interpretation: the three reportable families have **different remedies**; do not simply lengthen every shot—measurements show 21% of shots with sufficient length still fail to finish the line, so \"too short\" is rarely the real cause (the platform already auto-raises duration by dialogue when saving storyboards). The correct fix for truncated/off_script is regenerate_shot_video (how much the vendor says is random each time; rerolling often gets the full line); if the same drama repeatedly has off_script, switch engine. ★never_audited is the most important section of this report: those shots have never been checked; \"not checked\" does not mean \"no issue\". rescan=true will run ASR comparison for them (compute-intensive, not instant; limit controls per-run cap), default does not run. TTS-dubbed shots are out of scope (TTS necessarily reads the full line; low coverage can only be transcription error). If the same episode also has \"cuts too fast\", that is a separate issue; run scan_intra_shot_cuts.",
141
- "update_shot": "Shot-by-shot edit: change a single storyboard shot's text content (shot size/action/dialogue/visual description/camera movement, etc.), facial expression (expression_hint), duration (duration), final cut speed (speed_factor), character binding (character_ids), prop binding (prop_ids; full overwrite, [] clears—use it to fix a prop missed at import instead of re-importing the whole episode; edits do not auto-regenerate frames/video), voice-over marker (character_presence), and wardrobe binding (active_wardrobe_id / appearance_wardrobes). Send only fields to change; all others stay unchanged. ★Any shot edit (accepted or rejected) invalidates unconsumed quotes covering this shot; generation then returns 409 QUOTE_INVALIDATED—edit first, read back to verify, then quote. **Free** (pure text DB write). ★Changing dialogue automatically invalidates generated TTS voice-over and subtitles for this shot (tts must be regenerated); text edits do not auto-regenerate images/video. To make visuals follow text changes, edit then regen the corresponding shot. Use get_storyboards to inspect results (each shot includes character_ids / character_bindings / scene_id / prop_ids / active_wardrobe_id / appearance_wardrobes). ★★【Change clothes here, not in text】What appears in image generation is determined by **wardrobe binding**: single-character shots use active_wardrobe_id (one outfit for the whole shot); multi-character shots use appearance_wardrobes (per character). Writing \"wearing X clothes\" in description/action will not change clothes. Use list_wardrobe for wardrobe id; edits do not auto-regenerate images. To update visuals, regenerate this shot's first frame then video. ★★For native-audio shots (vendor-native audio), after changing dialogue the shot video is marked \"needs regeneration\"—because spoken lines are **baked into the video audio**. If you final-compose without regeneration, the final cut still speaks the old line (typical symptom: dialogue seems to have moved to another shot). compose_episode lists these shots under advisory `stale_video_after_edit`; correct handling is regenerate_shot_video before final compose. ★You may also directly edit this shot's four prompt bodies (image_prompt/video_prompt/first_frame_prompt/last_frame_prompt): read current values with get_shot_prompts first; do not overwrite from scratch. @char:N / @scene:M in the body are supplemental reference markers for image generation; keep them unchanged. ★Which character sheet is injected is determined by character_ids, and background by scene_id: deleting markers will not remove already-bound people from the image. To make someone not appear, edit character_ids; if they are voice-only, set character_presence to voice_only. Conversely, do not write @char markers for unbound characters—this will inject their image. ★★【If last-frame generation is blocked, edit here】If last-frame generation reports \"this shot is marked as a state change, but nowhere describes what it looks like at the end\" (TERMINAL_DESC_GATE), fix by writing **what the final image should look like** into this shot's last_frame_prompt, then regenerate the last frame. Do not retry image generation—shots of this type (action_motion_class=state_change without terminal state) historically succeed at 9.4%, versus 40.2% with terminal-state description; without adding the description, the vendor prompt has no terminal-state section, so it still draws the same as the first frame, is rejected again, and each regeneration still charges normally. terminal_desc_missing=true from get_shot_prompts is this signal.",
141
+ "update_shot": "Shot-by-shot edit: change a single storyboard shot's text content (shot size/action/dialogue/visual description/camera movement, etc.), facial expression (expression_hint), duration (duration), final cut speed (speed_factor), character binding (character_ids), prop binding (prop_ids; full overwrite, [] clears—use it to fix a prop missed at import instead of re-importing the whole episode; edits do not auto-regenerate frames/video), voice-over marker (character_presence), and wardrobe binding (active_wardrobe_id / appearance_wardrobes); read back shot size / angle / camera movement / edit intent and prompt text per shot with get_shot_prompts. Send only fields to change; all others stay unchanged. ★Any shot edit (accepted or rejected) invalidates unconsumed quotes covering this shot; generation then returns 409 QUOTE_INVALIDATED—edit first, read back to verify, then quote. **Free** (pure text DB write). ★Changing dialogue automatically invalidates generated TTS voice-over and subtitles for this shot (tts must be regenerated); text edits do not auto-regenerate images/video. To make visuals follow text changes, edit then regen the corresponding shot. Use get_storyboards to inspect results (each shot includes character_ids / character_bindings / scene_id / prop_ids / active_wardrobe_id / appearance_wardrobes). ★★【Change clothes here, not in text】What appears in image generation is determined by **wardrobe binding**: single-character shots use active_wardrobe_id (one outfit for the whole shot); multi-character shots use appearance_wardrobes (per character). Writing \"wearing X clothes\" in description/action will not change clothes. Use list_wardrobe for wardrobe id; edits do not auto-regenerate images. To update visuals, regenerate this shot's first frame then video. ★★For native-audio shots (vendor-native audio), after changing dialogue the shot video is marked \"needs regeneration\"—because spoken lines are **baked into the video audio**. If you final-compose without regeneration, the final cut still speaks the old line (typical symptom: dialogue seems to have moved to another shot). compose_episode lists these shots under advisory `stale_video_after_edit`; correct handling is regenerate_shot_video before final compose. ★You may also directly edit this shot's four prompt bodies (image_prompt/video_prompt/first_frame_prompt/last_frame_prompt): read current values with get_shot_prompts first; do not overwrite from scratch. @char:N / @scene:M in the body are supplemental reference markers for image generation; keep them unchanged. ★Which character sheet is injected is determined by character_ids, and background by scene_id: deleting markers will not remove already-bound people from the image. To make someone not appear, edit character_ids; if they are voice-only, set character_presence to voice_only. Conversely, do not write @char markers for unbound characters—this will inject their image. ★★【If last-frame generation is blocked, edit here】If last-frame generation reports \"this shot is marked as a state change, but nowhere describes what it looks like at the end\" (TERMINAL_DESC_GATE), fix by writing **what the final image should look like** into this shot's last_frame_prompt, then regenerate the last frame. Do not retry image generation—shots of this type (action_motion_class=state_change without terminal state) historically succeed at 9.4%, versus 40.2% with terminal-state description; without adding the description, the vendor prompt has no terminal-state section, so it still draws the same as the first frame, is rejected again, and each regeneration still charges normally. terminal_desc_missing=true from get_shot_prompts is this signal.",
142
142
  "rederive_shot_contract": "Using this shot's **current** prompt body and character binding, let the platform re-derive the composition contract (how many visible people, whether the subject is a person or a partial/object, shot size). The contract itself is internal: cannot be read or edited directly. This tool only returns outcome: updated (changed and effective) / unchanged (derived result same as current) / rejected (derived result self-contradictory, not adopted, original contract kept) / no_candidate (no usable result, original contract kept) / stale (shot changed during derivation, result not written; call again after edits), plus note for next step. Insufficient credits returns 402. ★When to use: image generation/precheck/review repeatedly says the number of people is wrong, or a partial shot (hand/prop close-up) is treated as a full-person shot in generation or review, and you have already edited text or bindings—the autofiller only fills blanks and does not overwrite existing contracts; without this tool, edits will not enter the contract. ★Correct order: first update_shot to make the image text correct (who is visible, who is voice-only via character_presence voice_only, unbind anyone who should not appear from character_ids), then call this tool; calling without text edits usually returns unchanged. ★One text AI call, postpaid by token (same chain as autofill_storyboards); inform the customer before calling. ★Only changes this one contract field; does not touch dialogue/prompts/other specialized fields. Generated first/last frames are not auto-regenerated; to update visuals, regenerate frames for this shot (quote first). ★updated invalidates unconsumed frame/video quotes for this shot and the same episode; quote again afterward.",
143
- "get_shot_prompts": "Read the four prompt **bodies** for one shot (image_prompt=first-frame image / video_prompt=dynamic performance / first_frame_prompt=what it looks like at start / last_frame_prompt=what it looks like at end), for direct fine-tuning then writing back with update_shot. Free. ★terminal_desc_missing=true in the response means this shot is marked as a \"state change\" but none of the three places describes the terminal state—last-frame generation will be blocked by the pre-gate. Fix by writing the end state into last_frame_prompt (do not retry image generation; retry will inevitably be rejected again and still charged). ★Also returns the current description (visual description) and lighting (shot lighting)—review_storyboards forbidden-term matches are often in description, so read it here before editing; write lighting into lighting. ★Also returns expression_hint (author-specified facial expression for this shot; null=unspecified, platform infers from dialogue). Edit it with update_shot. expression_inferred is the storyboard AI's inferred expression when the script did not specify expression (read-only; null=no inference, or this shot's dialogue/action/mood/description/intensity changed and the inference is expired and no longer used); it has lower priority than expression_hint—if inference is unsatisfactory, write expression_hint with update_shot to override it. ★Per-shot on demand: read only the shot you edit (episode list get_storyboards does not include prompts). ★Returned asset_tokens are supplemental reference markers in the body (@char:N / @scene:M); keep them unchanged when rewriting. Which character sheet is injected is determined by bindings (character_ids / scene_id in get_storyboards); deleting markers will not remove bound characters. Markers with #variant are the only source for that variant image. Writing a marker for an unbound character will inject that character's image. ★This is the body layer in the storyboard sheet; during image/video generation the platform also appends identity anchors, consistency constraints, and reference-image instructions (not here, and you do not need to write them). Changing prompts does not auto-regenerate images/video; to update visuals, regen the corresponding shot.",
143
+ "get_shot_prompts": "Read the four prompt **bodies** for one shot (image_prompt=first-frame image / video_prompt=dynamic performance / first_frame_prompt=what it looks like at start / last_frame_prompt=what it looks like at end), for direct fine-tuning then writing back with update_shot. Free. ★terminal_desc_missing=true in the response means this shot is marked as a \"state change\" but none of the three places describes the terminal state—last-frame generation will be blocked by the pre-gate. Fix by writing the end state into last_frame_prompt (do not retry image generation; retry will inevitably be rejected again and still charged). ★Also returns the current description (visual description), lighting (shot lighting) and sound_effect (shot sound effects)—review_storyboards forbidden-term matches are often in description / sound_effect, so read them here before editing; write lighting into lighting. ★Also returns the current shot_type (shot size) / angle / camera_movement / continuity_intent (edit intent)—after changing these with update_shot, read them back here to verify (the episode-wide get_storyboards does not include them); null = not set. ★Also returns expression_hint (author-specified facial expression for this shot; null=unspecified, platform infers from dialogue). Edit it with update_shot. expression_inferred is the storyboard AI's inferred expression when the script did not specify expression (read-only; null=no inference, or this shot's dialogue/action/mood/description/intensity changed and the inference is expired and no longer used); it has lower priority than expression_hint—if inference is unsatisfactory, write expression_hint with update_shot to override it. ★Per-shot on demand: read only the shot you edit (episode list get_storyboards does not include prompts). ★Returned asset_tokens are supplemental reference markers in the body (@char:N / @scene:M); keep them unchanged when rewriting. Which character sheet is injected is determined by bindings (character_ids / scene_id in get_storyboards); deleting markers will not remove bound characters. Markers with #variant are the only source for that variant image. Writing a marker for an unbound character will inject that character's image. ★This is the body layer in the storyboard sheet; during image/video generation the platform also appends identity anchors, consistency constraints, and reference-image instructions (not here, and you do not need to write them). Changing prompts does not auto-regenerate images/video; to update visuals, regen the corresponding shot.",
144
144
  "rerender_episode": "Recompose the final cut from the current timeline (use after shot edits/cropping). **Free** (pure ffmpeg+COS), asynchronous in background.",
145
145
  "replace_shot_dialogue": "Replace a shot's dialogue timbre/voice (transcribe + clone + redub). **Synchronous call**, returns product in about 1 minute, postpaid by usage with no debt. Requires this shot to have native-audio video + character voice character sheet audio. ★This is also the cheapest fix for \"this shot did not finish the line / spoke something else\": redub the full line with cloned voice and mute the native-audio segment, **without regenerating video**—charged at TTS tier (per thousand characters), orders of magnitude cheaper than regenerate_shot_video (billed per second; over a hundred credits per second at 720p). Tradeoff: the image lip-sync was performed to the original audio, so after replacement it may mismatch; almost lossless when lips are unclear (back view/long shot/voice-over), use caution on extreme close-ups. ★Product is automatically written back to the shot (returns persisted:true), but written back ≠ included in final cut: rely on productEffective from get_dialogue_repair_status—if true, rerender_episode to recompose; if false, first perform pendingCompose as instructed, then recompose, otherwise the final cut still uses old audio. ★If this shot already has a lip-sync product, the final cut prioritizes the lip-sync version, so replacing track will not take effect. For episode batch use repair_episode_dialogue.\n★Before writeback, the product is verified (same criteria as scan_dialogue_coverage): still truncated, repeated/extra speech (extra_speech), or not the line (off_script) → **not written back**, this cost automatically refunded, and error returns which category—these shots cannot be fixed by voice replacement; use regenerate_shot_video. On success, verify:verified=false means it could not be judged (transcription failed/line too short); it is still written back, but unverified, so listen yourself.",
146
146
  "revoice_narration": "Replace the voice for a shot's **narration/voice-over** (or re-synthesize after editing narration text). **Does not regenerate video**: keeps visuals and on-screen dialogue, only mutes the narration segments, synthesizes them with the current narration voice, mixes back, then verifies. Synchronous call, charged at TTS tier (per thousand characters). ★Edit first, then call: to change voice, first set_character_voice for the \"narration\" character (or design_voice to create one); to change text, first update_shot the narration line in dialogue. ★Pure narration shots (only narration in this shot) work directly; **mixed shots** (on-screen dialogue plus narration) require sentence count to match the speech segments in the video. If not, it errors instead of guessing (a wrong guess could mute on-screen dialogue too)—then only regenerate_shot_video can fix it. ★If the dialogue field has no narration line, it errors directly; if the vendor randomly speaks in a no-dialogue shot, use replace_shot_dialogue mute_only. ★After writeback, the final cut uses it directly (no extra switch); rerender_episode is enough to recompose. If verification fails, it is not written back, and narration synthesis cost is not refunded.",
@@ -160,7 +160,7 @@
160
160
  "get_bgm_status": "Check AI score generation status for an episode: running (whether generation is in progress) + list of library score tracks (track/covered shot segments/fade in/out) + cue count. Free. After score is done, re-run compose_episode to include it in the final cut.",
161
161
  "translate_subtitles": "Translate an episode's subtitles into a second language and enable bilingual subtitles. Backend async, postpaid by usage, no arrears.",
162
162
  "list_dramas": "List all short dramas under my account (drama_id/title/genre/episode count/progress). Free.",
163
- "get_drama": "Read details of one drama (settings/character count/scene count/asset stats, etc.). Free.",
163
+ "get_drama": "Read details of one drama (settings/character count/scene count/asset stats, etc.). Free. frame_chain_mode = the drama-wide cross-shot frame-chain mode (off/strict/reframe; change it with update_project_settings).",
164
164
  "get_characters": "Read the character list for one episode (names/character sheets/reference-sheet readiness). Free. Each character includes structured status: portrait_status/sheet_status (ready=stored in library/pending=generating or under audit·do not click repeatedly/rejected=image generated but rejected by consistency gate and not stored/failed/none) + on rejection: sheet_fail_reason·sheet_retryable·sheet_fail_hint (rejection verdict). ★When sheet_status=rejected, judge by retryable: consistency_rejected can be rerolled once (generate_character_sheet); **repeated rejections with nearly identical fail_hint = anchor fields conflict with character profile (structural guaranteed rejection); rerolling is pure wasted money**—first run run_precheck and check anchor-conflict warnings, remove or align character appearance pinned in visual_lock/art_bible with the profile, then reroll.",
165
165
  "get_scenes": "Read the scene list for an episode (name/description/whether scene image is ready). Free.",
166
166
  "get_assets": "Read all aggregated assets for a drama (characters/scenes/props/images). Free.",
@@ -212,13 +212,13 @@
212
212
  "get_seam_previews": "Check progress and results of preview_seams. Free. While status=running, read progress.done/total; when status=done, each entry of result.seams[] gives: from_shot_id/to_shot_id, transition (effective transition), left/right (in/out points on the source video, src_in_ms/src_out_ms, trim already applied), preview_url (the short clip), compare_image_url (left = last frame of the outgoing shot before the transition starts, right = first frame of the incoming shot after the transition ends), audit (audit_seams conclusion; not_enabled = not enabled for this drama). A non-empty result.synth_skipped_shot_ids means those shots have no synthesized voice-over yet and the preview treats them as silent. A single-shot episode returns seam_count=0.",
213
213
  "build_av_timing_contract": "★Run this first when an external agent assembles the cut itself, or to check why the final cut has the length it has — do not assemble by the seconds written in the storyboard. Free, zero charge (pure ffprobe + local activity detection; no vendor calls and no on-the-fly TTS synthesis). Returns the episode's A/V timing contract. Per shot: source.duration_ms (ffprobe-measured source length, not the storyboard seconds) and excess_over_declared_ms (extra tail the vendor delivered); trim.in_ms/out_ms (source in/out points used in the cut, auto head-trim and trim_shot included; untrimmed shots have full_length=true); action (effective action window and recommended trim window, reusing recommend_trim_window's activity detection); tail (freeze_pad_ms = frames the renderer clones to pad the shot, low_motion_in_cut_ms = low-motion tail still in the cut after the action ends); voice.in_final_cut (mixed_into_video = the voice is already mixed into the clip's audio, never dub it again; separate_track = separate dialogue track, dialogue_track gives its timeline interval; pending_synthesis/missing/unknown/double_voice — see instruction); timeline (start/end on the final-cut timeline, transition_in overlap, transition_out_overlap_ms, exclusive interval). The episode summary gives total duration, total transition overlap, per-track spans and tracks that run past the end of the picture. planned uses the same timeline build as compose_episode; final_cut reads the timeline the last final cut actually rendered and measures the final file (duration_check); drift_vs_planned lists shots that would change if you re-composed now. Async: this tool only starts the job; poll get_av_timing_contract until status=done. include_activity=false skips activity detection (faster, but no action window or low-motion tail).",
214
214
  "get_av_timing_contract": "Check progress and results of build_av_timing_contract. Free. While status=running read progress (stage=build_timeline/activity/probe); when status=done, result.planned is the per-shot contract a re-compose would produce now, result.final_cut is the last final cut (contract = derived from the stored timeline, probed = measured final file, duration_check.matches = total duration agrees within 100 ms, drift_vs_planned = shots that differ; when timeline_association≠verified the stored timeline is no longer the one the final cut rendered, so contract is not provided). ★When assembling yourself, place shots by shots[].timeline and cut sources by trim.in_ms/out_ms; for voice.in_final_cut=mixed_into_video use the clip's own audio and never lay another voice on top. A non-empty result.synth_skipped_shot_ids means those shots have no synthesized voice yet (synthesized and billed at compose time), so their dialogue-track intervals are missing.",
215
- "chain_frames": "Whole-episode first/last-frame relay chain: make each shot's first frame inherit the previous shot's last frame so inter-shot visuals are continuous (smoother than generating each shot independently). ★When to call: after first frames are done and any last frames required by tail_frame_plan are also filled, before review_frames / generate_videos. The platform only auto-runs this once when batch frame generation on the official site finishes; episodes generated shot by shot (generate_frames / generate_shot_frame) often have never been chained — get_storyboards seam_state=unchained means this kind of seam.\n★First use dry_run:true (free, does not write DB or generate images): returns planned_copy / planned_reframe / estimated_points / needs_last_frame. copy = directly replace this shot's first frame with the previous shot's last frame (free, but this shot's shot size becomes the same as the previous shot); reframe = use the previous shot's last frame as an anchor to regenerate this shot's first frame according to this shot's visual description (one image per seam, preserves shot size). Tell the client the plan and estimated_points; after confirmation, call again **without dry_run** to execute (postpaid by usage).\n★The platform decides which seams to chain: intentional cuts (scene/time jump/costume change/insert shot), shots with existing video, and already-chained seams are skipped — “already chained” = the first frame is the previous shot's last frame, or reframe is chained to the previous shot's **current** last frame, so repeated execution will not charge again. If the previous shot's last frame is later regenerated, that seam will reappear in the plan; that seam is indeed broken. To fill individual seams, use chain_shot_from_prev / chain_shot_from. Shots whose first frame is changed by execution and already have video will be marked pending regeneration. ★Execution only dispatches reframe and does not wait for image generation: use get_jobs to view first_frame generation rows for these shots; wait until all pending/processing are finished (for failed, check error_msg; for a single seam use chain_shot_from to reconnect; while the old first frame still exists, get_storyboards frame_status remains ready and failure is not visible), then use get_storyboards to verify seam_state and review_frames — auditing too early will audit the old first frame, and the token will be invalidated later.",
215
+ "chain_frames": "Whole-episode first/last-frame relay chain: make each shot's first frame inherit the previous shot's last frame so inter-shot visuals are continuous (smoother than generating each shot independently). ★When to call: after first frames are done and any last frames required by tail_frame_plan are also filled, before review_frames / generate_videos. The platform only auto-runs this once when batch frame generation on the official site finishes; episodes generated shot by shot (generate_frames / generate_shot_frame) often have never been chained — get_storyboards seam_state=unchained means this kind of seam.\n★First use dry_run:true (free, does not write DB or generate images): returns planned_copy / planned_reframe / estimated_points / needs_last_frame. copy = directly replace this shot's first frame with the previous shot's last frame (free, but this shot's shot size becomes the same as the previous shot); reframe = use the previous shot's last frame as an anchor to regenerate this shot's first frame according to this shot's visual description (one image per seam, preserves shot size). Tell the client the plan and estimated_points; after confirmation, call again **without dry_run** to execute (postpaid by usage).\n★The platform decides which seams to chain: intentional cuts (scene/time jump/costume change/insert shot), shots with existing video, and already-chained seams are skipped — “already chained” = the first frame is the previous shot's last frame, or reframe is chained to the previous shot's **current** last frame, so repeated execution will not charge again. If the previous shot's last frame is later regenerated, that seam will reappear in the plan; that seam is indeed broken. To fill individual seams, use chain_shot_from_prev / chain_shot_from. When the drama's frame_chain_mode=off the whole episode is skipped (empty plan); to chain, first switch it back to reframe/strict with update_project_settings. Shots whose first frame is changed by execution and already have video will be marked pending regeneration. ★Execution only dispatches reframe and does not wait for image generation: use get_jobs to view first_frame generation rows for these shots; wait until all pending/processing are finished (for failed, check error_msg; for a single seam use chain_shot_from to reconnect; while the old first frame still exists, get_storyboards frame_status remains ready and failure is not visible), then use get_storyboards to verify seam_state and review_frames — auditing too early will audit the old first frame, and the token will be invalidated later.",
216
216
  "chain_shot_from_prev": "(Free) Directly set the previous shot's last frame as this shot's first frame: visuals connect 100%, zero cost, no image generation. ★Use when: the two shots are a continuation from the same camera position and same shot size (seam_state=unchained/broken and this shot should already share the previous shot's composition). ★Do not use for seams with shot-size changes (wide → close-up, etc.): it will overwrite this shot's shot-size design, and later image generation may be judged “inconsistent with design” — for such seams use chain_shot_from with mode=reframe. If this shot already has video, it will be marked pending regeneration. If this shot's first frame was uploaded by the client (first_frame_source=upload) or is client-locked (first_frame_pinned), the call is rejected (409 reason=user-locked-frame); pass force:true only to overwrite it (any execution mode requires explicit client consent, including managed mode). force releases the upload / lock protection, and the new frame needs client re-acceptance.",
217
217
  "quote_chain_shot_from": "(Free quote) chain_shot_from with mode=reframe deducts **one image** (regenerate this shot's first frame anchored on the source frame); quote before execution (quote confirmation follows execution mode: professional mode / unconfirmed plan / this step is customer-controlled → explain to the customer and proceed only after customer approval; do not decide for them; this step is autopiloted → do not ask the customer, execute per get_production_plan autopilot.default_decisions, and the platform records it in get_autopilot_log). Returns quote_id / estimated_points; quote_id is one-time and valid only for this shot. mode=copy needs no quote. If this shot's first frame was uploaded by the client or is locked, no quote is issued without force (409 reason=user-locked-frame, not priced); after the client explicitly agrees to replace it, pass force:true to both the quote and the execution.",
218
218
  "chain_shot_from": "Use the first or last frame of **any shot** in the same episode as this shot's first frame. Two modes:\n· mode=copy(default, free): directly replace this shot's first frame with the source frame, pixel-identical—good for “return to the exact same image” or continuing the same camera position.\n· mode=reframe(deducts one image, must include quote_id from quote_chain_shot_from): regenerate the first frame anchored on the source frame and based on this shot's visual description—character/clothing/prop/lighting/scene continuity, while preserving this shot's own shot size and composition. Use this when the seam must connect while shot size changes.\n★If the source is not the previous shot's last frame (bookend / return to a previous image), the platform records the seam between this shot and the previous shot as an “intentional cut”, and automatic frame chaining will no longer overwrite it. If this shot already has video it will be marked for regeneration; if its first frame was uploaded by the customer or is finalized it will be rejected (409 reason=user-locked-frame, no image dispatched, no charge)—pass force:true only when overwriting it has explicit customer approval (required in every execution mode, including autopilot). force releases the upload / finalized protection and the new frame needs customer re-acceptance; for mode=reframe the quote must also carry force.",
219
219
  "quote_align_prev_shot": "(Free quote) align_prev_shot regenerates **the previous shot's video** (deducts one video); quote before execution (quote confirmation follows execution mode: professional mode / unconfirmed plan / this step is customer-controlled → explain to the customer and proceed only after customer approval; do not decide for them; this step is autopiloted → do not ask the customer, execute per get_production_plan autopilot.default_decisions, and the platform records it in get_autopilot_log). Returns quote_id / estimated_points / prev_storyboard_id(which shot will be regenerated); if first-time portrait verification fee applies, kyc_first_time_points is listed separately.",
220
220
  "align_prev_shot": "Seam-crack repair “align to previous shot”: this shot's first frame **does not change**; use it as the ending image and regenerate **the previous shot's video** in first/last-frame mode (previous shot's first frame unchanged), so the previous shot truly ends on this shot's opening image. Deducts one video and must include quote_id from quote_align_prev_shot. ★Use when the customer changed this shot's first frame (e.g. uploaded or regenerated a better one), but the previous shot's video is already done and you don't want to alter this shot's first frame to accommodate it. Do not use when neither shot has video yet—changing the first frame (chain_shot_from_prev / chain_shot_from) is cheaper. Async: poll get_storyboards for the previous shot's video_status.",
221
- "get_scene_group_plan": "Get the scene group plan for an episode (how shots are grouped for continuous long shots). Free.",
221
+ "get_scene_group_plan": "Get the scene group plan for an episode (how shots are grouped for continuous long shots). Free. ★Check the top-level `active` first: false = long-take mode (scene_group_mode) is off for this drama, so `groups` is only a preview of how shots would be grouped once enabled and is **not in effect** — videos are generated and billed shot by shot, and regenerate_shot_video only touches that one shot; to use groups, enable long-take mode via update_project_settings first. When active is true, only groups with merged=true are generated in one pass.",
222
222
  "quote_regenerate_scene_group": "Quote: how many credits to regenerate **one scene group** (one video request for the whole group, preserving intra-group continuity). Returns quote_id. No charge. shot_numbers must exactly equal the shot numbers of one group in get_scene_group_plan.\n★Optional video_engine: swap engine only for this whole-group regeneration (does not change the series-level video_engine); the quote is calculated with it and the quote_id pins it, so regenerate_scene_group will dispatch with it. The whole group is still one final cut, so total group duration must fit within that engine's single-segment limit (hailuo-3 15s; seedance-2.5/wan3.0 30s) and support this series resolution, otherwise 400—if so, use update_shot to set video_engine on individual shots (shots with it set will generate separately). Quote is calculated per shot (per-shot fallback if whole-group fails; per-shot is the upper bound); normal-path actual deduction is usually lower.",
223
223
  "regenerate_scene_group": "After confirmation, regenerate one scene group (one video request for the whole group, async in background; poll each shot's video_url via get_storyboards). Grouping and engine are pinned by quote_id and cannot be changed here; if any shot in the group changes after quote, or grouping changes, the quote becomes invalid (409); just re-quote (free). ⚠️ Batch quote confirmation flow: first call the corresponding quote_* tool to get estimated_points and quote_id, then call this tool with quote_id (quote confirmation follows execution mode: professional mode / unconfirmed plan / this step is customer-controlled → explain to the customer and proceed only after customer approval; do not decide for them; this step is autopiloted → do not ask the customer, execute per get_production_plan autopilot.default_decisions, and the platform records it in get_autopilot_log). Autopiloted step quotes must stay within the hard budget cap; if blocked by 402 BUDGET_WOULD_EXCEED, stop and ask the customer. ★**Image-generation quotes (character sheet / scene image / frame generation) provide two numbers**: estimated_points is the **upper bound** (estimated by the model's max reference-image count, ensuring you won't start with an underbudget and get interrupted by 402 halfway); typical_points in the same response is the **usual cost**. Tell the customer both—only saying the upper bound makes it seem much more expensive (with max reference images the upper bound can exceed 2× the usual value), while only saying the usual cost may leave insufficient balance. For fixed-price models they are equal, so one number is enough. Video-generation quote and deduction use the same function; no such range exists.",
224
224
  "generate_scene_groups": "Generate scene groups (group continuous shots; the foundation for continuous long shots / batch frame generation). Async in background.",
@@ -27,7 +27,7 @@
27
27
  "get_frame_retry_diagnosis": "免费只读查询图片任务的连败诊断、证据任务 ID 和下一步动作。diagnosis_required 时先调用本工具:审计故障重审已有候选,未知原因先复核;不得原样重抽或擅自改剧本。★返回的 recovery_options 是出图失败后的三选一(按免费→免费→付费排序,needs_attention=false 时不必打扰客户):① adopt_rejected 从被拒/落选候选里挑审计误判的(get_frame_candidates→adopt_frame_candidate,candidates 是可采用张数);② upload_fixed 拿本镜平台候选局部修补后 upload_shot_frame;③ regenerate 按诊断改内容后 quote_shot_frame→generate_shot_frame。ask_customer=true 时三条都摆给客户由客户选,不许替客户放行或擅自付费重抽;failure_class=transient 是偶发失败、稍等按原输入重试即可,not_self_healable 是欠费/点数不足/配额满/模型不可用、重生也无用(regenerate.available=false),先处理账户或换模型。",
28
28
  "get_image_dispatch": "免费只读查询一张镜头帧的派发台账:实际用了哪几张参考图、每张的用途与所属角色、是否送达模型、没送达或派发前被剔除的是哪一步因什么被剔(如时代预检点名的冲突物件),以及真正发给图片模型的最终提示词。用于回答「到底用了哪张图、为什么画面不像」;先查清再决定是否重出,别靠猜反复付费重抽。ledger=partial/none 表示该图生成于台账上线前,缺失字段如实为 null。",
29
29
  "get_frame_candidates": "免费只读:一个镜头首帧/尾帧的**全部候选**(出图验收工作台同一份数据)。每张候选给原图地址(被拒的也在,可直接打开看原尺寸)、状态、是否为当前在用(adopted)、拒因 reject(main 主码 / code 具体病因 / details 明细 / class 分流:needs_content_fix=要改内容、content_retryable=内容问题但重掷约 1/3 能成、transient=审核没审成或偶发——不是画面不合格)、审计证据 audit(warnings 中文结论、expected 设计要求、derived_shot_type 画面推出的景别及依据、boxes 主体与身体部位在画面里的位置框;2026-10-07 前的候选无存档为 null,不代表审过)、以及这张图实际用了哪些参考图(references:用途/所属角色/是否送达)。storyboard.tail_endstate 是「尾帧≈首帧」检查结论(current=false 表示结论对应的不是现在这两张图)。★镜头反复被拒、或客户问「被拒的那几张到底什么样 / 为什么不采用」时先调它:逐张看原图和证据,再决定改分镜、改参考还是重掷——别盲目付费重抽。要看某张的最终提示词用 get_image_dispatch(generation_id)。客户看过原图确认画面没问题、是审计误判时,用 adopt_frame_candidate 人工采用(免费);manual_adoption 非空 = 该候选是人工放行的。recovery_options 按帧位给出失败后的三选一(挑误拒 / 修图上传 / 重生),与 get_frame_retry_diagnosis 同口径。",
30
- "adopt_frame_candidate": "免费:人工采用一张已出完的首帧/尾帧候选(被审计拒掉 rejected、落选 dismissed,或曾经在用后被换下的 completed),作为本镜在用帧——审计误判时的人工兜底(例如作者契约写明的设定被判成冲突),也可随时换回之前那张。★必须先用 get_frame_candidates 让客户看过原图和拒因、客户明确同意采用后才调(采用被拒候选任何执行模式都须客户明确同意,托管也不例外);不许为了让流程走下去自行放行。只能采用本镜本帧位、已出完、有画面、且不是当前在用的那张;会在该候选上记录人工放行(谁/何时/原拒因),原拒因保留供统计。本镜已有视频的会标成待重生(视频是按旧帧出的,需 regenerate_shot_video)。本镜该帧是客户上传或已定稿的,要带 replace_user_frame:true 才会替换(并解除定稿)。同帧位有在途出图或本镜视频在途时返回 409,等它结束再采用。",
30
+ "adopt_frame_candidate": "免费:人工采用一张已出完的首帧/尾帧候选(被审计拒掉 rejected、落选 dismissed,或曾经在用后被换下的 completed),作为本镜在用帧——审计误判时的人工兜底(例如作者契约写明的设定被判成冲突),也可随时换回之前那张。★必须先用 get_frame_candidates 让客户看过原图和拒因、客户明确同意采用后才调(采用被拒候选任何执行模式都须客户明确同意,托管也不例外);不许为了让流程走下去自行放行。★采用前先对照本镜分镜(get_storyboards 的 first_frame_prompt / last_frame_prompt / action_in / action_out / movement)确认:采首帧要是动作起点、采尾帧要是动作终点——首帧候选若已是动作终态(人已到位、动作已做完)或把运镜终点画进了起点,采用后视频里就没有动作过程,换一张或改提示词重出。只能采用本镜本帧位、已出完、有画面、且不是当前在用的那张;会在该候选上记录人工放行(谁/何时/原拒因),原拒因保留供统计。本镜已有视频的会标成待重生(视频是按旧帧出的,需 regenerate_shot_video)。本镜该帧是客户上传或已定稿的,要带 replace_user_frame:true 才会替换(并解除定稿)。同帧位有在途出图或本镜视频在途时返回 409,等它结束再采用。",
31
31
  "get_stale_portrait_frames": "免费只读查询一集里哪些镜头的在用首帧/尾帧,是拿角色已被换掉的旧资产(旧定妆图、旧设定图、旧身体/发型图)画的。换定妆图后用它确认影响范围,再由客户决定重出哪些镜(重出要付费,本工具不改任何数据)。verdict=stale 必附证据:ledger-old-asset(派发台账直接记录用了旧图)/ references-previous-asset(参考图里有该角色以前的旧资产)/ portrait-born-after-frame(当前定妆图晚于该帧诞生);证不了的标 unknown 并给原因,不当作已过期。has_video=true 表示该镜视频也基于旧帧,重出帧后视频需重生。",
32
32
  "get_asset_versions": "只读查询一个镜头的全部图片/视频版本、历史查看链接、依赖 ID 与版本哈希,以及已生成→与当前输入一致→审核有效→已采用四项独立事实。历史缺少依赖记录时显示未知,不补造快照。免费。video_lock 是客户锁定的已验收视频(lock_shot_video):locked=true 时这条按沿用算有效,frames_changed_since_lock=true 表示锁定后帧又改过但不需要重出。",
33
33
  "lock_shot_video": "锁定某镜当前在用的视频为客户已验收版本(免费,不生成、不改素材)。用于客户明确说「这一镜就用这条」之后,首尾帧/场景/角色又被改过的情形:锁定后资产变动不再把这镜判过期——review_videos 不报 video_stale(改报 warning video_locked_frames_changed)、get_asset_versions 里这条 acceptance_locked=true 仍算当前有效(漂移原因照实列在 drift_while_locked)、原声剧声线 stale_shots 不列它、终拼预检不报编辑后未重生;regenerate_shot_video / edit_video_shot / repaint / reskin / 上传或清除实拍 / 整集 generate_videos 会替换它时一律 409 VIDEO_LOCKED。锁里冻结视频行 id 与它当时的生成输入(首尾帧 URL、prompt、参考清单)。只能锁当前在用的那条(传 generation_id 时必须正好是它,否则 409 NOT_CURRENT_VIDEO;本镜没视频 409 NO_VIDEO)。视频被别的路径换掉后锁自动失效(get_asset_versions 的 video_lock.broken=true)。★只有客户明确确认沿用才锁,不得把生成完成或模型判断当客户验收;要重出须客户同意后先 unlock_shot_video。",
@@ -51,11 +51,11 @@
51
51
  "autofill_storyboards": "(推荐)AI 一键给全集(或 storyboard_ids 指定的几镜)分镜补全空缺字段,默认**只填空缺、不覆盖已有**(overwrite=true 才覆盖)。提升分镜完整性,出图前做。后台异步,文本步后付(按实际调 AI 的镜计费)。★跑之前先确认角色/场景/道具绑定无误(对照客户原稿逐镜核对 get_storyboards 的 character_ids / scene_id / prop_ids)。补全之后发现漏绑用 update_shot 补绑即可,**不要整集重导**——重导会替换分镜、补全结果作废、要重新付费。★**先 quote_autofill 报价**(同样的 overwrite / storyboard_ids),把 shots_to_fill 与 estimated_points / typical_points 告诉客户,**客户同意再跑**本工具。★跑完用 get_autofill_status 看回执(写了哪些字段各几镜、跳过几镜、还缺几镜契约)告诉客户——补全写的内部字段 get_storyboards 读不到,别让客户以为白扣。★拆镜落库时平台已自动补过一轮:只填空模式下已没有空缺的镜(六个叙事文本字段都已有、有台词的镜声音方向也已有,契约阀开时契约也已有)直接跳过,不调 AI、不扣费;overwrite:true 才会整集重跑并逐镜计费。★补全写的是叙事/节奏类内部字段与构图契约,get_storyboards / get_shot_prompts 不返回这些字段,回读看不到变化属正常,看 get_autofill_status 回执里的计数即可;它**不改**出图/视频提示词正文。★平台开启契约自动补全时,也会尝试给**没有构图契约**的镜补上契约(是否开启以导入回执 contract_coverage 的 note 为准;可见人数/主体范围/景别,出图与审核都按它判;默认 overwrite:false 时已有契约不动,**overwrite:true 会连已有契约一起重写**)——导入时关了 auto_complete、回执 contract_coverage 的 note 指向本工具的,出图前调一次。本集已有补全在跑时本次**不排队**(防重复点击重复扣费),新导入的镜要等 get_autofill_status 到 done 后再调。★想先小范围试跑看效果:传 storyboard_ids(1~50 个本集镜 id,用 get_storyboards 取),只补这些镜,其它镜不调 AI、不扣费;不传 = 整集。本集已有补全在跑时子集不启动,回执 started=false、reason=fill batch already running,等 get_autofill_status 到 done 再调。",
52
52
  "enhance_shot_prompts": "(可选增强·★非必须·有副作用)AI 批量增强全集 image_prompt。★会**改写已有 prompt**(含手调的);且**务必 generate_frames 之前**做——出图后再改 prompt 会让图陈旧、要重生浪费钱。非跑通一部片的必需,客户点名再做。后台异步,文本步后付。",
53
53
  "complete_ending_motifs": "(可选增强·★非必须·条件性)给结尾段补全缺失的视觉母题(嫁接视觉回响到结尾镜)。★前置:该剧已设 motifs(没设=空操作);会**改结尾镜 action/描述**,务必出图前做(否则结尾镜已出图会陈旧)。后台异步,文本步后付。",
54
- "tail_frame_plan": "★免费只读:这一集**哪几镜需要独立尾帧**(末态≠首态的镜——大运镜/物体脱手/状态改变)。判定用的就是平台出视频时那套判据,你自己是猜不出来的,所以出完首帧务必调一次。返回 shots_needing_last_frame(总数)、ready(已有首帧、现在就能补尾帧的镜)、pending_first_frame(还需要尾帧但首帧尚未落地的镜——等首帧出完再调一次本工具)。拿到 ready 清单后:quote_frames + generate_frames 带 frame_type=last_frame 即可批量补。★尾帧补完(或本工具报 0)之后的下一步是接缝:chain_frames(dry_run:true) 看计划与预估、客户确认后执行,再 review_frames。★跳过尾帧不会报错,但那些镜出视频时只有首帧一个锚,末态由模型自由发挥——动作做不到位、大运镜结束又回到起点构图,多半就是这么来的。零扣费,可随时调。",
54
+ "tail_frame_plan": "★免费只读:这一集**哪几镜需要独立尾帧**(末态≠首态的镜——大运镜/物体脱手/状态改变)。运镜镜(摇/推/拉/移/升降,起止画面不同)按剧灰度计入;运镜要写进分镜的 movement 或 action(如「镜头缓慢向下摇到…」),只写在提示词里的「固定机位」会被当成静止。判定用的就是平台出视频时那套判据,你自己是猜不出来的,所以出完首帧务必调一次。返回 shots_needing_last_frame(总数)、ready(已有首帧、现在就能补尾帧的镜)、pending_first_frame(还需要尾帧但首帧尚未落地的镜——等首帧出完再调一次本工具)。拿到 ready 清单后:quote_frames + generate_frames 带 frame_type=last_frame 即可批量补。★尾帧补完(或本工具报 0)之后的下一步是接缝:chain_frames(dry_run:true) 看计划与预估、客户确认后执行,再 review_frames。★跳过尾帧不会报错,但那些镜出视频时只有首帧一个锚,末态由模型自由发挥——动作做不到位、大运镜结束又回到起点构图,多半就是这么来的。零扣费,可随时调。",
55
55
  "quote_frames": "报价:给某一集批量出帧要多少点。返回 frames_to_generate、estimated_points、quote_id。零扣费。frame_type 默认 first_frame(只给缺首帧的镜出);last_frame 只给「已有首帧且缺尾帧」的镜出;both 两者都补。★报价按**实际会用的模型与分辨率**分档,响应带 price_breakdown(逐档张数与单价);打算在 generate_frames 里临时换模型,报价时就要把同一个 image_model 传进来,否则两边不是一个价。★两边必须传同一个 image_model —— 不一致会被直接拒(400 IMAGE_MODEL_MISMATCH),因为模型决定计费档,不同源就是「预估≠扣费」。两边都不传也算一致(用该剧设定的模型)。已下架的型号(FLUX 全系列)一律拒收,别再传。★返回两个数:estimated_points 是**上界**(按参考图张数上限估,拿它准备余额就不会中途 402),typical_points 是**通常花费**。两个都告诉客户,只报上界会让人以为贵得多。固定价模型(如 Nano Banana 系列)下两者相等。",
56
56
  "generate_frames": "确认后批量出帧:后台异步。用 get_storyboards 轮询,first_frame_image/last_frame_image 逐镜填充即完成。★图片生成较慢——每张几十秒到数分钟(尤其高清模型),整集可能十几分钟。轮询看 frame_status:**pending=还在生成(继续耐心等,别当失败、别重复调 generate_frames,重复触发=白花钱)**、ready=完成、failed=才是真失败。别因为「等了一会儿还没出」就判定生成失败或重试。出视频前必须先出帧,否则视频会退化成无一致性锚点的画面。★**出帧前先把两个锚备齐**:定妆图(generate_portraits_and_sheets,锚人)与空景基板(generate_scene_images,锚景)。缺基板不会拦你,但每个场景的第一镜会没有背景锚(平台的兜底补图只惠及同场景后续镜),背景从首镜起就开始漂。用 get_pipeline_status 的 generate_scene_images 步核对 completed/total。frame_type 要与 quote_frames 用的一致(默认 first_frame)。★这是**批量补缺帧**:只给「缺该帧」的镜出图,已有首帧的镜会跳过——这是正常设计、不是\"系统拒绝重出\"。要**重出/重画某一镜已有的帧**(如换了定妆图要让新图生效),用 generate_shot_frame(单镜重生,平台带身份锚),不是这个工具、更不是自制图 upload_shot_frame。★**本工具默认只出首帧,出帧是两趟**:首帧出完必须调一次免费的 tail_frame_plan——它按平台自己的判据告出哪几镜需要独立尾帧(末态≠首态:大运镜/物体脱手/状态改变,占比约三成,你自己猜不出来),再用 frame_type=last_frame 批量补。生产实测 32 集里 30 集整集只出了首帧、其中 23 集一路出完视频:那些镜出视频时只有首帧一个锚,末态由模型自由发挥。本工具响应体里的 shots_needing_last_frame 就是这个数,不为 0 就别直接去 review_frames。★响应里的 frames_planned 是**计划数,不是已成功数**——本接口在后台派发循环开跑之前就返回了。真实进度只看 get_storyboards 的 first_frame_image / get_jobs 的逐条生成记录;余额不足(402)会中止整批,此时轮询再久也不会有结果,应去查余额而不是继续等。★★**个别镜反复出不来、其余镜都好了**:那不是等得不够久,是这几镜被内容闸连拒。看 get_storyboards 的 fail_reason(repeat_rejected / diagnosis_required / needs_content_fix / contract_rejected),若 diagnosis_required,先按 fail_hint 诊断已有候选;审计错误先重审,证据不足先复核,不要原样重抽或擅自改剧本。然后**跑 run_precheck**(事后也能跑,会告诉你是哪种矛盾),按它的提示用 update_shot 改景别/描述/绑定角色再重生。别继续 generate_frames 空转,也别把客户支去外部工具做图——外部图绕开身份锚与帧审计,人脸服装画风必漂。\n★【分镜审查硬闸·免费】本步前必须先调 review_storyboards:把返回的 findings 逐条原样告诉客户(每条带 code=问题类型、shots=命中镜号、action=该调哪个工具修),再把 review_token 传进本工具。未审查会被 400 拒。审查后又改了内容 → token 自动失效,复审一次即可(仍免费)。单镜工具(generate_shot_frame / regenerate_shot_video)只核本镜与相邻镜:改了别的镜不用复审;本镜、相邻镜或共享资产变了才 400——这时带 base_review_token=<旧 token> 调审查工具做增量复审,只重审变更镜,质检也只看变更镜。有 error 时默认拦截;客户知情并坚持照现状继续,才带 acknowledge_review:true——带病推进大概率产出废片且照常扣费(acknowledge_review 只代表客户本人同意,任何执行模式都须客户明确同意,托管也不例外);托管环节只有白名单内的启发式 error 能带 auto_acknowledge:true 放行(平台判,不在白名单回 400 AUTOPILOT_MUST_ASK:must_ask_customer=true 才暂停问客户,false = 按 action 自修复审)。★灰度剧还要你(agent)亲自质检:按 review_storyboards 返回的 agent_qc 逐件看素材、逐条答清单,调 submit_qc_report 提交后这张 token 才能用(没交 → 400 agent_qc_required;报告有问题 → 与 error 同样默认拦)。\n★【资产层硬闸·免费】还要先跑 review_assets(角色形象图/场景图/道具图),把它的 review_token 作为 asset_review_token 传进来(与分镜层的 review_token 并存,两张都要;灰度剧缺了会 400 并点名 review_assets)。出完帧不会让资产 token 失效。⚠️ 批量报价确认流程:先调对应的 quote_* 工具拿 estimated_points 与 quote_id,再用 quote_id 调本工具(报价确认按执行模式:专业模式 / 未确认方案 / 本环节由客户把控 → 讲给客户、客户同意才做,别替客户决定;本环节托管 → 不问客户,照 get_production_plan 的 autopilot.default_decisions 执行,平台记进 get_autopilot_log)。托管环节报价须在预算硬上限内,被 402 BUDGET_WOULD_EXCEED 拦下就停下问客户。★**出图类报价(定妆图/场景图/出帧)给的是两个数**:estimated_points 是**上界**(按该模型参考图张数上限估,保证你不会按低了的预算开跑、出到一半 402 中断);同一响应里的 typical_points 是**通常花费**。两个都要告诉客户——只说上界会让人以为贵得多(满参考图的上界可达通常值的 2 倍以上),只说通常值又会让余额准备不足。固定价模型下两者相等,这时说一个数就行。出视频的报价与扣费同函数,不存在这个区间。",
57
- "quote_shot_frame": "报价:重画/补出**某一镜的某一帧**要多少点(一帧=一张图)。返回 estimated_points、quote_id。零扣费。客户说「第 N 镜画错了/要改」时用它,而不是拿别的图像平台出图再 upload_shot_frame。★响应带 billing_kind/unit_points(实际计费档与单价);要在 generate_shot_frame 里换模型,报价时传同一个 image_model。★两边必须传同一个 image_model —— 不一致会被直接拒(400 IMAGE_MODEL_MISMATCH),因为模型决定计费档,不同源就是「预估≠扣费」。两边都不传也算一致(用该剧设定的模型)。已下架的型号(FLUX 全系列)一律拒收,别再传。★返回两个数:estimated_points 是**上界**(按参考图张数上限估,拿它准备余额就不会中途 402),typical_points 是**通常花费**。两个都告诉客户,只报上界会让人以为贵得多。固定价模型(如 Nano Banana 系列)下两者相等。",
58
- "generate_shot_frame": "确认后给**某一镜**出帧或重生该帧(异步)。这是修某一镜画面的正路:平台会带上该镜的角色身份锚、场景/道具参考图、画风锚与帧审计,重生出的图与全片一致;用外部工具出图再上传会绕开这整条链路,人物/服装/画风必漂。重生会覆盖该帧现有图(含此前上传的),并把本镜视频标为待重生。尾帧需本镜首帧已就绪(否则先用 first_frame 或 both)。完成判据:轮询 get_storyboards 看该镜 first_frame_image/last_frame_image 变化。\n★继承重开(reopen_pair_id):get_storyboards 某镜带这个字段时,原样传进来可以只重掷首尾帧里真正有问题的那一侧——另一侧此前已经生成好的候选原样保留,不重新生成、不重新计费。传了它就不用再传 frame_type(会被忽略,由平台判定该重哪一侧);quote_id 仍要用 quote_shot_frame 报价(frame_type 传 first_frame 或 last_frame 均可,单帧同价)。若该镜没有 reopen_pair_id 字段(不满足继承条件),这个参数不要传,走常规 frame_type 重试。\n★★出尾帧若被拦下并提示「此镜标为状态改变,但没有任何地方说明结束时是什么样子」:正解是用 update_shot 把结束状态写进 last_frame_prompt 再出,**别直接加 allow_missing_terminal 硬上**——这类镜照现状出尾帧的历史成功率只有 9.4%(有终态描述的 40.2%),硬上多半是白扣一次钱。只有确认这一镜就是要「几乎不变」的画面时才带那个参数。\n★一键出片托管环节:同一镜重出帧最多 3 轮(一次调用算一轮,both 也算一轮),到上限回 **409 AUTOPILOT_SHOT_REGEN_LIMIT**(未派发、未扣费,quote 未消耗)——别换个工具绕,停下问客户:客户同意再出就照常报价、生成时带 customer_approved_more_regens:true(再给一份上限);客户接受现状就往下走,下一步收费调用带 acknowledge_review:true 记下确认。专业模式与客户把控的环节不受这个上限约束。\n★【分镜审查硬闸·免费】本步前必须先调 review_storyboards:把返回的 findings 逐条原样告诉客户(每条带 code=问题类型、shots=命中镜号、action=该调哪个工具修),再把 review_token 传进本工具。未审查会被 400 拒。审查后又改了内容 → token 自动失效,复审一次即可(仍免费)。单镜工具(generate_shot_frame / regenerate_shot_video)只核本镜与相邻镜:改了别的镜不用复审;本镜、相邻镜或共享资产变了才 400——这时带 base_review_token=<旧 token> 调审查工具做增量复审,只重审变更镜,质检也只看变更镜。有 error 时默认拦截;客户知情并坚持照现状继续,才带 acknowledge_review:true——带病推进大概率产出废片且照常扣费(acknowledge_review 只代表客户本人同意,任何执行模式都须客户明确同意,托管也不例外);托管环节只有白名单内的启发式 error 能带 auto_acknowledge:true 放行(平台判,不在白名单回 400 AUTOPILOT_MUST_ASK:must_ask_customer=true 才暂停问客户,false = 按 action 自修复审)。★灰度剧还要你(agent)亲自质检:按 review_storyboards 返回的 agent_qc 逐件看素材、逐条答清单,调 submit_qc_report 提交后这张 token 才能用(没交 → 400 agent_qc_required;报告有问题 → 与 error 同样默认拦)。\n★【资产层硬闸·免费】还要先跑 review_assets(角色形象图/场景图/道具图),把它的 review_token 作为 asset_review_token 传进来(与分镜层的 review_token 并存,两张都要;灰度剧缺了会 400 并点名 review_assets)。出完帧不会让资产 token 失效。⚠️ 批量报价确认流程:先调对应的 quote_* 工具拿 estimated_points 与 quote_id,再用 quote_id 调本工具(报价确认按执行模式:专业模式 / 未确认方案 / 本环节由客户把控 → 讲给客户、客户同意才做,别替客户决定;本环节托管 → 不问客户,照 get_production_plan 的 autopilot.default_decisions 执行,平台记进 get_autopilot_log)。托管环节报价须在预算硬上限内,被 402 BUDGET_WOULD_EXCEED 拦下就停下问客户。★**出图类报价(定妆图/场景图/出帧)给的是两个数**:estimated_points 是**上界**(按该模型参考图张数上限估,保证你不会按低了的预算开跑、出到一半 402 中断);同一响应里的 typical_points 是**通常花费**。两个都要告诉客户——只说上界会让人以为贵得多(满参考图的上界可达通常值的 2 倍以上),只说通常值又会让余额准备不足。固定价模型下两者相等,这时说一个数就行。出视频的报价与扣费同函数,不存在这个区间。",
57
+ "quote_shot_frame": "报价:重画/补出**某一镜的某一帧**要多少点(一帧=一张图)。返回 estimated_points、quote_id。零扣费。客户说「第 N 镜画错了/要改」时用它,而不是拿别的图像平台出图再 upload_shot_frame。★响应带 billing_kind/unit_points(实际计费档与单价);要在 generate_shot_frame 里换模型,报价时传同一个 image_model。★两边必须传同一个 image_model —— 不一致会被直接拒(400 IMAGE_MODEL_MISMATCH),因为模型决定计费档,不同源就是「预估≠扣费」。两边都不传也算一致(用该剧设定的模型)。已下架的型号(FLUX 全系列)一律拒收,别再传。★frame_type=both 时,平台判这一镜不需要独立尾帧(末态≈首态、没有运镜)会只出首帧:报价 frames_to_generate=1、只计首帧,并带 last_frame_skipped 说明原因——**原样告诉客户尾帧不会出**。客户确实要尾帧(例如起止画面不同的运镜)就报价与生成都带 force_independent_last_frame:true。★返回两个数:estimated_points 是**上界**(按参考图张数上限估,拿它准备余额就不会中途 402),typical_points 是**通常花费**。两个都告诉客户,只报上界会让人以为贵得多。固定价模型(如 Nano Banana 系列)下两者相等。",
58
+ "generate_shot_frame": "确认后给**某一镜**出帧或重生该帧(异步)。这是修某一镜画面的正路:平台会带上该镜的角色身份锚、场景/道具参考图、画风锚与帧审计,重生出的图与全片一致;用外部工具出图再上传会绕开这整条链路,人物/服装/画风必漂。重生会覆盖该帧现有图(含此前上传的),并把本镜视频标为待重生。尾帧需本镜首帧已就绪(否则先用 first_frame 或 both)。完成判据:轮询 get_storyboards 看该镜 first_frame_image/last_frame_image 变化。★回执的 frames_dispatched 是真派出去的张数;both 的尾帧被平台判为不需要时会带 skipped_frames(没出、没扣尾帧的钱),原样告诉客户。\n★继承重开(reopen_pair_id):get_storyboards 某镜带这个字段时,原样传进来可以只重掷首尾帧里真正有问题的那一侧——另一侧此前已经生成好的候选原样保留,不重新生成、不重新计费。传了它就不用再传 frame_type(会被忽略,由平台判定该重哪一侧);quote_id 仍要用 quote_shot_frame 报价(frame_type 传 first_frame 或 last_frame 均可,单帧同价)。若该镜没有 reopen_pair_id 字段(不满足继承条件),这个参数不要传,走常规 frame_type 重试。\n★★出尾帧若被拦下并提示「此镜标为状态改变,但没有任何地方说明结束时是什么样子」:正解是用 update_shot 把结束状态写进 last_frame_prompt 再出,**别直接加 allow_missing_terminal 硬上**——这类镜照现状出尾帧的历史成功率只有 9.4%(有终态描述的 40.2%),硬上多半是白扣一次钱。只有确认这一镜就是要「几乎不变」的画面时才带那个参数。\n★一键出片托管环节:同一镜重出帧最多 3 轮(一次调用算一轮,both 也算一轮),到上限回 **409 AUTOPILOT_SHOT_REGEN_LIMIT**(未派发、未扣费,quote 未消耗)——别换个工具绕,停下问客户:客户同意再出就照常报价、生成时带 customer_approved_more_regens:true(再给一份上限);客户接受现状就往下走,下一步收费调用带 acknowledge_review:true 记下确认。专业模式与客户把控的环节不受这个上限约束。\n★【分镜审查硬闸·免费】本步前必须先调 review_storyboards:把返回的 findings 逐条原样告诉客户(每条带 code=问题类型、shots=命中镜号、action=该调哪个工具修),再把 review_token 传进本工具。未审查会被 400 拒。审查后又改了内容 → token 自动失效,复审一次即可(仍免费)。单镜工具(generate_shot_frame / regenerate_shot_video)只核本镜与相邻镜:改了别的镜不用复审;本镜、相邻镜或共享资产变了才 400——这时带 base_review_token=<旧 token> 调审查工具做增量复审,只重审变更镜,质检也只看变更镜。有 error 时默认拦截;客户知情并坚持照现状继续,才带 acknowledge_review:true——带病推进大概率产出废片且照常扣费(acknowledge_review 只代表客户本人同意,任何执行模式都须客户明确同意,托管也不例外);托管环节只有白名单内的启发式 error 能带 auto_acknowledge:true 放行(平台判,不在白名单回 400 AUTOPILOT_MUST_ASK:must_ask_customer=true 才暂停问客户,false = 按 action 自修复审)。★灰度剧还要你(agent)亲自质检:按 review_storyboards 返回的 agent_qc 逐件看素材、逐条答清单,调 submit_qc_report 提交后这张 token 才能用(没交 → 400 agent_qc_required;报告有问题 → 与 error 同样默认拦)。\n★【资产层硬闸·免费】还要先跑 review_assets(角色形象图/场景图/道具图),把它的 review_token 作为 asset_review_token 传进来(与分镜层的 review_token 并存,两张都要;灰度剧缺了会 400 并点名 review_assets)。出完帧不会让资产 token 失效。⚠️ 批量报价确认流程:先调对应的 quote_* 工具拿 estimated_points 与 quote_id,再用 quote_id 调本工具(报价确认按执行模式:专业模式 / 未确认方案 / 本环节由客户把控 → 讲给客户、客户同意才做,别替客户决定;本环节托管 → 不问客户,照 get_production_plan 的 autopilot.default_decisions 执行,平台记进 get_autopilot_log)。托管环节报价须在预算硬上限内,被 402 BUDGET_WOULD_EXCEED 拦下就停下问客户。★**出图类报价(定妆图/场景图/出帧)给的是两个数**:estimated_points 是**上界**(按该模型参考图张数上限估,保证你不会按低了的预算开跑、出到一半 402 中断);同一响应里的 typical_points 是**通常花费**。两个都要告诉客户——只说上界会让人以为贵得多(满参考图的上界可达通常值的 2 倍以上),只说通常值又会让余额准备不足。固定价模型下两者相等,这时说一个数就行。出视频的报价与扣费同函数,不存在这个区间。",
59
59
  "quote_local_frame_edit": "报价:**局部修改某一镜的某一帧**(修脸、闭嘴、去毛边、擦掉多出来的东西)要多少点。零扣费。客户只想改画面的一小块时用它,别拿外部图像工具改完再 upload_shot_frame——外部工具会连带改动已确认的其他细节、绕开身份锚与审计、来源链也断了;要整张重画才用 quote_shot_frame / generate_shot_frame。平台把修改区按羽化蒙版贴回原图:框外像素原样保留,只有框内被改。★计费:每个候选按一次出图扣(unit_points × candidates;张数固定,estimated_points 就是实扣,typical_points 与它相等)。**被平台判据拒掉的候选(贴回有接缝、没改到、身份审计不过)一律不退点**——报价时就要把这一点和点数一起讲给客户。厂商出图失败由平台自动退。★按剧、按类型灰度开放:没开放回 403 LOCAL_FRAME_EDIT_UNAVAILABLE,响应里 open_kinds 列出已对所有剧开放的类型(如 object_remove);要改的类型不在里面就只能 generate_shot_frame 整张重画。修脸类不带 character_id 回 400 CHARACTER_REQUIRED;修脸不送定妆图(只送底图局部),贴回后比对人脸判是不是同一个人(判不像的拒、拿不准的交人看,都照常计费)。",
60
60
  "local_frame_edit": "确认后**局部修改某一镜的某一帧**(异步,扣费)。参数必须与 quote_local_frame_edit 那次完全相同(区域 / 指令 / 类型 / 角色 / 候选数 / 底图任一项变了 → 409 QUOTE_PARAMS_CHANGED,重新报价即可,免费)。返回 edit_id,之后用 get_local_frame_edit 轮询。★**不会自动替换当前帧**:候选出完先给客户看(composited_url),客户选定后调 adopt_local_frame_edit 才写进这一镜、并把本镜视频标为待重生;不采用,当前帧就不变。★被判据拒掉的候选照常计费、不退点。\n★【分镜审查硬闸·免费】本步前必须先调 review_storyboards:把返回的 findings 逐条原样告诉客户(每条带 code=问题类型、shots=命中镜号、action=该调哪个工具修),再把 review_token 传进本工具。未审查会被 400 拒。审查后又改了内容 → token 自动失效,复审一次即可(仍免费)。单镜工具(generate_shot_frame / regenerate_shot_video)只核本镜与相邻镜:改了别的镜不用复审;本镜、相邻镜或共享资产变了才 400——这时带 base_review_token=<旧 token> 调审查工具做增量复审,只重审变更镜,质检也只看变更镜。有 error 时默认拦截;客户知情并坚持照现状继续,才带 acknowledge_review:true——带病推进大概率产出废片且照常扣费(acknowledge_review 只代表客户本人同意,任何执行模式都须客户明确同意,托管也不例外);托管环节只有白名单内的启发式 error 能带 auto_acknowledge:true 放行(平台判,不在白名单回 400 AUTOPILOT_MUST_ASK:must_ask_customer=true 才暂停问客户,false = 按 action 自修复审)。★灰度剧还要你(agent)亲自质检:按 review_storyboards 返回的 agent_qc 逐件看素材、逐条答清单,调 submit_qc_report 提交后这张 token 才能用(没交 → 400 agent_qc_required;报告有问题 → 与 error 同样默认拦)。\n★【资产层硬闸·免费】还要先跑 review_assets(角色形象图/场景图/道具图),把它的 review_token 作为 asset_review_token 传进来(与分镜层的 review_token 并存,两张都要;灰度剧缺了会 400 并点名 review_assets)。出完帧不会让资产 token 失效。⚠️ 批量报价确认流程:先调对应的 quote_* 工具拿 estimated_points 与 quote_id,再用 quote_id 调本工具(报价确认按执行模式:专业模式 / 未确认方案 / 本环节由客户把控 → 讲给客户、客户同意才做,别替客户决定;本环节托管 → 不问客户,照 get_production_plan 的 autopilot.default_decisions 执行,平台记进 get_autopilot_log)。托管环节报价须在预算硬上限内,被 402 BUDGET_WOULD_EXCEED 拦下就停下问客户。★**出图类报价(定妆图/场景图/出帧)给的是两个数**:estimated_points 是**上界**(按该模型参考图张数上限估,保证你不会按低了的预算开跑、出到一半 402 中断);同一响应里的 typical_points 是**通常花费**。两个都要告诉客户——只说上界会让人以为贵得多(满参考图的上界可达通常值的 2 倍以上),只说通常值又会让余额准备不足。固定价模型下两者相等,这时说一个数就行。出视频的报价与扣费同函数,不存在这个区间。",
61
61
  "get_local_frame_edit": "查一次局部返修的进度与结果(免费)。status=running 继续等;completed 后逐个候选看:composited_url(贴回原图后的成品,给客户看的就是它)、verdict(pass=可直接用;warn=能用但要人看——REGION_SEAM_WARN 边界可能有接缝 / EDIT_NOT_APPLIED 基本没改到 / IDENTITY_NEEDS_REVIEW 修脸后人脸比对分在灰区、平台不自动放行 / IDENTITY_NOT_JUDGEABLE 侧脸·低头·脸太小等判不了 / IDENTITY_COMPARE_LOW 旧版身份比对分偏低 / IDENTITY_AUDIT_UNAVAILABLE 身份没审成;reject=不建议用——REGION_MISALIGNED 贴回错位 / IDENTITY_MISMATCH 修脸后人脸比对判定换了人 / IDENTITY_AUDIT_REJECTED 帧审计不过,可能是原帧本身的构图问题)、reason_text(每条原因的中文说明,原样讲给客户)、metrics、identity_audit、identity_compare(修脸类身份比对:method=face_embedding 时按人脸特征向量判——与修改前同一张脸相似度 ≥0.75 放行、<0.60 判不像、中间交人看,vlm_reference 只记录;没有 method 字段的是旧版,只作参考)。★修脸结果仍要亲眼看是不是同一个人——侧脸、低头、小脸时平台判不了。下载 composited_url 亲眼看过、讲给客户,客户选定后用 adopt_local_frame_edit。被拒候选不退点(包括原帧本身问题导致帧审计不过的)。",
@@ -92,7 +92,7 @@
92
92
  "apply_extend_final": "把某个续写产物**设为本集成片**(免费,纯指针切换)。\n★这一步会**覆盖**本集当前的成片链接:之前的成片不再是对外那一版。先用 get_extend_final 看 final_url、确认客户满意再调。\n★之后若重新 compose_episode(终拼),成片会被终拼结果覆盖回去,applied 自动变 false。",
93
93
  "export_sheet_compare": "导出**设定图对照版**(角色设定图与成片画面的对照拼版,营销/交付用)。触发后台合成,用 get_sheet_compare 轮询。\n★这个能力**默认关**:它是剧集级开关(不是所有片子都允许这样对外输出),关着时回 **403**。看到 403 别重试、也别当成失败——告诉客户去官网的**剧集设置**里打开它。\n不传 character_id 就导出整集;传了只导这一个角色。",
94
94
  "get_sheet_compare": "轮询设定图对照版的导出状态。免费。回 enabled(剧集开关是否打开)/processing/result/error。\n★enabled=false 就是那个剧集开关没开——不是出错,去官网剧集设置里打开再导。",
95
- "update_project_settings": "建剧后修改项目设定。除画幅/分辨率/世界观Brief/族裔/题材/导演风格外,现覆盖★整剧视觉一致性锚(摄影DNA cinematography_prompt/美术圣经 art_bible/视觉锁定 visual_lock/视频风格正负向词/视觉母题 motifs)、音频(bgm_source 自有vs原生/bgm_volume_preset 音量/use_clip_audio 用视频原声)、字幕(show_subtitles/双语 subtitle_secondary_lang/位置/边距/动效)、转场——即项目设定页全部通用设定。免费。⚠️ 世界观 Brief/族裔/画幅/一致性锚等改后,已生成的内容不会自动更新,需重生对应内容。",
95
+ "update_project_settings": "建剧后修改项目设定。除画幅/分辨率/世界观Brief/族裔/题材/导演风格外,现覆盖★整剧视觉一致性锚(摄影DNA cinematography_prompt/美术圣经 art_bible/视觉锁定 visual_lock/视频风格正负向词/视觉母题 motifs)、音频(bgm_source 自有vs原生/bgm_volume_preset 音量/use_clip_audio 用视频原声)、字幕(show_subtitles/双语 subtitle_secondary_lang/位置/边距/动效)、转场——即项目设定页全部通用设定。免费。⚠️ 世界观 Brief/族裔/画幅/一致性锚等改后,已生成的内容不会自动更新,需重生对应内容。★frame_chain_mode 管整剧跨镜帧链:off=整剧不做(出帧落定后的自动衔接、chain_frames、首尾呼应都不派图不改帧,报价里也不再计入);reframe=默认;strict=相邻缝只裸拷贝上镜尾帧不重生(已设的首尾呼应仍按 reframe 重生、照常计入报价;要全不派图用 off)。关掉后想用 chain_frames 要先改回 reframe/strict;改模式不会自动重出已有帧。",
96
96
  "generate_world_concept": "(★默认必做·很多第三方平台漏做这步·仍走报价确认)生成世界观概念图(固定4格:全景/时代/主场景/色彩),提升整剧视觉一致性。★分镜后默认调这个,别跳过;但仍要告知客户预估点数(跑不跑按执行模式:专业模式 / 未确认方案 / 本环节由客户把控 → 讲给客户、客户同意才做,别替客户决定;本环节托管 → 不问客户,照 get_production_plan 的 autopilot.default_decisions 执行,平台记进 get_autopilot_log)(派发前平台按缺槽数 × 单张上界过预算预检,超出硬上限回 402、未扣费)。需 setting_brief ≥30字。图片步,按固定成本后付、不欠费。",
97
97
  "generate_art_bible": "生成美术圣经(色调/材质/气质,读角色+元数据)。文本步后付不欠费。",
98
98
  "extract_visual_lock": "从世界观 Brief + 角色抽取「视觉锁定」规则(写 visual_lock,统一出图风格/族裔)。文本步后付不欠费。",
@@ -142,9 +142,9 @@
142
142
  "scan_voice_consistency": "★原声剧(视频自带人声)客户报「同一个角色前后嗓音不一样 / 声线漂了」时跑这个。免费(本地推理,不调厂商)。对每个有台词的镜,听厂商生成的人声:台词念没念全,以及声音像不像该角色绑定的声线锚。**异步**:立即返回,后台整集约 10 分钟;同一集同时只跑一条(重复调用返回 started=false)。默认跳过已对当前视频扫过的镜,rescan=true 全部重扫。用 get_voice_consistency 查进度和逐镜结果。",
143
143
  "get_voice_consistency": "查声线一致性扫描的进度与逐镜结果(scan_voice_consistency 启动的)。免费。summary.voice_mismatch=声音不像该角色声线锚的镜号(重点看);dialogue_issues=台词没念完/念错/多出说话声的镜;not_scanned_or_stale=还没扫或视频换过需重扫。speaker_verdict=uncertain 表示人声太短判不了,不是问题。声线不一致的镜:先用 get_pipeline_status 的 native_voice_anchor 确认角色已绑声线,再 regenerate_shot_video 重出。",
144
144
  "scan_dialogue_coverage": "★客户报「话没说完就切 / 台词只念了一半」时先跑这个。默认**免费零扣费**(只读已落库的转录审计结果)。把该集每个原声镜的视频音轨与台词做词级比对,按族给出结论:truncated(念到一半就停) / off_script(念的大半不是台词:自说自话、重复上一镜、只有环境音) / extra_speech(台词念全了但还多念) / minor_gap(零星缺词,属转写误差,不必管) / ok。★判读:三个可上报的族**处置方向不同**,别一律加长镜头——实测镜长够的镜里仍有 21% 没念全,「太短」很少是真因(平台保存分镜时已按台词自动抬时长)。truncated/off_script 的正解都是 regenerate_shot_video(厂商每次说多少是随机的,重掷常能拿到整句);同一剧反复 off_script 则换引擎。★never_audited 是本报告最重要的一栏:那些镜从没被检测过,「没测过」不等于「没问题」。rescan=true 会对它们补跑 ASR 比对(耗算力、非瞬时,limit 控制单次上限),默认不跑。TTS 配音镜不在范围内(TTS 必然念全,低覆盖率只会是转写误差)。同一集若还伴随「切太快」,那是另一回事,跑 scan_intra_shot_cuts。",
145
- "update_shot": "逐镜编辑:改单个分镜的文本内容(景别/动作/台词/画面描述/运镜等)、面部表情(expression_hint)、时长(duration)、成片变速(speed_factor)、镜间转场(transition_type / transition_duration_ms)、角色绑定(character_ids)、道具绑定(prop_ids)、画外音标记(character_presence)与服装绑定(active_wardrobe_id / appearance_wardrobes)。只传要改的字段、其余不动。★改镜(成功或被拒)都会作废覆盖本镜的未消费报价,生成时回 409 QUOTE_INVALIDATED——先改成功、回读核对,再报价。**免费**(纯文本写库)。★改 dialogue 会自动失效本镜已生成的 TTS 配音与字幕(需重出 tts);改文本不会自动重出图/视频,如需让画面跟上文本改动,改完再 regen 对应镜。用 get_storyboards 查改后结果(每镜带 character_ids / character_bindings / scene_id / prop_ids / active_wardrobe_id / appearance_wardrobes)。★★【换衣服改这里,不是改文字】出图穿什么由**服装绑定**决定:单人镜用 active_wardrobe_id(整镜一件),多人同框各穿各的用 appearance_wardrobes(逐角色)。把「穿某某衣服」写进 description/action 不会换衣服。服装 id 用 list_wardrobe 查;改完不会自动重出图,要让画面跟上需重生本镜首帧再重生视频。★★原声镜(厂商原生音频)改 dialogue 后,本镜视频会被标记「待重生」——因为台词是**烤进视频人声**的,不重生就终拼,成片里念的仍是改动前的台词(典型现象:台词像是跑到了别的镜头上)。compose_episode 会以 advisory `stale_video_after_edit` 列出这些镜;正确处置是先 regenerate_shot_video 再终拼。★也可直接改本镜的四条提示词正文(image_prompt/video_prompt/first_frame_prompt/last_frame_prompt):改前先用 get_shot_prompts 读现值,别凭空覆盖——正文里的 @char:N / @scene:M 是出图时的补充参考标记,照原样保留即可。★注入谁的定妆图由 character_ids 决定、背景由 scene_id 决定:删标记不会让已绑定的人从画面消失,要让某人不出现就改 character_ids,他只有声音(画外音)就用 character_presence 标 voice_only;反过来别给未绑定的角色写 @char 标记——会把他的图注入进来。★★【出尾帧被拦下就是来改这里】出尾帧若报「此镜标为状态改变,但没有任何地方说明结束时是什么样子」(TERMINAL_DESC_GATE),修法是把**结束时画面是什么样**写进本镜 last_frame_prompt,然后重新出尾帧。别去重试出图——这类镜(action_motion_class=state_change 却没写终态)的尾帧历史成功率 9.4%,有终态描述的是 40.2%;不补描述就重生,送厂商的提示词里根本没有终态段,画出来仍和首帧一样、还是会被拒,而每次重生都照常扣费。get_shot_prompts 的 terminal_desc_missing=true 就是这个信号。",
145
+ "update_shot": "逐镜编辑:改单个分镜的文本内容(景别/动作/台词/画面描述/运镜等)、面部表情(expression_hint)、时长(duration)、成片变速(speed_factor)、镜间转场(transition_type / transition_duration_ms)、角色绑定(character_ids)、道具绑定(prop_ids)、画外音标记(character_presence)与服装绑定(active_wardrobe_id / appearance_wardrobes)。只传要改的字段、其余不动。★改镜(成功或被拒)都会作废覆盖本镜的未消费报价,生成时回 409 QUOTE_INVALIDATED——先改成功、回读核对,再报价。**免费**(纯文本写库)。★改 dialogue 会自动失效本镜已生成的 TTS 配音与字幕(需重出 tts);改文本不会自动重出图/视频,如需让画面跟上文本改动,改完再 regen 对应镜。用 get_storyboards 查改后结果(每镜带 character_ids / character_bindings / scene_id / prop_ids / active_wardrobe_id / appearance_wardrobes);景别/机位/运镜/剪辑意图与提示词正文用 get_shot_prompts 逐镜回读。★★【换衣服改这里,不是改文字】出图穿什么由**服装绑定**决定:单人镜用 active_wardrobe_id(整镜一件),多人同框各穿各的用 appearance_wardrobes(逐角色)。把「穿某某衣服」写进 description/action 不会换衣服。服装 id 用 list_wardrobe 查;改完不会自动重出图,要让画面跟上需重生本镜首帧再重生视频。★★原声镜(厂商原生音频)改 dialogue 后,本镜视频会被标记「待重生」——因为台词是**烤进视频人声**的,不重生就终拼,成片里念的仍是改动前的台词(典型现象:台词像是跑到了别的镜头上)。compose_episode 会以 advisory `stale_video_after_edit` 列出这些镜;正确处置是先 regenerate_shot_video 再终拼。★也可直接改本镜的四条提示词正文(image_prompt/video_prompt/first_frame_prompt/last_frame_prompt):改前先用 get_shot_prompts 读现值,别凭空覆盖——正文里的 @char:N / @scene:M 是出图时的补充参考标记,照原样保留即可。★注入谁的定妆图由 character_ids 决定、背景由 scene_id 决定:删标记不会让已绑定的人从画面消失,要让某人不出现就改 character_ids,他只有声音(画外音)就用 character_presence 标 voice_only;反过来别给未绑定的角色写 @char 标记——会把他的图注入进来。★★【出尾帧被拦下就是来改这里】出尾帧若报「此镜标为状态改变,但没有任何地方说明结束时是什么样子」(TERMINAL_DESC_GATE),修法是把**结束时画面是什么样**写进本镜 last_frame_prompt,然后重新出尾帧。别去重试出图——这类镜(action_motion_class=state_change 却没写终态)的尾帧历史成功率 9.4%,有终态描述的是 40.2%;不补描述就重生,送厂商的提示词里根本没有终态段,画出来仍和首帧一样、还是会被拒,而每次重生都照常扣费。get_shot_prompts 的 terminal_desc_missing=true 就是这个信号。",
146
146
  "rederive_shot_contract": "按本镜**当前**的正文与角色绑定,让平台重新推导构图契约(画面里可见几人、主体是人物还是局部/道具、景别)。契约本身不对外,读不到也改不了;本工具只回结论 outcome:updated(已改并生效)/ unchanged(推出来和原来一样)/ rejected(推出来自相矛盾,未采用,原契约保留)/ no_candidate(没拿到可用结果,原契约保留)/ stale(推导期间本镜又被改过,结果未写入,改完再调一次),附 note 说下一步。点数不足回 402。★什么时候用:出图/预检/审核反复说人数不对、局部镜(手部/道具特写)被当成完整人物出图或审核,而你已经改过正文或绑定——补全器只填空、不覆盖已有契约,不调本工具改动不会进契约。★正确顺序:先 update_shot 把画面写对(谁在画面里、谁只出声音用 character_presence 标 voice_only、不该出现的人从 character_ids 解绑),再调本工具;不改正文直接调多半回 unchanged。★一次文本 AI 调用,按 token 后付(与 autofill_storyboards 同链路),调用前告知客户。★只改契约这一个字段,不碰台词/提示词/其它专业字段;已出的首尾帧不会自动重出,要让画面跟上需对本镜重新出帧(先报价)。★updated 会作废本镜及同集未消费的出帧/出视频报价,之后要重新报价。",
147
- "get_shot_prompts": "读某一镜的四条提示词**正文**(image_prompt=首帧画面 / video_prompt=动态表演 / first_frame_prompt=开始时什么样 / last_frame_prompt=结束时什么样),供直接微调后用 update_shot 写回。免费。★回执里的 terminal_desc_missing=true 表示本镜标为「状态改变」却三处都没说终态——出尾帧会被前置闸拦下,修法是把结束状态写进 last_frame_prompt(别重试出图,重试必然重复被拒且照常扣费)。★pose_timeline_stale 非 null = 本镜动作起止姿态里的秒数时间轴超出了当前时长(多见于改短 duration 后),出视频时那一端已自动不送;新时间轴写进 video_prompt。★同时回 description(画面描述)与 lighting(本镜用光)现值——review_storyboards 的禁区词命中常在 description,改前先在这里读;用光写 lighting。★同时回 expression_hint(本镜作者指定的面部表情,null=未指定、由平台按台词反推),改它用 update_shot。expression_inferred 是拆镜 AI 在剧本没写神态时按本镜内容推断的表情(只读;null=没推断,或本镜台词/动作/氛围/描述/强度改过、推断已过期不再使用);它优先级低于 expression_hint——推断不合意就用 update_shot 写 expression_hint 覆盖它。★逐镜按需:改哪镜读哪镜(整集列表 get_storyboards 不含提示词)。★返回的 asset_tokens 是正文里的补充参考标记(@char:N / @scene:M),改写时原样保留即可:本镜注入谁的定妆图由绑定决定(get_storyboards 的 character_ids / scene_id),删标记不会让已绑定的人消失;带 #变体 的标记是那张变体图的唯一来源;给未绑定的角色写标记会把他的图注入进来。★这是分镜表里的正文层;出图/出视频时平台还会在其上拼身份锚、一致性约束与参考图指令(不在此处,也无需你写)。改完提示词不会自动重出图/视频,要让画面跟上得再 regen 对应镜。",
147
+ "get_shot_prompts": "读某一镜的四条提示词**正文**(image_prompt=首帧画面 / video_prompt=动态表演 / first_frame_prompt=开始时什么样 / last_frame_prompt=结束时什么样),供直接微调后用 update_shot 写回。免费。★回执里的 terminal_desc_missing=true 表示本镜标为「状态改变」却三处都没说终态——出尾帧会被前置闸拦下,修法是把结束状态写进 last_frame_prompt(别重试出图,重试必然重复被拒且照常扣费)。★pose_timeline_stale 非 null = 本镜动作起止姿态里的秒数时间轴超出了当前时长(多见于改短 duration 后),出视频时那一端已自动不送;新时间轴写进 video_prompt。★同时回 description(画面描述)、lighting(本镜用光)与 sound_effect(本镜音效)现值——review_storyboards 的禁区词命中常在 description / sound_effect,改前先在这里读;用光写 lighting。★同时回 shot_type(景别)/ angle(机位)/ camera_movement(运镜)/ continuity_intent(剪辑意图)现值——update_shot 改完这几项就在这里回读核对(整集 get_storyboards 不含它们);null=未设。★同时回 expression_hint(本镜作者指定的面部表情,null=未指定、由平台按台词反推),改它用 update_shot。expression_inferred 是拆镜 AI 在剧本没写神态时按本镜内容推断的表情(只读;null=没推断,或本镜台词/动作/氛围/描述/强度改过、推断已过期不再使用);它优先级低于 expression_hint——推断不合意就用 update_shot 写 expression_hint 覆盖它。★逐镜按需:改哪镜读哪镜(整集列表 get_storyboards 不含提示词)。★返回的 asset_tokens 是正文里的补充参考标记(@char:N / @scene:M),改写时原样保留即可:本镜注入谁的定妆图由绑定决定(get_storyboards 的 character_ids / scene_id),删标记不会让已绑定的人消失;带 #变体 的标记是那张变体图的唯一来源;给未绑定的角色写标记会把他的图注入进来。★这是分镜表里的正文层;出图/出视频时平台还会在其上拼身份锚、一致性约束与参考图指令(不在此处,也无需你写)。改完提示词不会自动重出图/视频,要让画面跟上得再 regen 对应镜。",
148
148
  "rerender_episode": "按当前 timeline 重拼成片(改完镜/裁剪后用)。**免费**(纯 ffmpeg+COS),后台异步。",
149
149
  "replace_shot_dialogue": "换某镜对白音色/声线(转写+克隆重配)。**同步调用**,约 1 分钟返回产物,按用量后付不欠费。要求本镜有原声视频+角色声线定妆音。★它也是「这一镜台词没念完/念了别的」最经济的修法:用克隆音重配整句并静音原声段,**不重新生成视频**——按 TTS 档(千字符)计费,比 regenerate_shot_video(按秒计费,720p 每秒上百点)低几个数量级。代价:画面口型是按原音演的,换音后可能对不上;口型看不清的镜(背身/远景/画外)几乎无损,大特写慎用。★产物自动写回该镜(返回 persisted:true),但写回 ≠ 进成片:以 get_dialogue_repair_status 的 productEffective 为准——true 就 rerender_episode 重拼;false 时按 pendingCompose 先补合成再重拼,否则成片仍是旧音频。★该镜已有对口型产物时,成片优先用对口型版,换轨不会生效。整集批量用 repair_episode_dialogue。\n★写回前会对产物复核(与 scan_dialogue_coverage 同一判据):换完仍断音(truncated)、重复念/多念(extra_speech)、念的不是台词(off_script)→ **不写回**、本次费用自动退回,返回错误说明哪一类——这类镜换音修不好,改用 regenerate_shot_video。成功时返回 verify:verified=false 表示没判出来(转写失败/台词太短),照常写回但没复核过,自己听一下。",
150
150
  "revoice_narration": "换某镜**旁白/画外音**的声音(或改过旁白文字后重配)。**不重新生成视频**:保留画面与出镜台词,只把旁白那几段静掉、按当前旁白声音重新合成并混回,再复核。同步调用,按 TTS 档(千字符)计费。★先改好再调:想换声音先 set_character_voice 给「旁白」角色(没有就 design_voice 造一个),想改文字先 update_shot 改 dialogue 里的旁白行。★纯旁白镜(本镜只有旁白)直接可用;**混合镜**(既有出镜台词又有旁白)要求分句数与视频里的语音段数一致,对不上就报错不猜(猜错会把出镜台词一起静掉)——这时只能 regenerate_shot_video。★台词栏没有旁白行会直接报错;厂商在无台词镜里乱念,用 replace_shot_dialogue 的 mute_only。★写回后成片会直接用它(不需要额外开关),rerender_episode 重拼即可;复核不通过不写回,旁白合成费不退。",
@@ -175,7 +175,7 @@
175
175
  "get_bgm_status": "查某集 AI 配乐生成状态:running(是否在生成)+已入库的配乐轨列表(track/覆盖镜段/淡入淡出)+cue 数。免费。配乐 done 后需重新 compose_episode 才进成片。",
176
176
  "translate_subtitles": "把某集字幕翻译成第二语言并开启双语。后台异步,按用量后付不欠费。",
177
177
  "list_dramas": "列出我名下的所有短剧(drama_id/剧名/类型/集数/进度)。免费。",
178
- "get_drama": "读一部剧的详情(设定/角色数/场景数/资产统计等)。免费。",
178
+ "get_drama": "读一部剧的详情(设定/角色数/场景数/资产统计等)。免费。frame_chain_mode = 整剧跨镜帧链模式(off/strict/reframe,改用 update_project_settings)。",
179
179
  "get_characters": "读某一集的角色列表(名字/定妆图/设定图就绪状态)。免费。每角色带结构化状态:portrait_status/sheet_status(ready=已入库/pending=生成或审计中·别重复点/rejected=图已生成但被一致性闸拒收未入库/failed/none)+ 拒收时的 sheet_fail_reason·sheet_retryable·sheet_fail_hint(拒收判词)。★sheet_status=rejected 时照 retryable 判:consistency_rejected 可重掷一次(generate_character_sheet);**连拒且 fail_hint 理由几乎相同 = 锚字段与人物档案冲突(结构性必拒),重掷纯白花钱**——先 run_precheck 看 anchor-conflict 警告,把 visual_lock/art_bible 里钉死的角色外观移除或对齐档案再重掷。",
180
180
  "get_scenes": "读某一集的场景列表(名字/描述/场景图是否就绪)。免费。",
181
181
  "get_assets": "读一部剧的全部资产聚合(角色/场景/道具/图片)。免费。",
@@ -231,13 +231,13 @@
231
231
  "get_av_timing_contract": "查 build_av_timing_contract 的进度与结果。免费。status=running 时看 progress(stage=build_timeline/activity/probe);status=done 时 result.planned 是现在重拼会得到的逐镜契约,result.final_cut 是上次成片(contract=存档时间轴推出的契约,probed=成片实测,duration_check.matches=总时长在 100ms 容差内一致,drift_vs_planned=两者不同的镜;timeline_association≠verified 时存档时间轴已不是成片用的那份,contract 不提供)。★自己拼片按 shots[].timeline 排位、按 trim.in_ms/out_ms 截源片;voice.in_final_cut=mixed_into_video 的镜直接用视频原声,绝不再叠配音。result.synth_skipped_shot_ids 非空 = 这些镜配音尚未合成(成片时现场合成扣费),对白轨区间暂缺。",
232
232
  "audit_seam_directions": "出视频前的接缝方向对照(提示性,不拦任何步骤):对每对相邻镜拿「上一镜尾帧(没有就首帧)↔ 本镜首帧」看五件事——同一主体在画面左右跳边(视线也反了会一并写明)、运动方向反了、景别跳级(同一主体大远景↔特写)。单镜都对、拼起来跳,多半是这几维。视线单独反向、主光方向会被观察但不报:生产回放里这两维误报率太高(宁漏不扰)。与 audit_seams 互补:那个比身份/服装/道具/物体状态,不管方向和位置。★何时调:首帧(和要的尾帧)都出完、chain_frames 跑过之后,review_frames / generate_videos 之前。换场、声明跳切、插入镜、字卡黑场的接缝自动跳过。★先 dry_run(默认,免费):回待观察接缝与 estimated_points(上界)/ typical_points(通常花费),两个都告诉客户,按实际文本 token 扣费;客户同意后传 dry_run=false + confirm_usage_billing=true。执行是异步的,立即返回;过一两分钟用 get_seam_directions 读结论。已观察过且两侧帧没换的接缝不重复扣费。",
233
233
  "get_seam_directions": "(免费)读 audit_seam_directions 的结论:issues 每条带接缝镜号、问题(主体跳边、运动反向、景别跳级)与 fixes 修复建议(chain_shot_from mode=reframe 以上一镜尾帧为锚重出本镜首帧 / update_shot 写明朝向后 generate_shot_frame / 上一镜已出视频时 align_prev_shot / split_shot 插过渡景别)。结论是提示性的:讲给客户,由客户挑要修的;有意的反打、转身、冲击剪辑可忽略。not_audited>0 = 还有接缝没观察或帧已换过;running=true = 还在跑。review_frames 的 seam_direction_advisory 是同一份结论的摘要。本工具只看出视频前的静帧;视频出完后查接缝用 preview_seams(免费短片预览)。",
234
- "chain_frames": "整集首尾帧接力链:让每镜首帧承接上镜尾帧,镜间画面连续(比各镜独立出帧更顺)。★何时调:首帧出完、tail_frame_plan 要的尾帧也补完之后,review_frames / generate_videos 之前。平台只在官网批量出帧结束时自动跑一次;逐镜出帧(generate_frames / generate_shot_frame)的集多半从没接过——get_storyboards 的 seam_state=unchained 就是这种缝。\n★先 dry_run:true(免费,不写库不出图):回 planned_copy / planned_reframe / estimated_points / needs_last_frame。copy=本镜首帧直接换成上镜尾帧(免费,但本镜景别会变成和上镜一样);reframe=以上镜尾帧为锚按本镜画面描述重生首帧(每道一张图,保景别)。把计划和 estimated_points 告诉客户,确认后**不带 dry_run** 再调一次执行(按用量后付)。\n★平台自己判哪道缝该接:有意切换(换场/时间跳跃/换装/插入镜)、已出视频的镜、已经接好的缝都会跳过——「已接好」= 首帧就是上镜尾帧,或 reframe 接在上镜**当前**尾帧上,所以重复执行不会重复扣费。上镜尾帧后来被重生过的缝会重新出现在计划里,那道缝确实断了。只补个别缝用 chain_shot_from_prev / chain_shot_from。执行后改了首帧的镜若已有视频会被标为待重生。★执行只派发 reframe、不等出图:用 get_jobs 看这些镜的 first_frame 出图行,等 pending/processing 全部结束(failed 的看 error_msg,单道用 chain_shot_from 重接;旧首帧还在时 get_storyboards 的 frame_status 仍是 ready、看不出失败),再用 get_storyboards 核对 seam_state、review_frames——提前审会审到旧首帧,token 随后作废。",
234
+ "chain_frames": "整集首尾帧接力链:让每镜首帧承接上镜尾帧,镜间画面连续(比各镜独立出帧更顺)。★何时调:首帧出完、tail_frame_plan 要的尾帧也补完之后,review_frames / generate_videos 之前。平台只在官网批量出帧结束时自动跑一次;逐镜出帧(generate_frames / generate_shot_frame)的集多半从没接过——get_storyboards 的 seam_state=unchained 就是这种缝。\n★先 dry_run:true(免费,不写库不出图):回 planned_copy / planned_reframe / estimated_points / needs_last_frame。copy=本镜首帧直接换成上镜尾帧(免费,但本镜景别会变成和上镜一样);reframe=以上镜尾帧为锚按本镜画面描述重生首帧(每道一张图,保景别)。把计划和 estimated_points 告诉客户,确认后**不带 dry_run** 再调一次执行(按用量后付)。\n★平台自己判哪道缝该接:有意切换(换场/时间跳跃/换装/插入镜)、已出视频的镜、已经接好的缝都会跳过——「已接好」= 首帧就是上镜尾帧,或 reframe 接在上镜**当前**尾帧上,所以重复执行不会重复扣费。上镜尾帧后来被重生过的缝会重新出现在计划里,那道缝确实断了。只补个别缝用 chain_shot_from_prev / chain_shot_from。剧级 frame_chain_mode=off 时整集不接(计划为空),要接先 update_project_settings 改回 reframe/strict。执行后改了首帧的镜若已有视频会被标为待重生。★执行只派发 reframe、不等出图:用 get_jobs 看这些镜的 first_frame 出图行,等 pending/processing 全部结束(failed 的看 error_msg,单道用 chain_shot_from 重接;旧首帧还在时 get_storyboards 的 frame_status 仍是 ready、看不出失败),再用 get_storyboards 核对 seam_state、review_frames——提前审会审到旧首帧,token 随后作废。",
235
235
  "chain_shot_from_prev": "(免费)把上一镜的尾帧**直接**设为本镜首帧:画面 100% 接上,零成本、不出图。★适用:两镜是同一机位、同一景别的延续(seam_state=unchained/broken 且本镜本来就该和上镜一个构图)。★别用于景别有变化的缝(全景→近景等):那会把本镜的景别设计冲掉,且后续出图可能被判「与设计不符」——这种缝用 chain_shot_from 的 mode=reframe。本镜已有视频的会被标为待重生。本镜首帧若是客户上传的(first_frame_source=upload)或已定稿(first_frame_pinned)会被拒(409 reason=user-locked-frame);覆盖它(任何执行模式都须客户明确同意,托管也不例外)才传 force:true(会解除上传 / 定稿保护,新图需客户重新验收)。",
236
236
  "quote_chain_shot_from": "(免费报价)chain_shot_from 的 mode=reframe 要扣**一张图**(以源帧为锚重生本镜首帧),执行前先报价(报价确认按执行模式:专业模式 / 未确认方案 / 本环节由客户把控 → 讲给客户、客户同意才做,别替客户决定;本环节托管 → 不问客户,照 get_production_plan 的 autopilot.default_decisions 执行,平台记进 get_autopilot_log)。回 quote_id / estimated_points;quote_id 一次性、只对这一镜有效。mode=copy 不需要报价。本镜首帧是客户上传的或已定稿的:不带 force 不出报价(409 reason=user-locked-frame,不计价);客户明确同意替换后报价与执行都带 force:true。",
237
237
  "chain_shot_from": "把同一集**任一镜**的首帧或尾帧接为本镜首帧。两种落法:\n· mode=copy(默认,免费):本镜首帧直接换成源帧,画面逐像素相同——适合「回到一模一样的画面」或同机位延续。\n· mode=reframe(扣一张图,必须带 quote_chain_shot_from 的 quote_id):以源帧为锚、按本镜画面描述重生首帧——人物/服装/道具/光线/场景延续,但保留本镜自己的景别与构图。景别有变化的缝要接,用这个。\n★源不是上一镜尾帧时(首尾呼应/回到某个画面),平台会把本镜与上一镜的缝记为「有意切换」,自动帧链不会再覆盖它。本镜已有视频的会被标为待重生;首帧是客户上传的或已定稿的会被拒(409 reason=user-locked-frame,不派图不扣费),覆盖它(任何执行模式都须客户明确同意,托管也不例外)才传 force:true(会解除上传 / 定稿保护,新图需客户重新验收;mode=reframe 的报价也要带 force)。",
238
238
  "quote_align_prev_shot": "(免费报价)align_prev_shot 会重生**上一镜的视频**(扣一条视频),执行前先报价(报价确认按执行模式:专业模式 / 未确认方案 / 本环节由客户把控 → 讲给客户、客户同意才做,别替客户决定;本环节托管 → 不问客户,照 get_production_plan 的 autopilot.default_decisions 执行,平台记进 get_autopilot_log)。回 quote_id / estimated_points / prev_storyboard_id(被重生的是哪一镜);含首次人像核验费时另列 kyc_first_time_points。",
239
239
  "align_prev_shot": "缝裂修复「对齐上一镜」:本镜首帧**不动**,以它为收尾画面、用首尾帧模式重生**上一镜的视频**(上一镜首帧不变),让上一镜真实收在本镜的开场画面上。扣一条视频,必须带 quote_align_prev_shot 的 quote_id。★适用:客户换过本镜首帧(比如上传或重生了一张更满意的),而上一镜的视频已经出好、不想改本镜首帧去迁就它。两镜都还没出视频时别用它——改首帧(chain_shot_from_prev / chain_shot_from)更便宜。异步:轮询 get_storyboards 看上一镜 video_status。",
240
- "get_scene_group_plan": "查某一集的场景组规划(镜头如何归组做连续长镜)。免费。",
240
+ "get_scene_group_plan": "查某一集的场景组规划(镜头如何归组做连续长镜)。免费。★先看回执顶层 active:false = 本剧长镜模式(scene_group_mode)未开启,groups 只是「开启后会怎么分」的预览、**不生效**——出视频按单镜逐个生成、按单镜计费,regenerate_shot_video 只动那一镜;要用分组先 update_project_settings 开启长镜模式。active:true 时 merged=true 的组才会整组一次生成。",
241
241
  "quote_regenerate_scene_group": "报价:重出**一个场景组**(整组一次视频请求,组内连贯性保留)要多少点。返回 quote_id。零扣费。shot_numbers 必须正好等于 get_scene_group_plan 里某一组的镜号。\n★可选 video_engine:只为这一次整组重出换引擎(不改剧级 video_engine);报价按它计、quote_id 钉死,regenerate_scene_group 派发的就是它。整组仍一次成片,所以整组总时长必须在该引擎单段上限内(hailuo-3 15s;seedance-2.5/wan3.0 30s)且支持本剧分辨率,否则 400——那种情况改用 update_shot 给个别镜设 video_engine(设了的镜会单独出)。报价按逐镜计(整组失败会逐镜兜底,逐镜是上界),正常路径实扣通常更低。",
242
242
  "regenerate_scene_group": "确认后重出一个场景组(整组一次视频请求,后台异步;用 get_storyboards 轮询各镜 video_url)。分组、引擎都由 quote_id 钉死,这里不能改;报价后组内任一镜被改、或分组变了,quote 作废(409),重新报价即可(免费)。⚠️ 批量报价确认流程:先调对应的 quote_* 工具拿 estimated_points 与 quote_id,再用 quote_id 调本工具(报价确认按执行模式:专业模式 / 未确认方案 / 本环节由客户把控 → 讲给客户、客户同意才做,别替客户决定;本环节托管 → 不问客户,照 get_production_plan 的 autopilot.default_decisions 执行,平台记进 get_autopilot_log)。托管环节报价须在预算硬上限内,被 402 BUDGET_WOULD_EXCEED 拦下就停下问客户。★**出图类报价(定妆图/场景图/出帧)给的是两个数**:estimated_points 是**上界**(按该模型参考图张数上限估,保证你不会按低了的预算开跑、出到一半 402 中断);同一响应里的 typical_points 是**通常花费**。两个都要告诉客户——只说上界会让人以为贵得多(满参考图的上界可达通常值的 2 倍以上),只说通常值又会让余额准备不足。固定价模型下两者相等,这时说一个数就行。出视频的报价与扣费同函数,不存在这个区间。",
243
243
  "generate_scene_groups": "生成场景组(把连续镜头归组,连续长镜/批量出图的地基)。后台异步。",
@@ -360,7 +360,8 @@ const PROJECT_SETTINGS_FIELDS = {
360
360
  speech: z.enum(['unspecified', 'forbidden', 'required']).optional(),
361
361
  music: z.enum(['unspecified', 'forbidden']).optional(),
362
362
  pacing: z.enum(['unspecified', 'quiet']).optional(),
363
- }).strict().nullable().optional().describe('客户明确创作约束:speech=forbidden 禁止对白/旁白/演唱,music=forbidden 仅禁止本片输出混入配乐(允许生成/保存/选择音乐素材),pacing=quiet 保持平静节奏。不推断;整对象替换,null 清除,省略保持。环境声/音效不受禁止人声影响。'),
363
+ ambient: z.enum(['normal', 'minimal']).optional(),
364
+ }).strict().nullable().optional().describe('客户明确创作约束:speech=forbidden 禁止对白/旁白/演唱,music=forbidden 仅禁止本片输出混入配乐(允许生成/保存/选择音乐素材),pacing=quiet 保持平静节奏,ambient=minimal 原声视频人声干净、环境音极轻、无底噪(客户嫌原声底噪/嘶声/嗡鸣大时设;默认 normal 保留自然环境音;只影响之后新出的视频,已出的要重出才生效)。不推断;★整对象替换——改其中一项要先 get_drama 读出现有 creative_contract 把其它键一并带上,否则被清掉;null 清除,省略保持。环境声/音效不受禁止人声影响。'),
364
365
  // drama 级图片模型(整剧统一画风):默认 ChatGPT Image 2.5 Flare(v0.9.1558)
365
366
  image_model: z.string().optional().describe('图片模型(★drama级·整剧统一画风·默认 ChatGPT Image 2.5 Flare)。可选:' +
366
367
  'gpt-image-2.5-flare(默认·基础11点+每张参考图18点)/gpt-image-2.5-sunburst(同价·中文字形与细节更准·慢约5秒)/' +
@@ -693,6 +694,7 @@ export function registerProduceTools(server, client) {
693
694
  'recovery_options 按帧位给出失败后的三选一(挑误拒 / 修图上传 / 重生),与 get_frame_retry_diagnosis 同口径。', { storyboard_id: z.number().int().positive() }, async ({ storyboard_id }) => jsonResult(await client.produceGet(`/storyboards/${storyboard_id}/frame-workbench`)));
694
695
  server.tool('adopt_frame_candidate', '免费:人工采用一张已出完的首帧/尾帧候选(被审计拒掉 rejected、落选 dismissed,或曾经在用后被换下的 completed),作为本镜在用帧——审计误判时的人工兜底(例如作者契约写明的设定被判成冲突),也可随时换回之前那张。' +
695
696
  '★必须先用 get_frame_candidates 让客户看过原图和拒因、客户明确同意采用后才调' + ALWAYS_ASK('采用被拒候选') + ';不许为了让流程走下去自行放行。' +
697
+ '★采用前先对照本镜分镜(get_storyboards 的 first_frame_prompt / last_frame_prompt / action_in / action_out / movement)确认:采首帧要是动作起点、采尾帧要是动作终点——首帧候选若已是动作终态(人已到位、动作已做完)或把运镜终点画进了起点,采用后视频里就没有动作过程,换一张或改提示词重出。' +
696
698
  '只能采用本镜本帧位、已出完、有画面、且不是当前在用的那张;会在该候选上记录人工放行(谁/何时/原拒因),原拒因保留供统计。' +
697
699
  '本镜已有视频的会标成待重生(视频是按旧帧出的,需 regenerate_shot_video)。本镜该帧是客户上传或已定稿的,要带 replace_user_frame:true 才会替换(并解除定稿)。' +
698
700
  '同帧位有在途出图或本镜视频在途时返回 409,等它结束再采用。', {
@@ -959,6 +961,7 @@ export function registerProduceTools(server, client) {
959
961
  '★前置:该剧已设 motifs(没设=空操作);会**改结尾镜 action/描述**,务必出图前做(否则结尾镜已出图会陈旧)。后台异步,文本步后付。', { episode_id: z.number().int().positive() }, async ({ episode_id }) => jsonResult(await client.producePost(`/episodes/${episode_id}/storyboards/complete-motifs`)));
960
962
  // ---------- 出首帧(frames) ----------
961
963
  server.tool('tail_frame_plan', '★免费只读:这一集**哪几镜需要独立尾帧**(末态≠首态的镜——大运镜/物体脱手/状态改变)。' +
964
+ '运镜镜(摇/推/拉/移/升降,起止画面不同)按剧灰度计入;运镜要写进分镜的 movement 或 action(如「镜头缓慢向下摇到…」),只写在提示词里的「固定机位」会被当成静止。' +
962
965
  '判定用的就是平台出视频时那套判据,你自己是猜不出来的,所以出完首帧务必调一次。' +
963
966
  '返回 shots_needing_last_frame(总数)、ready(已有首帧、现在就能补尾帧的镜)、' +
964
967
  'pending_first_frame(还需要尾帧但首帧尚未落地的镜——等首帧出完再调一次本工具)。' +
@@ -1019,15 +1022,19 @@ export function registerProduceTools(server, client) {
1019
1022
  '客户说「第 N 镜画错了/要改」时用它,而不是拿别的图像平台出图再 upload_shot_frame。' +
1020
1023
  '★响应带 billing_kind/unit_points(实际计费档与单价);要在 generate_shot_frame 里换模型,报价时传同一个 image_model。' +
1021
1024
  '★两边必须传同一个 image_model —— 不一致会被直接拒(400 IMAGE_MODEL_MISMATCH),因为模型决定计费档,不同源就是「预估≠扣费」。两边都不传也算一致(用该剧设定的模型)。已下架的型号(FLUX 全系列)一律拒收,别再传。' +
1025
+ '★frame_type=both 时,平台判这一镜不需要独立尾帧(末态≈首态、没有运镜)会只出首帧:报价 frames_to_generate=1、只计首帧,并带 last_frame_skipped 说明原因——**原样告诉客户尾帧不会出**。' +
1026
+ '客户确实要尾帧(例如起止画面不同的运镜)就报价与生成都带 force_independent_last_frame:true。' +
1022
1027
  QUOTE_RANGE_HINT, {
1023
1028
  storyboard_id: z.number().int().positive(),
1024
1029
  frame_type: FRAME_TYPE_ARG.optional().describe('默认 first_frame;both=首尾各一张'),
1025
1030
  image_model: z.string().optional().describe('按这个模型报价(★须与随后 generate_shot_frame 传的一致,否则 generate 会 400;不传=用 drama 级设定,默认 ChatGPT Image 2.5 Flare)'),
1026
- }, async ({ storyboard_id, frame_type, image_model }) => jsonResult(await client.producePost(`/storyboards/${storyboard_id}/frame/quote`, { frame_type, image_model })));
1031
+ force_independent_last_frame: z.boolean().optional().describe('只对 frame_type=both 有意义:true=客户明确要独立尾帧,不让平台判据跳过(报价按首尾两张算)。★须与 generate_shot_frame 传的一致,否则 409 重新报价'),
1032
+ }, async ({ storyboard_id, frame_type, image_model, force_independent_last_frame }) => jsonResult(await client.producePost(`/storyboards/${storyboard_id}/frame/quote`, { frame_type, image_model, force_independent_last_frame })));
1027
1033
  server.tool('generate_shot_frame', '确认后给**某一镜**出帧或重生该帧(异步)。这是修某一镜画面的正路:平台会带上该镜的角色身份锚、' +
1028
1034
  '场景/道具参考图、画风锚与帧审计,重生出的图与全片一致;用外部工具出图再上传会绕开这整条链路,人物/服装/画风必漂。' +
1029
1035
  '重生会覆盖该帧现有图(含此前上传的),并把本镜视频标为待重生。尾帧需本镜首帧已就绪(否则先用 first_frame 或 both)。' +
1030
- '完成判据:轮询 get_storyboards 看该镜 first_frame_image/last_frame_image 变化。\n' +
1036
+ '完成判据:轮询 get_storyboards 看该镜 first_frame_image/last_frame_image 变化。' +
1037
+ '★回执的 frames_dispatched 是真派出去的张数;both 的尾帧被平台判为不需要时会带 skipped_frames(没出、没扣尾帧的钱),原样告诉客户。\n' +
1031
1038
  '★继承重开(reopen_pair_id):get_storyboards 某镜带这个字段时,原样传进来可以只重掷首尾帧里' +
1032
1039
  '真正有问题的那一侧——另一侧此前已经生成好的候选原样保留,不重新生成、不重新计费。传了它就' +
1033
1040
  '不用再传 frame_type(会被忽略,由平台判定该重哪一侧);quote_id 仍要用 quote_shot_frame 报价' +
@@ -1046,9 +1053,10 @@ export function registerProduceTools(server, client) {
1046
1053
  reopen_pair_id: z.string().optional().describe('来自 get_storyboards 该镜的同名字段;只重掷有问题的那一侧,不必再传 frame_type'),
1047
1054
  image_model: z.string().optional().describe('临时覆盖本次重画的图片模型(★必须与 quote_shot_frame 传的那个一致,否则 400 IMAGE_MODEL_MISMATCH;不传=用 drama 级设定,默认 ChatGPT Image 2.5 Flare);取值同 generate_frames'),
1048
1055
  allow_missing_terminal: z.boolean().optional().describe('★逃生门,默认不传。本镜标为「状态改变」却没写终态时,出尾帧会被前置闸拦下;带 true 表示「我知道,照现状出」。正解是先 update_shot 补 last_frame_prompt——那类镜照现状出的成功率 9.4%,这个参数只用于确认本镜就该「几乎不变」的场合'),
1056
+ force_independent_last_frame: z.boolean().optional().describe('只对 frame_type=both 有意义:true=客户明确要独立尾帧,绕过平台判据(★须与 quote_shot_frame 传的一致)'),
1049
1057
  allow_era_ref_conflict: z.boolean().optional().describe('★默认不传。时代审核判定角色定妆参考与时代设定冲突时,出图会被拦下(未扣费):客户上传的定妆图及其派生图报 400 ERA_USER_REF_CONFLICT,平台生成的定妆图报 era_identity_ref_blocked。**先把冲突原因告诉客户、由客户确认造型无误**后才带 true' + ALWAYS_ASK('allow_era_ref_conflict ') + ':这些图保留不剔、照常出图。造型真不对就改定妆图,时代设定错了就 set_era_contract'),
1050
1058
  ...SHOT_REGEN_ARG,
1051
- }, async ({ storyboard_id, quote_id, review_token, asset_review_token, acknowledge_review, auto_acknowledge, frame_type, replace_user_frame, reopen_pair_id, image_model, allow_missing_terminal, allow_era_ref_conflict, customer_approved_more_regens }) => jsonResult(await client.producePost(`/storyboards/${storyboard_id}/frame/generate`, { quote_id, review_token, asset_review_token, acknowledge_review, auto_acknowledge, frame_type, replace_user_frame, reopen_pair_id, image_model, allow_missing_terminal, allow_era_ref_conflict, customer_approved_more_regens })));
1059
+ }, async ({ storyboard_id, quote_id, review_token, asset_review_token, acknowledge_review, auto_acknowledge, frame_type, replace_user_frame, reopen_pair_id, image_model, allow_missing_terminal, force_independent_last_frame, allow_era_ref_conflict, customer_approved_more_regens }) => jsonResult(await client.producePost(`/storyboards/${storyboard_id}/frame/generate`, { quote_id, review_token, asset_review_token, acknowledge_review, auto_acknowledge, frame_type, replace_user_frame, reopen_pair_id, image_model, allow_missing_terminal, force_independent_last_frame, allow_era_ref_conflict, customer_approved_more_regens })));
1052
1060
  // ---------- 镜头图局部返修(只修一小块,其余像素原样保留;按剧灰度) ----------
1053
1061
  const LOCAL_EDIT_ARGS = {
1054
1062
  storyboard_id: z.number().int().positive(),
@@ -1325,8 +1333,12 @@ export function registerProduceTools(server, client) {
1325
1333
  '(摄影DNA cinematography_prompt/美术圣经 art_bible/视觉锁定 visual_lock/视频风格正负向词/视觉母题 motifs)、' +
1326
1334
  '音频(bgm_source 自有vs原生/bgm_volume_preset 音量/use_clip_audio 用视频原声)、' +
1327
1335
  '字幕(show_subtitles/双语 subtitle_secondary_lang/位置/边距/动效)、转场——即项目设定页全部通用设定。免费。' +
1328
- '⚠️ 世界观 Brief/族裔/画幅/一致性锚等改后,已生成的内容不会自动更新,需重生对应内容。', {
1336
+ '⚠️ 世界观 Brief/族裔/画幅/一致性锚等改后,已生成的内容不会自动更新,需重生对应内容。' +
1337
+ '★frame_chain_mode 管整剧跨镜帧链:off=整剧不做(出帧落定后的自动衔接、chain_frames、首尾呼应都不派图不改帧,报价里也不再计入);' +
1338
+ 'reframe=默认;strict=相邻缝只裸拷贝上镜尾帧不重生(已设的首尾呼应仍按 reframe 重生、照常计入报价;要全不派图用 off)。关掉后想用 chain_frames 要先改回 reframe/strict;改模式不会自动重出已有帧。', {
1329
1339
  drama_id: z.number().int().positive(),
1340
+ frame_chain_mode: z.enum(['off', 'strict', 'reframe']).optional().describe('整剧跨镜帧链模式:off=整剧不做(含出帧落定后的自动衔接与 chain_frames)/strict=相邻缝只裸拷贝上镜尾帧(首尾呼应仍会重生计费)/reframe=默认。' +
1341
+ '关掉后想用 chain_frames 先改回 reframe 或 strict;改了不会自动重出已有帧。当前值见 get_drama 的 frame_chain_mode。'),
1330
1342
  genre: z.string().optional(),
1331
1343
  style: z.string().optional(),
1332
1344
  description: z.string().optional(),
@@ -1768,7 +1780,7 @@ export function registerProduceTools(server, client) {
1768
1780
  });
1769
1781
  server.tool('update_shot', '逐镜编辑:改单个分镜的文本内容(景别/动作/台词/画面描述/运镜等)、面部表情(expression_hint)、时长(duration)、成片变速(speed_factor)、镜间转场(transition_type / transition_duration_ms)、角色绑定(character_ids)、道具绑定(prop_ids)、画外音标记(character_presence)与服装绑定(active_wardrobe_id / appearance_wardrobes)。只传要改的字段、其余不动。★改镜(成功或被拒)都会作废覆盖本镜的未消费报价,生成时回 409 QUOTE_INVALIDATED——先改成功、回读核对,再报价。' +
1770
1782
  '**免费**(纯文本写库)。★改 dialogue 会自动失效本镜已生成的 TTS 配音与字幕(需重出 tts);' +
1771
- '改文本不会自动重出图/视频,如需让画面跟上文本改动,改完再 regen 对应镜。用 get_storyboards 查改后结果(每镜带 character_ids / character_bindings / scene_id / prop_ids / active_wardrobe_id / appearance_wardrobes)。' +
1783
+ '改文本不会自动重出图/视频,如需让画面跟上文本改动,改完再 regen 对应镜。用 get_storyboards 查改后结果(每镜带 character_ids / character_bindings / scene_id / prop_ids / active_wardrobe_id / appearance_wardrobes);景别/机位/运镜/剪辑意图与提示词正文用 get_shot_prompts 逐镜回读。' +
1772
1784
  '★★【换衣服改这里,不是改文字】出图穿什么由**服装绑定**决定:单人镜用 active_wardrobe_id(整镜一件),' +
1773
1785
  '多人同框各穿各的用 appearance_wardrobes(逐角色)。把「穿某某衣服」写进 description/action 不会换衣服。' +
1774
1786
  '服装 id 用 list_wardrobe 查;改完不会自动重出图,要让画面跟上需重生本镜首帧再重生视频。' +
@@ -1788,7 +1800,14 @@ export function registerProduceTools(server, client) {
1788
1800
  '还是会被拒,而每次重生都照常扣费。get_shot_prompts 的 terminal_desc_missing=true 就是这个信号。', {
1789
1801
  storyboard_id: z.number().int().positive(),
1790
1802
  product_text_contract: z.object({ version: z.literal(1), strategy: z.enum(['generate_with_review', 'original_media', 'postproduction']), targets: z.array(z.object({ asset_kind: z.enum(['prop', 'product']), asset_id: z.number().int().positive(), reference_url: z.string().url(), region: z.object({ x: z.number(), y: z.number(), width: z.number(), height: z.number() }), exact_text: z.string().min(1).max(256) })).min(1).max(4) }).nullable().optional().describe('明确保留的实物原字:资产 ID、原图、归一化区域、原文及处理方式;生成不保证逐字正确,必须人工核对。null 清除声明,不回填历史。'),
1791
- continuity_intent: z.enum(['continuous_action', 'shot_change', 'insert_detail', 'jump_cut']).optional().describe('本镜相对上镜的剪辑意图:连续动作、换景别、插入细节、有意跳切。改变后旧双边审核失效;不自动生成或补审。'),
1803
+ continuity_intent: z.enum(['continuous_action', 'shot_change', 'insert_detail', 'jump_cut']).optional().describe('本镜相对上镜的剪辑意图,决定跨镜帧链与续拍怎么接:' +
1804
+ 'continuous_action=同一动作往下走——帧链接续(本镜首帧接上镜尾帧);同场景、同景别、同一组角色且不是正反打时,平台开了续拍的剧会改走续拍' +
1805
+ '(拿上一镜视频当参考往下延长,不送本镜首尾帧);' +
1806
+ 'shot_change=换景别/换机位(含正反打、过肩反打)——帧链按上镜尾帧重取景出本镜首帧,★不走续拍,本镜照常按自己的首尾帧出视频;' +
1807
+ 'insert_detail=插入细节镜——断开帧链、不续拍,本镜独立出;' +
1808
+ 'jump_cut=有意跳切——断开帧链、不续拍,本镜独立出。' +
1809
+ '★正反打/过肩反打(越过A肩头拍B → 越过B肩头拍A)标 shot_change,别标 continuous_action。剧级 frame_chain_mode=off 时帧链一律不接,续拍规则不变。' +
1810
+ '改变后旧双边审核失效;不自动生成或补审,已出的帧/视频不会自动重出。'),
1792
1811
  character_ids: z.array(z.number().int().positive()).optional()
1793
1812
  .describe('本镜出场角色 ID 列表(★全量覆盖式,非增量,漏传的角色会被解绑)。决定出图时注入哪些角色的定妆图/设定图——非人角色(动物/生物)也必须绑定,否则形象会漂移。id 必须来自当前集已关联角色'),
1794
1813
  prop_ids: z.array(z.number().int().positive()).max(8).optional()
@@ -1822,6 +1841,8 @@ export function registerProduceTools(server, client) {
1822
1841
  lighting: z.string().optional().describe('本镜用光(如「逆光」「左侧窗光、脸一半在暗处」)。★用光写这里,不要写进画面描述(description)或提示词:' +
1823
1842
  '那几个字段写光影词会被 review_storyboards 判 forbidden_term 拦下,这一条不在禁区词扫描范围。出视频时作为 [Lighting] 段送达,出图按它匹配场景光照变体。' +
1824
1843
  '全量覆盖现值,现值用 get_shot_prompts 读;改完不会自动重出图/视频'),
1844
+ sound_effect: z.string().nullable().optional().describe('本镜音效(如「木门吱呀」「远处犬吠」;全量覆盖现值,null 清空)。出视频时作为 [Audio] 段送给视频引擎,' +
1845
+ 'review_storyboards 的禁区词也扫这一条(hits 里 field=sound_effect 时就在这里改)。现值用 get_shot_prompts 读;改完不会自动重出视频,要让声音跟上需重生本镜视频(先报价)'),
1825
1846
  shot_type: z.string().optional().describe('景别(如 特写/中景/全景/远景)'),
1826
1847
  angle: z.string().optional().describe('机位角度'),
1827
1848
  camera_movement: z.string().optional().describe('运镜(推/拉/摇/移/跟/固定)'),
@@ -1871,7 +1892,8 @@ export function registerProduceTools(server, client) {
1871
1892
  '★回执里的 terminal_desc_missing=true 表示本镜标为「状态改变」却三处都没说终态——' +
1872
1893
  '出尾帧会被前置闸拦下,修法是把结束状态写进 last_frame_prompt(别重试出图,重试必然重复被拒且照常扣费)。' +
1873
1894
  '★pose_timeline_stale 非 null = 本镜动作起止姿态里的秒数时间轴超出了当前时长(多见于改短 duration 后),出视频时那一端已自动不送;新时间轴写进 video_prompt。' +
1874
- '★同时回 description(画面描述)与 lighting(本镜用光)现值——review_storyboards 的禁区词命中常在 description,改前先在这里读;用光写 lighting。' +
1895
+ '★同时回 description(画面描述)、lighting(本镜用光)与 sound_effect(本镜音效)现值——review_storyboards 的禁区词命中常在 description / sound_effect,改前先在这里读;用光写 lighting。' +
1896
+ '★同时回 shot_type(景别)/ angle(机位)/ camera_movement(运镜)/ continuity_intent(剪辑意图)现值——update_shot 改完这几项就在这里回读核对(整集 get_storyboards 不含它们);null=未设。' +
1875
1897
  '★同时回 expression_hint(本镜作者指定的面部表情,null=未指定、由平台按台词反推),改它用 update_shot。' +
1876
1898
  'expression_inferred 是拆镜 AI 在剧本没写神态时按本镜内容推断的表情(只读;null=没推断,或本镜台词/动作/氛围/描述/强度改过、推断已过期不再使用);它优先级低于 expression_hint——' +
1877
1899
  '推断不合意就用 update_shot 写 expression_hint 覆盖它。' +
@@ -2167,7 +2189,7 @@ export function registerProduceTools(server, client) {
2167
2189
  server.tool('translate_subtitles', '把某集字幕翻译成第二语言并开启双语。后台异步,按用量后付不欠费。', { episode_id: z.number().int().positive(), lang: z.string().describe('目标语言(如 en/ja/ko)') }, async ({ episode_id, lang }) => jsonResult(await client.producePost(`/episodes/${episode_id}/subtitles/translate`, { lang })));
2168
2190
  // ========== P1 · 读取层(闭环必需:能读回自己建的东西)==========
2169
2191
  server.tool('list_dramas', '列出我名下的所有短剧(drama_id/剧名/类型/集数/进度)。免费。', {}, async () => jsonResult(await client.produceGet('/dramas')));
2170
- server.tool('get_drama', '读一部剧的详情(设定/角色数/场景数/资产统计等)。免费。', { drama_id: z.number().int().positive() }, async ({ drama_id }) => jsonResult(await client.produceGet(`/dramas/${drama_id}`)));
2192
+ server.tool('get_drama', '读一部剧的详情(设定/角色数/场景数/资产统计等)。免费。frame_chain_mode = 整剧跨镜帧链模式(off/strict/reframe,改用 update_project_settings)。', { drama_id: z.number().int().positive() }, async ({ drama_id }) => jsonResult(await client.produceGet(`/dramas/${drama_id}`)));
2171
2193
  server.tool('get_characters', '读某一集的角色列表(名字/定妆图/设定图就绪状态)。免费。每角色带结构化状态:' +
2172
2194
  'portrait_status/sheet_status(ready=已入库/pending=生成或审计中·别重复点/rejected=图已生成但被' +
2173
2195
  '一致性闸拒收未入库/failed/none)+ 拒收时的 sheet_fail_reason·sheet_retryable·sheet_fail_hint(拒收判词)。' +
@@ -2555,6 +2577,7 @@ export function registerProduceTools(server, client) {
2555
2577
  '★平台自己判哪道缝该接:有意切换(换场/时间跳跃/换装/插入镜)、已出视频的镜、已经接好的缝都会跳过——' +
2556
2578
  '「已接好」= 首帧就是上镜尾帧,或 reframe 接在上镜**当前**尾帧上,所以重复执行不会重复扣费。' +
2557
2579
  '上镜尾帧后来被重生过的缝会重新出现在计划里,那道缝确实断了。只补个别缝用 chain_shot_from_prev / chain_shot_from。' +
2580
+ '剧级 frame_chain_mode=off 时整集不接(计划为空),要接先 update_project_settings 改回 reframe/strict。' +
2558
2581
  '执行后改了首帧的镜若已有视频会被标为待重生。★执行只派发 reframe、不等出图:用 get_jobs 看这些镜的 first_frame 出图行,' +
2559
2582
  '等 pending/processing 全部结束(failed 的看 error_msg,单道用 chain_shot_from 重接;旧首帧还在时 get_storyboards 的 frame_status 仍是 ready、看不出失败),' +
2560
2583
  '再用 get_storyboards 核对 seam_state、review_frames——提前审会审到旧首帧,token 随后作废。', {
@@ -2608,7 +2631,10 @@ export function registerProduceTools(server, client) {
2608
2631
  storyboard_id: z.number().int().positive().describe('缝右侧那一镜'),
2609
2632
  quote_id: z.string().describe('来自 quote_align_prev_shot'),
2610
2633
  }, async ({ storyboard_id, quote_id }) => jsonResult(await client.producePost(`/storyboards/${storyboard_id}/align-prev`, { quote_id })));
2611
- server.tool('get_scene_group_plan', '查某一集的场景组规划(镜头如何归组做连续长镜)。免费。', { episode_id: z.number().int().positive() }, async ({ episode_id }) => jsonResult(await client.produceGet(`/episodes/${episode_id}/scene-group-plan`)));
2634
+ server.tool('get_scene_group_plan', '查某一集的场景组规划(镜头如何归组做连续长镜)。免费。' +
2635
+ '★先看回执顶层 active:false = 本剧长镜模式(scene_group_mode)未开启,groups 只是「开启后会怎么分」的预览、**不生效**——' +
2636
+ '出视频按单镜逐个生成、按单镜计费,regenerate_shot_video 只动那一镜;要用分组先 update_project_settings 开启长镜模式。' +
2637
+ 'active:true 时 merged=true 的组才会整组一次生成。', { episode_id: z.number().int().positive() }, async ({ episode_id }) => jsonResult(await client.produceGet(`/episodes/${episode_id}/scene-group-plan`)));
2612
2638
  server.tool('quote_regenerate_scene_group', '报价:重出**一个场景组**(整组一次视频请求,组内连贯性保留)要多少点。返回 quote_id。零扣费。' +
2613
2639
  'shot_numbers 必须正好等于 get_scene_group_plan 里某一组的镜号。' +
2614
2640
  '\n★可选 video_engine:只为这一次整组重出换引擎(不改剧级 video_engine);报价按它计、quote_id 钉死,regenerate_scene_group 派发的就是它。' +
package/openapi.json CHANGED
@@ -2,8 +2,8 @@
2
2
  "openapi": "3.1.0",
3
3
  "info": {
4
4
  "title": "StarReel Production API",
5
- "version": "0.1.224",
6
- "description": "Turn a script into a finished, downloadable short-drama episode over REST.\n\nPipeline: script → AI rewrite → cast/scenes/props extraction → storyboards → portraits & sheets + scene plates → keyframes → video shots → TTS → final cut (.mp4).\n\n**Billing is prepaid and agent-safe**: big-ticket stages are quote-then-generate (`quote_*` returns a `quote_id`). For video, quote == actual charge. For images the quote is a *range* — models billed per reference image are priced before those are assembled, so `estimated_points` is the upper bound (size the balance by it and a run never dies half-way) and `typical_points` is the usual cost; fixed-price models return the two equal. Insufficient balance returns 402 — nothing half-runs and the account never goes negative.\n\nAuth: exchange your API key at `POST /v1/agent/token` for a 15-minute bearer token.\n\nGenerated from the @starreel/mcp v0.1.224 tool surface (operationIds match MCP tool names 1:1)."
5
+ "version": "0.1.230",
6
+ "description": "Turn a script into a finished, downloadable short-drama episode over REST.\n\nPipeline: script → AI rewrite → cast/scenes/props extraction → storyboards → portraits & sheets + scene plates → keyframes → video shots → TTS → final cut (.mp4).\n\n**Billing is prepaid and agent-safe**: big-ticket stages are quote-then-generate (`quote_*` returns a `quote_id`). For video, quote == actual charge. For images the quote is a *range* — models billed per reference image are priced before those are assembled, so `estimated_points` is the upper bound (size the balance by it and a run never dies half-way) and `typical_points` is the usual cost; fixed-price models return the two equal. Insufficient balance returns 402 — nothing half-runs and the account never goes negative.\n\nAuth: exchange your API key at `POST /v1/agent/token` for a 15-minute bearer token.\n\nGenerated from the @starreel/mcp v0.1.230 tool surface (operationIds match MCP tool names 1:1)."
7
7
  },
8
8
  "servers": [
9
9
  {
@@ -1059,6 +1059,13 @@
1059
1059
  "unspecified",
1060
1060
  "quiet"
1061
1061
  ]
1062
+ },
1063
+ "ambient": {
1064
+ "type": "string",
1065
+ "enum": [
1066
+ "normal",
1067
+ "minimal"
1068
+ ]
1062
1069
  }
1063
1070
  },
1064
1071
  "required": [
@@ -1257,7 +1264,7 @@
1257
1264
  "put": {
1258
1265
  "operationId": "update_project_settings",
1259
1266
  "summary": "建剧后修改项目设定",
1260
- "description": "建剧后修改项目设定。除画幅/分辨率/世界观Brief/族裔/题材/导演风格外,现覆盖★整剧视觉一致性锚(摄影DNA cinematography_prompt/美术圣经 art_bible/视觉锁定 visual_lock/视频风格正负向词/视觉母题 motifs)、音频(bgm_source 自有vs原生/bgm_volume_preset 音量/use_clip_audio 用视频原声)、字幕(show_subtitles/双语 subtitle_secondary_lang/位置/边距/动效)、转场——即项目设定页全部通用设定。免费。⚠️ 世界观 Brief/族裔/画幅/一致性锚等改后,已生成的内容不会自动更新,需重生对应内容。",
1267
+ "description": "建剧后修改项目设定。除画幅/分辨率/世界观Brief/族裔/题材/导演风格外,现覆盖★整剧视觉一致性锚(摄影DNA cinematography_prompt/美术圣经 art_bible/视觉锁定 visual_lock/视频风格正负向词/视觉母题 motifs)、音频(bgm_source 自有vs原生/bgm_volume_preset 音量/use_clip_audio 用视频原声)、字幕(show_subtitles/双语 subtitle_secondary_lang/位置/边距/动效)、转场——即项目设定页全部通用设定。免费。⚠️ 世界观 Brief/族裔/画幅/一致性锚等改后,已生成的内容不会自动更新,需重生对应内容。★frame_chain_mode 管整剧跨镜帧链:off=整剧不做(出帧落定后的自动衔接、chain_frames、首尾呼应都不派图不改帧,报价里也不再计入);reframe=默认;strict=相邻缝只裸拷贝上镜尾帧不重生(已设的首尾呼应仍按 reframe 重生、照常计入报价;要全不派图用 off)。关掉后想用 chain_frames 要先改回 reframe/strict;改模式不会自动重出已有帧。",
1261
1268
  "tags": [
1262
1269
  "dramas"
1263
1270
  ],
@@ -1279,6 +1286,14 @@
1279
1286
  "schema": {
1280
1287
  "type": "object",
1281
1288
  "properties": {
1289
+ "frame_chain_mode": {
1290
+ "type": "string",
1291
+ "enum": [
1292
+ "off",
1293
+ "strict",
1294
+ "reframe"
1295
+ ]
1296
+ },
1282
1297
  "genre": {
1283
1298
  "type": "string"
1284
1299
  },
@@ -1426,6 +1441,13 @@
1426
1441
  "unspecified",
1427
1442
  "quiet"
1428
1443
  ]
1444
+ },
1445
+ "ambient": {
1446
+ "type": "string",
1447
+ "enum": [
1448
+ "normal",
1449
+ "minimal"
1450
+ ]
1429
1451
  }
1430
1452
  },
1431
1453
  "required": [
@@ -1585,7 +1607,7 @@
1585
1607
  "get": {
1586
1608
  "operationId": "get_drama",
1587
1609
  "summary": "读一部剧的详情(设定/角色数/场景数/资产统计等)",
1588
- "description": "读一部剧的详情(设定/角色数/场景数/资产统计等)。免费。",
1610
+ "description": "读一部剧的详情(设定/角色数/场景数/资产统计等)。免费。frame_chain_mode = 整剧跨镜帧链模式(off/strict/reframe,改用 update_project_settings)。",
1589
1611
  "tags": [
1590
1612
  "dramas"
1591
1613
  ],
@@ -6005,7 +6027,7 @@
6005
6027
  "post": {
6006
6028
  "operationId": "chain_frames",
6007
6029
  "summary": "整集首尾帧接力链:让每镜首帧承接上镜尾帧,镜间画面连续(比各镜独立出帧更顺)",
6008
- "description": "整集首尾帧接力链:让每镜首帧承接上镜尾帧,镜间画面连续(比各镜独立出帧更顺)。★何时调:首帧出完、tail_frame_plan 要的尾帧也补完之后,review_frames / generate_videos 之前。平台只在官网批量出帧结束时自动跑一次;逐镜出帧(generate_frames / generate_shot_frame)的集多半从没接过——get_storyboards 的 seam_state=unchained 就是这种缝。\n★先 dry_run:true(免费,不写库不出图):回 planned_copy / planned_reframe / estimated_points / needs_last_frame。copy=本镜首帧直接换成上镜尾帧(免费,但本镜景别会变成和上镜一样);reframe=以上镜尾帧为锚按本镜画面描述重生首帧(每道一张图,保景别)。把计划和 estimated_points 告诉客户,确认后**不带 dry_run** 再调一次执行(按用量后付)。\n★平台自己判哪道缝该接:有意切换(换场/时间跳跃/换装/插入镜)、已出视频的镜、已经接好的缝都会跳过——「已接好」= 首帧就是上镜尾帧,或 reframe 接在上镜**当前**尾帧上,所以重复执行不会重复扣费。上镜尾帧后来被重生过的缝会重新出现在计划里,那道缝确实断了。只补个别缝用 chain_shot_from_prev / chain_shot_from。执行后改了首帧的镜若已有视频会被标为待重生。★执行只派发 reframe、不等出图:用 get_jobs 看这些镜的 first_frame 出图行,等 pending/processing 全部结束(failed 的看 error_msg,单道用 chain_shot_from 重接;旧首帧还在时 get_storyboards 的 frame_status 仍是 ready、看不出失败),再用 get_storyboards 核对 seam_state、review_frames——提前审会审到旧首帧,token 随后作废。",
6030
+ "description": "整集首尾帧接力链:让每镜首帧承接上镜尾帧,镜间画面连续(比各镜独立出帧更顺)。★何时调:首帧出完、tail_frame_plan 要的尾帧也补完之后,review_frames / generate_videos 之前。平台只在官网批量出帧结束时自动跑一次;逐镜出帧(generate_frames / generate_shot_frame)的集多半从没接过——get_storyboards 的 seam_state=unchained 就是这种缝。\n★先 dry_run:true(免费,不写库不出图):回 planned_copy / planned_reframe / estimated_points / needs_last_frame。copy=本镜首帧直接换成上镜尾帧(免费,但本镜景别会变成和上镜一样);reframe=以上镜尾帧为锚按本镜画面描述重生首帧(每道一张图,保景别)。把计划和 estimated_points 告诉客户,确认后**不带 dry_run** 再调一次执行(按用量后付)。\n★平台自己判哪道缝该接:有意切换(换场/时间跳跃/换装/插入镜)、已出视频的镜、已经接好的缝都会跳过——「已接好」= 首帧就是上镜尾帧,或 reframe 接在上镜**当前**尾帧上,所以重复执行不会重复扣费。上镜尾帧后来被重生过的缝会重新出现在计划里,那道缝确实断了。只补个别缝用 chain_shot_from_prev / chain_shot_from。剧级 frame_chain_mode=off 时整集不接(计划为空),要接先 update_project_settings 改回 reframe/strict。执行后改了首帧的镜若已有视频会被标为待重生。★执行只派发 reframe、不等出图:用 get_jobs 看这些镜的 first_frame 出图行,等 pending/processing 全部结束(failed 的看 error_msg,单道用 chain_shot_from 重接;旧首帧还在时 get_storyboards 的 frame_status 仍是 ready、看不出失败),再用 get_storyboards 核对 seam_state、review_frames——提前审会审到旧首帧,token 随后作废。",
6009
6031
  "tags": [
6010
6032
  "episodes"
6011
6033
  ],
@@ -7528,7 +7550,7 @@
7528
7550
  "get": {
7529
7551
  "operationId": "tail_frame_plan",
7530
7552
  "summary": "★免费只读:这一集**哪几镜需要独立尾帧**(末态≠首态的镜——大运镜/物体脱手/状态改变)",
7531
- "description": "★免费只读:这一集**哪几镜需要独立尾帧**(末态≠首态的镜——大运镜/物体脱手/状态改变)。判定用的就是平台出视频时那套判据,你自己是猜不出来的,所以出完首帧务必调一次。返回 shots_needing_last_frame(总数)、ready(已有首帧、现在就能补尾帧的镜)、pending_first_frame(还需要尾帧但首帧尚未落地的镜——等首帧出完再调一次本工具)。拿到 ready 清单后:quote_frames + generate_frames 带 frame_type=last_frame 即可批量补。★尾帧补完(或本工具报 0)之后的下一步是接缝:chain_frames(dry_run:true) 看计划与预估、客户确认后执行,再 review_frames。★跳过尾帧不会报错,但那些镜出视频时只有首帧一个锚,末态由模型自由发挥——动作做不到位、大运镜结束又回到起点构图,多半就是这么来的。零扣费,可随时调。",
7553
+ "description": "★免费只读:这一集**哪几镜需要独立尾帧**(末态≠首态的镜——大运镜/物体脱手/状态改变)。运镜镜(摇/推/拉/移/升降,起止画面不同)按剧灰度计入;运镜要写进分镜的 movement 或 action(如「镜头缓慢向下摇到…」),只写在提示词里的「固定机位」会被当成静止。判定用的就是平台出视频时那套判据,你自己是猜不出来的,所以出完首帧务必调一次。返回 shots_needing_last_frame(总数)、ready(已有首帧、现在就能补尾帧的镜)、pending_first_frame(还需要尾帧但首帧尚未落地的镜——等首帧出完再调一次本工具)。拿到 ready 清单后:quote_frames + generate_frames 带 frame_type=last_frame 即可批量补。★尾帧补完(或本工具报 0)之后的下一步是接缝:chain_frames(dry_run:true) 看计划与预估、客户确认后执行,再 review_frames。★跳过尾帧不会报错,但那些镜出视频时只有首帧一个锚,末态由模型自由发挥——动作做不到位、大运镜结束又回到起点构图,多半就是这么来的。零扣费,可随时调。",
7532
7554
  "tags": [
7533
7555
  "episodes"
7534
7556
  ],
@@ -9245,7 +9267,7 @@
9245
9267
  "get": {
9246
9268
  "operationId": "get_scene_group_plan",
9247
9269
  "summary": "查某一集的场景组规划(镜头如何归组做连续长镜)",
9248
- "description": "查某一集的场景组规划(镜头如何归组做连续长镜)。免费。",
9270
+ "description": "查某一集的场景组规划(镜头如何归组做连续长镜)。免费。★先看回执顶层 active:false = 本剧长镜模式(scene_group_mode)未开启,groups 只是「开启后会怎么分」的预览、**不生效**——出视频按单镜逐个生成、按单镜计费,regenerate_shot_video 只动那一镜;要用分组先 update_project_settings 开启长镜模式。active:true 时 merged=true 的组才会整组一次生成。",
9249
9271
  "tags": [
9250
9272
  "episodes"
9251
9273
  ],
@@ -13261,7 +13283,7 @@
13261
13283
  "put": {
13262
13284
  "operationId": "update_shot",
13263
13285
  "summary": "逐镜编辑:改单个分镜的文本内容(景别/动作/台词/画面描述/运镜等)、面部表情(expression_hint)、时长(duration)、成片变速(speed_factor)、镜间转场(transition_type / transiti",
13264
- "description": "逐镜编辑:改单个分镜的文本内容(景别/动作/台词/画面描述/运镜等)、面部表情(expression_hint)、时长(duration)、成片变速(speed_factor)、镜间转场(transition_type / transition_duration_ms)、角色绑定(character_ids)、道具绑定(prop_ids)、画外音标记(character_presence)与服装绑定(active_wardrobe_id / appearance_wardrobes)。只传要改的字段、其余不动。★改镜(成功或被拒)都会作废覆盖本镜的未消费报价,生成时回 409 QUOTE_INVALIDATED——先改成功、回读核对,再报价。**免费**(纯文本写库)。★改 dialogue 会自动失效本镜已生成的 TTS 配音与字幕(需重出 tts);改文本不会自动重出图/视频,如需让画面跟上文本改动,改完再 regen 对应镜。用 get_storyboards 查改后结果(每镜带 character_ids / character_bindings / scene_id / prop_ids / active_wardrobe_id / appearance_wardrobes)。★★【换衣服改这里,不是改文字】出图穿什么由**服装绑定**决定:单人镜用 active_wardrobe_id(整镜一件),多人同框各穿各的用 appearance_wardrobes(逐角色)。把「穿某某衣服」写进 description/action 不会换衣服。服装 id 用 list_wardrobe 查;改完不会自动重出图,要让画面跟上需重生本镜首帧再重生视频。★★原声镜(厂商原生音频)改 dialogue 后,本镜视频会被标记「待重生」——因为台词是**烤进视频人声**的,不重生就终拼,成片里念的仍是改动前的台词(典型现象:台词像是跑到了别的镜头上)。compose_episode 会以 advisory `stale_video_after_edit` 列出这些镜;正确处置是先 regenerate_shot_video 再终拼。★也可直接改本镜的四条提示词正文(image_prompt/video_prompt/first_frame_prompt/last_frame_prompt):改前先用 get_shot_prompts 读现值,别凭空覆盖——正文里的 @char:N / @scene:M 是出图时的补充参考标记,照原样保留即可。★注入谁的定妆图由 character_ids 决定、背景由 scene_id 决定:删标记不会让已绑定的人从画面消失,要让某人不出现就改 character_ids,他只有声音(画外音)就用 character_presence 标 voice_only;反过来别给未绑定的角色写 @char 标记——会把他的图注入进来。★★【出尾帧被拦下就是来改这里】出尾帧若报「此镜标为状态改变,但没有任何地方说明结束时是什么样子」(TERMINAL_DESC_GATE),修法是把**结束时画面是什么样**写进本镜 last_frame_prompt,然后重新出尾帧。别去重试出图——这类镜(action_motion_class=state_change 却没写终态)的尾帧历史成功率 9.4%,有终态描述的是 40.2%;不补描述就重生,送厂商的提示词里根本没有终态段,画出来仍和首帧一样、还是会被拒,而每次重生都照常扣费。get_shot_prompts 的 terminal_desc_missing=true 就是这个信号。",
13286
+ "description": "逐镜编辑:改单个分镜的文本内容(景别/动作/台词/画面描述/运镜等)、面部表情(expression_hint)、时长(duration)、成片变速(speed_factor)、镜间转场(transition_type / transition_duration_ms)、角色绑定(character_ids)、道具绑定(prop_ids)、画外音标记(character_presence)与服装绑定(active_wardrobe_id / appearance_wardrobes)。只传要改的字段、其余不动。★改镜(成功或被拒)都会作废覆盖本镜的未消费报价,生成时回 409 QUOTE_INVALIDATED——先改成功、回读核对,再报价。**免费**(纯文本写库)。★改 dialogue 会自动失效本镜已生成的 TTS 配音与字幕(需重出 tts);改文本不会自动重出图/视频,如需让画面跟上文本改动,改完再 regen 对应镜。用 get_storyboards 查改后结果(每镜带 character_ids / character_bindings / scene_id / prop_ids / active_wardrobe_id / appearance_wardrobes);景别/机位/运镜/剪辑意图与提示词正文用 get_shot_prompts 逐镜回读。★★【换衣服改这里,不是改文字】出图穿什么由**服装绑定**决定:单人镜用 active_wardrobe_id(整镜一件),多人同框各穿各的用 appearance_wardrobes(逐角色)。把「穿某某衣服」写进 description/action 不会换衣服。服装 id 用 list_wardrobe 查;改完不会自动重出图,要让画面跟上需重生本镜首帧再重生视频。★★原声镜(厂商原生音频)改 dialogue 后,本镜视频会被标记「待重生」——因为台词是**烤进视频人声**的,不重生就终拼,成片里念的仍是改动前的台词(典型现象:台词像是跑到了别的镜头上)。compose_episode 会以 advisory `stale_video_after_edit` 列出这些镜;正确处置是先 regenerate_shot_video 再终拼。★也可直接改本镜的四条提示词正文(image_prompt/video_prompt/first_frame_prompt/last_frame_prompt):改前先用 get_shot_prompts 读现值,别凭空覆盖——正文里的 @char:N / @scene:M 是出图时的补充参考标记,照原样保留即可。★注入谁的定妆图由 character_ids 决定、背景由 scene_id 决定:删标记不会让已绑定的人从画面消失,要让某人不出现就改 character_ids,他只有声音(画外音)就用 character_presence 标 voice_only;反过来别给未绑定的角色写 @char 标记——会把他的图注入进来。★★【出尾帧被拦下就是来改这里】出尾帧若报「此镜标为状态改变,但没有任何地方说明结束时是什么样子」(TERMINAL_DESC_GATE),修法是把**结束时画面是什么样**写进本镜 last_frame_prompt,然后重新出尾帧。别去重试出图——这类镜(action_motion_class=state_change 却没写终态)的尾帧历史成功率 9.4%,有终态描述的是 40.2%;不补描述就重生,送厂商的提示词里根本没有终态段,画出来仍和首帧一样、还是会被拒,而每次重生都照常扣费。get_shot_prompts 的 terminal_desc_missing=true 就是这个信号。",
13265
13287
  "tags": [
13266
13288
  "storyboards"
13267
13289
  ],
@@ -13472,6 +13494,12 @@
13472
13494
  "lighting": {
13473
13495
  "type": "string"
13474
13496
  },
13497
+ "sound_effect": {
13498
+ "type": [
13499
+ "string",
13500
+ "null"
13501
+ ]
13502
+ },
13475
13503
  "shot_type": {
13476
13504
  "type": "string"
13477
13505
  },
@@ -14322,7 +14350,7 @@
14322
14350
  "post": {
14323
14351
  "operationId": "adopt_frame_candidate",
14324
14352
  "summary": "免费:人工采用一张已出完的首帧/尾帧候选(被审计拒掉 rejected、落选 dismissed,或曾经在用后被换下的 completed),作为本镜在用帧——审计误判时的人工兜底(例如作者契约写明的设定被判成冲突),也可随时换回之前那张",
14325
- "description": "免费:人工采用一张已出完的首帧/尾帧候选(被审计拒掉 rejected、落选 dismissed,或曾经在用后被换下的 completed),作为本镜在用帧——审计误判时的人工兜底(例如作者契约写明的设定被判成冲突),也可随时换回之前那张。★必须先用 get_frame_candidates 让客户看过原图和拒因、客户明确同意采用后才调(采用被拒候选任何执行模式都须客户明确同意,托管也不例外);不许为了让流程走下去自行放行。只能采用本镜本帧位、已出完、有画面、且不是当前在用的那张;会在该候选上记录人工放行(谁/何时/原拒因),原拒因保留供统计。本镜已有视频的会标成待重生(视频是按旧帧出的,需 regenerate_shot_video)。本镜该帧是客户上传或已定稿的,要带 replace_user_frame:true 才会替换(并解除定稿)。同帧位有在途出图或本镜视频在途时返回 409,等它结束再采用。",
14353
+ "description": "免费:人工采用一张已出完的首帧/尾帧候选(被审计拒掉 rejected、落选 dismissed,或曾经在用后被换下的 completed),作为本镜在用帧——审计误判时的人工兜底(例如作者契约写明的设定被判成冲突),也可随时换回之前那张。★必须先用 get_frame_candidates 让客户看过原图和拒因、客户明确同意采用后才调(采用被拒候选任何执行模式都须客户明确同意,托管也不例外);不许为了让流程走下去自行放行。★采用前先对照本镜分镜(get_storyboards 的 first_frame_prompt / last_frame_prompt / action_in / action_out / movement)确认:采首帧要是动作起点、采尾帧要是动作终点——首帧候选若已是动作终态(人已到位、动作已做完)或把运镜终点画进了起点,采用后视频里就没有动作过程,换一张或改提示词重出。只能采用本镜本帧位、已出完、有画面、且不是当前在用的那张;会在该候选上记录人工放行(谁/何时/原拒因),原拒因保留供统计。本镜已有视频的会标成待重生(视频是按旧帧出的,需 regenerate_shot_video)。本镜该帧是客户上传或已定稿的,要带 replace_user_frame:true 才会替换(并解除定稿)。同帧位有在途出图或本镜视频在途时返回 409,等它结束再采用。",
14326
14354
  "tags": [
14327
14355
  "storyboards"
14328
14356
  ],
@@ -14466,7 +14494,7 @@
14466
14494
  "post": {
14467
14495
  "operationId": "generate_shot_frame",
14468
14496
  "summary": "确认后给**某一镜**出帧或重生该帧(异步)",
14469
- "description": "确认后给**某一镜**出帧或重生该帧(异步)。这是修某一镜画面的正路:平台会带上该镜的角色身份锚、场景/道具参考图、画风锚与帧审计,重生出的图与全片一致;用外部工具出图再上传会绕开这整条链路,人物/服装/画风必漂。重生会覆盖该帧现有图(含此前上传的),并把本镜视频标为待重生。尾帧需本镜首帧已就绪(否则先用 first_frame 或 both)。完成判据:轮询 get_storyboards 看该镜 first_frame_image/last_frame_image 变化。\n★继承重开(reopen_pair_id):get_storyboards 某镜带这个字段时,原样传进来可以只重掷首尾帧里真正有问题的那一侧——另一侧此前已经生成好的候选原样保留,不重新生成、不重新计费。传了它就不用再传 frame_type(会被忽略,由平台判定该重哪一侧);quote_id 仍要用 quote_shot_frame 报价(frame_type 传 first_frame 或 last_frame 均可,单帧同价)。若该镜没有 reopen_pair_id 字段(不满足继承条件),这个参数不要传,走常规 frame_type 重试。\n★★出尾帧若被拦下并提示「此镜标为状态改变,但没有任何地方说明结束时是什么样子」:正解是用 update_shot 把结束状态写进 last_frame_prompt 再出,**别直接加 allow_missing_terminal 硬上**——这类镜照现状出尾帧的历史成功率只有 9.4%(有终态描述的 40.2%),硬上多半是白扣一次钱。只有确认这一镜就是要「几乎不变」的画面时才带那个参数。\n★一键出片托管环节:同一镜重出帧最多 3 轮(一次调用算一轮,both 也算一轮),到上限回 **409 AUTOPILOT_SHOT_REGEN_LIMIT**(未派发、未扣费,quote 未消耗)——别换个工具绕,停下问客户:客户同意再出就照常报价、生成时带 customer_approved_more_regens:true(再给一份上限);客户接受现状就往下走,下一步收费调用带 acknowledge_review:true 记下确认。专业模式与客户把控的环节不受这个上限约束。\n★【分镜审查硬闸·免费】本步前必须先调 review_storyboards:把返回的 findings 逐条原样告诉客户(每条带 code=问题类型、shots=命中镜号、action=该调哪个工具修),再把 review_token 传进本工具。未审查会被 400 拒。审查后又改了内容 → token 自动失效,复审一次即可(仍免费)。单镜工具(generate_shot_frame / regenerate_shot_video)只核本镜与相邻镜:改了别的镜不用复审;本镜、相邻镜或共享资产变了才 400——这时带 base_review_token=<旧 token> 调审查工具做增量复审,只重审变更镜,质检也只看变更镜。有 error 时默认拦截;客户知情并坚持照现状继续,才带 acknowledge_review:true——带病推进大概率产出废片且照常扣费(acknowledge_review 只代表客户本人同意,任何执行模式都须客户明确同意,托管也不例外);托管环节只有白名单内的启发式 error 能带 auto_acknowledge:true 放行(平台判,不在白名单回 400 AUTOPILOT_MUST_ASK:must_ask_customer=true 才暂停问客户,false = 按 action 自修复审)。★灰度剧还要你(agent)亲自质检:按 review_storyboards 返回的 agent_qc 逐件看素材、逐条答清单,调 submit_qc_report 提交后这张 token 才能用(没交 → 400 agent_qc_required;报告有问题 → 与 error 同样默认拦)。\n★【资产层硬闸·免费】还要先跑 review_assets(角色形象图/场景图/道具图),把它的 review_token 作为 asset_review_token 传进来(与分镜层的 review_token 并存,两张都要;灰度剧缺了会 400 并点名 review_assets)。出完帧不会让资产 token 失效。⚠️ 批量报价确认流程:先调对应的 quote_* 工具拿 estimated_points 与 quote_id,再用 quote_id 调本工具(报价确认按执行模式:专业模式 / 未确认方案 / 本环节由客户把控 → 讲给客户、客户同意才做,别替客户决定;本环节托管 → 不问客户,照 get_production_plan 的 autopilot.default_decisions 执行,平台记进 get_autopilot_log)。托管环节报价须在预算硬上限内,被 402 BUDGET_WOULD_EXCEED 拦下就停下问客户。★**出图类报价(定妆图/场景图/出帧)给的是两个数**:estimated_points 是**上界**(按该模型参考图张数上限估,保证你不会按低了的预算开跑、出到一半 402 中断);同一响应里的 typical_points 是**通常花费**。两个都要告诉客户——只说上界会让人以为贵得多(满参考图的上界可达通常值的 2 倍以上),只说通常值又会让余额准备不足。固定价模型下两者相等,这时说一个数就行。出视频的报价与扣费同函数,不存在这个区间。",
14497
+ "description": "确认后给**某一镜**出帧或重生该帧(异步)。这是修某一镜画面的正路:平台会带上该镜的角色身份锚、场景/道具参考图、画风锚与帧审计,重生出的图与全片一致;用外部工具出图再上传会绕开这整条链路,人物/服装/画风必漂。重生会覆盖该帧现有图(含此前上传的),并把本镜视频标为待重生。尾帧需本镜首帧已就绪(否则先用 first_frame 或 both)。完成判据:轮询 get_storyboards 看该镜 first_frame_image/last_frame_image 变化。★回执的 frames_dispatched 是真派出去的张数;both 的尾帧被平台判为不需要时会带 skipped_frames(没出、没扣尾帧的钱),原样告诉客户。\n★继承重开(reopen_pair_id):get_storyboards 某镜带这个字段时,原样传进来可以只重掷首尾帧里真正有问题的那一侧——另一侧此前已经生成好的候选原样保留,不重新生成、不重新计费。传了它就不用再传 frame_type(会被忽略,由平台判定该重哪一侧);quote_id 仍要用 quote_shot_frame 报价(frame_type 传 first_frame 或 last_frame 均可,单帧同价)。若该镜没有 reopen_pair_id 字段(不满足继承条件),这个参数不要传,走常规 frame_type 重试。\n★★出尾帧若被拦下并提示「此镜标为状态改变,但没有任何地方说明结束时是什么样子」:正解是用 update_shot 把结束状态写进 last_frame_prompt 再出,**别直接加 allow_missing_terminal 硬上**——这类镜照现状出尾帧的历史成功率只有 9.4%(有终态描述的 40.2%),硬上多半是白扣一次钱。只有确认这一镜就是要「几乎不变」的画面时才带那个参数。\n★一键出片托管环节:同一镜重出帧最多 3 轮(一次调用算一轮,both 也算一轮),到上限回 **409 AUTOPILOT_SHOT_REGEN_LIMIT**(未派发、未扣费,quote 未消耗)——别换个工具绕,停下问客户:客户同意再出就照常报价、生成时带 customer_approved_more_regens:true(再给一份上限);客户接受现状就往下走,下一步收费调用带 acknowledge_review:true 记下确认。专业模式与客户把控的环节不受这个上限约束。\n★【分镜审查硬闸·免费】本步前必须先调 review_storyboards:把返回的 findings 逐条原样告诉客户(每条带 code=问题类型、shots=命中镜号、action=该调哪个工具修),再把 review_token 传进本工具。未审查会被 400 拒。审查后又改了内容 → token 自动失效,复审一次即可(仍免费)。单镜工具(generate_shot_frame / regenerate_shot_video)只核本镜与相邻镜:改了别的镜不用复审;本镜、相邻镜或共享资产变了才 400——这时带 base_review_token=<旧 token> 调审查工具做增量复审,只重审变更镜,质检也只看变更镜。有 error 时默认拦截;客户知情并坚持照现状继续,才带 acknowledge_review:true——带病推进大概率产出废片且照常扣费(acknowledge_review 只代表客户本人同意,任何执行模式都须客户明确同意,托管也不例外);托管环节只有白名单内的启发式 error 能带 auto_acknowledge:true 放行(平台判,不在白名单回 400 AUTOPILOT_MUST_ASK:must_ask_customer=true 才暂停问客户,false = 按 action 自修复审)。★灰度剧还要你(agent)亲自质检:按 review_storyboards 返回的 agent_qc 逐件看素材、逐条答清单,调 submit_qc_report 提交后这张 token 才能用(没交 → 400 agent_qc_required;报告有问题 → 与 error 同样默认拦)。\n★【资产层硬闸·免费】还要先跑 review_assets(角色形象图/场景图/道具图),把它的 review_token 作为 asset_review_token 传进来(与分镜层的 review_token 并存,两张都要;灰度剧缺了会 400 并点名 review_assets)。出完帧不会让资产 token 失效。⚠️ 批量报价确认流程:先调对应的 quote_* 工具拿 estimated_points 与 quote_id,再用 quote_id 调本工具(报价确认按执行模式:专业模式 / 未确认方案 / 本环节由客户把控 → 讲给客户、客户同意才做,别替客户决定;本环节托管 → 不问客户,照 get_production_plan 的 autopilot.default_decisions 执行,平台记进 get_autopilot_log)。托管环节报价须在预算硬上限内,被 402 BUDGET_WOULD_EXCEED 拦下就停下问客户。★**出图类报价(定妆图/场景图/出帧)给的是两个数**:estimated_points 是**上界**(按该模型参考图张数上限估,保证你不会按低了的预算开跑、出到一半 402 中断);同一响应里的 typical_points 是**通常花费**。两个都要告诉客户——只说上界会让人以为贵得多(满参考图的上界可达通常值的 2 倍以上),只说通常值又会让余额准备不足。固定价模型下两者相等,这时说一个数就行。出视频的报价与扣费同函数,不存在这个区间。",
14470
14498
  "tags": [
14471
14499
  "storyboards"
14472
14500
  ],
@@ -14524,6 +14552,9 @@
14524
14552
  "allow_missing_terminal": {
14525
14553
  "type": "boolean"
14526
14554
  },
14555
+ "force_independent_last_frame": {
14556
+ "type": "boolean"
14557
+ },
14527
14558
  "allow_era_ref_conflict": {
14528
14559
  "type": "boolean"
14529
14560
  },
@@ -14984,7 +15015,7 @@
14984
15015
  "post": {
14985
15016
  "operationId": "quote_shot_frame",
14986
15017
  "summary": "报价:重画/补出**某一镜的某一帧**要多少点(一帧=一张图)",
14987
- "description": "报价:重画/补出**某一镜的某一帧**要多少点(一帧=一张图)。返回 estimated_points、quote_id。零扣费。客户说「第 N 镜画错了/要改」时用它,而不是拿别的图像平台出图再 upload_shot_frame。★响应带 billing_kind/unit_points(实际计费档与单价);要在 generate_shot_frame 里换模型,报价时传同一个 image_model。★两边必须传同一个 image_model —— 不一致会被直接拒(400 IMAGE_MODEL_MISMATCH),因为模型决定计费档,不同源就是「预估≠扣费」。两边都不传也算一致(用该剧设定的模型)。已下架的型号(FLUX 全系列)一律拒收,别再传。★返回两个数:estimated_points 是**上界**(按参考图张数上限估,拿它准备余额就不会中途 402),typical_points 是**通常花费**。两个都告诉客户,只报上界会让人以为贵得多。固定价模型(如 Nano Banana 系列)下两者相等。",
15018
+ "description": "报价:重画/补出**某一镜的某一帧**要多少点(一帧=一张图)。返回 estimated_points、quote_id。零扣费。客户说「第 N 镜画错了/要改」时用它,而不是拿别的图像平台出图再 upload_shot_frame。★响应带 billing_kind/unit_points(实际计费档与单价);要在 generate_shot_frame 里换模型,报价时传同一个 image_model。★两边必须传同一个 image_model —— 不一致会被直接拒(400 IMAGE_MODEL_MISMATCH),因为模型决定计费档,不同源就是「预估≠扣费」。两边都不传也算一致(用该剧设定的模型)。已下架的型号(FLUX 全系列)一律拒收,别再传。★frame_type=both 时,平台判这一镜不需要独立尾帧(末态≈首态、没有运镜)会只出首帧:报价 frames_to_generate=1、只计首帧,并带 last_frame_skipped 说明原因——**原样告诉客户尾帧不会出**。客户确实要尾帧(例如起止画面不同的运镜)就报价与生成都带 force_independent_last_frame:true。★返回两个数:estimated_points 是**上界**(按参考图张数上限估,拿它准备余额就不会中途 402),typical_points 是**通常花费**。两个都告诉客户,只报上界会让人以为贵得多。固定价模型(如 Nano Banana 系列)下两者相等。",
14988
15019
  "tags": [
14989
15020
  "storyboards"
14990
15021
  ],
@@ -15016,6 +15047,9 @@
15016
15047
  },
15017
15048
  "image_model": {
15018
15049
  "type": "string"
15050
+ },
15051
+ "force_independent_last_frame": {
15052
+ "type": "boolean"
15019
15053
  }
15020
15054
  }
15021
15055
  }
@@ -15378,7 +15412,7 @@
15378
15412
  "get": {
15379
15413
  "operationId": "get_shot_prompts",
15380
15414
  "summary": "读某一镜的四条提示词**正文**(image_prompt=首帧画面 / video_prompt=动态表演 / first_frame_prompt=开始时什么样 / last_frame_prompt=结束时什么样),供直接微调后用 u",
15381
- "description": "读某一镜的四条提示词**正文**(image_prompt=首帧画面 / video_prompt=动态表演 / first_frame_prompt=开始时什么样 / last_frame_prompt=结束时什么样),供直接微调后用 update_shot 写回。免费。★回执里的 terminal_desc_missing=true 表示本镜标为「状态改变」却三处都没说终态——出尾帧会被前置闸拦下,修法是把结束状态写进 last_frame_prompt(别重试出图,重试必然重复被拒且照常扣费)。★pose_timeline_stale 非 null = 本镜动作起止姿态里的秒数时间轴超出了当前时长(多见于改短 duration 后),出视频时那一端已自动不送;新时间轴写进 video_prompt。★同时回 description(画面描述)与 lighting(本镜用光)现值——review_storyboards 的禁区词命中常在 description,改前先在这里读;用光写 lighting。★同时回 expression_hint(本镜作者指定的面部表情,null=未指定、由平台按台词反推),改它用 update_shot。expression_inferred 是拆镜 AI 在剧本没写神态时按本镜内容推断的表情(只读;null=没推断,或本镜台词/动作/氛围/描述/强度改过、推断已过期不再使用);它优先级低于 expression_hint——推断不合意就用 update_shot 写 expression_hint 覆盖它。★逐镜按需:改哪镜读哪镜(整集列表 get_storyboards 不含提示词)。★返回的 asset_tokens 是正文里的补充参考标记(@char:N / @scene:M),改写时原样保留即可:本镜注入谁的定妆图由绑定决定(get_storyboards 的 character_ids / scene_id),删标记不会让已绑定的人消失;带 #变体 的标记是那张变体图的唯一来源;给未绑定的角色写标记会把他的图注入进来。★这是分镜表里的正文层;出图/出视频时平台还会在其上拼身份锚、一致性约束与参考图指令(不在此处,也无需你写)。改完提示词不会自动重出图/视频,要让画面跟上得再 regen 对应镜。",
15415
+ "description": "读某一镜的四条提示词**正文**(image_prompt=首帧画面 / video_prompt=动态表演 / first_frame_prompt=开始时什么样 / last_frame_prompt=结束时什么样),供直接微调后用 update_shot 写回。免费。★回执里的 terminal_desc_missing=true 表示本镜标为「状态改变」却三处都没说终态——出尾帧会被前置闸拦下,修法是把结束状态写进 last_frame_prompt(别重试出图,重试必然重复被拒且照常扣费)。★pose_timeline_stale 非 null = 本镜动作起止姿态里的秒数时间轴超出了当前时长(多见于改短 duration 后),出视频时那一端已自动不送;新时间轴写进 video_prompt。★同时回 description(画面描述)、lighting(本镜用光)与 sound_effect(本镜音效)现值——review_storyboards 的禁区词命中常在 description / sound_effect,改前先在这里读;用光写 lighting。★同时回 shot_type(景别)/ angle(机位)/ camera_movement(运镜)/ continuity_intent(剪辑意图)现值——update_shot 改完这几项就在这里回读核对(整集 get_storyboards 不含它们);null=未设。★同时回 expression_hint(本镜作者指定的面部表情,null=未指定、由平台按台词反推),改它用 update_shot。expression_inferred 是拆镜 AI 在剧本没写神态时按本镜内容推断的表情(只读;null=没推断,或本镜台词/动作/氛围/描述/强度改过、推断已过期不再使用);它优先级低于 expression_hint——推断不合意就用 update_shot 写 expression_hint 覆盖它。★逐镜按需:改哪镜读哪镜(整集列表 get_storyboards 不含提示词)。★返回的 asset_tokens 是正文里的补充参考标记(@char:N / @scene:M),改写时原样保留即可:本镜注入谁的定妆图由绑定决定(get_storyboards 的 character_ids / scene_id),删标记不会让已绑定的人消失;带 #变体 的标记是那张变体图的唯一来源;给未绑定的角色写标记会把他的图注入进来。★这是分镜表里的正文层;出图/出视频时平台还会在其上拼身份锚、一致性约束与参考图指令(不在此处,也无需你写)。改完提示词不会自动重出图/视频,要让画面跟上得再 regen 对应镜。",
15382
15416
  "tags": [
15383
15417
  "storyboards"
15384
15418
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@starreel/mcp",
3
- "version": "0.1.224",
3
+ "version": "0.1.230",
4
4
  "mcpName": "ai.starreel/starreel",
5
5
  "description": "StarReel MCP server — drive the AI short-drama production pipeline (script → storyboards → frames → video → final cut) from Claude, Cursor, or any MCP client",
6
6
  "license": "MIT",
package/server.json CHANGED
@@ -2,13 +2,13 @@
2
2
  "$schema": "https://static.modelcontextprotocol.io/schemas/2025-09-29/server.schema.json",
3
3
  "name": "ai.starreel/starreel",
4
4
  "description": "Turn a script into a finished, downloadable short-drama episode — via MCP or REST.",
5
- "version": "0.1.224",
5
+ "version": "0.1.230",
6
6
  "websiteUrl": "https://starreel.ai",
7
7
  "packages": [
8
8
  {
9
9
  "registryType": "npm",
10
10
  "identifier": "@starreel/mcp",
11
- "version": "0.1.224",
11
+ "version": "0.1.230",
12
12
  "transport": {
13
13
  "type": "stdio"
14
14
  },