generate_audio
Starts an audio generation on the signed-in aicut account, puts the aicut card in front of the user, and returns the new job's id immediately. It does NOT wait for the audio. WHAT: one tool for all three kinds of audio - spoken voice-over, music, and sound effects - chosen by the `model` you pass, not by a different tool. WHEN: the user asks for speech, a voice-over, music, a soundtrack, or a sound effect. Call `list_models` with `type: "audio"` first if you have not this session: the models take DIFFERENT arguments (a speech model takes `text` and `voice`, a music model takes `prompt` and `length_ms`, a sound-effect model takes `text` and `duration`), and sending a field the chosen model does not publish is rejected rather than ignored. For a speech model, `list_voices` is where the `voice` id comes from - `list_models` publishes no voice list. HOW IT SOUNDS is separately steerable, and none of it costs anything extra: `stability`, `similarity_boost`, `style` and `speed` on a speech model, `force_instrumental` on music, `loop` on a sound effect. WHICH ONES A MODEL TAKES VARIES BETWEEN MODELS OF THE SAME KIND - `elevenlabs-tts-v3` takes `stability` alone while `elevenlabs-tts-v2` takes all four - so read the chosen model's `parameters` in `list_models` rather than assuming; a knob it does not publish is rejected, not quietly dropped. Every one is optional, and leaving it out gives the provider's own default, which is the right call unless the user asked for something the default does not give (a flatter read, a faster delivery, a track with no vocals, an effect that loops). They change the RESULT, never the price, so they need no re-quote. AFTER: the audio is not ready when this returns. Call `wait_for_generation` with the returned id and `media: "audio"`, then follow the two rules below. THE CARD: this call has ALREADY put the aicut card in front of the user. It shows the prompt and the model straight away - plus the aspect ratio and a correctly-shaped empty frame for a video or an image, while AUDIO has neither and simply shows the prompt until the player appears - and it fills in the finished media on its own, so you do not have to do anything to make that happen. Do NOT call `show_generation` for this job: the card is already in the conversation and a second call would put a duplicate one beside it. `show_generation` is only for bringing back an EARLIER generation the user asks to see again. HOW TO WAIT: call `wait_for_generation` with this job's id and its `media`. It waits SERVER-SIDE for up to 15 seconds and opens no card. If it answers `terminal: false`, wait `poll_after_seconds` and call `wait_for_generation` again with the same arguments - keep doing that until it answers `terminal: true`, then tell the user in ONE short line what came out. Do not poll `get_video` / `get_image` / `get_audio` in a loop instead, and do not spawn timers or background shells to wait. Say nothing between waits: do NOT tell the user the generation is running and that you will fetch the result when they ask - just wait, then tell them it is done. IF YOU CANNOT RENDER AN AICUT CARD - a terminal, a plain SDK client, anything that did not negotiate the MCP Apps UI extension - then no card appeared here, so give the user the `url` from the wait result directly. aicut cannot see which clients render cards and sends the same answer to all of them. TIMING: audio usually finishes in under a minute - often within 10 seconds for a short sound effect - and can take up to about 4 minutes for a long script. Do not assume it failed before then, and do not spawn timers or background shells to wait: call `wait_for_generation` (it waits server-side for up to 15 seconds per call), wait its `poll_after_seconds` and call it again, and stop when it answers `terminal: true`. `get_audio` is a single immediate read for one job's raw fields - it is not the waiting loop and must not be polled in one. COST: this spends the user's tokens, and audio is priced on a RATE (per character for speech, per minute for music, per second for sound effects) rather than from a fixed table - so `list_models` gives you `pricing_rates`, not a row to read a price out of. Do not multiply it yourself: pass `estimate_only: true` with the exact settings you intend to send and use the number it returns. Do that whenever the user has not already agreed to the cost, and always before a long script or a long track. 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. 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.
generate_cast_portraits
BUYS the portraits for a cast draft: one image generation per member that still needs a face, charged at the chosen image model's rate, then saves every member to the user's character library. This is the cast's paid step - the webapp's 'Generate cast · N T' button. WHEN: the user has READ the draft from `generate_cast`, accepted it, and given an explicit go to the price. State the price first, and take BOTH numbers from the draft's own `portrait_models` rather than from anywhere else - each entry carries `per_portrait_tokens` and the roster's `total_tokens` on that model, priced against the live catalog for the exact settings a cast portrait uses. Say it as 'portraits: 3 on <the default model> = <its total_tokens> T, or <another model> at <its per_portrait_tokens> each. Go?' and wait for the yes. Never quote a rate from memory: the same model prices differently for a cast portrait than for an ordinary image. 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. THE CARD: this call has ALREADY put the aicut cast card in front of the user - every member with name, role and portrait, each portrait filling in on its own as it generates, and a Download on each face. Do NOT poll the portraits while the card is there: no `get_image` or `wait_for_generation` loops. ONE read is not a loop - if the user asks how a portrait is doing, or the story create refuses with a 409 because a portrait is still generating, read that member's `portrait_image_id` once with `get_image` and say what it says. Review stays in the CHAT: ask the user whether the cast is good. If ONE face is wrong, `regenerate_cast_portrait` redraws that member for one portrait's price; if one CHARACTER is wrong - they want it smaller, older, a different thing - `describe_cast_member` rewrites that member for one portrait's price; only a roster they reject as a WHOLE means a fresh `generate_cast` draft (free) and a second, fully charged `generate_cast_portraits`. Either single-member call puts that member back on a cast card of its own, so do NOT reach for `show_generation` to show a portrait. THE CARD NAMES THE PAID MOVES but has no button for any of them, so the user will ask you for them in the chat. IF YOU CANNOT RENDER AN AICUT CARD - a terminal, a plain SDK client, anything that did not negotiate the MCP Apps UI extension - no card appeared, so poll each member whose `portrait_status` is `generating` with `wait_for_generation` (media `image`, its `portrait_image_id`) and give the user the portrait urls yourself. aicut cannot see which clients render cards and sends the same answer to all of them. AFTER: portraits generate asynchronously - but only for the members that needed one. A member with `portrait_status: "ready"` and a null `portrait_image_id` was NOT generated and NOT charged: it either arrived photographed (a preset-bound member, which is why the draft marked it `needs_portrait: false`) or it already had a face from an earlier attempt. Do not report those as missing. A member whose `id` is null could not be saved to the library and cannot be used - only non-null ids work as `cast_member_ids` on `generate_story_video`. ONCE IT SUCCEEDS THE DRAFT IS SPENT: the roster is in the user's library, and calling this tool again with the same `draft_id` buys nothing - it answers 404 `cast_draft_not_found` normally, or - in the rare case where the spent draft was not cleared - a 201 carrying `charged_tokens: 0`, meaning nothing was bought and the library rows were simply re-written. Either way no face is paid for twice; report the second call as 'already done', never as a second purchase. IF THE USER DISLIKES ONE FACE: `regenerate_cast_portrait` redraws THAT member for one portrait's price. Calling `generate_cast` again authors a different cast entirely, and its portraits are a fresh charge. COST: the draft's own `portrait_models` figures are what you quote - they were priced when the roster was written. `estimate_only: true` re-prices the chosen model against the CURRENT catalog without spending, which is the number to use if the draft has been sitting for a while. The 201 answers `charged_tokens`: what actually moved. IF IT REFUSES PART WAY THROUGH (402, or a cap): the portraits that had already generated were CHARGED, and the refusal says so - `partial_cast: true` with `portraits_minted` and `charged_tokens`. Tell the user that number; do NOT report the refusal as 'nothing was charged'. Retrying the SAME `draft_id` afterwards generates only the members still missing a portrait and charges only those, so the retry is safe and cheaper than the first call. REFUSALS you act on: 400 `invalid_request` naming `draft_id` = what you passed is not a cast draft id at all (a job id, a member id, an id you composed) - draft ids come from `generate_cast` and nowhere else, so re-read that response or write a fresh draft; it does NOT mean you left the argument out. 404 `cast_draft_not_found` = the draft is real but is unknown here, already spent, or older than two hours - write a fresh one with `generate_cast` (free), or read the cast you already bought from `list_characters`. NEITHER OF THOSE IS FIXED SOMEWHERE ELSE: there is no other route to a draft, and no HTTP endpoint to go looking for. 409 `cast_in_progress` = portraits for this account are already being generated, this call charged nothing, wait for the first one. 409 `cast_just_created` = a set just finished; check `list_characters` before paying again. 402 = not enough tokens. 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. 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.
generate_fake_text_video
CREATES a fake-text video: a phone chat conversation that types itself out over a gameplay or green-screen background, with every line read aloud in the voice you pick for that side. It is one of aicut's most-used short-form formats. YOU WRITE THE SCRIPT. There is no script tool and no writer behind this endpoint - the `messages` array you send IS the conversation that gets made, in that order. Write it yourself from what the user asked for, show it to them as plain text before spending anything, and change it until they like it. Iterating on the script costs nothing. A WORKED EXAMPLE of `messages` - a four-line chat where the phone's owner is on the right: `[{"text":"i saw what you posted","from":"left"},{"text":"and?","from":"right"},{"text":"you told me you were working","from":"left"},{"text":"i was. at his place.","from":"right"}]`. That is the whole format: an ordered list of bubbles, each with the line and the side. Write the conversation the way a real one runs - short lines, one thought each, a hook in the first two bubbles, and a last line worth screenshotting. AFTER: the response carries the job id, the price split (`generation_tokens` for the spoken audio, `render_tokens` for the video file) and `renders_automatically: true`. If it ALSO carries `start_confirmed: false`, the job exists but aicut never saw its start confirmed - do not create it again, watch that job id and tell the user it may need a retry if it has not moved in ten minutes. THAT LAST ONE MATTERS: unlike an AI Video Story there is no fire step and no render step - this one call makes the finished video. Wait for it with `wait_for_generation`; when it is terminal, `get_video` carries the file url. REFUSALS (the common ones, not all of them - always read the `code` you actually get): 400 = the script or a setting is not accepted, and the message says which (an empty line, a missing `from`, an unknown template or voice, or the whole chat reaching 6000 characters of dialogue, which is the ceiling - shorten it, aicut will not silently cut it for you). 402 = not enough tokens for the whole video; the body carries `required` and `balance`. 503 `fake_text_unavailable` = the video was not started and nothing was charged; retry the same call once. COST: quoted per character of dialogue, in two parts that are both charged - call with `estimate_only: true` first and state `estimated_tokens` (the total) to the user. A longer script costs more, AND SO DOES THE VOICE PROVIDER: ElevenLabs is about four times openai/polly per character. Change a provider and re-run `estimate_only`; never carry an older quote across that change. WHAT THIS TOOL DOES NOT OFFER, so you do not go looking: background music, specific gameplay clips, images or sound effects inside the chat, contact photos, promotions, a second chat in one video, and the `cantina` skin. Those live in the aicut web app - say so rather than approximating them in the script. (Cloned and custom voices ARE offered - see `voice_left` / `voice_right`.) THE WATERMARK is decided by the account's plan, not by this call: free accounts get the aicut mark on the video. Say so if the user asks; there is no argument that changes it. DELIVERY: hand the user ONE thing - the finished video. Do not re-list the script back at them after it is made. 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. 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.
generate_image
Generates an AI image on the signed-in aicut account and puts the aicut card in front of the user. It waits for the image server-side for as long as one request safely can - about 20 seconds - so it usually returns the finished image with its `url` directly. WHEN: the user asks for an image. Call `list_models` first if you have not this session - the `model` id and the allowed values for every other argument come from there, and a combination it does not publish is rejected. AFTER: check `status`. If it is `succeeded` the image is finished - go straight to the SHOW rule below. If it is `queued` or `processing`, the image was not ready in time and is still being made: call `wait_for_generation` with the returned id and `media: "image"`, then follow both rules below. THE CARD: this call has ALREADY put the aicut card in front of the user. It shows the prompt and the model straight away - plus the aspect ratio and a correctly-shaped empty frame for a video or an image, while AUDIO has neither and simply shows the prompt until the player appears - and it fills in the finished media on its own, so you do not have to do anything to make that happen. Do NOT call `show_generation` for this job: the card is already in the conversation and a second call would put a duplicate one beside it. `show_generation` is only for bringing back an EARLIER generation the user asks to see again. HOW TO WAIT: call `wait_for_generation` with this job's id and its `media`. It waits SERVER-SIDE for up to 15 seconds and opens no card. If it answers `terminal: false`, wait `poll_after_seconds` and call `wait_for_generation` again with the same arguments - keep doing that until it answers `terminal: true`, then tell the user in ONE short line what came out. Do not poll `get_video` / `get_image` / `get_audio` in a loop instead, and do not spawn timers or background shells to wait. Say nothing between waits: do NOT tell the user the generation is running and that you will fetch the result when they ask - just wait, then tell them it is done. IF YOU CANNOT RENDER AN AICUT CARD - a terminal, a plain SDK client, anything that did not negotiate the MCP Apps UI extension - then no card appeared here, so give the user the `url` from the wait result directly. aicut cannot see which clients render cards and sends the same answer to all of them. TIMING: an image usually finishes in under 90 seconds, and can take up to about 4 minutes. `generate_image` waits about 20 seconds for it server-side; if it returns while the image is still `processing`, call `wait_for_generation` rather than waiting in a timer or a background shell. COST: this spends the user's tokens. Pass `estimate_only: true` first to get the exact price without creating anything - and do that whenever the user has not already agreed to the cost, or when the balance may be tight. 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. 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.
generate_image_story
CREATES an AI image story: a narrated script turned into a sequence of AI-generated images, read aloud with captions over it. aicut's most-used format for facts, history, horror, storytime and explainer shorts. YOU WRITE THE SCRIPT, AND ONLY THE SCRIPT. The `text` you send is the narration that gets spoken, verbatim, in that order - there is no writer behind this endpoint. Draft it yourself from what the user asked for, show it to them as plain text before spending anything, and change it until they like it. Iterating on the script costs nothing. What you must NOT write is the pictures: aicut segments your script and writes every image prompt itself. A WORKED EXAMPLE of `text`: `"In 1943 a Soviet pilot was shot down behind enemy lines. He walked eighteen days through the snow on two broken legs. When he reached his own trenches, they did not believe he was alive. Then he asked for his plane back."` That is the whole format: a narration script in plain prose, the way it should be READ ALOUD. No scene numbers, no image directions, no stage notes, no speaker labels - aicut cuts it into scenes and writes the picture for each one. Write it the way a good voiceover sounds: short sentences, a hook in the first line, one idea at a time. PRICE IS DRIVEN BY THE IMAGE COUNT, not by the words. `estimate_only: true` returns `scene_count` and `voice_provider` next to the money - say the count and the price. The three levers, in the order to reach for them: `seconds_per_image` (3 is the default; 5 buys fewer images for the same script and is the cheap direction, 2 is the busy/expensive one), `image_model` (`zit-realism` is the cheap default; `gpt-image-2.5` costs noticeably more per image - offer it only when the user wants the best-looking result and quote it before you pick it), and `voice_provider` (ElevenLabs reads best and costs more per character of narration than openai/polly). Re-quote after changing any of the three; never carry an older number across a change. STYLES ARE OPTIONAL AND THEY ARE NOT FREE. `list_image_story_styles` returns aicut's authored looks; passing one as `style_id` forces the expensive edit-capable image model, so re-quote with `estimate_only` after adding one. Without a style you get aicut's default photorealistic look, which is what most videos use. AFTER: the response carries the job id, `scene_count`, the price split (`generation_tokens` for the images and narration, `render_tokens` for the video file) and `renders_automatically: true`. If it ALSO carries `start_confirmed: false`, the job exists but aicut never saw its start confirmed - do not create it again, watch that job id and tell the user it may need a retry if it has not moved in fifteen minutes. THERE IS NO FIRE STEP AND NO RENDER STEP: this one call makes the finished video. Wait for it with `wait_for_generation`; when it is terminal, `get_video` carries the file url. It takes longer than a single image - every scene is generated. LANGUAGE: write `text` in the language you name. aicut detects the script's language and TRANSLATES it when it differs from `language`, and a translated script has a different length - so the quote is exact for the script you sent and only for that. Do not send English and ask for German expecting the quoted price; write the German. REFUSALS (the common ones, not all of them - always read the `code` you actually get): 400 = the script or a setting is not accepted, and the message says which (a script over the language's character limit, which aicut will NOT silently cut for you; a script that needs more images than one video can carry, where the fix is a longer `seconds_per_image`; an unknown style id, model, voice or language). 402 = not enough tokens for the whole video; the body carries `required` and `balance`. 503 `image_story_unavailable` = the video was not started and nothing was charged; retry the same call once. THE WATERMARK is decided by the account's plan, not by this call: free accounts get the aicut mark on the video. Say so if the user asks; there is no argument that changes it. DELIVERY: hand the user ONE thing - the finished video. Do not re-list the script back at them after it is made. 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. 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.
generate_lipsync
Takes a picture of a person and an audio file, and generates a video of THAT person speaking or singing the audio, lip-synced. Returns the new job's id immediately. The result is exactly as long as the audio. WHEN: the user wants a talking avatar, a presenter, a voiceover put on a face, or a portrait to say something. The picture supplies the person; the audio supplies both the performance AND the length. The audio must be a `generate_audio` result on this account - pass the id that tool returned, or its url. An external audio url cannot be used here yet, so if the user has audio elsewhere, the way in is to make it with `generate_audio` first. THE CARD: this call has ALREADY put the aicut card in front of the user. It shows the prompt and the model straight away - plus the aspect ratio and a correctly-shaped empty frame for a video or an image, while AUDIO has neither and simply shows the prompt until the player appears - and it fills in the finished media on its own, so you do not have to do anything to make that happen. Do NOT call `show_generation` for this job: the card is already in the conversation and a second call would put a duplicate one beside it. `show_generation` is only for bringing back an EARLIER generation the user asks to see again. HOW TO WAIT: call `wait_for_generation` with this job's id and its `media`. It waits SERVER-SIDE for up to 15 seconds and opens no card. If it answers `terminal: false`, wait `poll_after_seconds` and call `wait_for_generation` again with the same arguments - keep doing that until it answers `terminal: true`, then tell the user in ONE short line what came out. Do not poll `get_video` / `get_image` / `get_audio` in a loop instead, and do not spawn timers or background shells to wait. Say nothing between waits: do NOT tell the user the generation is running and that you will fetch the result when they ask - just wait, then tell them it is done. IF YOU CANNOT RENDER AN AICUT CARD - a terminal, a plain SDK client, anything that did not negotiate the MCP Apps UI extension - then no card appeared here, so give the user the `url` from the wait result directly. aicut cannot see which clients render cards and sends the same answer to all of them. TIMING: a video usually finishes in 1-3 minutes, and can take up to about 6. Do not assume it failed before then, and do not spawn timers or background shells to wait: call `wait_for_generation` (it waits server-side for up to 15 seconds per call), wait its `poll_after_seconds` and call it again, and stop when it answers `terminal: true`. `get_video` is a single immediate read for one job's raw fields - it is not the waiting loop and must not be polled in one. COST: this spends the user's tokens, and the price is the AUDIO's length times a per-second rate that depends on the resolution - so a two-minute voiceover costs many times a ten-second one, and 1080p costs twice 720p. The audio's length is MEASURED BY THE SERVER from the file itself, never taken from anything you say - that measurement, rounded UP to the next whole second, is the price and the charge. Audio the server cannot measure is REFUSED with nothing charged. There is deliberately no length argument on this tool. Pass `estimate_only: true` first to get the exact price. An EXTERNAL url is downloaded and stored on the account before it can be measured, which uses one of the account's daily media-ingest slots. Quoting and then creating from the SAME url costs that once, not twice - aicut reuses what it already imported - and a url already on the account costs nothing at all. 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. 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.
generate_story_video
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.
generate_video
Starts an AI video generation on the signed-in aicut account, puts the aicut card in front of the user, and returns the new job's id immediately. It does NOT wait for the video. WHEN: the user asks for a video to be made. Call `list_models` first if you have not this session - the `model` id and the allowed values for every other argument come from there, and a combination it does not publish is rejected. AFTER: the video is not ready when this returns, and waiting for it is not something you do by hand. Call `wait_for_generation` with the returned id and `media: "video"`, then follow the two rules below. THE CARD: this call has ALREADY put the aicut card in front of the user. It shows the prompt and the model straight away - plus the aspect ratio and a correctly-shaped empty frame for a video or an image, while AUDIO has neither and simply shows the prompt until the player appears - and it fills in the finished media on its own, so you do not have to do anything to make that happen. Do NOT call `show_generation` for this job: the card is already in the conversation and a second call would put a duplicate one beside it. `show_generation` is only for bringing back an EARLIER generation the user asks to see again. HOW TO WAIT: call `wait_for_generation` with this job's id and its `media`. It waits SERVER-SIDE for up to 15 seconds and opens no card. If it answers `terminal: false`, wait `poll_after_seconds` and call `wait_for_generation` again with the same arguments - keep doing that until it answers `terminal: true`, then tell the user in ONE short line what came out. Do not poll `get_video` / `get_image` / `get_audio` in a loop instead, and do not spawn timers or background shells to wait. Say nothing between waits: do NOT tell the user the generation is running and that you will fetch the result when they ask - just wait, then tell them it is done. IF YOU CANNOT RENDER AN AICUT CARD - a terminal, a plain SDK client, anything that did not negotiate the MCP Apps UI extension - then no card appeared here, so give the user the `url` from the wait result directly. aicut cannot see which clients render cards and sends the same answer to all of them. TIMING: a video usually finishes in 1-3 minutes, and can take up to about 6. Do not assume it failed before then, and do not spawn timers or background shells to wait: call `wait_for_generation` (it waits server-side for up to 15 seconds per call), wait its `poll_after_seconds` and call it again, and stop when it answers `terminal: true`. `get_video` is a single immediate read for one job's raw fields - it is not the waiting loop and must not be polled in one. COST: this spends the user's tokens. Pass `estimate_only: true` first to get the exact price without creating anything - and do that whenever the user has not already agreed to the cost, or when the balance may be tight. 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. 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.