Multi-step human approval that survives restarts
Pause execution mid-run for a human decision. State persists in PostgreSQL, so a crashed server resumes exactly where it left off.
Block an agent for a human decision — for hours, days, or across a server restart. The control plane writes the execution state to PostgreSQL before pausing, then a webhook callback resumes the same execution after the human responds.
from agentfield import Agent
app = Agent(node_id="content-pipeline", version="1.0.0")
@app.reasoner()
async def publish_with_review(brief: str) -> dict:
# Step 1: AI drafts
draft = await app.ai(system="You are a senior copywriter.", user=brief)
# Pause #1 — editor reviews the draft (state is now in Postgres)
review = await app.pause(
approval_request_id="draft-review",
approval_request_url="https://cms.example.com/review/draft",
expires_in_hours=24,
)
if review.decision != "approved":
return {"status": review.decision, "feedback": review.feedback}
# Step 2: AI revises using the editor's feedback
final = await app.ai(
system="Revise based on editorial feedback.",
user=f"Draft: {draft}\nFeedback: {review.feedback}",
)
# Pause #2 — publisher signs off before going live
sign_off = await app.pause(
approval_request_id="final-approval",
approval_request_url="https://cms.example.com/review/final",
expires_in_hours=4,
)
if sign_off.decision == "approved":
await app.call("publisher.publish", content=final)
return {"status": sign_off.decision}
app.run()If the agent process restarts mid-pause, reconnect to the pending approval:
result = await app.wait_for_resume(
approval_request_id="draft-review",
timeout=24 * 3600,
)What this gives you
- Multiple human gates inside a single execution.
- Crash-safe: the execution state lives in PostgreSQL, not in agent memory.
- Resolutions arrive via HMAC-signed webhook — your reviewer UI just POSTs the decision.
Next
Cryptographic receipts for every AI decision
Every reasoner execution produces a signed, offline-verifiable W3C Verifiable Credential with SHA-256 hashes of input and output.
Trigger agents from GitHub, Stripe, Slack, or any custom webhook
Bind a reasoner to an external event source. The control plane verifies the signature, drops replays, and dispatches the event to your reasoner.