jobs_wait outcomes: wait_slice_expired, operator_stopped, omitted
What each jobs_wait answer means on Sume's hosted MCP and what your agent should do next: call again, stop waiting on stopped ids, or read omitted results.

A jobs_wait answer on the Sume hosted MCP tells you one of three things. outcome: "wait_slice_expired" means the slice ended and the jobs are still running, so call it again with the same job_ids. outcome: "operator_stopped" means Sume operations stopped at least one id; those jobs are terminal with no output, their holds are refunded, and operator_stopped.pending_job_ids lists the ids still running. results_omitted.job_ids names completed jobs whose results did not fit in the answer; read them with one batch jobs_result. All three are described in Jobs and results, read 2026-10-06.
Why a slice ends before the job does
On remote MCP the default timeout_seconds is 50 and the cap is 55. The REST API accepts larger values and clamps them. A wait that returns at the slice boundary has not failed; the transcription is still running and still billing normally. Starting a new paid job instead is the mistake the docs warn about.
| Answer | Meaning | Next call |
|---|---|---|
wait_slice_expired | Time slice ended, jobs still running | jobs_wait with the same ids |
operator_stopped | At least one id stopped by operations; holds refunded | Stop waiting on the stopped ids; wait on pending_job_ids |
results_omitted.job_ids | Results too large for one answer | One batch jobs_result for those ids |
| Unknown or foreign id | The whole call fails | Fix the id list |
A handler for the answer
If your agent wraps the tool in code, branch on the answer instead of letting a model improvise. The sample below ran against three hand-written answers.
def next_action(answer):
outcome = answer.get("outcome")
omitted = (answer.get("results_omitted") or {}).get("job_ids", [])
if outcome == "wait_slice_expired":
return "wait again with the same job_ids"
if outcome == "operator_stopped":
stopped = answer.get("operator_stopped") or {}
return f"stopped ids are final; keep waiting on {stopped.get('pending_job_ids', [])}"
if omitted:
return f"read {omitted} with one batch jobs_result"
return "done"
print(next_action({"outcome": "wait_slice_expired"}))
print(next_action({"outcome": "operator_stopped", "operator_stopped": {"pending_job_ids": ["j2"]}}))
print(next_action({"results_omitted": {"job_ids": ["j3"]}}))Do not ask again about a stopped id
The docs state that waiting again on stopped ids cannot change the answer. Remove them from the list, record them as stopped, and carry on with the rest. Check the ledger with a usage lookup if you need to confirm that nothing was debited.
Sources
Related posts
More in Integrations
- Render a Short over MCP: timeline_create, jobs_wait, timeline_get
Three hosted MCP tool calls turn a Timeline document into a vertical Short: create with an idempotency_key, wait on the job, then fetch the result.
- GitHub Actions job that renders a 9:16 clip on Sume as an artifact
A workflow file that replaces a Sora render step: submit to Sume, poll with a deadline, and upload the mp4 as a build artifact. The key stays in a secret.
- stt_create dry_run and max_spend_usd: cap an MCP transcription run
On Sume's hosted MCP, dry_run previews admission and cost without submitting, and max_spend_usd caps a paid stt_create. Add an idempotency_key to every write.
- Viber bot video message: 26 MB, 180 s, .mp4 URL, a Sume clip
Viber's bot API wants an MP4 URL ending in .mp4, 26 MB max, 180 s max, and a JPEG thumbnail. A 60 second Sume avatar clip fits. The checks to run first.
Written by Sume