From reviewing cloudflare/agents-starter#154: the AI SDK models human-in-the-loop approval as states of the persisted tool-call part itself (input-available → approval-requested → output-available | output-denied | output-error) with a per-tool needsApproval: async (input) => boolean predicate.
Two adoptable pieces for agent-app, done compliance-grade (theirs is UX-grade — client-trusted approval, no audit trail):
- Per-call approval predicates. Today
taxonomy.regulatedTypes is a static set. Add an optional needsApproval?: (args, ctx) => boolean | Promise<boolean> seam per proposal type so products can gate by cost threshold, environment, or first-use rather than always/never. Keep fail-closed: predicate errors → approval required.
- Normalized tool-part lifecycle states in LoopEvents + persisted messages. Emit tool-call state transitions (
input-available, approval-requested, output-available, output-denied, output-error) so UIs render one switch over part state and approvals survive reload because they live in message history — no separate pending-approvals store to reconcile.
Unlike the starter, approval responses must be recorded server-side (who/when/decision in the proposals table) and the predicate re-checked at execution time, never trusted from the client.
🤖 Generated with Claude Code
From reviewing cloudflare/agents-starter#154: the AI SDK models human-in-the-loop approval as states of the persisted tool-call part itself (
input-available → approval-requested → output-available | output-denied | output-error) with a per-toolneedsApproval: async (input) => booleanpredicate.Two adoptable pieces for agent-app, done compliance-grade (theirs is UX-grade — client-trusted approval, no audit trail):
taxonomy.regulatedTypesis a static set. Add an optionalneedsApproval?: (args, ctx) => boolean | Promise<boolean>seam per proposal type so products can gate by cost threshold, environment, or first-use rather than always/never. Keep fail-closed: predicate errors → approval required.input-available,approval-requested,output-available,output-denied,output-error) so UIs render one switch over part state and approvals survive reload because they live in message history — no separate pending-approvals store to reconcile.Unlike the starter, approval responses must be recorded server-side (who/when/decision in the proposals table) and the predicate re-checked at execution time, never trusted from the client.
🤖 Generated with Claude Code