실행과 결과
이 문서는 영문 원고를 AI로 번역한 내용이라 표현이 어색할 수 있습니다.
Format run은 비동기입니다. POST .../runs는 즉시 receipt를 건네며, 이후 무슨 일이
있었는지는 그 receipt로 알 수 있습니다.
한 run은 여전히 한 단위의 작업입니다. bulk 요청은 새 실행 엔진이 아니라 그 run들의
서버 측 큐입니다 — 대량 실행을 보세요. 큐 진행은
GET /v1/format-run-queues/{queue_id}(큐 receipt의 status_url)에서 counts와
item 상태를 폴링합니다. 각 자식은 이 페이지의 Format-run 엔드포인트를 그대로 씁니다.
폴링은 항상 동작합니다. Run 웹훅은 루프 없이 같은
receipt를 api.dev.sume.com과 api.sume.com 모두에서 밀어 줍니다.
정확한 요청·응답 스키마는 라이브 OpenAPI
(https://api.sume.com/reference/json)에서 가져옵니다. 여기 표는 읽기 쉬운 요약이며,
두 번째 스키마가 아닙니다.
수명주기
| Status | Meaning |
|---|---|
queued | 수락되었고, 아직 시작되지 않았습니다. |
processing | run이 작업 중입니다. |
completed | 끝났습니다. output과 artifacts가 채워집니다. |
failed | 오류와 함께 끝났습니다. |
canceled | 취소 요청으로 멈췄습니다. |
skipped | 이미 진행 중인 run이 있어 실행되지 않았습니다. |
canceled는 l이 하나인 철자입니다. 이것은 API 자체의 상태 이름이며 내부 job
상태가 아닙니다 — job 쪽 문자열이 그대로 온다고 가정하지 마세요.
Bulk 큐
POST /v1/formats/{format_id}/bulk-runs(및 vanity 쌍)는 큐 객체
(object: "format.run_queue", id frq_…)를 반환합니다. 그 목록의 진행은 Format-run
폴링이 아니라 GET /v1/format-run-queues/{queue_id}입니다. 큐 status가
completed이면 모든 item이 종료입니다. counts.failed / counts.canceled를
보세요. 자식 receipt는 GET /v1/format-runs/{run_id}에 있습니다. 전체 계약:
대량 실행.
읽기 엔드포인트 세 개
receipt는 자체 URL을 담습니다. 경로를 직접 만들지 말고 그 URL을 따르세요.
| Field | Endpoint | Returns |
|---|---|---|
status_url | GET /v1/format-runs/{run_id}/status | id, status, started_at, finished_at, next_action, cancelable — 가벼운 폴링입니다. |
result_url | GET /v1/format-runs/{run_id}/result | 전체 receipt. 진행 중이면 details.status에 현재 상태와 함께 409 run_not_completed입니다. |
cancel_url | POST /v1/format-runs/{run_id}/cancel | 현재 receipt입니다. |
| — | GET /v1/format-runs/{run_id} | 어떤 상태에서든 전체 receipt입니다. |
Run receipt
GET /v1/format-runs/{run_id}는 전체 형태를 반환합니다.
| Field | Notes |
|---|---|
id, object | object는 format.run입니다. |
format | { "id", "slug", "title", "version" }. id는 불투명한 skl_…입니다. |
status | 위 표를 참고하세요. |
trigger | { "source": "cron" | "manual" | "api", "idempotency_key" }. API run은 api입니다. |
created_at, started_at, finished_at | 뒤의 둘은 해당 시점까지 null입니다. |
output_schema | { "name", "strict", "source" } — output을 만든 스키마입니다. 구조화 출력을 참고하세요. |
output | 구조화된 결과입니다. 종료가 아닌 모든 상태와 output_error가 설정된 경우에는 null입니다. |
output_error | 투영이 output을 만들지 못했을 때 { "code", "message", "details" }입니다. 출력을 만들 수 없을 때를 참고하세요. |
primary_output_key | output에서 보여줄 하나의 URL에 해당하는 키입니다. completed가 아니면 null입니다. |
primary_output_url | primary_output_key의 해석된 URL입니다. completed가 아니면 null입니다. |
artifacts | run이 만든 모든 내구성 파일입니다. 종료될 때까지 비어 있습니다. |
usage | { "currency": "USD", "billable_amount_usd_micros", "generation_spend_cap_usd_micros" }이거나, spend를 읽지 못했을 때 null입니다. |
error | { "code", "message" }. status가 failed일 때만 non-null입니다. |
skip_reason | skipped run에서 채워지며, 그 외에는 null입니다. |
request_id | 로그에 남기세요. 지원팀이 요청하는 값입니다. |
status_url, result_url, cancel_url | 위를 참고하세요. |
events_url | 이 run의 phase 타임라인 — 무엇을, 언제부터 하고 있는지. Format run에서는 non-null이고, Action·Agent Completion receipt는 여전히 null입니다. |
cancelable | queued 또는 processing인 동안 true입니다. |
next_action | 권장하는 다음 단계입니다 — 아래를 참고하세요. |
webhook_delivery | 등록한 콜백의 전달 상태입니다. 등록하지 않았다면 null입니다 — 아래를 참고하세요. |
idempotency_hit | 이 receipt가 새 run이 아니라 멱등성 재전송일 때 true입니다. |
artifacts[]는 output을 채우는 같은 job 원장에서 가져오므로 둘은 항상 일치합니다.
미디어 필드는 만료되지 않는 내구성 있는 media.sume.com HTTPS URL입니다.
으로 분기하기
Receipt가 내보내는 값은 아래 세 가지뿐입니다:
next_action | When | Do |
|---|---|---|
poll_status | queued 또는 processing | 백오프로 계속 폴링하세요. |
retry_later | skipped | Format 단일 실행(on_active_run: "skip")을 요청했는데 다른 run이 활성이었습니다. 다시 시도하세요. |
none | 종료된 모든 run — completed, failed, canceled | 더 가져올 것이 없습니다. 실패한 경우 사유는 이미 이 receipt의 error와 output_error에 있습니다. |
Format run receipt에서 fix_input, contact_support, inspect_events는
기대하지 마세요. 앞의 둘은 generation job 표면의 값입니다. inspect_events는
공개 events 경로가 없던 시절에 없어진 값이고, 그대로 두었습니다 — 이제
events_url로 phase 타임라인을 읽을 수 있지만, 종료된 run에서 필요한 답은 이미
손에 든 receipt에 있습니다.
웹훅 전달 확인하기
communication.webhook_url로 run을 만들었다면 모든 receipt에 그 콜백이 어떻게 됐는지
알려 주는 webhook_delivery 블록이 들어 있습니다. 등록하지 않고 만든 run에서는
null입니다.
status | 의미 |
|---|---|
not_armed | URL은 저장됐지만 예약된 것이 없습니다 — run이 아직 종료되지 않았거나, 이 환경에서 run 웹훅 전달이 꺼져 있습니다. |
pending | 예약됐고 첫 시도를 기다립니다. |
retrying | 시도가 실패했습니다. next_attempt_at이 다음 시도 시각입니다. HTTP 429는 exponential backoff 위에 Retry-After를 존중합니다(최대 1시간). |
delivered | 엔드포인트가 2xx를 반환했습니다. |
failed / exhausted | 포기했습니다(10회). last_status_code와 last_error를 읽으세요. 여기 429는 수신함 rate limit입니다. run 자체는 그대로이니 result_url을 폴링하세요. |
not_armed는 URL은 저장됐지만 아직 전송이 예약되지 않은 상태입니다(대개 run이
아직 종료되지 않음). 종료 후에는 보통 pending → delivered(또는 재시도/실패
상태)로 움직입니다. 폴링은 백업으로 계속 쓸 수 있습니다.
last_error는 우리 쪽 전송 오류(타임아웃, 연결 실패, 2xx가 아닌 상태)이며 여러분의
응답 본문이 아닙니다.
읽기
usage.billable_amount_usd_micros는 이 run에 귀속된 generation spend입니다 —
run의 generation_spend_cap_usd_micros가 강제되는 같은 누적 합이며, 예약분과 확정분을
모두 셉니다. run이 진행되는 동안 올라가고, 종료되면 정착합니다.
아닌 것이 두 가지입니다. Agent 자체의 LLM 턴은 별도 지갑으로 청구되므로 제외되며,
run의 총비용이 아닙니다. 또한 receipt 숫자이지 청구서가 아닙니다 —
GET /v1/usage가 권위 있는 빌링 기록입니다.
usage 자체가 null인 경우는 spend를 전혀 읽지 못했을 때입니다. 아직 정말 아무것도
쓰지 않았다는 뜻인 0과는 다릅니다.
어떤 버전이 실행됐는지
format.version은 그 run을 만든 Format 버전을 기록합니다. Format을 수정하면 버전이
올라가고 이미 발급된 receipt는 건드리지 않으므로, 과거 run은 실제로 실행한 버전을
항상 알려 줍니다.
Format의 run 목록
최신이 먼저입니다. limit은 1–100을 받으며 기본값은 20입니다. API 트리거를 한 번도
쓰지 않은 Format은 404가 아니라 빈 목록을 돌려줍니다.
응답은 한 페이지입니다:
전체 이력을 훑으려면 has_more가 false가 될 때까지 next_cursor를 cursor로
다시 넘기세요:
cursor는 불투명한 값입니다 — 그대로 다시 넘기고, 파싱하거나 직접 만들지 마세요.
(created_at, id) 기준 keyset이므로 페이지를 넘기는 도중 새 run이 생겨도 이미 읽은
페이지로 행이 밀려들지 않습니다. 우리가 발급하지 않은 cursor는 조용히 최신 run부터
다시 시작하지 않고 400 invalid_request로 거절합니다.
vanity 경로도 같습니다: GET /v1/formats/{handle}/{slug}/runs.
취소
formats:write가 필요하며 멱등합니다. 이미 종료 상태에 도달한 run을 취소하는 것은
no-op이며, 어느 쪽이든 현재 receipt가 돌아옵니다.
끝까지
프로덕션에서는 고정 5초 sleep 대신 exponential backoff를 쓰세요. 비디오를 만드는 run은 분 단위 작업입니다. 매초 폴링해도 이득이 없고 rate limit만 소모합니다.
다음
- 구조화 출력 —
output형태와 null일 때 할 일 - Format 호출하기 — invoke 계약과 모든 제출 오류
- 대량 실행 — 이 run들의 큐, 그리고
GET /v1/format-run-queues/{id} - Run 웹훅 — 폴링 대신 밀어 주는 종료 receipt