Human-in-the-loop for the Vercel AI SDK
Let your Vercel AI SDK agent ask a human on their phone.
Your AI SDK agent asks before a refund or a delete. Your user taps Approve or Deny on their phone.
What Vercel AI SDK gives you
toolApproval, with a policy that answers first
AI SDK 7 checks every tool call against toolApproval on generateText, streamText and ToolLoopAgent before it runs. needsApproval on the tool is now deprecated. @ai-sdk/policy-opa can answer from Open Policy Agent rules: allow, deny, needs approval, or not applicable.
import { opaPolicy } from "@ai-sdk/policy-opa"
await generateText({
model,
tools,
toolApproval: opaPolicy({ client, path: "agent/call/decision" }),
})Where it stops
- A call that needs approval comes back to your code. Nobody is told, and the wait and resume are yours.
- The policy is Rego you deploy. Moving a refund limit from $500 to $750 is a pull request.
- It does not know which of your users owns the action, or how to reach them.
- Running it means maintaining Rego: a compiled bundle in your app, or an OPA server you operate.
The fix
Pushary gets your user's answer.
The AI SDK can stop a tool call before it runs, but it tells nobody. pusharyApproval sends the question to your user's phone and hands the answer back to the SDK.
Pushary adds human approval to AI SDK 7 through toolApproval. The example gates issueRefund and leaves lookupOrder alone. policy: false requires a person to answer instead of letting a saved Pushary rule decide. Approve runs the refund; deny or no answer leaves it blocked. Keep the API key and the signed-in user ID on your server.
npm i @pushary/ai-sdk ai zodimport { generateText, stepCountIs } from "ai"
import { enroll, pusharyApproval } from "@pushary/ai-sdk"
// Once per user: show this link as a button or QR code.
const { universalLink } = await enroll({ apiKey: process.env.PUSHARY_API_KEY! }, user.id)
const { text } = await generateText({
model: "openai/gpt-4o",
tools: { issueRefund, lookupOrder },
// Only issueRefund asks your user. lookupOrder runs untouched.
toolApproval: pusharyApproval({ externalId: user.id, tools: ["issueRefund"], policy: false }),
stopWhen: stepCountIs(5),
prompt: "Refund order 1234.",
})- AI SDK setup, streaming, timeouts and retries
- Step-by-step AI SDK human approval tutorial
- Listed in the Vercel AI SDK tools registry
Or let the model ask a question
createPusharyTools adds an askHuman tool for a yes or no, a choice like Standard or Express shipping, or a typed answer. The model decides when to call it, so it is optional. A prompt that says “ask first” does not stop a refund. Put pusharyApproval on the refund tool for that.
import { generateText, stepCountIs } from "ai"
import { createPusharyTools } from "@pushary/ai-sdk"
const { text } = await generateText({
model: "openai/gpt-4o",
tools: createPusharyTools({ apiKey: process.env.PUSHARY_API_KEY!, externalId: user.id }),
stopWhen: stepCountIs(10),
prompt: "Ask the customer to choose Standard or Express shipping.",
})How it works
From install to the first answer
Connect your user once. Put the approval on the risky step. Pushary sends the question, waits for the answer and saves it.
- 01
Install the package
Run npm i @pushary/ai-sdk ai zod. Keep your API key in PUSHARY_API_KEY on your server, never in the browser.
- 02
Connect your user once
One call returns a link. Show it as a button or QR code. Your user opens it on their phone with the free Pushary app. No account, no payment.
- 03
Put the approval on the risky tool
Pass pusharyApproval to toolApproval with your authenticated user id and the tools that need a yes. Set policy: false when a person must always decide. Every other tool runs as before.
- 04
Act on the answer
Approve runs the tool. Deny, expiry or no answer comes back denied, and the tool does not run. A retried call reuses the same request instead of asking twice.
A question can be a yes or no, a choice from a list, or a typed answer. Every answer is saved.
Before you ship
Things that bite on Vercel AI SDK
- toolApproval needs AI SDK 7
- The gate uses toolApproval, which AI SDK 5 and 6 do not have. The askHuman tool works from AI SDK 5 on. Upgrade before you rely on the gate, or your refund tool has nothing in front of it.
- Give the model a step to use the answer
- With a single step, the askHuman answer comes back as a tool result and the run ends. Allow another step with stopWhen if the model should act on that answer. Neither setting gives the model permission to run a risky tool.
- Streaming hides the pause
- With streamText the UI keeps rendering while the tool waits. It looks like the agent is still thinking when it is waiting on a person. Show the pending approval in your UI, or users will retry the prompt.
The Partner plan
Your agent asks your users, not just you
Ship your agent to your users. Each of them approves its risky actions from their phone, under your brand.
Your users never make a Pushary account or pay us.
Your users answer on their own phones
Connect each user once with a link. They install the free Pushary app and answer from the lock screen, with no account of their own.
No answer means no
Run the action only after an explicit Approve. A request that is still waiting, expired or cancelled never counts as a yes. Pushary keeps every request, so your code can pick it up again after a restart.
Reaches them on their phone
The app comes first, because only the app puts Approve and Deny on the lock screen. Browser notifications come next. You build no delivery system.
Every answer saved
Every answer is saved with who answered and when. You can search and export it, and with a callback URL, each answer is also sent to your server as a signed webhook.
FAQ
Questions, answered
Is there a Vercel AI SDK package for Pushary?
How does the askHuman tool pause the agent?
What happens if the person never answers?
Do my end-users need a Pushary account or API key?
Where does the notification get delivered?
Let your Vercel AI SDK agent ask before it acts.
Connect a user once, ask with one call, and run the action only on a yes. Every answer is saved.
Start freePartner plan, $99 a month. Your users never make a Pushary account or pay us.