Pattern · Agents

New

Agent Run SwiftUI Block

A long-running agent task live: state, elapsed time, current activity, steps, tokens and cost, Pause and Stop, then its result.

The status section for an agent working in the background. It shows the state, a ticking clock, what the agent is doing now, a segmented step bar and the tokens and cost so far, with Pause, Resume and a confirmed Stop, and Notify me when done through the system permission. It settles into a summary with the outputs to open, or the reason and Retry when it fails.

  • SwiftUI
  • iOS 17.0+
  • agent-run
Get SwiftPieces Pro

$199 once, every piece included. See how installing works · Sign in

01

What's included

SwiftUI source you own, built on Apple frameworks only.

  • Queued, Running, Paused, Needs input, Finished and Failed in one tinted chip
  • Elapsed time ticking in the brand's figures, with the activity changing in place
  • A segmented step bar and tokens and cost so far
  • Pause, Resume and Stop with a confirmation, and Notify me when done
  • Settles into a summary with outputs and Open, or the reason with Retry

02

Implementation notes

How it behaves, what it handles, and the decisions behind it.

A surface card shows the run's state as a tinted chip (Queued, Running, Paused, Needs input, Finished or Failed) with the step it's on, the task's title, and the elapsed time in the brand's figures, ticking each second while it runs and holding while paused. Under it, the agent's current activity changes in place beside a small spinner, a segmented bar lights a segment per finished step with the running one half lit, and a hairline separates the tokens and cost used so far. Pause and Resume run your closures with progress in the button, and Stop asks "Stop this run?" before it runs yours. Notify me when done asks for notification permission the first time it is turned on and, when notifications are off, says so with Open Settings. When the agent needs an answer, its question replaces the activity with Respond. On finish the block settles into the result: the time, tokens and cost, a short summary, the outputs with Open, and the primary action opening the first. On failure the reason shows with Retry. nil shows grey shapes in the block's own layout.

Notes

  • AgentRunBlock(run:notify:onPause:onResume:onStop:onRetry:onRespond:onOpen:) takes one Run. It is a section: no navigation stack, background, padding or scroll view of its own, so place it in your own column.
  • AgentRunBlock.Run has a title, a State, the current activity, the step from 1 and the stepCount, the elapsed seconds banked before resumedAt, optional tokens and cost (with currencyCode), and the summary and outputs it shows when finished. elapsed(at:) gives the running total; Run.sample is the expenses run from the preview.
  • Run.State is .queued(position:), .running, .paused, .needsInput(question), .finished or .failed(reason). Stopping is a failure with your reason ("You stopped the run on step 5.").
  • Run.Output has a title, an optional detail, a symbol and an optional url. Open uses openURL unless you pass onOpen; an output with neither shows no Open.
  • Pass a new Run whenever the agent reports progress. Keep resumedAt set while running so the clock ticks on its own between updates.
  • onPause and onResume show Pause and Resume; onStop shows Stop, behind a confirmation; onRetry shows Retry on failure; onRespond shows Respond when the agent needs input. Leaving one out hides its button. A thrown error shows its errorDescription under the buttons; CancellationError() goes back quietly.
  • notify binds Notify me when done; nil hides the row. Turning it on asks UNUserNotificationCenter for permission when it hasn't been asked, and stays off if it's refused. The block checks again when the app becomes active. Schedule the notification yourself when the run finishes.
  • Haptics mark success when the run finishes, a warning when it needs input and an error when it fails.
  • VoiceOver reads the state chip, the elapsed time in words, the activity as "Now: …", the steps as "4 of 9 done", and announces pause, resume and stop. Pause and Stop stack at accessibility sizes.
  • Reduce Motion turns every change into a short fade.
  • AgentRunBlockExample at the end of AgentRunBlock.swift is the screen in the preview: a run reconciling a month of expenses that advances a step every 1.6 seconds, pauses and resumes, stops after confirming, and finishes with three outputs. Pass wrapsInNavigationStack: false to push it in your own stack.

Theming

  • Reads SPTheme from @Environment(\.spTheme) and requires the design-system item.
  • Cards are color.surface with radius.lg, 16 point padding and SPHairline dividers in separator; groups sit 24 points apart.
  • The elapsed time is the one display moment: the brand's face (type.face) at 34 points with monospaced digits, type.numeralWeight capped at semibold, in type.figureDesign when the face isn't bundled. The title is type.headline, the activity type.subhead, figures type.subhead with monospaced digits, labels type.caption.
  • The chip is info while running, warning when it needs input, success when finished and danger when failed, each on a 14% tint, or textSecondary on fill when queued or paused. Step segments are textPrimary on fill.
  • Pause and Resume are the secondary button on fill; Stop is on fill with danger text. Respond, Retry and Open are the accent with accentOn text, one at a time.
  • Changes animate with motion.smooth and buttons with motion.snappy; every animation becomes a short fade under Reduce Motion.

Requirements

  • Notify me when done uses UNUserNotificationCenter; no capability or Info.plist key is needed to ask.