Avatar preview failed on Sume MCP: stop_and_ask, do not generate video

When an avatar video preview fails or is canceled, Sume MCP returns recovery code stop_and_ask: do not call generate_video, report the reason, offer a rewrite.

4 min readSume
All posts

If an avatar video preview fails or is canceled on Sume's hosted MCP, the tool result carries agent.recovery.code: stop_and_ask. The agent must not call avatar-video-previews_generate_video, must report the provider reason in the user's language, and should offer a scene or script rewrite instead of retrying the identical payload.

The two-stage flow

Avatar video previews split the work. The create call produces stills. After the user approves them, avatar-video-previews_generate_video is called with an empty payload, because admission uses the stored preview, and then jobs_wait follows. The server's next-step list for avatar-video-previews_create says exactly this, including a STOP for still approval.

So a failed preview is the cheap place to stop. Calling generate-video anyway would start the expensive stage on stills that do not exist.

Two different rejections

The hint separates two policy rejections that look alike to a model: an image-policy reject at the preview stage, which comes from the still-image model, and a video-policy reject at the generate-video stage, which comes from the video model. They need different edits. A preview reject means rewrite the scene description or the reference. A generate-video reject means the approved stills passed but the motion or script did not.

Avatar preview failure handling on Sume MCP (read 2026-10-05 against the Sume codebase)
ObservedRecovery codeAgent action
Preview status failed or canceledstop_and_askStop. No generate_video. Report reason.
Stills ready, user approvesnoneCall generate_video with payload {}
Preview still processingnonePoll avatar-video-previews_get later

Branching in your harness

Route on the recovery code, not on free text.

def next_action(result: dict) -> str:
    agent = result.get('agent') or {}
    recovery = agent.get('recovery') or {}
    if recovery.get('code') == 'stop_and_ask':
        return 'ask_user: ' + recovery.get('hint', '')
    step = agent.get('next_step') or {}
    return 'call: ' + step.get('tool', 'none')

print(next_action({'agent': {'recovery': {'code': 'stop_and_ask', 'hint': 'Preview failed'}}}))

Limits

This recovery applies to failed or canceled preview reads. A running preview is not a failure, so keep polling. Where a job fails for another reason, read the failure through jobs_get, as in the failed job post, because jobs_result returns 409 on a failed job.

Report the reason without quoting prompts or signed URLs. Sume's results tell agents not to echo them in reports.

Why not just retry

A retry of the identical preview payload runs into the same decision. The server hint is explicit that the identical payload must not be auto-retried. A rewrite changes the inputs, so treat it as a new request with its own idempotency_key rather than reusing the old one. Keep the failed preview id in your notes so the user can see what was changed between attempts.

If you run unattended, stop_and_ask is a good place to hand off to a person. A model can draft the rewrite, but a human or a policy check should approve it, since the generate-video stage is the expensive one.

Checklist before you ship

  • Branch on agent.recovery.code, never on the wording of the hint.
  • Block the generate_video tool in your harness while a preview is failed or canceled.
  • Show the user the provider reason in their language, without prompts or signed URLs.
  • Offer one rewrite, and run it as a new preview with its own idempotency_key.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume