generate_story_video
shallowpro.aicut/aicut · Verify this server
Starts an AI Video Story EPISODE: the engine writes the whole multi-scene episode from the idea, draws the OPENING PICTURE OF EVERY SCENE (the `start_frame` in this API's fields), and PARKS the run so the user can look at those pictures before anything moves. This is stage 1 of 3 - no scene videos generate yet, and this tool returns immediately. TALK TO THE USER IN THOSE PLAIN WORDS: 'the opening picture of each scene', 'the pictures', 'the still for scene 2'. 'Start frames' and 'frames review' are field names in the responses you read - do not say them to the user. WHEN: the series is picked and its FULL entry fetched (`list_series` with `series_id` - that is where the duration ladder and the prices are), the idea is iterated with the user in chat, and - for a series whose `cast.required` is true - the cast is drafted (`generate_cast`), its portraits are bought (`generate_cast_portraits`) and DONE, and the user approved them. INPUT DISCIPLINE (hard rule): you pass ONE IDEA - a short paragraph - plus options. You NEVER author scenes, episode JSON, dialogue, or image prompts; the engine owns all generation. A `scenes` field is rejected. CAST: pass the approved members' ids from `generate_cast_portraits` (or existing cast members from `list_characters`, kind `cast_member`) as `cast_member_ids`. Members whose portraits are still generating are refused with a 409 - wait for the portraits first. A `cast.writer_owned` series refuses cast ids (it casts itself). THE CARD: this call has ALREADY put the aicut frames card in front of the user. It follows the episode through writing and frame generation on its own and shows the scene-by-scene review rows the moment the run parks - each one the opening picture, what happens in that scene, and a Show more for what is said in it. You do not poll anything to make that happen. Do NOT call `wait_for_generation` or loop `get_video` WHILE THE CARD IS WALKING TO THE REVIEW: say one short line (what was ordered, and that the opening picture of each scene will appear on the card for them to look at - plain words, not 'start frames' or 'frames review'), then STOP and wait for the user. When they answer, act on WHICH KIND of complaint it is: `change_story_scene` when what HAPPENS in a scene is wrong (it rewrites that scene and redraws it), `regenerate_story_frame` when only the PICTURE is wrong, `set_scene_kept` to cut a scene, and `fire_story_video` ONLY once they have given a go that names firing the scene videos at the price you quoted - liking the pictures is not that go. THE CARD STOPS UPDATING ONCE IT REACHES THE REVIEW, so a redraw you order afterwards does NOT appear on it: read `get_video` until that lane's `regenerate` is terminal, and then call `show_generation` with the episode id to put a fresh grid in front of the user. That is the one place a second card is wanted rather than a duplicate. THE CARD SHOWS BAD OUTCOMES TOO, and neither is something you sit and wait through: a writer failure ends the card on its failed note, and an episode whose frames all failed parks with an EMPTY grid. If the user asks about either, make ONE `get_video` read and tell them what it says (see IF WRITING FAILS and IF EVERY FRAME FAILS) - one read, not a loop. Call `wait_for_generation` ONLY when no card rendered - a terminal, a plain SDK client, anything that did not negotiate the MCP Apps UI extension; there, poll `get_video` until `story.stage` is `frames_review` and give the user the frame urls yourself. aicut cannot see which clients render cards and sends the same answer to all of them. AFTER: the response is the parked job (`story.stage`), which moves `starting` -> `generating_frames` -> `frames_review` with each frame's url. A parked episode STAYS at `frames_review` until it is fired, so nothing is waiting on you there - the next move is the USER's. Redraw frames they dislike with `regenerate_story_frame`, cut ones they want gone with `set_scene_kept`, then `fire_story_video` generates the scene videos. RENDER is the last stage: once the episode succeeds (or `story.stage` is `ready_to_render`), `render_story_video` produces the final file - or the user renders in the aicut web editor, where the episode also appears. IF EVERY FRAME FAILS: the episode reaches `frames_review` with no usable image - none of the frames has a `url`. Tell the user plainly: no pictures came back, every one failed, and NO VIDEO HAS BEEN CHARGED - the scene videos are only bought at fire. Their two moves are the same as the webapp's, and BOTH KEEP THE EPISODE: redraw the ones they want with `regenerate_story_frame`, and cut the ones they do not want with `set_scene_kept` (free, and it drops the fire price by those lanes). THE REDRAW IS THE ONE THAT UNBLOCKS IT - cutting alone never gets there, because every KEPT scene needs an image before fire (`409 scenes_missing_frames`) and the last kept scene cannot be cut. So do not offer cutting as an alternative to redrawing: it is how the user drops the scenes they are not going to redraw. Do not reach for `delete_video` here: it throws away an episode whose start frames are ALREADY PAID FOR and gives none of that back, so it is a genuine last resort for a user who wants the whole episode gone, not the second exit. Do not fire an episode while it has no usable frame. IF WRITING FAILS: `get_video` answers `status: "failed"` with `story.stage: "writing_failed"` - TERMINAL, stop polling. Nothing was charged for the episode and the cast is saved: offer the user a retry, which is simply a fresh `generate_story_video` call with the same idea and the same `cast_member_ids` (it quotes and charges like any new episode - no double charge, the failed one took nothing). The dead job charges nothing and can simply be left, or removed with `delete_video`. DEFAULTS: the series' `defaults` block from `list_series` with `series_id` is what it is tuned for - use it unless the USER names a model, and never interview the user about options they did not ask about. `defaults.language` is the language the SERIES is written in (some are German formats): omit `language` and it is used automatically - only pass one when the user asked for a different language. NOT ON THIS SURFACE (deliberate - the aicut webapp owns them today): dance scenes, multi-part / continuation episodes, recreate-from-a-video, per-scene location or setting images, custom per-scene scripts, open-idea (series-less) episodes, and part of the cast edit surface (renaming a member, adding your own, adding one from a photo - a single portrait CAN be redrawn with `regenerate_cast_portrait`, and a member CAN be changed into a different character with `describe_cast_member`). AT FRAME REVIEW the webapp additionally offers, and this surface does not: changing ONE scene's length (which re-prices the fire), editing a scene's DIALOGUE line by line, and pinning a per-scene reference still. Say so if the user asks for one - do NOT try to emulate them through the idea text, through a redraw, or by starting the episode over. WHAT IS NO LONGER ON THAT LIST: changing what HAPPENS in a scene. `change_story_scene` takes a plain sentence ('the kid should look super sad'), rewrites that scene's own setting / people / action text from it and redraws its picture for one image's price - and the change reaches the scene VIDEO too, not only the still. COST: this charges the FRAMES stage now and refuses accounts that could not afford the whole episode. Quote the chosen length's own rung from the series' FULL `list_series` entry (the `series_id` call - the compact catalog has no rungs) - `frames_tokens` now, `videos_tokens` at fire, `total_tokens` for the episode - in the message where you ask for the go, together with the promise that the videos are only charged when the user fires them. EVERY RUNG THAT SHIPS IS `exact`, so its price is ONE number rather than a range - and if one ever ships with `exact: false`, do not read the price off the rung at all: call `estimate_only` and quote that. TILDE WHAT THE RUNG SAYS IS NOT FIRM, which is a SEPARATE question from `exact`: `videos_estimated` true means the episode writer is not held to `videos_tokens` (it picks its own scene count and lengths whatever the rung orders), and `frames_estimated` true means the same for `frames_tokens` (the rung ordered only a total length, so that figure is what the expected scene count costs). Mark each true one with a tilde even when `exact` is true - a rung is routinely both - and tilde the TOTAL whenever EITHER is true, since the total is the two halves added. Those are the sign-off's own verdicts, so quoting them this way reads exactly as the webapp's button does. ONE CAVEAT: `frames_tokens` is priced at the series' DEFAULT start-frame model, so if you also pass `start_frame_model` the frames charge will differ - quote from `estimate_only` in that case, never from the published rung. `estimate_only` echoes the SAME markers (`frames_estimated`, `videos_estimated`, `scene_count_estimated`), so tilde its figures on exactly the same rule - it is a quote, not a firmer number than the rung it came from. SO DOES THE PAID 201, and that is the response you report off: if it comes back with `frames_estimated` or `scene_count_estimated` true, then `frames_stage_tokens`, `estimated_tokens` and `scene_count` on it are all still estimates, and you say so in the line where you tell the user what was ordered. `estimate_only: true` re-quotes the same split against the live balance without spending. The frames figure follows the REAL written scene count: on series whose writer sizes the episode itself the written episode can carry a few scenes more or fewer than the rung derives, and `fire_story_video`'s own `estimate_only` is the exact remaining price at fire time, for exactly the lanes that will generate. WHEN YOU CAN STATE THE ALL-IN TOTAL, which is not before the cast. Four things are bought across an episode: the cast portraits, the start frames, the scene videos and the final render. THREE of them are quotable up front - the two stage figures ride the rung above, and `pricing.render_tokens_per_minute` on the same `list_series` entry is what a rendered minute costs. THE PORTRAITS ARE NOT: their number is `portraits_needed` on the FREE `generate_cast` response, which does not exist until the cast has been drafted. So the itemized total is stated AFTER the free cast call and BEFORE the portraits are bought - that is the first moment every line of it is real. Do not guess a portrait count from the idea to get a total sooner, and do not present the two stage figures as the whole episode: say what they cover. IF THIS SERIES NEEDS A CAST, THE QUOTE SAYS SO. An `estimate_only` answer carries `cast_required` and `cast_member_ids_missing` when the series takes one: `cast_member_ids_missing: true` means this exact request PRICES but would be REFUSED - the price is real, the call is not yet executable. Do not ask for a go on it. Draft the cast (`generate_cast`, free), buy its portraits, and quote again with the member ids. SIZING: the only sizing question you ever ask is LENGTH in seconds - 'how long should it be? 30 seconds is the default.' NEVER ask the user for a scene count. Do NOT derive a length or a count yourself either - the series' published `pricing.video_models[].durations.options` IS the picker: each entry is a real episode length in seconds with the scene count the rung derives and the tokens it costs. THAT BLOCK COMES FROM `list_series` WITH `series_id` (the compact catalog carries no ladder and no prices - only a rough `episode_tokens` range for pitching), so make that call before you offer lengths or state any price. Offer the lengths near what the user asked for, then pass the chosen entry's `seconds` as `duration_seconds`. `durations.default_seconds` is the rung to assume when they express no preference. Every rung that ships is `exact`, so its price is ONE number rather than a range; if one ever ships with `exact: false`, do not read the price off the rung at all - call `estimate_only` and quote that. `videos_estimated` and `frames_estimated` are a different question, and they say whether each figure is one the episode writer is HELD to: tilde every figure whose flag is true even on an `exact` rung, and tilde the total whenever either is. And `scene_count_estimated` says the same about the rung's `scene_count`. NEVER STATE A SCENE COUNT AS FACT. A rung's `scene_count` is what THAT RUNG DERIVES, not what the episode will contain: the writer sizes the episode itself and routinely lands a scene or two either side - on a rung whose `frames_estimated` is true it is not held to the count at all. So do not say 'at 20s that's 3 scenes'. If the user asks how many scenes they get, answer with the hedge attached - 'the writer decides; this length usually comes out around 3' - and never let a count you stated become a number the user thinks they bought. The count is not a sizing input, not a quote, and not a promise. AND DO NOT VOLUNTEER IT AT ALL: `scene_count` is internal bookkeeping that rides these responses so the machinery can be reasoned about, not a fact the product tells anyone - the webapp never shows a user a scene count and never asks for one, so neither do you. Answer it only if the user asks, with the hedge above, and never open a sizing question with it. OFFER THE IMAGE MODEL, ONCE. The pictures are what the user actually looks at, so do not pick the image model silently while asking them about the video model - name it in the SAME line as the thing you are already asking, with the default already chosen and its price: 'the opening picture of each scene is drawn by <default> (<price>) - or <alternative> for <price>; the video is <video model>.' ONE line, not an interview, and not a second question: if they express no preference, use the series' own default and move on. It IS the series' tuned look, so recommend it rather than presenting a menu. Never ask about a model the user cannot see the effect of, and never re-ask on a later episode in the same conversation. SAY IT IN PLAIN WORDS - name what the model DRAWS as the user would say it ('the opening picture of each scene', 'the cast's faces'), never in argument names: 'start frames' and `start_frame_model` are field names, not phrases to say out loud. SPEND ETIQUETTE (the money grammar): in the webapp the priced button is the user's own finger; in chat YOUR tool call is not - so state the price IN THE SAME MESSAGE as the ask, and the user's explicit go is the button press. Never charge on inference: quoting is not asking, and after a price you wait for the yes. THIS APPLIES TO EVERY TOOL CARRYING THIS NOTE, including this one. A GO IS SCOPED TO ONE PURCHASE, AND IT MUST BE UNAMBIGUOUS. The user's instruction has to NAME the thing you are about to buy, or refer to it so plainly that it cannot mean anything else. A BARE AFFIRMATION - 'go', 'yes', 'ok', 'do it', 'just do it', 'sure' - counts ONLY when ALL THREE of these hold: the message immediately before it was YOUR priced ask for THAT EXACT action, nothing else was raised in between, and NOTHING THE USER ASKED FOR EARLIER IS STILL OUTSTANDING. That last one is the trap the others miss: if the user's OWN previous turn asked for something else - a refusal, a different scene, an edit, a redraw, a question - their 'just do it' may be answering THAT, and it is AMBIGUOUS even when your priced ask happens to be the last thing said in the thread. An ambiguous affirmation is not a go: ask WHICH one they mean and state that price again. WHEN IN DOUBT ABOUT WHAT A 'GO' REFERS TO, ASK. A wrong guess spends the user's money on something they never asked for, and nothing on this surface can undo it or give it back - asking costs one sentence. An episode's STAGES - cast portraits, episode create, fire, render - are each their own priced ask. A STANDING GO IS NOT UNLIMITED: 'just make it' or 'go ahead with the whole episode' authorizes the stages you PRICED IN THAT SAME MESSAGE, in the order you named them, and nothing beyond them - so do not re-ask per stage while it holds, and do not stretch it over a stage whose price the user never saw. IT EXPIRES THE MOMENT THE USER RAISES ANYTHING ELSE - a change, a question, a refusal, a redraw, a new idea - and after that the next stage needs its own priced ask. ONE STAGE IS NEVER COVERED BY A STANDING GO AT ALL: the FIRE (`fire_story_video`) is irreversible and the biggest single charge in the episode, so it always takes a go that NAMES firing, whatever was said earlier - see that tool's own note. A REDRAW IS NOT A STAGE: `regenerate_story_frame` and `regenerate_cast_portrait` are extra spends the user asks for one at a time, so state that price every time, even under a standing go. A standing go never carries to a different episode, and never to `generate_video`, `generate_image` or `generate_audio` - each of those is its own ask. ACCOUNT FOR YOUR OWN CALLS: if the user says something happened that you did not intend - a charge they did not expect, a step they did not ask for - RE-READ YOUR OWN TOOL CALLS IN THIS CONVERSATION before you answer, and tell them plainly which tools you called and when. NEVER SPECULATE ABOUT A CAUSE YOU CANNOT OBSERVE: not a button on an aicut card, not the user's own click, not their client. The aicut cards CANNOT SPEND - the only tools they ever call are the reads (`get_video` / `get_image` / `get_audio`), and their buttons either save a file or send a VISIBLE user turn into the chat - none of them calls a spending tool - so saying a card might have generated or charged something is false, not a hedge. (If a spend followed one of those visible turns, it was still YOUR call, and the honest answer names it.) If your call history disagrees with what you told the user, say what you actually called and let them correct you; do not invent an explanation that makes the two agree. BREVITY: lead with the ONE decision you need from the user, and keep at most one short paragraph before the question. Never re-explain the staged flow (cast -> frames -> fire -> render) once it has been explained in this conversation - after that, name only the next step. When suggesting episode ideas, offer at most 3, one line each. IDEMPOTENCY: `idempotency_key` is optional and makes a retry safe. Set it on the FIRST call, not only on a retry - the job is addressed by the key, so a key added afterwards cannot find a job that was created without one. Reusing a key REPLAYS the job that key already created and returns it unchanged - even if you send a different prompt or different settings, and even after that job has finished. A key is therefore spent permanently. Do NOT reuse one to make another generation: two deliberate generations are two jobs and need two different keys (or none). ONE EXCEPTION, on `render_story_video`: replaying a key whose render FAILED answers 409 `render_failed` rather than replaying the failure, because a spent key stays spent - retry that one with a NEW key or with none. A KEY IS NOT SCOPED TO A TOOL: it addresses a job on the whole account, so reusing the key you gave `generate_video` on `generate_story_video` replays that first video instead of starting an episode. One key, one thing you made. (`render_story_video` is the one door that namespaces its own, which is why an episode's key can be reused on its render without colliding - but there is no reason to reuse it there either.) Never derive the key from the request body. You do NOT need to pass one to be safe against a duplicated delivery: aicut already derives a per-call key server-side, so a retry the transport makes on its own replays rather than charging twice. Pass your own only when YOU want to retry a call whose answer you never saw. OUTPUT: this returns JSON for you to read. When you report back to the user, give them the media URL plus a one-line summary. Do not paste the raw JSON, job ids, or internal field names into the conversation.
1 trials · measured 27 days ago
generate_story_video scores 100.0/100 on Vouch's measured behaviour index, from 1 real invocation trials against pro.aicut/aicut, measured 11 Sept 2026 under methodology v0.2.0. Every measured component scored 100.
Component breakdown
| Component | Weight | Value |
|---|---|---|
| Reliability | 35% | not applicable |
| Schema integrity | 25% | 100.0 |
| Failure behaviour | 15% | not applicable |
| Latency | 15% | not applicable |
| Concurrency | 10% | not applicable |
Tool details
- Transport
- remote
- Credential class
- gated
- Input schema
- not declared
- Output schema
- not declared
- Side-effect classification
- unclassified
Score history
| Day | Score | Tier | Methodology |
|---|---|---|---|
| 2026-09-11 | 100.0 | shallow | v0.2.0 |
Probe evidence
| Probe | Outcomes |
|---|---|
| schema_integrity | pass: 1 |
Raw request/response logs are not archived yet — the outcome counts above are drawn directly from every recorded trial.
Embed this score
Available for every tool, scored or not — not a verification perk. Always links back to this page.
[](https://vouch.tools/tools/64786c3c-4b43-418c-bde5-f96833999d63)