Human-in-the-loop for the Vercel AI SDK

Let your Vercel AI SDK agent ask a human on their phone.

Add an askHuman tool to collect a customer answer in the native Pushary app.

The integration

Add it to your Vercel AI SDK agent

Pushary returns an askHuman tool for generateText or streamText. Resolve the enrolled customer from trusted application context and pass the Partner key on your server. The tool collects confirm, select or input responses through the native app during a bounded wait. It is optional: adding it or instructing the model to ask does not prevent another tool from executing. Protected actions need an enforced framework approval boundary and validated outcomes.

bash
npm i @pushary/ai-sdk
optional customer question
import { generateText, stepCountIs } from "ai"
import { openai } from "@ai-sdk/openai"
import { createPusharyTools, enroll } from "@pushary/ai-sdk"

await enroll({ apiKey: process.env.PUSHARY_API_KEY! }, user.id)

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.",
})

Why you need it

Vercel AI SDK pauses the agent. Pushary reaches the human.

The AI SDK owns the approval boundary. Pushary reaches the authorized customer and records their response. A stored decision does not preserve an in-flight generateText call: your application must persist the relevant run state, validate the response and arrange continuation. Use the package README matching your installed version; updated enforced-approval examples are awaiting a forthcoming package release. Preserve pending approval identity separately from messages.

What Vercel AI SDK already gives you

toolApproval, and a policy that returns a verdict

The AI SDK does not just pause any more. Approval logic moved from needsApproval on the tool, now deprecated, onto toolApproval on generateText, streamText and ToolLoopAgent, and @ai-sdk/policy-opa evaluates each call against Open Policy Agent and answers allow, deny, requires-approval or not-applicable. That is a real policy layer and it is good. It answers what should happen. What it does not answer is who hears about the ones it cannot settle.

native
import { opaPolicy } from "@ai-sdk/policy-opa"

await generateText({
  model,
  tools,
  toolApproval: opaPolicy({ client, path: "agent/call/decision" }),
})

Where it stops

  • requires-approval still surfaces to your code, not to a person. The delivery, the waiting and the resume are yours to build.
  • The policy is Rego you deploy. Moving a refund threshold from $500 to $750 is a pull request, not a row your support lead edits.
  • It decides about the run, not about a named human. There is no notion of which of your end-users owns this action or how to reach them.
  • Running it means running OPA. That is a server or sidecar you operate, on top of the app you were already shipping.

Before you ship it

Things that bite on Vercel AI SDK

Choose whether the model needs another step
A one-step call can return the customer answer as a tool result. Allow another step if the model should use that answer. Neither setting grants permission to execute a protected action.
A prompt is not an approval gate
The model can skip an optional askHuman tool. Enforce approval on the protected tool itself using the supported framework boundary; never rely on a prompt to prevent a refund, deletion or other action.
Streaming hides the pause
With streamText the UI keeps rendering while the tool blocks, so it can look like the agent is still thinking when it is actually waiting on a person. Surface the pending decision in your UI or users will retry the prompt.

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.

  1. 01

    Install and connect a phone

    Install the package and use a server-only Partner key. Present the enrollment link to the authorized customer and have them complete enrollment in the native app before asking.

  2. 02

    Add the askHuman tool

    Pass your Partner key and a trusted externalId to createPusharyTools, then add its tools to generateText or streamText. This adds customer questions, not an action gate.

  3. 03

    Protect actions separately

    Use the framework approval boundary for protected tools. A shipping-choice prompt can use the optional ask tool; a refund must remain blocked until your code validates the required approval.

  4. 04

    Act on the decision

    Inspect the returned outcome. Confirm, select and input carry different values; a choice or written answer is not approval of a separate action. Keep unanswered or expired requests distinct from a recorded rejection.

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.

The Partner plan

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.

$99/ month, every framework included
Start with Pushary

Your users never see a Pushary login or bill.

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 that opens the Pushary app, and every approval lands with the right person. No account and no key on their side.

Durable, fail-closed waits

Pushary stores the decision; your application persists its own paused workflow and schedules resumption. Require an explicit, verified approval before acting. Pending, expired and cancelled requests are not approval.

Phone-first delivery

Pushary reaches the person on the device they carry: the app first, because it is the only channel that puts Approve and Deny on a lock screen, 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

Is there a Vercel AI SDK package for Pushary?
Yes. @pushary/ai-sdk is published on npm. Follow the README for your installed version, including Partner credentials and enrollment. The updated approval integration is awaiting release; source examples depending on @pushary/server 2.1 are not yet available from the currently published package.
How does the askHuman tool pause the agent?
The tool holds the current call open until it returns an answer or reaches its wait limit. This does not make the JavaScript process or agent run durable. Delayed answers require application-owned state and continuation.
What happens if the person never answers?
An unanswered request supplies no human approval. Your protected-action code must keep the action blocked. Retaining the decision record does not automatically resume a tool call after a timeout or restart.
Do my end-users need a Pushary account or API key?
No. You reference each user by your own externalId. They connect a phone once with a one-tap link that opens the Pushary app, and they need no account and no key of their own. They never see a Pushary login or bill.
Where does the notification get delivered?
The native Pushary app is the primary answer surface. Confirm requests can offer notification actions; choices and written answers open the app. Slack and legacy web delivery remain available where configured.

Let your Vercel AI SDK agent ask a human.

Connect a user with one tap, ask a human with one call, and act on a fail-closed decision. Every decision is saved to a durable ledger you can audit.

Start with Pushary

Partner plan, $99 a month. Your users never see a Pushary login or bill.