@starreel/mcp 0.1.231 → 0.1.238

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
@@ -106,6 +106,7 @@ announces a condensed version as MCP `instructions` at connect time.
106
106
  | A product / brand | `create_drama` (`project_type: "ad"` or `"brand_film"`) → `add_product` → `generate_product_sheet` | writing brand copy as dialogue (it gets spoken) |
107
107
  | Generated shots / a cut that needs changes | `scan_dialogue_coverage` / `scan_intra_shot_cuts` first, then `get_shot_prompts` · `update_shot` · `replace_shot_dialogue` · `repair_episode_dialogue` · `split_shot` · `trim_shot` · `regenerate_shot_video` · `edit_video_shot` → `rerender_episode`. To put **specific shots on a different video engine** in a whole-episode run, pass `shot_engines` (`{storyboard_id: engine}`) to `quote_videos` (a scene group that contains a picked shot is **split into per-shot generation** — listed in `shot_engines_ungrouped`; its other shots stay on the drama engine but lose the group's one-take continuity, so don't break a good group for one shot; a shot that already has a video is not re-run by the episode run, so picking an engine for it is rejected). Re-quoting after a partial run prices only the shots that will actually be dispatched (`shots_total`; already-finished ones are counted in `shots_already_done`, except that a scene group with any unfinished shot is re-run whole). To make a shot **always** use a different engine (single, batch and regen alike), set `video_engine` with `update_shot` (stored on the shot, shown in the web workbench; such a shot is never put in a scene group; explicit per-call parameters still win). To re-run **one scene group** (one request, keeps in-group continuity) — optionally on a different engine for that run — use `quote_regenerate_scene_group` (`shot_numbers` = exactly one group from `get_scene_group_plan`, optional `video_engine`; the whole group must fit that engine's single-clip limit) → `regenerate_scene_group`. To retry **one shot on a different video engine**, pass `model` to `quote_regenerate_shot_video` (that shot, that regeneration only — the drama's `video_engine` is untouched; the quote pins the engine, so changing it means re-quoting) | re-composing to fix what a clip *says*; switching the whole drama's `video_engine` just to fix one shot |
108
108
  | One person at several ages built as separate characters, and their portraits look like different people (or a mole switches sides) | pick the character whose portrait is right as the reference: `quote_derive_character_portrait` (`reference_character_id`, `age_stage`) → customer agrees → `derive_character_portrait` → `get_derived_portrait_candidates` (inspect each) → `adopt_derived_portrait` → `generate_character_sheet`. Check the target's `appearance` describes clothing for that age first — cross-character derivation dresses the target from its own profile, not the reference image | re-running batch portraits hoping the faces line up; editing the reference image elsewhere and uploading it |
109
+ | Finished first / last frames are not used by the video (`frame_delivery` says `reference_video_exclusive`, or the quote has an `av_anchor_strips_frames` advisory) | `get_av_anchors` → show the customer which shot the costume video anchor was cut from (open `anchor_url`) → with their OK `clear_character_av_anchor` → re-quote. Removing it means dialogue shots no longer anchor to the clip's voice; `allow_auto_rebuild: true` re-enables automatic anchoring | regenerating frames again (they will be stripped again); removing the anchor without telling the customer about the voice trade-off |
109
110
  | Wants old portraits / sheets / a shot's old tail frame "deleted" | `set_character_portrait` (old assets listed in `old_assets`) · `clear_shot_frame` (old tail frame) → `regenerate_shot_video`; `list_unlinked_assets` lists the drama's unlinked old assets (a history list, not proof of ownership). Both only **unlink** — files are not deleted (`physically_deleted` is always empty; `in_history: false` means the platform kept no record, so save that URL if it matters). Tell the customer exactly that | telling the customer the old image was deleted; writing `last_frame_image: null` through the internal API |
110
111
  | Customer explicitly accepted a shot's video, then its frames / scene / character changed (the platform now flags that video stale) | `lock_shot_video` (only after the customer confirms; locks the **current** video plus the inputs it was made from — frames, prompt, reference list). While locked: `review_videos` stops reporting `video_stale` for it (a `video_locked_frames_changed` warning instead), `get_asset_versions` shows `acceptance_locked`, native-voice `stale_shots` skip it, and every call that would replace it (`regenerate_shot_video`, `edit_video_shot`, repaint / reskin, footage upload / clear, a whole-episode `generate_videos` that would re-run its scene group) is refused with **409 VIDEO_LOCKED**. To replace it later, get the customer's OK and `unlock_shot_video` first. If the video is swapped by another path the lock lapses on its own (`video_lock.broken`) | regenerating an accepted shot just because it shows as stale; locking on your own judgement or because generation finished |
111
112
  | Wants an old image **permanently** deleted from storage (not just unlinked) | `preview_delete_asset` → show the customer exactly what it says (blocking references, history that will break, copies) → only after an explicit "confirm delete" → `delete_asset` with the `confirm_token`. Irreversible; only the drama owner; only files with trusted provenance (generated for this drama, or uploaded through the platform with a grant record) | deleting without showing the preview; retrying automatically; treating `list_unlinked_assets` as proof the file is unused |
@@ -480,8 +481,15 @@ content that will be rejected.
480
481
  **If frames keep getting the head count or the subject wrong** (a hand / prop insert
481
482
  drawn or judged as a full person, an off-screen speaker counted as visible, precheck or
482
483
  frame review repeatedly complaining about how many people are in shot), the shot's
483
- composition contract is wrong. You cannot read or edit that contract directly, and the
484
- completion passes only fill empty contracts, so editing text alone does not reach it.
484
+ composition contract is wrong. You cannot edit that contract directly (`get_shot_prompts`
485
+ returns only its conclusion as `frame_contract`: `on_screen_count`, `subject_kind`, `stale`),
486
+ and the completion passes only fill empty contracts, so editing text alone does not reach it.
487
+ The platform tells you when an edit probably left it behind: after `update_shot` changes the
488
+ shot type, bindings, voice-only marks, description, action or the first-frame prompt, the
489
+ receipt carries `frame_contract_advisory`; `review_storyboards` reports `frame_contract_stale`
490
+ (or `frame_contract_binding_conflict` when every bound character is voice-only but the
491
+ contract still expects people), and frame quotes carry `frame_contract_advisory`. Treat any
492
+ of these as the cue below. Read `action` with `get_shot_prompts` before rewriting it.
485
493
  Fix the shot with `update_shot` first (who is on screen; mark voice-only speakers with
486
494
  `character_presence: voice_only`; unbind people who should not appear), then call
487
495
  `rederive_shot_contract` (one metered text call — tell the customer). It returns only an
@@ -25,8 +25,8 @@
25
25
  "quote_storyboards": "Quote: credits to split one episode script into storyboards. No charge. Returns quote_id and a **range**: estimated_points=budget upper bound(prepare balance by this; no 402 mid-split), typical_points=usual cost—tell user both; only upper bound looks absurdly expensive, only typical may underfund balance. AI decides the number of shots(estimated_shots is an estimate), so exact credits are impossible. ★price_breakdown includes not only \"shot splitting\" but also automatic completion triggered after splitting(fills empty fields per shot; when wardrobe assets exist, schedules wardrobe timeline)—they happen with shot splitting and charge together, so include them in the total you tell user. After receiving consent, call generate_storyboards with quote_id.",
26
26
  "generate_storyboards": "Confirm then split into storyboards: runs in background (minutes), returns immediately status:generating. Poll with get_storyboards. ★Note: storyboard splitting will **replace all existing storyboards for the entire episode** (all tuned/generated images are lost; you must spend again). 5-7 seconds per shot is the **normal** duration optimized for AI video generation; do not resplit just because a shot feels “a bit long”. If storyboards already exist, backend blocks; only pass confirm_replace=true after confirming replacement. ★Typical duration 5~10 minutes (production measured 7~8.4 minutes; **a single LLM call may take 3~7 minutes**). **No storyboards within 60 seconds or even 3 minutes is normal**—use get_run_status to see whether it is still running. running:true means keep waiting; resending equals redoing the entire episode’s storyboards.\n★【Rewrite review hard gate · free】Before this step you must call review_script first: report each 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. No review will be rejected with 400. If content changes after review → token auto-invalidates; review once again (still free). error findings block by default; only if the customer is informed and insists on proceeding as-is may you pass acknowledge_review:true—pushing forward with known issues will likely produce unusable video and still charge normally (acknowledge_review only means the customer personally agrees; every execution mode requires explicit customer consent, autopilot included). 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 to ask customer, false = self-fix and re-review per action). ★Gray-release dramas also require you (agent) to personally QC: inspect assets one by one per agent_qc returned by review_script, answer every checklist item, and submit via submit_qc_report before this token can be used (not submitted → 400 agent_qc_required; problematic report → blocks like error by default). ⚠️ 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 only do it after customer agrees; do not decide for them. 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 the customer. ★**Image-generation quotes (character sheet/scene image/frame generation) provide two numbers**: estimated_points is the **upper bound** (estimated using that model’s maximum reference-image count, ensuring you do not start with an underbudget and hit 402 midway); typical_points in the same response is the **usual spend**. Tell the customer both—only stating the upper bound makes it look much more expensive (the full-reference upper bound can exceed the usual value by over 2x), while only stating the usual value may leave insufficient balance. For fixed-price models the two are equal, so one number is enough. Video-generation quote and charging use the same function; this range does not exist.",
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
- "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
- "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.",
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=none does not mean no references were sent; read ledger_note (code + reason: local repair / zero-reference dispatch / before ledger launch / last frame reused first frame, etc.); missing fields are honestly null.",
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); when reference_ledger_note is non-empty it explains why there is no reference record or the list is empty (no_references_sent=really dispatched with zero references, see dropped_before_dispatch for why / local_frame_edit=local repair sends only a base-image crop and a mask / zero_refs_unrecorded / legacy_before_ledger, etc.); do not describe an empty list as “nothing was sent”. 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
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.",
@@ -56,7 +56,7 @@
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
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. ★When the first frame is generated (first_frame/both) the response includes continuity: follows_previous_shot=true means the previous shot's last frame will be pinned as reference image #1 (carrying over that shot's people, pose and camera position); note explains why. If this shot should not continue from the previous one (jump cut, scene change, a detail close-up of only hands/props, etc.), pass continuity_mode:'independent' on both the quote and the generate call. ★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
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. The receipt for a first frame includes continuity (whether this run continues from the previous shot, and why); continuity_mode must match the quote, otherwise 409 — re-quote.\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
- "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.",
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★**frame_delivery = the frames actually sent to the vendor, per shot**: it lists billed shots with an independent last frame, plus billed shots whose first frame is NOT delivered (with reason, e.g. reference_video_exclusive = a costume video anchor / motion reference is attached); first_frame.verified=false = the preview did not finish, so delivery is unverified — do not present it as delivered; check per shot with quote_regenerate_shot_video. Billed shots not listed = first frame verified as delivered normally, no independent last frame. An av_anchor_strips_frames advisory = these shots lose their first/last frames to a character's costume video anchor; tell the customer the shot numbers, and to keep the frames use get_av_anchors to see the source, then (with the customer's OK) clear_character_av_anchor and re-quote.\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.",
62
62
  "get_final_cut": "Check an episode final cut status and download link. When status=completed, returns download_url(our COS direct link, downloadable directly). Free. ★bgm_stale=true means BGM was generated/modified after the final cut and is not yet in the final cut: just compose_episode again (free), do not re-render. ★If a current delivery version has been set (external version registered by register_external_delivery, or platform version specified by set_current_delivery), also returns delivery—that is the version the customer actually received; download_url remains the platform's latest stitched final cut. To see what every final-cut version used and its hash, use list_deliveries.",
@@ -161,7 +161,9 @@
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
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
- "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.",
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. has_av_anchor=true means the character has a costume video anchor attached (it strips the first/last frames of shots featuring that character); see get_av_anchors for its source and how to remove it.",
165
+ "get_av_anchors": "Read the current costume video anchor (AV anchor) of each character in a drama. Free. A costume video anchor is a ~3-second clip the platform automatically cuts from a video already generated for that character; during video generation it is injected as a reference video to anchor the character's look, costume and voice. ★Tell the customer the consequence: the vendor makes reference videos and first/last frames mutually exclusive — once an anchor is attached, the finished first frame and last frame of shots featuring that character are NOT sent to the video vendor (except shots with an independent last frame that take the first/last-frame route; the frame_delivery of quote_videos / quote_regenerate_shot_video is authoritative). Per character it returns status (active / disabled / none), anchor_url (the clip; open it to watch), source (kind=auto built automatically / manual specified by hand; storyboard_id·storyboard_number = which shot it was cut from; start_s·dur_s = the cut window), clip_duration_s, created_at, auto_rebuild (on = when there is no anchor, video generation will build one automatically). provenance=unrecorded means the anchor was built before this feature shipped and its source was not recorded: inferred_source is only a guess from the automatic shot-selection rule — do not present it as fact; have the customer open anchor_url. av_anchor_ref_enabled=false means this drama does not attach anchors when generating video, so an existing anchor has no effect. To remove an anchor use clear_character_av_anchor.",
166
+ "clear_character_av_anchor": "Remove a character's costume video anchor and disable automatic anchor building. Free. ★Only call after the customer confirms; first explain the anchor's source to them with get_av_anchors. Explain both sides of the consequence: (1) after removal, shots featuring that character get their first frame delivered again instead of being stripped by the reference-video exclusion (the last frame still follows the usual rules such as action type; the frame_delivery of a fresh quote is authoritative); (2) dialogue shots no longer anchor to the voice in the clip — the voice is generated by the vendor from text and the first frame only, so it may vary across shots; appearance is anchored by the portrait / first frame instead. Default is disable: video generation will no longer attach it and will not rebuild it automatically. allow_auto_rebuild:true = only clear the anchor without disabling (next video generation will automatically pick a shot and rebuild it, stripping first/last frames again); it is also how to re-enable after disabling. This unlinks, it does not delete: the clip file is kept, and the receipt's unlinked lists the removed URL (see list_unlinked_assets). Existing videos are not affected; re-quote afterwards (quote_videos / quote_regenerate_shot_video) and check frame_delivery and advisories.",
165
167
  "get_scenes": "Read the scene list for an episode (name/description/whether scene image is ready). Free.",
166
168
  "get_assets": "Read all aggregated assets for a drama (characters/scenes/props/images). Free.",
167
169
  "get_jobs": "Check a drama's task queue progress (pending/processing/done/failed for image/video/compositing stages). Use after async generation to track progress. Free. ★Full-episode frame generation (generate_frames) dispatches shot by shot in the background; rejected shots will not appear in the task list—check response frame_dispatch_rejections (per shot storyboard_id/frame_type/code/message). code=ERA_USER_REF_CONFLICT means the customer-uploaded character sheet was judged conflicting by Era review: relay message to the customer (allow_era_ref_conflict requires the customer's explicit consent in any execution mode, autopilot included); after confirmation, call generate_shot_frame for those shots with allow_era_ref_conflict=true. This list is cleared after restart.",
@@ -25,8 +25,8 @@
25
25
  "quote_storyboards": "报价:把某一集的剧本拆成分镜(storyboards)要多少点。零扣费。返回 quote_id 与一个**区间**:estimated_points=预算上沿(按它备余额,拆到一半不会 402)、typical_points=通常花费——两个都告诉用户,只报上沿显得贵得离谱,只报典型又会让余额备不够。拆出几镜由 AI 按剧本决定(estimated_shots 是估算),故无法精确到点。★price_breakdown 里除「拆镜」外还有拆完**自动**触发的补全(每镜补空字段;有服装资产时排服装时间线)——它们随拆镜一起发生、会一起扣费,告诉用户总数时要含在内。拿到后征求同意,再用 quote_id 调 generate_storyboards。",
26
26
  "generate_storyboards": "确认后拆镜:后台跑(分钟级),立即返回 status:generating。用 get_storyboards 轮询。★注意:拆镜会**替换整集所有已有分镜**(已调好/已出图的全丢、要重花钱重来)。每镜 5-7 秒是对 AI 出视频优化的**正常**时长,别因「一镜偏长」觉得有问题就重拆。已有分镜时后端会拦,确认重拆才带 confirm_replace=true。★典型耗时 5~10 分钟(生产实测 7~8.4 分钟;**单次 LLM 调用就可能 3~7 分钟**)。**60 秒、甚至 3 分钟内查不到分镜都是正常的**——用 get_run_status 判断是否还在跑。running:true 就继续等;重发一次等于把整集分镜重来一遍。\n★【改写稿审查硬闸·免费】本步前必须先调 review_script:把返回的 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_script 返回的 agent_qc 逐件看素材、逐条答清单,调 submit_qc_report 提交后这张 token 才能用(没交 → 400 agent_qc_required;报告有问题 → 与 error 同样默认拦)。⚠️ 批量报价确认流程:先调对应的 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 倍以上),只说通常值又会让余额准备不足。固定价模型下两者相等,这时说一个数就行。出视频的报价与扣费同函数,不存在这个区间。",
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
- "get_image_dispatch": "免费只读查询一张镜头帧的派发台账:实际用了哪几张参考图、每张的用途与所属角色、是否送达模型、没送达或派发前被剔除的是哪一步因什么被剔(如时代预检点名的冲突物件),以及真正发给图片模型的最终提示词。用于回答「到底用了哪张图、为什么画面不像」;先查清再决定是否重出,别靠猜反复付费重抽。ledger=partial/none 表示该图生成于台账上线前,缺失字段如实为 null。",
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 同口径。",
28
+ "get_image_dispatch": "免费只读查询一张镜头帧的派发台账:实际用了哪几张参考图、每张的用途与所属角色、是否送达模型、没送达或派发前被剔除的是哪一步因什么被剔(如时代预检点名的冲突物件),以及真正发给图片模型的最终提示词。用于回答「到底用了哪张图、为什么画面不像」;先查清再决定是否重出,别靠猜反复付费重抽。ledger=none 不等于没送参考,看 ledger_note(code + 原因:局部返修 / 零参考派发 / 台账上线前 / 尾帧复用首帧等);缺失字段如实为 null。",
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:用途/所属角色/是否送达);reference_ledger_note 非空时说明为什么没有参考图记录或参考为空(no_references_sent=确实零参考派发,原因看 dropped_before_dispatch / local_frame_edit=局部返修只送底图裁片和蒙版 / zero_refs_unrecorded / legacy_before_ledger 等),空列表别说成「什么都没送」。storyboard.tail_endstate 是「尾帧≈首帧」检查结论(current=false 表示结论对应的不是现在这两张图)。★镜头反复被拒、或客户问「被拒的那几张到底什么样 / 为什么不采用」时先调它:逐张看原图和证据,再决定改分镜、改参考还是重掷——别盲目付费重抽。要看某张的最终提示词用 get_image_dispatch(generation_id)。客户看过原图确认画面没问题、是审计误判时,用 adopt_frame_candidate 人工采用(免费);manual_adoption 非空 = 该候选是人工放行的。recovery_options 按帧位给出失败后的三选一(挑误拒 / 修图上传 / 重生),与 get_frame_retry_diagnosis 同口径。",
30
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 表示锁定后帧又改过但不需要重出。",
@@ -52,15 +52,15 @@
52
52
  "enhance_shot_prompts": "(可选增强·★非必须·有副作用)AI 批量增强全集 image_prompt。★会**改写已有 prompt**(含手调的);且**务必 generate_frames 之前**做——出图后再改 prompt 会让图陈旧、要重生浪费钱。非跑通一部片的必需,客户点名再做。后台异步,文本步后付。",
53
53
  "complete_ending_motifs": "(可选增强·★非必须·条件性)给结尾段补全缺失的视觉母题(嫁接视觉回响到结尾镜)。★前置:该剧已设 motifs(没设=空操作);会**改结尾镜 action/描述**,务必出图前做(否则结尾镜已出图会陈旧)。后台异步,文本步后付。",
54
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
- "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 系列)下两者相等。",
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 全系列)一律拒收,别再传。★响应带 frame_contract_advisory 时,列出的镜构图契约(画面里几人、主体是人物还是局部/道具)可能已过期或与绑定矛盾——出图仍按旧契约来;先讲给客户,同意后对这些镜调 rederive_shot_contract 再重新报价。★返回两个数: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 全系列)一律拒收,别再传。★frame_type=both 时,平台判这一镜不需要独立尾帧(末态≈首态、没有运镜)会只出首帧:报价 frames_to_generate=1、只计首帧,并带 last_frame_skipped 说明原因——**原样告诉客户尾帧不会出**。客户确实要尾帧(例如起止画面不同的运镜)就报价与生成都带 force_independent_last_frame:true。★出首帧(first_frame/both)时响应带 continuity:follows_previous_shot=true 表示上一镜尾帧会钉在参考图第 1 位(承接上一镜的人物、姿势与机位),note 说明原因。这一镜不该接上一镜(跳切、换场、只拍手/道具的局部特写等),报价与生成都带 continuity_mode:'independent'。★返回两个数:estimated_points 是**上界**(按参考图张数上限估,拿它准备余额就不会中途 402),typical_points 是**通常花费**。两个都告诉客户,只报上界会让人以为贵得多。固定价模型(如 Nano Banana 系列)下两者相等。",
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。★响应带 frame_contract_advisory 时,列出的镜构图契约(画面里几人、主体是人物还是局部/道具)可能已过期或与绑定矛盾——出图仍按旧契约来;先讲给客户,同意后对这些镜调 rederive_shot_contract 再重新报价。★出首帧(first_frame/both)时响应带 continuity:follows_previous_shot=true 表示上一镜尾帧会钉在参考图第 1 位(承接上一镜的人物、姿势与机位),note 说明原因。这一镜不该接上一镜(跳切、换场、只拍手/道具的局部特写等),报价与生成都带 continuity_mode:'independent'。★返回两个数:estimated_points 是**上界**(按参考图张数上限估,拿它准备余额就不会中途 402),typical_points 是**通常花费**。两个都告诉客户,只报上界会让人以为贵得多。固定价模型(如 Nano Banana 系列)下两者相等。",
58
58
  "generate_shot_frame": "确认后给**某一镜**出帧或重生该帧(异步)。这是修某一镜画面的正路:平台会带上该镜的角色身份锚、场景/道具参考图、画风锚与帧审计,重生出的图与全片一致;用外部工具出图再上传会绕开这整条链路,人物/服装/画风必漂。重生会覆盖该帧现有图(含此前上传的),并把本镜视频标为待重生。尾帧需本镜首帧已就绪(否则先用 first_frame 或 both)。完成判据:轮询 get_storyboards 看该镜 first_frame_image/last_frame_image 变化。★回执的 frames_dispatched 是真派出去的张数;both 的尾帧被平台判为不需要时会带 skipped_frames(没出、没扣尾帧的钱),原样告诉客户。出首帧的回执带 continuity(这次承接没承接上一镜、原因);continuity_mode 须与报价时一致,否则 409 重新报价。\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。被拒候选不退点(包括原帧本身问题导致帧审计不过的)。",
62
62
  "adopt_local_frame_edit": "采用某个局部返修候选:把它写成这一镜的当前帧(免费)。与上传帧同一套后续处理:本镜视频标为待重生、相邻接缝跟着修。★只在客户看过并选定后调用。返修之后这一帧若已换过 → 409 BASE_FRAME_CHANGED(对当前帧重新发起);verdict=reject 的候选默认拒绝采用(409 CANDIDATE_REJECTED),客户看过坚持要用才带 accept_rejected:true。",
63
- "quote_videos": "报价:给某一集批量出视频要多少点(与实际扣费同函数,较准)。返回 estimated_points、quote_id。零扣费。⚠️ 视频是大额花费,务必把点数清楚告诉用户并等其确认。\n★**只计这次真会派发的镜**:已出视频的镜整集续跑时跳过,不重出不计价——shots_total = 这次计价的镜数(不是集内总镜数),shots_already_done = 已出视频、这次跳过的镜数。例外:场景组只要有一镜没出视频就**整组重出**,组内已出的镜同样计价。全部已出视频 ⇒ 400(没有可派发的镜,要重出某镜用 regenerate_shot_video)。报价之后若有镜的视频被清空(变成待出视频),generate_videos 会 409 要求重新报价,不按报价外的镜扣费。\n★**按镜指定视频引擎**:传 shot_engines={分镜id: 引擎} 即只为这些镜、这一次整集生成换引擎(不改剧级 video_engine,其余镜照旧)。报价按它逐镜计价,quote_id 把引擎钉死,generate_videos 派发的就是它——要改引擎必须重新报价。回执 shot_engines = 实际生效的映射;shot_engines_ungrouped = 因含指定镜而**拆成逐镜出**的场景组(场景组的时长与多关键帧是按剧引擎规划的,换引擎整组出会丢镜/丢关键帧;拆组后组内其余镜仍按剧引擎逐镜出,失去组内一次成片的连贯性,所以别为一镜去拆一个好好的组——先看 get_scene_group_plan)。所选引擎必须支持本剧分辨率(seedance-2.5 只有 480p/720p;hailuo-3 只有 720p/1080p;wan3.0/wan3.0-prime 480p~1080p),且镜头时长不超过该引擎单镜上限(seedance-2.5/wan3.0 30s,hailuo-3 15s),否则 400(超长会被厂商截断,要么换引擎要么 split_shot)。指定引擎的镜必须这次会出视频:已出视频的镜整集生成不会重出,给它指定引擎 ⇒ 400;拆成逐镜的场景组只计没出视频的组员。只想重出个别已出过视频的镜,用 quote_regenerate_shot_video 的 model 更省。★响应可能带**未接缝提示**(不影响 review_token / 报价 / 状态码):review_frames 与 generate_videos 是 unchained_seam_advisory,quote_videos 是 advisories 里 code=unchained_seams。seams 列的是 chain_frames 会接、却还没接上的相邻缝(from_shot→to_shot),status=no_stamp(从没接过)/ pending(发起过衔接、还没落地或审计未出结论)/ stale_anchor(上次承接的锚已失效:上一镜尾帧在衔接之后又被重生过,需要重接)/ join_failed(上次发起的衔接重生被拒 / 失败 / 落选,没落地)/ audit_failed(衔接落地但审计判不连续,看 get_storyboards 的 seam_failed_dims)/ first_frame_regenerated(接缝审过之后下镜首帧又被重出、没走承接路径,原衔接已不算数)/ not_linked(规划器判没接上、原因证据不足);都按计划重接即可;video_locked 是下镜已出视频的同类缝,chain_frames 不再改它们,只能逐镜 chain_shot_from_prev / chain_shot_from 换首帧后 regenerate_shot_video(都先报价)。出视频前看到 seams 就先 chain_frames(dry_run:true) 把计划与报价告诉客户,客户同意再执行,执行后重调 review_frames。",
63
+ "quote_videos": "报价:给某一集批量出视频要多少点(与实际扣费同函数,较准)。返回 estimated_points、quote_id。零扣费。⚠️ 视频是大额花费,务必把点数清楚告诉用户并等其确认。\n★**frame_delivery = 本次逐镜真正送到厂商的帧**:列出有独立尾帧的计价镜,以及首帧不送达的计价镜(带 reason,如 reference_video_exclusive=挂了定妆视频锚/运动参考);first_frame.verified=false = 预览没跑完、送不送未核验,别当已送达讲,可逐镜 quote_regenerate_shot_video 核对;没列出的计价镜 = 已核验首帧照常送达、无独立尾帧。advisories 里出现 av_anchor_strips_frames = 这些镜被角色定妆视频锚剥掉首尾帧,把镜号讲给客户,要保住首尾帧就 get_av_anchors 看来源、客户同意后 clear_character_av_anchor 摘锚再重新报价。\n★**只计这次真会派发的镜**:已出视频的镜整集续跑时跳过,不重出不计价——shots_total = 这次计价的镜数(不是集内总镜数),shots_already_done = 已出视频、这次跳过的镜数。例外:场景组只要有一镜没出视频就**整组重出**,组内已出的镜同样计价。全部已出视频 ⇒ 400(没有可派发的镜,要重出某镜用 regenerate_shot_video)。报价之后若有镜的视频被清空(变成待出视频),generate_videos 会 409 要求重新报价,不按报价外的镜扣费。\n★**按镜指定视频引擎**:传 shot_engines={分镜id: 引擎} 即只为这些镜、这一次整集生成换引擎(不改剧级 video_engine,其余镜照旧)。报价按它逐镜计价,quote_id 把引擎钉死,generate_videos 派发的就是它——要改引擎必须重新报价。回执 shot_engines = 实际生效的映射;shot_engines_ungrouped = 因含指定镜而**拆成逐镜出**的场景组(场景组的时长与多关键帧是按剧引擎规划的,换引擎整组出会丢镜/丢关键帧;拆组后组内其余镜仍按剧引擎逐镜出,失去组内一次成片的连贯性,所以别为一镜去拆一个好好的组——先看 get_scene_group_plan)。所选引擎必须支持本剧分辨率(seedance-2.5 只有 480p/720p;hailuo-3 只有 720p/1080p;wan3.0/wan3.0-prime 480p~1080p),且镜头时长不超过该引擎单镜上限(seedance-2.5/wan3.0 30s,hailuo-3 15s),否则 400(超长会被厂商截断,要么换引擎要么 split_shot)。指定引擎的镜必须这次会出视频:已出视频的镜整集生成不会重出,给它指定引擎 ⇒ 400;拆成逐镜的场景组只计没出视频的组员。只想重出个别已出过视频的镜,用 quote_regenerate_shot_video 的 model 更省。★响应可能带**未接缝提示**(不影响 review_token / 报价 / 状态码):review_frames 与 generate_videos 是 unchained_seam_advisory,quote_videos 是 advisories 里 code=unchained_seams。seams 列的是 chain_frames 会接、却还没接上的相邻缝(from_shot→to_shot),status=no_stamp(从没接过)/ pending(发起过衔接、还没落地或审计未出结论)/ stale_anchor(上次承接的锚已失效:上一镜尾帧在衔接之后又被重生过,需要重接)/ join_failed(上次发起的衔接重生被拒 / 失败 / 落选,没落地)/ audit_failed(衔接落地但审计判不连续,看 get_storyboards 的 seam_failed_dims)/ first_frame_regenerated(接缝审过之后下镜首帧又被重出、没走承接路径,原衔接已不算数)/ not_linked(规划器判没接上、原因证据不足);都按计划重接即可;video_locked 是下镜已出视频的同类缝,chain_frames 不再改它们,只能逐镜 chain_shot_from_prev / chain_shot_from 换首帧后 regenerate_shot_video(都先报价)。出视频前看到 seams 就先 chain_frames(dry_run:true) 把计划与报价告诉客户,客户同意再执行,执行后重调 review_frames。",
64
64
  "generate_videos": "确认后批量出视频:一条后台链跑完整集,余额不足会自动中止整链(防重复扣)。要求本集已出首帧(未出会被拒)。用 get_storyboards 轮询 video_url 逐镜填充即完成。\n★【镜头图片审查硬闸·免费】本步前必须先调 review_frames:把返回的 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_frames 返回的 agent_qc 逐件看素材、逐条答清单,调 submit_qc_report 提交后这张 token 才能用(没交 → 400 agent_qc_required;报告有问题 → 与 error 同样默认拦)。⚠️ 批量报价确认流程:先调对应的 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 倍以上),只说通常值又会让余额准备不足。固定价模型下两者相等,这时说一个数就行。出视频的报价与扣费同函数,不存在这个区间。\n★【完成后质检·免费】出完等它落库(get_storyboards 看 video_status / get_pipeline_status),再调 review_videos 审视频与配音层(缺视频 / 旧帧出的视频 / 片尾硬切 / 意外人声 / 配音缺失 / 音色未分配 / 原声声线过期),修完复审;再按 agent_qc 亲自逐镜看视频、听配音(动作到位、不变脸、台词念全、嗓音对),submit_qc_report 提交;compose_episode 要带它的 review_token。★响应可能带**未接缝提示**(不影响 review_token / 报价 / 状态码):review_frames 与 generate_videos 是 unchained_seam_advisory,quote_videos 是 advisories 里 code=unchained_seams。seams 列的是 chain_frames 会接、却还没接上的相邻缝(from_shot→to_shot),status=no_stamp(从没接过)/ pending(发起过衔接、还没落地或审计未出结论)/ stale_anchor(上次承接的锚已失效:上一镜尾帧在衔接之后又被重生过,需要重接)/ join_failed(上次发起的衔接重生被拒 / 失败 / 落选,没落地)/ audit_failed(衔接落地但审计判不连续,看 get_storyboards 的 seam_failed_dims)/ first_frame_regenerated(接缝审过之后下镜首帧又被重出、没走承接路径,原衔接已不算数)/ not_linked(规划器判没接上、原因证据不足);都按计划重接即可;video_locked 是下镜已出视频的同类缝,chain_frames 不再改它们,只能逐镜 chain_shot_from_prev / chain_shot_from 换首帧后 regenerate_shot_video(都先报价)。出视频前看到 seams 就先 chain_frames(dry_run:true) 把计划与报价告诉客户,客户同意再执行,执行后重调 review_frames。",
65
65
  "compose_episode": "把某一集所有镜头视频拼成一条成片(终拼)。**免费**(纯拼接,无需报价确认),后台异步。发起前有终拼预检:缺视频的镜或仍在生成中的视频任务会 400 硬阻断并列出问题镜(blockers),补齐后重试;确要拼部分成片传 force=true(缺视频镜被跳过,成片缺镜,留痕)。响应里的 advisories(时长偏差/孤儿任务/缺TTS/post_production_pending 后期特效未完成)只提醒不阻断,建议逐条处理后再拼。发起后用 get_final_cut 轮询。\n★【视频与配音审查硬闸·免费】本步前必须先调 review_videos:把返回的 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_videos 返回的 agent_qc 逐件看素材、逐条答清单,调 submit_qc_report 提交后这张 token 才能用(没交 → 400 agent_qc_required;报告有问题 → 与 error 同样默认拦)。\n★★【成片前自检·review_videos 通过后、compose_episode 之前】别靠反复导出整片、手工试转场来找问题——逐镜与接缝的问题有专门工具,拼之前按序过一遍:①这一集换过定妆图 / 设定图 / 场景图 / 镜头帧 → 先 get_stale_portrait_frames(episode_id,免费)看哪些镜的在用帧还基于旧资产,拿不准该用哪一版的镜再 get_asset_versions(storyboard_id,免费)逐镜看版本与依赖(unknown 是证据不足、不是已过期;重出要付费,清单讲给客户由客户定);②scan_intra_shot_cuts(episode_id,免费)查厂商在单镜内自行硬切的镜;③逐镜 recommend_trim_window(storyboard_id,免费)看冻结尾段与有效动作区间(组内镜返回 applicable=false,跳过),有推荐就 trim_shot 应用(免费);④audit_seams(episode_id)查相邻镜接缝的剪辑连续性:默认 dry_run 只列待审范围(免费),真执行按实际文本 token 计费,讲给客户、客户明确接受后才带 dry_run:false + confirm_usage_billing:true,结果看 get_storyboards 的 seam_review;⑤再 compose_episode。拼完成片发现跳切 / 拖尾 / 接不上,回到这几个工具按镜定位后只修那几镜,别整片反复导出试错。这些都是提示性检查,不过闸;裁剪与接缝审核不让 review_videos 的 token 失效。\n★【完成后质检·免费】成片出来后跑 review_final_cut(缺镜/字幕放不下/身份锚/跳轴/错别字,proofread=false 则不扣费),结论讲给客户;客户确认后才 confirm_delivery_acceptance(交付验收任何执行模式都须客户明确同意,托管也不例外)。force 只越过终拼预检,不越过审查闸。",
66
66
  "get_final_cut": "查某一集成片状态与下载链接。status=completed 时返回 download_url(我方 COS 直链,可直接下载)。免费。★bgm_stale=true 表示配乐在成片之后生成/改动、尚未进成片:重新 compose_episode(免费)即可,别用 re-render。★若设过当前交付版(register_external_delivery 登记的外部版,或 set_current_delivery 指定的平台版),另返回 delivery——那才是客户实际收到的一版;download_url 仍是平台最新一次拼的成片。要看每一版成片用了什么、哈希是多少,用 list_deliveries。",
@@ -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);景别/机位/运镜/剪辑意图与提示词正文用 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
- "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(本镜用光)与 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 对应镜。",
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 就是这个信号。★★【构图契约不会跟着改】改 shot_type / character_ids / character_presence / description / action / image_prompt / first_frame_prompt 后,本镜的构图契约(画面里可见几人、主体是人物还是手部等局部/道具、景别)不会自动重推,出图组织画面与帧审计判人数仍按旧契约来(典型:改成局部特写、解绑全部角色,出图照样画人像)。回执带 frame_contract_advisory 就是这种情况:讲给客户,客户同意后调 rederive_shot_contract(按 token 后付)重推,得出 updated 再报价出图;客户确认画面人数与主体都没变可以不推。★改 action 前先用 get_shot_prompts 读现值(action),别凭空整段覆盖。",
146
+ "rederive_shot_contract": "按本镜**当前**的正文与角色绑定,让平台重新推导构图契约(画面里可见几人、主体是人物还是局部/道具、景别)。契约本体不对外、改不了(get_shot_prompts 的 frame_contract 只给人数 / 主体类型 / 是否可能过期这几个结论);本工具只回结论 outcome:updated(已改并生效)/ unchanged(推出来和原来一样)/ rejected(推出来自相矛盾,未采用,原契约保留)/ no_candidate(没拿到可用结果,原契约保留)/ stale(推导期间本镜又被改过,结果未写入,改完再调一次),附 note 说下一步。点数不足回 402。★什么时候用:出图/预检/审核反复说人数不对、局部镜(手部/道具特写)被当成完整人物出图或审核,而你已经改过正文或绑定——补全器只填空、不覆盖已有契约,不调本工具改动不会进契约。update_shot 回执带 frame_contract_advisory、get_shot_prompts 的 frame_contract.stale=true、review_storyboards 报 frame_contract_stale / frame_contract_binding_conflict、出帧报价带 frame_contract_advisory,都是该调本工具的信号;得出 updated 或 unchanged 后「可能过期」标记清除(rejected / stale / no_candidate 保留)。★正确顺序:先 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(本镜用光)与 sound_effect(本镜音效)现值——review_storyboards 的禁区词命中常在 description / sound_effect,改前先在这里读;用光写 lighting。★同时回 shot_type(景别)/ angle(机位)/ camera_movement(运镜)/ continuity_intent(剪辑意图)现值——update_shot 改完这几项就在这里回读核对(整集 get_storyboards 不含它们);null=未设。★同时回 action(动作,update_shot 可改,改前先在这里读)与 action_in / action_out(动作起止姿态,只读)现值。★同时回 frame_contract{on_screen_count, subject_kind, stale, stale_fields?, binding_conflict?, note?}:本镜构图契约的**结论**——出图组织画面、帧审计判人数都按它(契约本体不对外)。stale=true = 契约生成后改过景别 / 绑定 / 画面描述等、可能已过期;binding_conflict=true = 绑定的角色全部只出声音而契约仍要画人;两种都按 note 建议客户调 rederive_shot_contract(按 token 后付)。★同时回 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 重拼即可;复核不通过不写回,旁白合成费不退。",
@@ -176,7 +176,9 @@
176
176
  "translate_subtitles": "把某集字幕翻译成第二语言并开启双语。后台异步,按用量后付不欠费。",
177
177
  "list_dramas": "列出我名下的所有短剧(drama_id/剧名/类型/集数/进度)。免费。",
178
178
  "get_drama": "读一部剧的详情(设定/角色数/场景数/资产统计等)。免费。frame_chain_mode = 整剧跨镜帧链模式(off/strict/reframe,改用 update_project_settings)。",
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 里钉死的角色外观移除或对齐档案再重掷。",
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 里钉死的角色外观移除或对齐档案再重掷。has_av_anchor=true 表示该角色挂着定妆视频锚(会剥掉含该角色镜头的首尾帧),来源与摘除见 get_av_anchors。",
180
+ "get_av_anchors": "读某剧各角色的定妆视频锚(AV anchor)现况。免费。定妆视频锚是平台从该角色已出的某镜视频里自动截的约 3 秒片段,出视频时作参考视频注入,用来锚定该角色的长相、服装和声线。★后果要讲给客户:厂商规定参考视频与首尾帧互斥——锚一挂上,含该角色的镜做好的首帧、尾帧都不会送到视频厂商(有独立尾帧、走首尾帧路由的镜除外,以 quote_videos / quote_regenerate_shot_video 的 frame_delivery 为准)。每角色返回 status(active 在用 / disabled 已停用 / none 无锚)、anchor_url(锚片,可直接打开看)、source(kind=auto 自动建 / manual 手动指定;storyboard_id·storyboard_number 截自哪一镜;start_s·dur_s 截取窗口)、clip_duration_s、created_at、auto_rebuild(on=没锚时出视频会自动建一条)。provenance=unrecorded 是本功能上线前建的锚,来源没有记录:inferred_source 只是按自动选镜规则推测,别当事实讲,让客户打开 anchor_url 看。av_anchor_ref_enabled=false 表示本剧出视频不挂锚,锚存在也无影响。要摘锚用 clear_character_av_anchor。",
181
+ "clear_character_av_anchor": "摘掉某角色的定妆视频锚并停用自动建锚。免费。★必须客户确认后再调,先用 get_av_anchors 把锚的来源讲给客户。后果两面都要讲清:①摘锚后含该角色的镜首帧恢复送达,不再因参考视频互斥被剥(尾帧仍按动作类型等常规规则判定,以重新报价的 frame_delivery 为准);②台词镜的声线不再锚定锚片里的嗓音,只靠厂商按文字和首帧生成,跨镜声线可能有差异;长相改由定妆照/首帧锚定。默认停用:之后出视频不再挂它,也不会自动重建。allow_auto_rebuild:true = 只清锚不停用(下次出视频平台自动重选一镜重建,首尾帧又会被剥),也是停用后的恢复入口。这是解除引用不是删除:锚片文件不删,回执 unlinked 列出摘下的 URL(list_unlinked_assets 可查)。已出的视频不受影响;摘完重新报价(quote_videos / quote_regenerate_shot_video)核对 frame_delivery 与 advisories。",
180
182
  "get_scenes": "读某一集的场景列表(名字/描述/场景图是否就绪)。免费。",
181
183
  "get_assets": "读一部剧的全部资产聚合(角色/场景/道具/图片)。免费。",
182
184
  "get_jobs": "查一部剧的任务队列进度(出图/出视频/合成各阶段的 pending/processing/done/failed)。异步生成后用它看进度。免费。★整集出帧(generate_frames)是后台逐镜派发,被拒的镜不会出现在任务列表里——看响应的 frame_dispatch_rejections(每镜 storyboard_id/frame_type/code/message)。code=ERA_USER_REF_CONFLICT 表示客户上传的定妆图被时代审核判冲突:把 message 转告客户(allow_era_ref_conflict 任何执行模式都须客户明确同意,托管也不例外),客户确认后带 allow_era_ref_conflict=true 对那几镜 generate_shot_frame。重启后该列表清空。",
@@ -272,7 +272,7 @@ export const PIPELINE = [
272
272
  },
273
273
  {
274
274
  step: '8 出视频',
275
- tools: ['quote_videos', 'generate_videos', 'get_scene_group_plan', 'generate_scene_groups', 'quote_regenerate_shot_video', 'regenerate_shot_video', 'quote_edit_video_shot', 'edit_video_shot', 'upload_shot_footage(实拍素材镜:客户录屏/产品实拍直接当该镜视频,不出视频不扣费)', 'get_edit_capabilities', 'get_repaint_capabilities', 'quote_repaint_shot_video', 'repaint_shot_video', 'quote_reskin_shot_video', 'reskin_shot_video', 'get_repaint_status', 'restore_repaint_original'],
275
+ tools: ['quote_videos', 'generate_videos', 'get_scene_group_plan', 'generate_scene_groups', 'quote_regenerate_shot_video', 'regenerate_shot_video', 'quote_edit_video_shot', 'edit_video_shot', 'upload_shot_footage(实拍素材镜:客户录屏/产品实拍直接当该镜视频,不出视频不扣费)', 'get_edit_capabilities', 'get_repaint_capabilities', 'quote_repaint_shot_video', 'repaint_shot_video', 'quote_reskin_shot_video', 'reskin_shot_video', 'get_repaint_status', 'restore_repaint_original', 'get_av_anchors(定妆视频锚现况:挂锚的镜首尾帧不送)', 'clear_character_av_anchor(客户确认后摘锚·免费)'],
276
276
  billing: '报价确认后扣点',
277
277
  note: 'video_engine 必须在出视频前定(写实真人剧 seedance-2.5 或降本 hailuo-3 / 动漫·风格化 seedance-2.5 或 wan3.0·wan 绝不用于写实真人;' + MODEL_AVAILABILITY_NOTE + ');切换不回溯已生成镜头。',
278
278
  },
@@ -684,11 +684,11 @@ export function registerProduceTools(server, client) {
684
684
  '② upload_fixed 拿本镜平台候选局部修补后 upload_shot_frame;③ regenerate 按诊断改内容后 quote_shot_frame→generate_shot_frame。' +
685
685
  'ask_customer=true 时三条都摆给客户由客户选,不许替客户放行或擅自付费重抽;failure_class=transient 是偶发失败、稍等按原输入重试即可,' +
686
686
  'not_self_healable 是欠费/点数不足/配额满/模型不可用、重生也无用(regenerate.available=false),先处理账户或换模型。', { image_id: z.number().int().positive() }, async ({ image_id }) => jsonResult(await client.produceGet(`/images/${image_id}/diagnosis`)));
687
- server.tool('get_image_dispatch', '免费只读查询一张镜头帧的派发台账:实际用了哪几张参考图、每张的用途与所属角色、是否送达模型、没送达或派发前被剔除的是哪一步因什么被剔(如时代预检点名的冲突物件),以及真正发给图片模型的最终提示词。用于回答「到底用了哪张图、为什么画面不像」;先查清再决定是否重出,别靠猜反复付费重抽。ledger=partial/none 表示该图生成于台账上线前,缺失字段如实为 null。', { image_id: z.number().int().positive() }, async ({ image_id }) => jsonResult(await client.produceGet(`/images/${image_id}/dispatch`)));
687
+ server.tool('get_image_dispatch', '免费只读查询一张镜头帧的派发台账:实际用了哪几张参考图、每张的用途与所属角色、是否送达模型、没送达或派发前被剔除的是哪一步因什么被剔(如时代预检点名的冲突物件),以及真正发给图片模型的最终提示词。用于回答「到底用了哪张图、为什么画面不像」;先查清再决定是否重出,别靠猜反复付费重抽。ledger=none 不等于没送参考,看 ledger_note(code + 原因:局部返修 / 零参考派发 / 台账上线前 / 尾帧复用首帧等);缺失字段如实为 null。', { image_id: z.number().int().positive() }, async ({ image_id }) => jsonResult(await client.produceGet(`/images/${image_id}/dispatch`)));
688
688
  server.tool('get_frame_candidates', '免费只读:一个镜头首帧/尾帧的**全部候选**(出图验收工作台同一份数据)。每张候选给原图地址(被拒的也在,可直接打开看原尺寸)、状态、是否为当前在用(adopted)、' +
689
689
  '拒因 reject(main 主码 / code 具体病因 / details 明细 / class 分流:needs_content_fix=要改内容、content_retryable=内容问题但重掷约 1/3 能成、transient=审核没审成或偶发——不是画面不合格)、' +
690
690
  '审计证据 audit(warnings 中文结论、expected 设计要求、derived_shot_type 画面推出的景别及依据、boxes 主体与身体部位在画面里的位置框;2026-10-07 前的候选无存档为 null,不代表审过)、' +
691
- '以及这张图实际用了哪些参考图(references:用途/所属角色/是否送达)。storyboard.tail_endstate 是「尾帧≈首帧」检查结论(current=false 表示结论对应的不是现在这两张图)。' +
691
+ '以及这张图实际用了哪些参考图(references:用途/所属角色/是否送达);reference_ledger_note 非空时说明为什么没有参考图记录或参考为空(no_references_sent=确实零参考派发,原因看 dropped_before_dispatch / local_frame_edit=局部返修只送底图裁片和蒙版 / zero_refs_unrecorded / legacy_before_ledger 等),空列表别说成「什么都没送」。storyboard.tail_endstate 是「尾帧≈首帧」检查结论(current=false 表示结论对应的不是现在这两张图)。' +
692
692
  '★镜头反复被拒、或客户问「被拒的那几张到底什么样 / 为什么不采用」时先调它:逐张看原图和证据,再决定改分镜、改参考还是重掷——别盲目付费重抽。要看某张的最终提示词用 get_image_dispatch(generation_id)。' +
693
693
  '客户看过原图确认画面没问题、是审计误判时,用 adopt_frame_candidate 人工采用(免费);manual_adoption 非空 = 该候选是人工放行的。' +
694
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`)));
@@ -974,6 +974,7 @@ export function registerProduceTools(server, client) {
974
974
  '★报价按**实际会用的模型与分辨率**分档,响应带 price_breakdown(逐档张数与单价);' +
975
975
  '打算在 generate_frames 里临时换模型,报价时就要把同一个 image_model 传进来,否则两边不是一个价。' +
976
976
  '★两边必须传同一个 image_model —— 不一致会被直接拒(400 IMAGE_MODEL_MISMATCH),因为模型决定计费档,不同源就是「预估≠扣费」。两边都不传也算一致(用该剧设定的模型)。已下架的型号(FLUX 全系列)一律拒收,别再传。' +
977
+ '★响应带 frame_contract_advisory 时,列出的镜构图契约(画面里几人、主体是人物还是局部/道具)可能已过期或与绑定矛盾——出图仍按旧契约来;先讲给客户,同意后对这些镜调 rederive_shot_contract 再重新报价。' +
977
978
  QUOTE_RANGE_HINT, {
978
979
  episode_id: z.number().int().positive(),
979
980
  frame_type: FRAME_TYPE_ARG.optional().describe('默认 first_frame;last_frame=补尾帧;both=首尾都补'),
@@ -1026,6 +1027,7 @@ export function registerProduceTools(server, client) {
1026
1027
  '★两边必须传同一个 image_model —— 不一致会被直接拒(400 IMAGE_MODEL_MISMATCH),因为模型决定计费档,不同源就是「预估≠扣费」。两边都不传也算一致(用该剧设定的模型)。已下架的型号(FLUX 全系列)一律拒收,别再传。' +
1027
1028
  '★frame_type=both 时,平台判这一镜不需要独立尾帧(末态≈首态、没有运镜)会只出首帧:报价 frames_to_generate=1、只计首帧,并带 last_frame_skipped 说明原因——**原样告诉客户尾帧不会出**。' +
1028
1029
  '客户确实要尾帧(例如起止画面不同的运镜)就报价与生成都带 force_independent_last_frame:true。' +
1030
+ '★响应带 frame_contract_advisory 时,列出的镜构图契约(画面里几人、主体是人物还是局部/道具)可能已过期或与绑定矛盾——出图仍按旧契约来;先讲给客户,同意后对这些镜调 rederive_shot_contract 再重新报价。' +
1029
1031
  '★出首帧(first_frame/both)时响应带 continuity:follows_previous_shot=true 表示上一镜尾帧会钉在参考图第 1 位(承接上一镜的人物、姿势与机位),note 说明原因。' +
1030
1032
  '这一镜不该接上一镜(跳切、换场、只拍手/道具的局部特写等),报价与生成都带 continuity_mode:\'independent\'。' +
1031
1033
  QUOTE_RANGE_HINT, {
@@ -1103,6 +1105,9 @@ export function registerProduceTools(server, client) {
1103
1105
  // ---------- 出视频(videos,大额) ----------
1104
1106
  server.tool('quote_videos', '报价:给某一集批量出视频要多少点(与实际扣费同函数,较准)。返回 estimated_points、quote_id。零扣费。' +
1105
1107
  '⚠️ 视频是大额花费,务必把点数清楚告诉用户并等其确认。' +
1108
+ '\n★**frame_delivery = 本次逐镜真正送到厂商的帧**:列出有独立尾帧的计价镜,以及首帧不送达的计价镜(带 reason,如 reference_video_exclusive=挂了定妆视频锚/运动参考);' +
1109
+ 'first_frame.verified=false = 预览没跑完、送不送未核验,别当已送达讲,可逐镜 quote_regenerate_shot_video 核对;没列出的计价镜 = 已核验首帧照常送达、无独立尾帧。advisories 里出现 av_anchor_strips_frames = 这些镜被角色定妆视频锚剥掉首尾帧,' +
1110
+ '把镜号讲给客户,要保住首尾帧就 get_av_anchors 看来源、客户同意后 clear_character_av_anchor 摘锚再重新报价。' +
1106
1111
  '\n★**只计这次真会派发的镜**:已出视频的镜整集续跑时跳过,不重出不计价——shots_total = 这次计价的镜数(不是集内总镜数),' +
1107
1112
  'shots_already_done = 已出视频、这次跳过的镜数。例外:场景组只要有一镜没出视频就**整组重出**,组内已出的镜同样计价。' +
1108
1113
  '全部已出视频 ⇒ 400(没有可派发的镜,要重出某镜用 regenerate_shot_video)。' +
@@ -1804,7 +1809,12 @@ export function registerProduceTools(server, client) {
1804
1809
  '(TERMINAL_DESC_GATE),修法是把**结束时画面是什么样**写进本镜 last_frame_prompt,然后重新出尾帧。' +
1805
1810
  '别去重试出图——这类镜(action_motion_class=state_change 却没写终态)的尾帧历史成功率 9.4%,' +
1806
1811
  '有终态描述的是 40.2%;不补描述就重生,送厂商的提示词里根本没有终态段,画出来仍和首帧一样、' +
1807
- '还是会被拒,而每次重生都照常扣费。get_shot_prompts 的 terminal_desc_missing=true 就是这个信号。', {
1812
+ '还是会被拒,而每次重生都照常扣费。get_shot_prompts 的 terminal_desc_missing=true 就是这个信号。' +
1813
+ '★★【构图契约不会跟着改】改 shot_type / character_ids / character_presence / description / action / image_prompt / first_frame_prompt 后,' +
1814
+ '本镜的构图契约(画面里可见几人、主体是人物还是手部等局部/道具、景别)不会自动重推,出图组织画面与帧审计判人数仍按旧契约来' +
1815
+ '(典型:改成局部特写、解绑全部角色,出图照样画人像)。回执带 frame_contract_advisory 就是这种情况:讲给客户,' +
1816
+ '客户同意后调 rederive_shot_contract(按 token 后付)重推,得出 updated 再报价出图;客户确认画面人数与主体都没变可以不推。' +
1817
+ '★改 action 前先用 get_shot_prompts 读现值(action),别凭空整段覆盖。', {
1808
1818
  storyboard_id: z.number().int().positive(),
1809
1819
  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 清除声明,不回填历史。'),
1810
1820
  continuity_intent: z.enum(['continuous_action', 'shot_change', 'insert_detail', 'jump_cut']).optional().describe('本镜相对上镜的剪辑意图,决定跨镜帧链与续拍怎么接:' +
@@ -1853,7 +1863,7 @@ export function registerProduceTools(server, client) {
1853
1863
  shot_type: z.string().optional().describe('景别(如 特写/中景/全景/远景)'),
1854
1864
  angle: z.string().optional().describe('机位角度'),
1855
1865
  camera_movement: z.string().optional().describe('运镜(推/拉/摇/移/跟/固定)'),
1856
- action: z.string().optional().describe('动作描述'),
1866
+ action: z.string().optional().describe('动作描述(全量覆盖现值;★先用 get_shot_prompts 读现值 action 再改,别整段盲覆盖——里面残留已解绑角色的名字会让审查报 binding_character_mentioned_unbound、重推构图契约时也会被读进去)'),
1857
1867
  dialogue: z.string().optional().describe('台词(★改后自动失效本镜 TTS/字幕,需重出配音)'),
1858
1868
  location: z.string().optional().describe('地点'),
1859
1869
  time: z.string().optional().describe('时间/时段'),
@@ -1884,11 +1894,13 @@ export function registerProduceTools(server, client) {
1884
1894
  return jsonResult(await client.producePut(`/storyboards/${storyboard_id}`, payload));
1885
1895
  });
1886
1896
  server.tool('rederive_shot_contract', '按本镜**当前**的正文与角色绑定,让平台重新推导构图契约(画面里可见几人、主体是人物还是局部/道具、景别)。' +
1887
- '契约本身不对外,读不到也改不了;本工具只回结论 outcome:updated(已改并生效)/ unchanged(推出来和原来一样)/ ' +
1897
+ '契约本体不对外、改不了(get_shot_prompts 的 frame_contract 只给人数 / 主体类型 / 是否可能过期这几个结论);本工具只回结论 outcome:updated(已改并生效)/ unchanged(推出来和原来一样)/ ' +
1888
1898
  'rejected(推出来自相矛盾,未采用,原契约保留)/ no_candidate(没拿到可用结果,原契约保留)/ ' +
1889
1899
  'stale(推导期间本镜又被改过,结果未写入,改完再调一次),附 note 说下一步。点数不足回 402。' +
1890
1900
  '★什么时候用:出图/预检/审核反复说人数不对、局部镜(手部/道具特写)被当成完整人物出图或审核,' +
1891
1901
  '而你已经改过正文或绑定——补全器只填空、不覆盖已有契约,不调本工具改动不会进契约。' +
1902
+ 'update_shot 回执带 frame_contract_advisory、get_shot_prompts 的 frame_contract.stale=true、review_storyboards 报 frame_contract_stale / frame_contract_binding_conflict、' +
1903
+ '出帧报价带 frame_contract_advisory,都是该调本工具的信号;得出 updated 或 unchanged 后「可能过期」标记清除(rejected / stale / no_candidate 保留)。' +
1892
1904
  '★正确顺序:先 update_shot 把画面写对(谁在画面里、谁只出声音用 character_presence 标 voice_only、' +
1893
1905
  '不该出现的人从 character_ids 解绑),再调本工具;不改正文直接调多半回 unchanged。' +
1894
1906
  '★一次文本 AI 调用,按 token 后付(与 autofill_storyboards 同链路),调用前告知客户。' +
@@ -1901,6 +1913,10 @@ export function registerProduceTools(server, client) {
1901
1913
  '★pose_timeline_stale 非 null = 本镜动作起止姿态里的秒数时间轴超出了当前时长(多见于改短 duration 后),出视频时那一端已自动不送;新时间轴写进 video_prompt。' +
1902
1914
  '★同时回 description(画面描述)、lighting(本镜用光)与 sound_effect(本镜音效)现值——review_storyboards 的禁区词命中常在 description / sound_effect,改前先在这里读;用光写 lighting。' +
1903
1915
  '★同时回 shot_type(景别)/ angle(机位)/ camera_movement(运镜)/ continuity_intent(剪辑意图)现值——update_shot 改完这几项就在这里回读核对(整集 get_storyboards 不含它们);null=未设。' +
1916
+ '★同时回 action(动作,update_shot 可改,改前先在这里读)与 action_in / action_out(动作起止姿态,只读)现值。' +
1917
+ '★同时回 frame_contract{on_screen_count, subject_kind, stale, stale_fields?, binding_conflict?, note?}:本镜构图契约的**结论**——' +
1918
+ '出图组织画面、帧审计判人数都按它(契约本体不对外)。stale=true = 契约生成后改过景别 / 绑定 / 画面描述等、可能已过期;' +
1919
+ 'binding_conflict=true = 绑定的角色全部只出声音而契约仍要画人;两种都按 note 建议客户调 rederive_shot_contract(按 token 后付)。' +
1904
1920
  '★同时回 expression_hint(本镜作者指定的面部表情,null=未指定、由平台按台词反推),改它用 update_shot。' +
1905
1921
  'expression_inferred 是拆镜 AI 在剧本没写神态时按本镜内容推断的表情(只读;null=没推断,或本镜台词/动作/氛围/描述/强度改过、推断已过期不再使用);它优先级低于 expression_hint——' +
1906
1922
  '推断不合意就用 update_shot 写 expression_hint 覆盖它。' +
@@ -2202,7 +2218,26 @@ export function registerProduceTools(server, client) {
2202
2218
  '一致性闸拒收未入库/failed/none)+ 拒收时的 sheet_fail_reason·sheet_retryable·sheet_fail_hint(拒收判词)。' +
2203
2219
  '★sheet_status=rejected 时照 retryable 判:consistency_rejected 可重掷一次(generate_character_sheet);' +
2204
2220
  '**连拒且 fail_hint 理由几乎相同 = 锚字段与人物档案冲突(结构性必拒),重掷纯白花钱**——' +
2205
- '先 run_precheck 看 anchor-conflict 警告,把 visual_lock/art_bible 里钉死的角色外观移除或对齐档案再重掷。', { episode_id: z.number().int().positive() }, async ({ episode_id }) => jsonResult(await client.produceGet(`/episodes/${episode_id}/characters`)));
2221
+ '先 run_precheck 看 anchor-conflict 警告,把 visual_lock/art_bible 里钉死的角色外观移除或对齐档案再重掷。' +
2222
+ 'has_av_anchor=true 表示该角色挂着定妆视频锚(会剥掉含该角色镜头的首尾帧),来源与摘除见 get_av_anchors。', { episode_id: z.number().int().positive() }, async ({ episode_id }) => jsonResult(await client.produceGet(`/episodes/${episode_id}/characters`)));
2223
+ server.tool('get_av_anchors', '读某剧各角色的定妆视频锚(AV anchor)现况。免费。定妆视频锚是平台从该角色已出的某镜视频里自动截的约 3 秒片段,' +
2224
+ '出视频时作参考视频注入,用来锚定该角色的长相、服装和声线。' +
2225
+ '★后果要讲给客户:厂商规定参考视频与首尾帧互斥——锚一挂上,含该角色的镜做好的首帧、尾帧都不会送到视频厂商' +
2226
+ '(有独立尾帧、走首尾帧路由的镜除外,以 quote_videos / quote_regenerate_shot_video 的 frame_delivery 为准)。' +
2227
+ '每角色返回 status(active 在用 / disabled 已停用 / none 无锚)、anchor_url(锚片,可直接打开看)、' +
2228
+ 'source(kind=auto 自动建 / manual 手动指定;storyboard_id·storyboard_number 截自哪一镜;start_s·dur_s 截取窗口)、' +
2229
+ 'clip_duration_s、created_at、auto_rebuild(on=没锚时出视频会自动建一条)。' +
2230
+ 'provenance=unrecorded 是本功能上线前建的锚,来源没有记录:inferred_source 只是按自动选镜规则推测,别当事实讲,让客户打开 anchor_url 看。' +
2231
+ 'av_anchor_ref_enabled=false 表示本剧出视频不挂锚,锚存在也无影响。要摘锚用 clear_character_av_anchor。', { drama_id: z.number().int().positive() }, async ({ drama_id }) => jsonResult(await client.produceGet(`/dramas/${drama_id}/av-anchors`)));
2232
+ server.tool('clear_character_av_anchor', '摘掉某角色的定妆视频锚并停用自动建锚。免费。★必须客户确认后再调,先用 get_av_anchors 把锚的来源讲给客户。' +
2233
+ '后果两面都要讲清:①摘锚后含该角色的镜首帧恢复送达,不再因参考视频互斥被剥(尾帧仍按动作类型等常规规则判定,以重新报价的 frame_delivery 为准);' +
2234
+ '②台词镜的声线不再锚定锚片里的嗓音,只靠厂商按文字和首帧生成,跨镜声线可能有差异;长相改由定妆照/首帧锚定。' +
2235
+ '默认停用:之后出视频不再挂它,也不会自动重建。allow_auto_rebuild:true = 只清锚不停用(下次出视频平台自动重选一镜重建,首尾帧又会被剥),' +
2236
+ '也是停用后的恢复入口。这是解除引用不是删除:锚片文件不删,回执 unlinked 列出摘下的 URL(list_unlinked_assets 可查)。' +
2237
+ '已出的视频不受影响;摘完重新报价(quote_videos / quote_regenerate_shot_video)核对 frame_delivery 与 advisories。', {
2238
+ character_id: z.number().int().positive(),
2239
+ allow_auto_rebuild: z.boolean().optional().describe('true=只清锚、保持自动建锚(或恢复已停用的自动建锚);缺省=摘锚并停用'),
2240
+ }, async ({ character_id, allow_auto_rebuild }) => jsonResult(await client.producePost(`/characters/${character_id}/av-anchor/clear`, allow_auto_rebuild !== undefined ? { allow_auto_rebuild } : {})));
2206
2241
  server.tool('get_scenes', '读某一集的场景列表(名字/描述/场景图是否就绪)。免费。', { episode_id: z.number().int().positive() }, async ({ episode_id }) => jsonResult(await client.produceGet(`/episodes/${episode_id}/scenes`)));
2207
2242
  server.tool('get_assets', '读一部剧的全部资产聚合(角色/场景/道具/图片)。免费。', { drama_id: z.number().int().positive() }, async ({ drama_id }) => jsonResult(await client.produceGet(`/dramas/${drama_id}/assets`)));
2208
2243
  // ========== P1 · 任务进度 + 成本/预算 ==========
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.231",
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.231 tool surface (operationIds match MCP tool names 1:1)."
5
+ "version": "0.1.238",
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.238 tool surface (operationIds match MCP tool names 1:1)."
7
7
  },
8
8
  "servers": [
9
9
  {
@@ -373,6 +373,68 @@
373
373
  }
374
374
  }
375
375
  },
376
+ "/characters/{character_id}/av-anchor/clear": {
377
+ "post": {
378
+ "operationId": "clear_character_av_anchor",
379
+ "summary": "摘掉某角色的定妆视频锚并停用自动建锚",
380
+ "description": "摘掉某角色的定妆视频锚并停用自动建锚。免费。★必须客户确认后再调,先用 get_av_anchors 把锚的来源讲给客户。后果两面都要讲清:①摘锚后含该角色的镜首帧恢复送达,不再因参考视频互斥被剥(尾帧仍按动作类型等常规规则判定,以重新报价的 frame_delivery 为准);②台词镜的声线不再锚定锚片里的嗓音,只靠厂商按文字和首帧生成,跨镜声线可能有差异;长相改由定妆照/首帧锚定。默认停用:之后出视频不再挂它,也不会自动重建。allow_auto_rebuild:true = 只清锚不停用(下次出视频平台自动重选一镜重建,首尾帧又会被剥),也是停用后的恢复入口。这是解除引用不是删除:锚片文件不删,回执 unlinked 列出摘下的 URL(list_unlinked_assets 可查)。已出的视频不受影响;摘完重新报价(quote_videos / quote_regenerate_shot_video)核对 frame_delivery 与 advisories。",
381
+ "tags": [
382
+ "characters"
383
+ ],
384
+ "parameters": [
385
+ {
386
+ "name": "character_id",
387
+ "in": "path",
388
+ "required": true,
389
+ "schema": {
390
+ "type": "integer",
391
+ "exclusiveMinimum": 0
392
+ }
393
+ }
394
+ ],
395
+ "requestBody": {
396
+ "required": false,
397
+ "content": {
398
+ "application/json": {
399
+ "schema": {
400
+ "type": "object",
401
+ "properties": {
402
+ "allow_auto_rebuild": {
403
+ "type": "boolean"
404
+ }
405
+ }
406
+ }
407
+ }
408
+ }
409
+ },
410
+ "responses": {
411
+ "200": {
412
+ "description": "StarReel envelope",
413
+ "content": {
414
+ "application/json": {
415
+ "schema": {
416
+ "type": "object",
417
+ "properties": {
418
+ "code": {
419
+ "type": "integer"
420
+ },
421
+ "message": {
422
+ "type": "string"
423
+ },
424
+ "data": {
425
+ "description": "Operation result payload"
426
+ }
427
+ }
428
+ }
429
+ }
430
+ }
431
+ },
432
+ "402": {
433
+ "description": "Insufficient prepaid balance (never overdrafts); response carries `needed` points"
434
+ }
435
+ }
436
+ }
437
+ },
376
438
  "/characters/{character_id}/derive-portrait": {
377
439
  "post": {
378
440
  "operationId": "derive_character_portrait",
@@ -1927,6 +1989,53 @@
1927
1989
  }
1928
1990
  }
1929
1991
  },
1992
+ "/dramas/{drama_id}/av-anchors": {
1993
+ "get": {
1994
+ "operationId": "get_av_anchors",
1995
+ "summary": "读某剧各角色的定妆视频锚(AV anchor)现况",
1996
+ "description": "读某剧各角色的定妆视频锚(AV anchor)现况。免费。定妆视频锚是平台从该角色已出的某镜视频里自动截的约 3 秒片段,出视频时作参考视频注入,用来锚定该角色的长相、服装和声线。★后果要讲给客户:厂商规定参考视频与首尾帧互斥——锚一挂上,含该角色的镜做好的首帧、尾帧都不会送到视频厂商(有独立尾帧、走首尾帧路由的镜除外,以 quote_videos / quote_regenerate_shot_video 的 frame_delivery 为准)。每角色返回 status(active 在用 / disabled 已停用 / none 无锚)、anchor_url(锚片,可直接打开看)、source(kind=auto 自动建 / manual 手动指定;storyboard_id·storyboard_number 截自哪一镜;start_s·dur_s 截取窗口)、clip_duration_s、created_at、auto_rebuild(on=没锚时出视频会自动建一条)。provenance=unrecorded 是本功能上线前建的锚,来源没有记录:inferred_source 只是按自动选镜规则推测,别当事实讲,让客户打开 anchor_url 看。av_anchor_ref_enabled=false 表示本剧出视频不挂锚,锚存在也无影响。要摘锚用 clear_character_av_anchor。",
1997
+ "tags": [
1998
+ "dramas"
1999
+ ],
2000
+ "parameters": [
2001
+ {
2002
+ "name": "drama_id",
2003
+ "in": "path",
2004
+ "required": true,
2005
+ "schema": {
2006
+ "type": "integer",
2007
+ "exclusiveMinimum": 0
2008
+ }
2009
+ }
2010
+ ],
2011
+ "responses": {
2012
+ "200": {
2013
+ "description": "StarReel envelope",
2014
+ "content": {
2015
+ "application/json": {
2016
+ "schema": {
2017
+ "type": "object",
2018
+ "properties": {
2019
+ "code": {
2020
+ "type": "integer"
2021
+ },
2022
+ "message": {
2023
+ "type": "string"
2024
+ },
2025
+ "data": {
2026
+ "description": "Operation result payload"
2027
+ }
2028
+ }
2029
+ }
2030
+ }
2031
+ }
2032
+ },
2033
+ "402": {
2034
+ "description": "Insufficient prepaid balance (never overdrafts); response carries `needed` points"
2035
+ }
2036
+ }
2037
+ }
2038
+ },
1930
2039
  "/dramas/{drama_id}/bill": {
1931
2040
  "get": {
1932
2041
  "operationId": "get_drama_bill",
@@ -6136,7 +6245,7 @@
6136
6245
  "get": {
6137
6246
  "operationId": "get_characters",
6138
6247
  "summary": "读某一集的角色列表(名字/定妆图/设定图就绪状态)",
6139
- "description": "读某一集的角色列表(名字/定妆图/设定图就绪状态)。免费。每角色带结构化状态: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 里钉死的角色外观移除或对齐档案再重掷。",
6248
+ "description": "读某一集的角色列表(名字/定妆图/设定图就绪状态)。免费。每角色带结构化状态: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 里钉死的角色外观移除或对齐档案再重掷。has_av_anchor=true 表示该角色挂着定妆视频锚(会剥掉含该角色镜头的首尾帧),来源与摘除见 get_av_anchors。",
6140
6249
  "tags": [
6141
6250
  "episodes"
6142
6251
  ],
@@ -7480,7 +7589,7 @@
7480
7589
  "post": {
7481
7590
  "operationId": "quote_frames",
7482
7591
  "summary": "报价:给某一集批量出帧要多少点",
7483
- "description": "报价:给某一集批量出帧要多少点。返回 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 系列)下两者相等。",
7592
+ "description": "报价:给某一集批量出帧要多少点。返回 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 全系列)一律拒收,别再传。★响应带 frame_contract_advisory 时,列出的镜构图契约(画面里几人、主体是人物还是局部/道具)可能已过期或与绑定矛盾——出图仍按旧契约来;先讲给客户,同意后对这些镜调 rederive_shot_contract 再重新报价。★返回两个数:estimated_points 是**上界**(按参考图张数上限估,拿它准备余额就不会中途 402),typical_points 是**通常花费**。两个都告诉客户,只报上界会让人以为贵得多。固定价模型(如 Nano Banana 系列)下两者相等。",
7484
7593
  "tags": [
7485
7594
  "episodes"
7486
7595
  ],
@@ -11080,7 +11189,7 @@
11080
11189
  "post": {
11081
11190
  "operationId": "quote_videos",
11082
11191
  "summary": "报价:给某一集批量出视频要多少点(与实际扣费同函数,较准)",
11083
- "description": "报价:给某一集批量出视频要多少点(与实际扣费同函数,较准)。返回 estimated_points、quote_id。零扣费。⚠️ 视频是大额花费,务必把点数清楚告诉用户并等其确认。\n★**只计这次真会派发的镜**:已出视频的镜整集续跑时跳过,不重出不计价——shots_total = 这次计价的镜数(不是集内总镜数),shots_already_done = 已出视频、这次跳过的镜数。例外:场景组只要有一镜没出视频就**整组重出**,组内已出的镜同样计价。全部已出视频 ⇒ 400(没有可派发的镜,要重出某镜用 regenerate_shot_video)。报价之后若有镜的视频被清空(变成待出视频),generate_videos 会 409 要求重新报价,不按报价外的镜扣费。\n★**按镜指定视频引擎**:传 shot_engines={分镜id: 引擎} 即只为这些镜、这一次整集生成换引擎(不改剧级 video_engine,其余镜照旧)。报价按它逐镜计价,quote_id 把引擎钉死,generate_videos 派发的就是它——要改引擎必须重新报价。回执 shot_engines = 实际生效的映射;shot_engines_ungrouped = 因含指定镜而**拆成逐镜出**的场景组(场景组的时长与多关键帧是按剧引擎规划的,换引擎整组出会丢镜/丢关键帧;拆组后组内其余镜仍按剧引擎逐镜出,失去组内一次成片的连贯性,所以别为一镜去拆一个好好的组——先看 get_scene_group_plan)。所选引擎必须支持本剧分辨率(seedance-2.5 只有 480p/720p;hailuo-3 只有 720p/1080p;wan3.0/wan3.0-prime 480p~1080p),且镜头时长不超过该引擎单镜上限(seedance-2.5/wan3.0 30s,hailuo-3 15s),否则 400(超长会被厂商截断,要么换引擎要么 split_shot)。指定引擎的镜必须这次会出视频:已出视频的镜整集生成不会重出,给它指定引擎 ⇒ 400;拆成逐镜的场景组只计没出视频的组员。只想重出个别已出过视频的镜,用 quote_regenerate_shot_video 的 model 更省。★响应可能带**未接缝提示**(不影响 review_token / 报价 / 状态码):review_frames 与 generate_videos 是 unchained_seam_advisory,quote_videos 是 advisories 里 code=unchained_seams。seams 列的是 chain_frames 会接、却还没接上的相邻缝(from_shot→to_shot),status=no_stamp(从没接过)/ pending(发起过衔接、还没落地或审计未出结论)/ stale_anchor(上次承接的锚已失效:上一镜尾帧在衔接之后又被重生过,需要重接)/ join_failed(上次发起的衔接重生被拒 / 失败 / 落选,没落地)/ audit_failed(衔接落地但审计判不连续,看 get_storyboards 的 seam_failed_dims)/ first_frame_regenerated(接缝审过之后下镜首帧又被重出、没走承接路径,原衔接已不算数)/ not_linked(规划器判没接上、原因证据不足);都按计划重接即可;video_locked 是下镜已出视频的同类缝,chain_frames 不再改它们,只能逐镜 chain_shot_from_prev / chain_shot_from 换首帧后 regenerate_shot_video(都先报价)。出视频前看到 seams 就先 chain_frames(dry_run:true) 把计划与报价告诉客户,客户同意再执行,执行后重调 review_frames。",
11192
+ "description": "报价:给某一集批量出视频要多少点(与实际扣费同函数,较准)。返回 estimated_points、quote_id。零扣费。⚠️ 视频是大额花费,务必把点数清楚告诉用户并等其确认。\n★**frame_delivery = 本次逐镜真正送到厂商的帧**:列出有独立尾帧的计价镜,以及首帧不送达的计价镜(带 reason,如 reference_video_exclusive=挂了定妆视频锚/运动参考);first_frame.verified=false = 预览没跑完、送不送未核验,别当已送达讲,可逐镜 quote_regenerate_shot_video 核对;没列出的计价镜 = 已核验首帧照常送达、无独立尾帧。advisories 里出现 av_anchor_strips_frames = 这些镜被角色定妆视频锚剥掉首尾帧,把镜号讲给客户,要保住首尾帧就 get_av_anchors 看来源、客户同意后 clear_character_av_anchor 摘锚再重新报价。\n★**只计这次真会派发的镜**:已出视频的镜整集续跑时跳过,不重出不计价——shots_total = 这次计价的镜数(不是集内总镜数),shots_already_done = 已出视频、这次跳过的镜数。例外:场景组只要有一镜没出视频就**整组重出**,组内已出的镜同样计价。全部已出视频 ⇒ 400(没有可派发的镜,要重出某镜用 regenerate_shot_video)。报价之后若有镜的视频被清空(变成待出视频),generate_videos 会 409 要求重新报价,不按报价外的镜扣费。\n★**按镜指定视频引擎**:传 shot_engines={分镜id: 引擎} 即只为这些镜、这一次整集生成换引擎(不改剧级 video_engine,其余镜照旧)。报价按它逐镜计价,quote_id 把引擎钉死,generate_videos 派发的就是它——要改引擎必须重新报价。回执 shot_engines = 实际生效的映射;shot_engines_ungrouped = 因含指定镜而**拆成逐镜出**的场景组(场景组的时长与多关键帧是按剧引擎规划的,换引擎整组出会丢镜/丢关键帧;拆组后组内其余镜仍按剧引擎逐镜出,失去组内一次成片的连贯性,所以别为一镜去拆一个好好的组——先看 get_scene_group_plan)。所选引擎必须支持本剧分辨率(seedance-2.5 只有 480p/720p;hailuo-3 只有 720p/1080p;wan3.0/wan3.0-prime 480p~1080p),且镜头时长不超过该引擎单镜上限(seedance-2.5/wan3.0 30s,hailuo-3 15s),否则 400(超长会被厂商截断,要么换引擎要么 split_shot)。指定引擎的镜必须这次会出视频:已出视频的镜整集生成不会重出,给它指定引擎 ⇒ 400;拆成逐镜的场景组只计没出视频的组员。只想重出个别已出过视频的镜,用 quote_regenerate_shot_video 的 model 更省。★响应可能带**未接缝提示**(不影响 review_token / 报价 / 状态码):review_frames 与 generate_videos 是 unchained_seam_advisory,quote_videos 是 advisories 里 code=unchained_seams。seams 列的是 chain_frames 会接、却还没接上的相邻缝(from_shot→to_shot),status=no_stamp(从没接过)/ pending(发起过衔接、还没落地或审计未出结论)/ stale_anchor(上次承接的锚已失效:上一镜尾帧在衔接之后又被重生过,需要重接)/ join_failed(上次发起的衔接重生被拒 / 失败 / 落选,没落地)/ audit_failed(衔接落地但审计判不连续,看 get_storyboards 的 seam_failed_dims)/ first_frame_regenerated(接缝审过之后下镜首帧又被重出、没走承接路径,原衔接已不算数)/ not_linked(规划器判没接上、原因证据不足);都按计划重接即可;video_locked 是下镜已出视频的同类缝,chain_frames 不再改它们,只能逐镜 chain_shot_from_prev / chain_shot_from 换首帧后 regenerate_shot_video(都先报价)。出视频前看到 seams 就先 chain_frames(dry_run:true) 把计划与报价告诉客户,客户同意再执行,执行后重调 review_frames。",
11084
11193
  "tags": [
11085
11194
  "episodes"
11086
11195
  ],
@@ -11927,7 +12036,7 @@
11927
12036
  "get": {
11928
12037
  "operationId": "get_image_dispatch",
11929
12038
  "summary": "免费只读查询一张镜头帧的派发台账:实际用了哪几张参考图、每张的用途与所属角色、是否送达模型、没送达或派发前被剔除的是哪一步因什么被剔(如时代预检点名的冲突物件),以及真正发给图片模型的最终提示词",
11930
- "description": "免费只读查询一张镜头帧的派发台账:实际用了哪几张参考图、每张的用途与所属角色、是否送达模型、没送达或派发前被剔除的是哪一步因什么被剔(如时代预检点名的冲突物件),以及真正发给图片模型的最终提示词。用于回答「到底用了哪张图、为什么画面不像」;先查清再决定是否重出,别靠猜反复付费重抽。ledger=partial/none 表示该图生成于台账上线前,缺失字段如实为 null。",
12039
+ "description": "免费只读查询一张镜头帧的派发台账:实际用了哪几张参考图、每张的用途与所属角色、是否送达模型、没送达或派发前被剔除的是哪一步因什么被剔(如时代预检点名的冲突物件),以及真正发给图片模型的最终提示词。用于回答「到底用了哪张图、为什么画面不像」;先查清再决定是否重出,别靠猜反复付费重抽。ledger=none 不等于没送参考,看 ledger_note(code + 原因:局部返修 / 零参考派发 / 台账上线前 / 尾帧复用首帧等);缺失字段如实为 null。",
11931
12040
  "tags": [
11932
12041
  "images"
11933
12042
  ],
@@ -13283,7 +13392,7 @@
13283
13392
  "put": {
13284
13393
  "operationId": "update_shot",
13285
13394
  "summary": "逐镜编辑:改单个分镜的文本内容(景别/动作/台词/画面描述/运镜等)、面部表情(expression_hint)、时长(duration)、成片变速(speed_factor)、镜间转场(transition_type / transiti",
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 就是这个信号。",
13395
+ "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 就是这个信号。★★【构图契约不会跟着改】改 shot_type / character_ids / character_presence / description / action / image_prompt / first_frame_prompt 后,本镜的构图契约(画面里可见几人、主体是人物还是手部等局部/道具、景别)不会自动重推,出图组织画面与帧审计判人数仍按旧契约来(典型:改成局部特写、解绑全部角色,出图照样画人像)。回执带 frame_contract_advisory 就是这种情况:讲给客户,客户同意后调 rederive_shot_contract(按 token 后付)重推,得出 updated 再报价出图;客户确认画面人数与主体都没变可以不推。★改 action 前先用 get_shot_prompts 读现值(action),别凭空整段覆盖。",
13287
13396
  "tags": [
13288
13397
  "storyboards"
13289
13398
  ],
@@ -14303,7 +14412,7 @@
14303
14412
  "get": {
14304
14413
  "operationId": "get_frame_candidates",
14305
14414
  "summary": "免费只读:一个镜头首帧/尾帧的**全部候选**(出图验收工作台同一份数据)",
14306
- "description": "免费只读:一个镜头首帧/尾帧的**全部候选**(出图验收工作台同一份数据)。每张候选给原图地址(被拒的也在,可直接打开看原尺寸)、状态、是否为当前在用(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 同口径。",
14415
+ "description": "免费只读:一个镜头首帧/尾帧的**全部候选**(出图验收工作台同一份数据)。每张候选给原图地址(被拒的也在,可直接打开看原尺寸)、状态、是否为当前在用(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:用途/所属角色/是否送达);reference_ledger_note 非空时说明为什么没有参考图记录或参考为空(no_references_sent=确实零参考派发,原因看 dropped_before_dispatch / local_frame_edit=局部返修只送底图裁片和蒙版 / zero_refs_unrecorded / legacy_before_ledger 等),空列表别说成「什么都没送」。storyboard.tail_endstate 是「尾帧≈首帧」检查结论(current=false 表示结论对应的不是现在这两张图)。★镜头反复被拒、或客户问「被拒的那几张到底什么样 / 为什么不采用」时先调它:逐张看原图和证据,再决定改分镜、改参考还是重掷——别盲目付费重抽。要看某张的最终提示词用 get_image_dispatch(generation_id)。客户看过原图确认画面没问题、是审计误判时,用 adopt_frame_candidate 人工采用(免费);manual_adoption 非空 = 该候选是人工放行的。recovery_options 按帧位给出失败后的三选一(挑误拒 / 修图上传 / 重生),与 get_frame_retry_diagnosis 同口径。",
14307
14416
  "tags": [
14308
14417
  "storyboards"
14309
14418
  ],
@@ -15023,7 +15132,7 @@
15023
15132
  "post": {
15024
15133
  "operationId": "quote_shot_frame",
15025
15134
  "summary": "报价:重画/补出**某一镜的某一帧**要多少点(一帧=一张图)",
15026
- "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。★出首帧(first_frame/both)时响应带 continuity:follows_previous_shot=true 表示上一镜尾帧会钉在参考图第 1 位(承接上一镜的人物、姿势与机位),note 说明原因。这一镜不该接上一镜(跳切、换场、只拍手/道具的局部特写等),报价与生成都带 continuity_mode:'independent'。★返回两个数:estimated_points 是**上界**(按参考图张数上限估,拿它准备余额就不会中途 402),typical_points 是**通常花费**。两个都告诉客户,只报上界会让人以为贵得多。固定价模型(如 Nano Banana 系列)下两者相等。",
15135
+ "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。★响应带 frame_contract_advisory 时,列出的镜构图契约(画面里几人、主体是人物还是局部/道具)可能已过期或与绑定矛盾——出图仍按旧契约来;先讲给客户,同意后对这些镜调 rederive_shot_contract 再重新报价。★出首帧(first_frame/both)时响应带 continuity:follows_previous_shot=true 表示上一镜尾帧会钉在参考图第 1 位(承接上一镜的人物、姿势与机位),note 说明原因。这一镜不该接上一镜(跳切、换场、只拍手/道具的局部特写等),报价与生成都带 continuity_mode:'independent'。★返回两个数:estimated_points 是**上界**(按参考图张数上限估,拿它准备余额就不会中途 402),typical_points 是**通常花费**。两个都告诉客户,只报上界会让人以为贵得多。固定价模型(如 Nano Banana 系列)下两者相等。",
15027
15136
  "tags": [
15028
15137
  "storyboards"
15029
15138
  ],
@@ -15428,7 +15537,7 @@
15428
15537
  "get": {
15429
15538
  "operationId": "get_shot_prompts",
15430
15539
  "summary": "读某一镜的四条提示词**正文**(image_prompt=首帧画面 / video_prompt=动态表演 / first_frame_prompt=开始时什么样 / last_frame_prompt=结束时什么样),供直接微调后用 u",
15431
- "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 对应镜。",
15540
+ "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=未设。★同时回 action(动作,update_shot 可改,改前先在这里读)与 action_in / action_out(动作起止姿态,只读)现值。★同时回 frame_contract{on_screen_count, subject_kind, stale, stale_fields?, binding_conflict?, note?}:本镜构图契约的**结论**——出图组织画面、帧审计判人数都按它(契约本体不对外)。stale=true = 契约生成后改过景别 / 绑定 / 画面描述等、可能已过期;binding_conflict=true = 绑定的角色全部只出声音而契约仍要画人;两种都按 note 建议客户调 rederive_shot_contract(按 token 后付)。★同时回 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 对应镜。",
15432
15541
  "tags": [
15433
15542
  "storyboards"
15434
15543
  ],
@@ -15475,7 +15584,7 @@
15475
15584
  "post": {
15476
15585
  "operationId": "rederive_shot_contract",
15477
15586
  "summary": "按本镜**当前**的正文与角色绑定,让平台重新推导构图契约(画面里可见几人、主体是人物还是局部/道具、景别)",
15478
- "description": "按本镜**当前**的正文与角色绑定,让平台重新推导构图契约(画面里可见几人、主体是人物还是局部/道具、景别)。契约本身不对外,读不到也改不了;本工具只回结论 outcome:updated(已改并生效)/ unchanged(推出来和原来一样)/ rejected(推出来自相矛盾,未采用,原契约保留)/ no_candidate(没拿到可用结果,原契约保留)/ stale(推导期间本镜又被改过,结果未写入,改完再调一次),附 note 说下一步。点数不足回 402。★什么时候用:出图/预检/审核反复说人数不对、局部镜(手部/道具特写)被当成完整人物出图或审核,而你已经改过正文或绑定——补全器只填空、不覆盖已有契约,不调本工具改动不会进契约。★正确顺序:先 update_shot 把画面写对(谁在画面里、谁只出声音用 character_presence 标 voice_only、不该出现的人从 character_ids 解绑),再调本工具;不改正文直接调多半回 unchanged。★一次文本 AI 调用,按 token 后付(与 autofill_storyboards 同链路),调用前告知客户。★只改契约这一个字段,不碰台词/提示词/其它专业字段;已出的首尾帧不会自动重出,要让画面跟上需对本镜重新出帧(先报价)。★updated 会作废本镜及同集未消费的出帧/出视频报价,之后要重新报价。",
15587
+ "description": "按本镜**当前**的正文与角色绑定,让平台重新推导构图契约(画面里可见几人、主体是人物还是局部/道具、景别)。契约本体不对外、改不了(get_shot_prompts 的 frame_contract 只给人数 / 主体类型 / 是否可能过期这几个结论);本工具只回结论 outcome:updated(已改并生效)/ unchanged(推出来和原来一样)/ rejected(推出来自相矛盾,未采用,原契约保留)/ no_candidate(没拿到可用结果,原契约保留)/ stale(推导期间本镜又被改过,结果未写入,改完再调一次),附 note 说下一步。点数不足回 402。★什么时候用:出图/预检/审核反复说人数不对、局部镜(手部/道具特写)被当成完整人物出图或审核,而你已经改过正文或绑定——补全器只填空、不覆盖已有契约,不调本工具改动不会进契约。update_shot 回执带 frame_contract_advisory、get_shot_prompts 的 frame_contract.stale=true、review_storyboards 报 frame_contract_stale / frame_contract_binding_conflict、出帧报价带 frame_contract_advisory,都是该调本工具的信号;得出 updated 或 unchanged 后「可能过期」标记清除(rejected / stale / no_candidate 保留)。★正确顺序:先 update_shot 把画面写对(谁在画面里、谁只出声音用 character_presence 标 voice_only、不该出现的人从 character_ids 解绑),再调本工具;不改正文直接调多半回 unchanged。★一次文本 AI 调用,按 token 后付(与 autofill_storyboards 同链路),调用前告知客户。★只改契约这一个字段,不碰台词/提示词/其它专业字段;已出的首尾帧不会自动重出,要让画面跟上需对本镜重新出帧(先报价)。★updated 会作废本镜及同集未消费的出帧/出视频报价,之后要重新报价。",
15479
15588
  "tags": [
15480
15589
  "storyboards"
15481
15590
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@starreel/mcp",
3
- "version": "0.1.231",
3
+ "version": "0.1.238",
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.231",
5
+ "version": "0.1.238",
6
6
  "websiteUrl": "https://starreel.ai",
7
7
  "packages": [
8
8
  {
9
9
  "registryType": "npm",
10
10
  "identifier": "@starreel/mcp",
11
- "version": "0.1.231",
11
+ "version": "0.1.238",
12
12
  "transport": {
13
13
  "type": "stdio"
14
14
  },