Watch a Sume Format run by phase: preparing, running, finalizing

Pass timeline: true to subscribeFormatRun or waitForRun, or call getFormatRunTimeline, to show phases during a long run. It doubles the polling rate.

5 min readSume
All posts

Pass timeline: true to subscribeFormatRun or to waitForRun for a Format run, and read the phase from snapshot.timeline in the onStatus callback. The phases are preparing, running and finalizing, each with a timestamp and a status. For a run that you do not wait on, call getFormatRunTimeline(runId, { client }) instead.

A phase gives a person something to read while a long run goes on. For a run that takes many minutes, a bare processing label looks stuck, and users cancel or resubmit, which costs money. A phase name and its timestamp usually settles that.

A concrete use is a customer facing status page. Show the phase name and the elapsed time since its timestamp, and keep the wording plain. A person who sees that a run is in the finalizing phase understands that the end is near, and is less likely to cancel it or ask for a refund.

What the timeline adds to status

The status field says processing, and for a run that lasts a quarter of an hour that is not much to tell a user. The timeline answers the question of what the run is doing right now, at the level of the three phases, without exposing anything inside the run.

The timeline is a phase record and not a log stream. The docs say that Sume does not publish agent output, tool calls or sandbox internals, so do not build a UI that promises a play by play. Show the three phases and their times, and nothing else.

Stay honest about what the three phases mean. They are coarse. A run can spend most of its time in running, and the timeline will not split that into smaller steps. Treat it as a progress hint for people, not as a measurement for dashboards.

Defaults and limits

Know these defaults before you turn it on.

Pick the watcher by the situation. Use subscribeFormatRun when your code also submits the run, because it handles the submit and the wait together. Use waitForRun when you already hold a run id, for instance after a restart. Use getFormatRunTimeline when you only want to show a progress strip and some other code owns the wait.

Run watching options (read 2026-10-05)
Option or helperDefaultNote
subscribeFormatRun timeout20 minutesSends an automatic UUID idempotency key unless you pass null
waitForRun timeout10 minutesfamily is required
waitForRun transient failures6 toleratedThen it throws
timelinefalseDoubles the request rate when true

Render the current phase

The function below turns the snapshot shape from the docs into one display line. It is plain TypeScript, with no SDK import, so you can unit test it with a canned timeline.

The cost of that extra read is real. Each poll reads the run and also reads the timeline, so the request rate doubles. With a read bucket of thousands of requests a minute that is rarely a problem for one watcher, but it adds up for a dashboard that follows many runs at once.

The sample keeps the status and the phase in one line, because that is what most UIs need. If the timeline is missing, for example when you did not pass timeline: true, the function falls back to the status alone, so the same code works with or without the option.

interface PhaseEntry {
  at: string;
  phase: "preparing" | "running" | "finalizing";
  status: string;
  duration_ms: number | null;
}

export function phaseLine(status: string, timeline?: PhaseEntry[]): string {
  const last = timeline?.at(-1);
  if (!last) return `${status}`;
  return `${status} - ${last.phase} (${last.status})`;
}

console.log(phaseLine("processing"));
console.log(phaseLine("processing", [
  { at: "2026-10-05T10:00:00Z", phase: "preparing", status: "completed", duration_ms: 4000 },
  { at: "2026-10-05T10:00:04Z", phase: "running", status: "running", duration_ms: null },
]));

Deadlines and timeouts

The deadline logic is worth knowing. The helper checks the deadline before it sleeps, not after, so a caller who asks for a 5 second timeout gets the timeout in 5 seconds, not 5 seconds plus a poll interval. A timeout does not cancel the run. It ends your watching only, so resume with the same run id, and never submit the paid request again.

Do not branch your business logic on a phase. Phases are for display. Decisions belong to the terminal status and the outcome, which are the stable fields, and a phase name added later should not change what your code does with a finished run.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume