Human-in-the-loop for the OpenAI Agents SDK
Human approvals for the OpenAI Agents SDK, on a phone.
Define a function tool whose body calls decisions.ask({ question, externalId, type }). When the agent calls the tool, Pushary sends the question as a push notification to that user's phone, and the call blocks until the person approves, denies, or answers. The answer is fail-closed, so the agent waits for a real decision instead of timing out into an action. Use @pushary/server in TypeScript or pip install pushary in Python. There is no OpenAI-Agents-specific package, so the standard SDK works alongside the SDK's own tool definitions.
import os
from agents import function_tool
from pushary import PusharyServer
px = PusharyServer(api_key=os.environ["PUSHARY_API_KEY"])
# Connect the user's phone once.
px.enroll("user_123")
@function_tool
def ask_human(question: str) -> str:
d = px.decisions.ask(question=question, external_id="user_123", type="confirm")
return "approved" if d["approved"] else f"not approved ({d['status']})"
# agent = Agent(name="...", tools=[ask_human])Why you need it
OpenAI Agents SDK pauses the agent. Pushary reaches the human.
The OpenAI Agents SDK can pause a run with its own approval interruption, and it does not deliver that pending decision to a person or keep the record. A Pushary function tool sends the question to a phone, blocks on a fail-closed answer, and logs it. Route the SDK's needsApproval to the same tool so the person who decides can be your own end-user.
How it works
From ask to resume
Connect the phone once, then ask a human from the tool or step that guards the action. The waiting, the delivery, and the record are handled for you.
- 01
Install and set your key
Run pip install pushary in Python or npm i @pushary/server in TypeScript, and set PUSHARY_API_KEY.
- 02
Connect the phone
Call enroll(external_id) once per end-user to connect their phone with a keyless one-tap link.
- 03
Define an ask-human tool
Write a function tool whose body calls decisions.ask(), and register it on your agent. It works alongside the SDK's own tool() and function_tool definitions.
- 04
Act on the decision
The tool returns a fail-closed answer. Use it to approve or reject the guarded action, or to resolve a needsApproval interruption and resume.
A decision is a yes or no confirm, a multiple-choice select, or a free-text input. Every one is stored with its outcome and kept in the audit log.
For your users
Your agent asks your users, not just you
Ship the agent to real users and let each of them approve their own decisions from their phone, under your brand.
Your users answer on their own phones
The externalId is your own id for the end-user. Connect their phone once with a keyless one-tap link, and every approval lands with the right person. No account, no app, no key on their side.
Durable, fail-closed waits
The agent stays open on a durable wait backed by a decisions ledger. If nobody answers in the window you set, the decision comes back denied, so a timeout or a restart never turns into an unapproved action.
Phone-first delivery
Pushary reaches the person on the device they carry: native app push first, then PWA push notifications, then Slack if you route it there. You do not build a delivery pipeline.
Signed webhooks and an audit trail
Every decision is written to a durable ledger you can query and export, and resolved decisions post a signed webhook to your callback URL. You have the record of who approved what and when.
FAQ
Questions, answered
Human-in-the-loop for other frameworks
Let your OpenAI Agents SDK agent ask a human.
Connect a user with one tap, ask a human with one call, and act on a fail-closed decision. The durable store and the audit log come with it.
Partner plan, $99 a month. Your users never see a Pushary login or bill.