resonate-human-in-the-loop-pattern-python — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited resonate-human-in-the-loop-pattern-python (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
A human-in-the-loop workflow suspends on a durable promise that is resolved (or rejected) by something outside the Resonate worker set — a person clicking an Approve button, a webhook from a third-party system, an operator running a CLI command. The worker doesn't poll or sleep; it opens a ctx.promise() and awaits it, and Resonate wakes it when the promise settles.
from __future__ import annotations
import asyncio, os, time
from typing import TYPE_CHECKING
from resonate.resonate import Resonate
from resonate.types import Value
if TYPE_CHECKING:
from resonate.context import Context
r = Resonate(url=os.environ.get("RESONATE_URL", "http://localhost:8001"))
async def notify_reviewer(ctx: Context, order_id: str, amount: int, approval_id: str) -> str:
# Side effects live in leaves — this prints/notifies exactly once
print(f" order {order_id} (${amount}) needs review; promise id: {approval_id!r}")
return approval_id
async def ship_order(ctx: Context, order_id: str) -> str:
return f"shipped-{order_id}"
async def cancel_order(ctx: Context, order_id: str) -> str:
return f"canceled-{order_id}"
async def fulfill_order(ctx: Context, order_id: str, amount: int) -> str:
# Open the approval promise; its id is deterministic (derived from the workflow id)
approval = ctx.promise()
approval_id = await approval.id()
# Notify the reviewer via a leaf (side effects belong in leaves)
await ctx.run(notify_reviewer, order_id=order_id, amount=amount, approval_id=approval_id)
# Suspend here — the worker holds no state while waiting
# This can be seconds, hours, or days; no process needs to stay alive
decision_raw = await approval
if decision_raw.get("approve"):
return await ctx.run(ship_order, order_id=order_id)
return await ctx.run(cancel_order, order_id=order_id)From outside the worker (a webhook, a UI route, a CLI):
from resonate.types import Value
# Resolve the promise — wakes the suspended workflow
await r.promises.resolve(approval_id, Value(data={"approve": True, "note": "looks good"}))
# Or reject it
await r.promises.reject(approval_id, Value(data={"reason": "policy violation"}))r.promises.resolve/reject are async — always await them.
The SDK's examples/human-in-the-loop shows the full pattern with a ReviewerInbox dependency (an asyncio.Future) so the simulated reviewer learns the promise id the instant the leaf creates it — without polling:
import asyncio
from resonate.resonate import Resonate
from resonate.types import Value
class ReviewerInbox:
def __init__(self) -> None:
self.approval_id: asyncio.Future[str] = asyncio.get_running_loop().create_future()
def publish(self, approval_id: str) -> None:
if not self.approval_id.done():
self.approval_id.set_result(approval_id)
async def notify_reviewer(ctx, order_id: str, amount: int, approval_id: str) -> str:
print(f" order {order_id} (${amount}) pending; id: {approval_id!r}")
ctx.get_dependency(ReviewerInbox).publish(approval_id)
return approval_id
async def fulfill_order(ctx, order_id: str, amount: int) -> str:
approval = ctx.promise()
approval_id = await approval.id()
await ctx.run(notify_reviewer, order_id=order_id, amount=amount, approval_id=approval_id)
decision_raw = await approval
if decision_raw.get("approve"):
return await ctx.run(ship_order, order_id=order_id, note=decision_raw.get("note", ""))
return await ctx.run(cancel_order, order_id=order_id, note=decision_raw.get("note", ""))
async def main() -> None:
r = Resonate(url="http://localhost:8001")
inbox = ReviewerInbox()
r.with_dependency(inbox)
r.register(fulfill_order)
try:
wid = f"fulfill-{time.time_ns()}"
handle = r.run(wid, fulfill_order, "order-42", 199)
# Simulated reviewer: wait for the inbox, then resolve
async def simulate_reviewer() -> None:
approval_id = await inbox.approval_id
await r.promises.resolve(approval_id, Value(data={"approve": True, "note": "ok"}))
reviewer = asyncio.create_task(simulate_reviewer())
out = await handle.result()
await reviewer
print(f"OK: {out}")
finally:
await r.stop()
asyncio.run(main())The orchestrator and the external resolver need to agree on the promise ID. When you call ctx.promise() without an explicit id, the SDK assigns a deterministic id derived from the workflow's own promise id (e.g., {workflow_id}.1 for the first promise). Your leaf captures and publishes this id so the external resolver knows where to settle.
If you need a portable, human-readable id, pass a keyword argument (not yet in the v0.7.0 public API for ctx.promise; derive it from workflow inputs and embed it in the leaf instead). The safe pattern is always: open the promise, await its id, pass the id to a leaf for notification.
Pass data to the resolver via a leaf that publishes the promise id alongside any routing metadata:
async def notify_for_travel(
ctx: Context, traveler_id: str, destination: str, approval_id: str
) -> str:
# In a real system: Slack message, email, dashboard row
print(f" travel approval needed: {traveler_id} → {destination} [{approval_id}]")
return approval_idThe reviewer sees the id and calls r.promises.resolve(approval_id, Value(data=decision)).
A typical FastAPI webhook route that resolves a promise:
from fastapi import FastAPI, Request
from resonate.resonate import Resonate
from resonate.types import Value
app = FastAPI()
r = Resonate(url="http://localhost:8001")
@app.post("/webhooks/docusign")
async def docusign_callback(req: Request) -> dict:
body = await req.json()
envelope_id = body["envelopeId"]
status = body["status"]
if status == "completed":
await r.promises.resolve(
f"docusign:{envelope_id}",
Value(data={"signed": True, "signed_at": body["completedAt"]}),
)
elif status in {"declined", "voided"}:
await r.promises.reject(
f"docusign:{envelope_id}",
Value(data={"reason": status}),
)
return {"ok": True}Note: the worker that is awaiting ctx.promise() is woken as soon as the webhook resolves.
Fan out to independent approvers; wait for all to respond:
async def multi_approver(ctx: Context, request_id: str, count: int) -> dict:
# Open N approval promises in sequence (each gets a deterministic id)
approvals = [ctx.promise() for _ in range(count)]
ids = [await a.id() for a in approvals]
# Notify each approver via a leaf
for i, approval_id in enumerate(ids):
await ctx.run(notify_approver, request_id, i, approval_id)
# Await all decisions
decisions = [await a for a in approvals]
approved_count = sum(1 for d in decisions if d.get("approve"))
if approved_count == count:
return {"status": "approved"}
return {"status": "rejected", "approved": approved_count, "of": count}r.promises.resolve/reject wrap the payload in a Value object. Import from resonate.types. are all async** — always await` them.await r.promises.resolve(...).Bad:
async def bad_approval(ctx: Context, order_id: str) -> dict:
# Polling defeats the point
while True:
status = await ctx.run(check_approval_status, order_id)
if status:
break
await ctx.sleep(timedelta(seconds=30))
return {"status": "approved"}ctx.promise() gives you wake-on-event; polling wastes checkpoints and loses the ability to pass decision data into the workflow.
resonate-basic-ephemeral-world-usage-python — r.promises.resolve/reject/get from the ephemeral world (webhook handler side)resonate-basic-durable-world-usage-python — ctx.promise, ctx.get_dependencyresonate-saga-pattern-python — sagas with human-gated stepsdurable-execution — foundational replay semantics; promise-wait survives crashes~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.