generate_cast_portraits

shallow

pro.aicut/aicut · Verify this server

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.

100.0/100

1 trials · measured 27 days ago

generate_cast_portraits 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

ComponentWeightValue
Reliability35%not applicable
Schema integrity25%100.0
Failure behaviour15%not applicable
Latency15%not applicable
Concurrency10%not applicable

Tool details

Transport
remote
Credential class
gated
Input schema
not declared
Output schema
not declared
Side-effect classification
unclassified

Score history

DayScoreTierMethodology
2026-09-11100.0shallowv0.2.0

Probe evidence

ProbeOutcomes
schema_integritypass: 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.

Vouch score: generate_cast_portraits
[![Vouch score](https://vouch.tools/api/tools/4b7ed107-26de-4fc0-b5c7-3d7d1709f34c/badge.svg)](https://vouch.tools/tools/4b7ed107-26de-4fc0-b5c7-3d7d1709f34c)
generate_cast_portraits — Vouch