Agent Completion result: read output.videos, images, audio and files
A completed Agent Completion puts its last text in output.text and generated media in output.images, videos, audio and files, as durable media.sume.com URLs.

Read the result from output on the completed run. By default it has the sume/action-run-output/v1 shape: the agent's last text is in output.text, and generated media is in output.images, output.videos, output.audio and output.files. The run also fills artifacts and records spend in usage, and media URLs are durable media.sume.com HTTPS URLs (Agent Completions).
When the result is ready
Creating a completion returns 202 and a receipt, not the result. The statuses are queued, processing, completed, failed and canceled. Poll the status_url until next_action is no longer poll_status, or register communication.webhook_url and take one signed POST when the run completes or fails.
output is null until the run is terminal. A completed run fills it. A run can also complete with real artifacts but fail to fit your output_schema, which the webhook docs call degraded, so check output_error before you trust output.
| Field | Holds | Note |
|---|---|---|
| output.text | The agent's last text | Default output shape |
| output.images / videos / audio / files | Generated media | Durable media.sume.com URLs |
| artifacts | Media harvested from the run | Empty until terminal |
| usage | Spend record | Null when spend could not be read |
| status_url | Poll target | Use it, do not build URLs |
Pull the URLs out
The function below walks a receipt-shaped dictionary and returns every media URL. The sample receipt is illustrative and uses a placeholder URL. I assume each media entry is an object with a url, or a bare string, so adjust after you inspect a real receipt. It runs offline.
MEDIA = ("images", "videos", "audio", "files")
def media_urls(receipt: dict) -> list:
out = receipt.get("output") or {}
urls = []
for kind in MEDIA:
for item in out.get(kind) or []:
url = item.get("url") if isinstance(item, dict) else item
if url:
urls.append(url)
return urls
if __name__ == "__main__":
sample = {"status": "completed", "output": {"text": "Done",
"videos": [{"url": "https://media.sume.com/x/clip.mp4"}]}}
print(media_urls(sample))Mind the access model
Media URLs do not expire, and the Format run docs say anyone who has a URL can open it. If your product needs per-customer access, copy or proxy the media instead of passing the URL along.
Also log the receipt's request_id and the run id, which together are what support needs, and keep generated URLs out of chat transcripts.
Binding output to your own schema
If your agent needs a fixed shape, send output_schema on the create call, with an optional primary_output_key naming the headline result. Sume parses the run's output against that schema after the run completes. The contract is the same as for Action runs, so a Format or schedule integration you already have can share the parser.
A schema that asks for a field the run never produces leads to a degraded outcome, which is why you should read output_error and the artifacts together rather than assuming that output is the whole story.
Checklist
Before you ship a reader for completion results, check these.
- Treat
output: nullon a non-terminal run as normal. - Read
output_errorwhenoutputis empty on a completed run. - Do not re-submit because your poll timed out; the run keeps going.
- Cancel with
POST /v1/agent-runs/{id}/cancelif you no longer need it.
Sources
Related posts
More in Developers
- Agent quoted $13.31 for a 13-cent Sume job: the micros divisor
Divide billable_amount_usd_micros by 1,000,000 for dollars. Dividing by 10,000 gives cents and overstates spend 100x. Sume MCP flags this as usd_unit_mismatch.
- catalog_list vs tools_list: finding HTTP-only Sume features
tools_list shows what this MCP session can call. catalog_list shows API capabilities, some with no MCP tool. Read both before telling a user it can't be done.
- Agent run webhook: created_at orders deliveries, request_id dedupes
An agent.run.terminal delivery has two ids that look alike. request_id dedupes retries; created_at orders deliveries. Includes a Python receiver.
- Run webhook payload is null: payload_too_large means fetch result_url
Sume cannot send a receipt over 1 MiB inline. The webhook arrives with payload null and error.code payload_too_large. The run did not fail. Fetch result_url.
Written by Sume