Retry only the missing ad variants with previous_run_id on a Format

When a variants run returns some clips as null, continue it with previous_run_id and name the missing slots, so you do not pay for the finished variants again.

4 min readSume
All posts

To redo only the ad variants that came back empty, send a new run to the same Format with previous_run_id set to the earlier run and an instruction that names the missing slots. Sume replays what the agent produced, so the finished variants stay as they are. Bind the same output_schema again, because it is not inherited.

Start from the partial receipt

This follows the variants schema where each video_url is nullable. A run that makes three of five clips still satisfies the schema, so you get the three and a clear list of which two are null.

What can be continued

A run can be continued only if its receipt shows a thread_id and either completed status or a non-empty artifacts[]. A failed run that left work is fine, and a run that left nothing is not. A continuation is a new run with a new id, its own spend cap and its own single webhook, and the original never changes. The two share a thread_id, which you cannot pass yourself.

Continuation refusals (Sume docs, read 2026-10-05)
ResponseMeaningDo
404 previous_run_not_foundUnknown id or another ownerCheck the run id and key
400 previous_run_format_mismatchRun started on another FormatCall the original Format
409 previous_run_not_terminalStill runningPoll, then retry
400 previous_run_not_resumableNo thread or nothing madeStart a new run

Find the gaps and continue

The script reads the earlier receipt, finds variants whose video_url is null, and starts the continuation with an Idempotency-Key that ends in a retry counter. Bump the counter only when you really want another attempt. A replayed key with the same body returns the same run with no second charge.

import json, os, urllib.request

API = "https://api.sume.com"
SCHEMA = json.load(open("variants-schema.json"))

def call(method, path, body=None, key=None):
    h = {"Authorization": "Bearer " + os.environ["SUME_API_KEY"],
         "Content-Type": "application/json"}
    if key:
        h["Idempotency-Key"] = key
    data = json.dumps(body).encode() if body else None
    with urllib.request.urlopen(urllib.request.Request(API + path, data, h, method=method)) as r:
        return json.load(r)["data"]

def main():
    run_id = os.environ["RUN_ID"]
    prev = call("GET", "/v1/format-runs/" + run_id)
    out = prev["output"] or {"variants": []}
    gaps = [i + 1 for i, v in enumerate(out["variants"]) if v["video_url"] is None]
    if not gaps:
        return print("nothing missing")
    body = {"previous_run_id": run_id, "generation_spend_cap_usd": 10,
      "instruction": "Redo only variants " + str(gaps) + ". Keep the others unchanged.",
      "output_schema": {"name": "acme/ad-variants/v1", "strict": True, "schema": SCHEMA}}
    new = call("POST", "/v1/formats/sume/sume-product-commercial/runs", body, run_id + "-retry-1")
    print(new["id"], new["status"])

main()

Two things to remember

Save the schema from the first run to variants-schema.json so both calls send the same contract. If output was null on the first run, read artifacts[] instead and list the gaps by hand, since there is no typed list to scan. The continued run's artifacts[] lists all media of the whole conversation, but usage stays per run, so add the two runs when you book spend.

Sources

Related posts

More in Formats

All Formats posts

Written by Sume