Skip to content

Approvals

When a tool is in a policy's Review list, guard() returns requires_human_review=True and the action pauses. A human approves or denies via the Gavrun dashboard.

Polling for approval

python
result = client.guard(
    action="send_outreach_email",
    execute=lambda: None,   # deferred
    tools=["send_outreach_email"],
    prompt=f"Send email to {contact_email}",
    attachments=[{"type": "email_draft", "subject": subject, "body": body}],
)

if result.requires_human_review:
    approval_id = result.decision.get("approval_id")
    decision_id = result.decision.get("decision_id")
    print(f"Waiting for approval: https://agentmanager.gavrun.ai/approvals")

    while True:
        status = client.get_approval_status(approval_id=approval_id)
        if status["status"] == "approved":
            # Execute the action now
            send_email(contact_email, subject, body)
            break
        elif status["status"] == "denied":
            raise PermissionError("Email send denied by reviewer")
        time.sleep(3)

get_approval_status()

python
def get_approval_status(
    self,
    *,
    approval_id: str | None = None,
    decision_id: str | None = None,
    request_id: str | None = None,
) -> dict[str, Any]

At least one parameter is required.

Response fields

FieldTypeDescription
statusstr"pending" | "approved" | "denied"
metadatadictOriginal attachments + any edited_attachments from reviewer
reviewer_notestr | NoneOptional note left by the reviewer
decided_atstr | NoneISO timestamp when the decision was made

Reviewer edits

If the reviewer edits the action (e.g. modifies an email draft before approving), the edited version is available in metadata["edited_attachments"]:

python
status = client.get_approval_status(approval_id=approval_id)
if status["status"] == "approved":
    meta = status.get("metadata", {})
    edited = meta.get("edited_attachments")
    if edited:
        # Use reviewer's version
        draft = edited[0]
    else:
        # Use original draft
        draft = meta["attachments"][0]
    send_email(contact_email, draft["subject"], draft["body"])

Attachments

Pass attachments to guard() to show context to the reviewer:

python
client.guard(
    action="send_email",
    execute=lambda: None,
    tools=["send_email"],
    attachments=[{
        "type": "email_draft",
        "subject": "Q3 update",
        "body": "Dear ...",
    }],
)

The dashboard renders email_draft attachments with an editable subject/body.

Apache 2.0 License