Pattern · Agents
NewAgent Approval SwiftUI Block
An agent asks before it acts: the action, its risk and a preview of the change, then Allow once, Always allow or Deny.
The permission prompt for an agent about to act. A card names the agent and tool with a tinted risk chip, states the action and why, counts down to an automatic deny when it has a deadline, and previews the change as an email, a list of affected items or a value before and after. Each answer runs your closure in place, and the block folds to a one-line outcome.
- SwiftUI
- iOS 17.0+
- agent-approval
$199 once, every piece included. See how installing works · Sign in
01
What's included
SwiftUI source you own, built on Apple frameworks only.
- The action as a verb and target, the agent and tool, and a Low, Medium or High risk chip
- Previews an email, the affected items with Show all, or a value before and after
- Allow once, Always allow for the tool and Deny, each with working and failed in place
- An optional countdown that denies on its own
- Folds to "Allowed once · 2:41 PM" once decided
02
Implementation notes
How it behaves, what it handles, and the decisions behind it.
One surface card names the agent and the tool it would use beside a tinted risk chip (Low, Medium or High risk), then what it wants to do as a verb and a target, "Send an email to 3 people", and why. When the request has a deadline, a line counts down ("Auto-denies in 1:24"), turns to the warning colour in its last ten seconds and denies the request on its own at zero. Preview opens what would change: the email with its recipients, subject and body; the affected items, three at first with Show all; or a value before and after. Allow once is the primary action, Always allow for the tool the secondary one and Deny a plain one. The tapped button shows progress while your closure runs and the others wait; a thrown error shows under them and keeps the request open. Once decided, the block folds to one line with its symbol: "Allowed once · 2:41 PM", "Always allowed", "Denied" or "Expired". nil shows grey shapes in the block's own layout.
Notes
AgentApprovalBlock(request:showsPreview:onDecision:)takes oneRequestand the decision closure. It is a section: no navigation stack, background, padding or scroll view of its own, so place it in your own column or a sheet.AgentApprovalBlock.Requesthas a stableid, theaction, an optionalreason, theagent, thetooland its SF Symbol, aRisk(.low,.medium,.high), an optionalPreview, an optionalexpiresdate and an optionalresolution.Request.sampleis the email from the preview.Request.Previewis.message(to:subject:body:),.items([Item])or.change(label:before:after:). AnItemhas a title, an optional detail and a symbol.onDecisionreceives.allowOnce,.alwaysAllowor.deny, and.denywhen the request expires. Return to settle on the outcome. Throwing shows the error'serrorDescription(or "Your answer didn't reach the agent. Try again."); throwCancellationError()to go back quietly.- Pass a
resolutionto show a request decided earlier or elsewhere. A request with a newidresets the block. - Haptics mark success when an action is allowed, a warning when it is denied and an error when sending the answer fails.
- VoiceOver reads the agent and tool ("Assistant wants to use Mail"), the action as a header, the countdown in seconds, the change as "From $180.00 left to $156.00 left", and announces the outcome. The risk chip moves under the source line and before and after stack when text is large.
- Reduce Motion turns opening the preview and folding into short fades.
AgentApprovalBlockExampleat the end ofAgentApprovalBlock.swiftis the screen in the preview: the email request with 90 seconds before it expires, and Allow once taking a moment before it folds. PasswrapsInNavigationStack: falseto push it in your own stack.
Theming
- Reads
SPThemefrom@Environment(\.spTheme)and requires thedesign-systemitem. - The card is
color.surfacewithradius.lg, 16 point padding and anSPHairlineabove Preview; the preview sits onfillatradius.sm. The buttons sit 24 points under the card. - The action is
type.title3, the reason and email bodytype.subhead, the source line, fields and countdowntype.footnote. - The risk chip is
success,warningordangeron a 14% tint of it. The countdown turnswarningin its last ten seconds; errors aredanger; an allowed outcome's symbol issuccess. - Allow once is the
accentwithaccentOntext, the only accent on the block; Always allow is the secondary button onfill, Deny plaintextPrimarytext. - Changes animate with
motion.smoothand buttons withmotion.snappy; every animation becomes a short fade under Reduce Motion.
03
Keep building
Pieces that work well next to this one.