Nova 2.5 Sonic async tool calls: start a Sume job, return the job id

With asynchronous tool calling, a Nova 2.5 Sonic agent can start a Sume music or caption job, answer at once with the job id, and poll status later.

5 min readSume
All posts

Give a Nova 2.5 Sonic agent a tool that only starts a Sume job and returns the job id, then check the job later. Sume generation endpoints already work this way: they accept a valid request, return a durable job, and finish in the background. That matches the asynchronous tool calling AWS announced for Nova 2.5 Sonic, where the model can keep the conversation going while a tool call runs.

AWS announced Nova 2.5 Sonic on October 5, 2026 (read 2026-10-11) as a speech-to-speech model for real-time voice agents, available in US East (N. Virginia), US West (Oregon), Europe (Stockholm) and Asia Pacific (Tokyo). The announcement lists a 256K context window, seven languages, asynchronous tool calling, controllable turn-taking, voice and text in the same session, and pricing at the same level as Nova 2 Sonic. Sume does not run Nova Sonic; the pattern here is your agent calling the Sume API as a tool.

Why does a slow job suit an async tool?

A music or caption job takes longer than a spoken answer should wait. A blocking tool would hold the caller in silence. An asynchronous tool lets the agent say that work has started, keep talking, and report the result when it lands.

Sume's jobs docs describe the states a job moves through: queued, processing, then completed, failed or canceled. Queued is a normal accepted state for paid generation, and the docs say not to submit the original paid request again just because a local process timed out.

Sume job states a voice agent should handle (Sume jobs docs, read 2026-10-11)
StatusWhat the agent saysTerminal
queuedIt is waiting to startNo
processingIt is being madeNo
completedIt is ready; read the resultYes
failedIt did not work; offer to retryYes
canceledIt was stoppedYes

What does the tool handler look like?

The sketch below starts a Music Router job and returns immediately. Music Router jobs are POST /v1/music-router/generate with sume/music-auto, and the Sume catalog lists a fixed $0.125 per audio generation. The Idempotency-Key comes from the agent turn, so a repeated tool call does not create a second paid job. The code refuses an empty API key before it sends anything.

import os, requests

API = "https://api.sume.com"

def start_music(prompt, key, idem):
    if not key:
        raise RuntimeError("SUME_API_KEY is empty")
    r = requests.post(
        f"{API}/v1/music-router/generate",
        headers={"Authorization": f"Bearer {key}", "Idempotency-Key": idem},
        json={"model": "sume/music-auto", "prompt": prompt},
        timeout=30)
    r.raise_for_status()
    body = r.json()
    return body.get("request_id") or body.get("id")

def music_status(job_id, key):
    r = requests.get(f"{API}/v1/jobs/{job_id}/status",
                     headers={"Authorization": f"Bearer {key}"}, timeout=30)
    r.raise_for_status()
    return r.json().get("status")

# Tool handler for a voice agent: answer at once, check later.
def tool_make_jingle(args, key=os.environ.get("SUME_API_KEY", "")):
    job = start_music(args["prompt"] + " Instrumental, no vocals.",
                      key, "agent-turn-" + args["turn_id"])
    return {"job_id": job, "say": "Started. I will tell you when it is ready."}

What should the agent never do?

Never wait inside the tool call for a long job; the point of the async pattern is that the conversation continues. Never invent a result when a job is still queued, and never retry a paid create with a new idempotency key unless the user asks for a new take. A new key means a new job and a new charge, which is the right behavior for a second take and the wrong one for a timeout.

How does the agent learn the job finished?

Two options. Poll GET /v1/jobs/{id}/status with backoff from a second tool such as check_jingle, or submit with mode webhook and a public HTTPS webhook_url, which delivers one terminal event: job.completed, job.failed or job.canceled. Keep a poll as a fallback, as the webhooks docs recommend.

When the job is completed, read GET /v1/jobs/{id}/result and take the artifact with type audio from result.artifacts. Then let the agent play or link it. Do not read audio out of the status call; it reports state, and the result is where the artifact lives. Keep the job id in the session so a dropped connection can resume the same job instead of paying twice.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume