The mechanism
Human oversight is useful when the reviewer sees a concrete action and has authority to approve it. A prompt saying “Proceed?” is inadequate if the tool arguments can change afterward. Approval should bind the principal, operation, resource, payload, expected revision and expiry. The executor checks that binding immediately before acting.
The current SDK provides a HumanInTheLoop intervention with interrupt/resume, terminal and callback modes. Those mechanisms help pause execution, but your application still owns reviewer authentication, session ownership and the business meaning of an approval. A resumed interrupt is not automatically proof that the right person approved the right action.
A worked approval check
Offline, application logic only. This simplified check illustrates two essential comparisons. A real service also needs authenticated identities, signatures or trusted storage, expiry, policy evaluation and atomic execution.
import hashlib
import json
def intent_hash(intent):
data = json.dumps(intent, sort_keys=True, separators=(",", ":"))
return hashlib.sha256(data.encode()).hexdigest()
intent = {"operation": "append_note", "incident_id": "INC-104",
"text": "Request carrier scan", "expected_revision": 7}
approval = {"intent_hash": intent_hash(intent), "reviewer": "operator-demo"}
assert approval["intent_hash"] == intent_hash(intent)
changed = {**intent, "text": "Mark resolved"}
assert approval["intent_hash"] != intent_hash(changed)
Hashing does not authenticate the reviewer or protect a mutable approval record by itself. It gives the trusted service a stable representation to compare. Store approvals where the model cannot edit them, and require the executor to reject altered intent rather than silently applying the latest proposal.
In a web flow, present the operation, destination and proposed diff before approval. If the underlying incident changes while the reviewer is reading, the expected-revision check should detect that race. Ask for renewed review when the changed state materially alters the action.
Practice: attack the approval boundary
Offline. Test five cases: correct reviewer and unchanged intent; another tenant’s reviewer; changed payload; expired approval; and stale resource revision. Expected observation: only the fully matching case may proceed, and even it must still pass current destination policy.
Then test a double submission with the same approval and request key. Reuse the idempotency design from chapter 8 so a browser retry does not append two notes. Finally, simulate a process restart while the agent is paused. The approval request and session state need durable correlation; a missing response should not default to approval.
Troubleshooting and trade-offs
Approval fatigue appears when every harmless read requires confirmation. Classify operations by actual authority and consequences, then reserve review for decisions where it adds value. Do not hide a dangerous write behind an innocuous tool name to reduce prompts.
A safety classifier can help route review but is not a substitute for authenticated authorization. A reviewer may also make mistakes; minimize the diff and show evidence clearly. Keep the default for missing, ambiguous or stale approval explicit, and never treat elapsed time as consent.
Interview practice
Why bind approval to a payload hash and resource revision?
The hash detects changed intent; the revision detects changed target state. Together they reduce the chance that an approval for one concrete action is reused for a different action or stale context.
What remains necessary after an SDK interrupt is resumed?
Authenticate the responder, verify session and tenant ownership, validate the exact approved intent and expiry, recheck current policy and execute idempotently. Resume is a control-flow event, not a complete authorization system.
Completion check
Build a review card for one synthetic note proposal. Demonstrate rejection of changed intent and a stale revision. Explain how the same approval survives a retry without expanding its scope.
Sources and version notes
Checked 6 October 2026. Python examples target strands-agents==1.58.0 unless labelled otherwise. Live documentation can change; compare your installed version before adapting an example.
Make the understanding yours.
Use the completion check above. Mark this chapter when you can explain the mechanism and its limits.
Self-assessed reading progress. This does not certify that a lab ran or a system is secure.