RobotRock

Vercel Workflow

Use robotrock/workflow when you need a durable wait for human input inside Vercel Workflow — workflows that survive restarts and suspend without consuming compute until someone acts in the RobotRock inbox.

If you run agents with the Vercel AI SDK inside workflow tools or DurableAgent, see Vercel AI for mode: "workflow" on robotrock/ai tools.

Installation

npm install robotrock workflow
# or
bun add robotrock workflow

workflow is an optional peer dependency of robotrock/workflow. Install both in the app that defines your workflows.

How it works

  1. sendToHumanInWorkflow() calls createWebhook() and obtains webhook.url.
  2. A step creates the RobotRock task with that URL as the client webhook.
  3. The workflow suspends on await webhook until RobotRock POSTs the handler payload when a human completes an action.
  4. validUntil is enforced with Promise.race against sleep(timeout).

You do not configure a client webhook yourself — the SDK sets it from the workflow webhook URL.

Environment variables

Same as other SDK entry points:

  • ROBOTROCK_API_KEY (required)
  • ROBOTROCK_BASE_URL or ROBOTROCK_API_URL (optional)
  • ROBOTROCK_APP (optional default inbox app bucket; override per call with app on the payload)

sendToHumanInWorkflow

Call from a function whose first statement is "use workflow":

import { sendToHumanInWorkflow } from "robotrock/workflow";

export async function deploymentApproval(version: string) {
  "use workflow";

  const result = await sendToHumanInWorkflow({
    type: "deploy-approval",
    name: `Deploy ${version}`,
    description: "Approve production deployment",
    actions: [
      { id: "approve", title: "Deploy now" },
      { id: "reject", title: "Block deploy" },
    ] as const,
    context: {
      data: { version },
    },
  });

  if (result.actionId === "reject") {
    throw new Error("Deploy blocked");
  }

  return { deployed: true, version, handledBy: result.handledBy };
}

approveByHumanInWorkflow

Fixed approve / decline actions:

import { approveByHumanInWorkflow } from "robotrock/workflow";

export async function releaseGate(name: string) {
  "use workflow";

  const result = await approveByHumanInWorkflow({
    type: "release-gate",
    name,
    description: "Confirm release to production",
  });

  return result.actionId === "approve";
}

Webhook security

createWebhook() exposes a public URL at /.well-known/workflow/v1/webhook/:token. That is convenient for RobotRock callbacks but is not authenticated beyond the random token.

For stricter control, use createHook() in your own workflow and call resumeHook() from a verified API route after verifyRobotRockWebhook() — see Webhooks.

Vercel AI SDK (mode: "workflow")

When tools run inside a workflow (for example DurableAgent tool execute without "use step"), pass workflow mode so execute uses webhooks instead of polling:

import { DurableAgent } from "@workflow/ai/agent";
import { approveByHumanTool } from "robotrock/ai/workflow";

const approveByHuman = approveByHumanTool({
  mode: "workflow",
  app: "my-agent",
});

// Register approveByHuman on your agent tools — execute suspends until a human decides

Tool approval bridge in a workflow-backed agent:

import { runWithRobotRockApprovals } from "robotrock/ai/workflow";

await runWithRobotRockApprovals({
  context: { mode: "workflow", app: "my-agent" },
  generate: (messages) => generateText({ model, tools, toolApproval, messages, prompt }),
});

Import paths: robotrock/ai (all modes), robotrock/ai/workflow (workflow-oriented docs and re-exports).

Workflow-level vs step-level tools

CapabilityStep ("use step")Workflow ("use workflow")
createWebhook()NoYes
RobotRock sendToHumanInWorkflowOrchestrated from workflowYes
approveByHumanTool({ mode: "workflow" })No — use workflow-level executeYes

RobotRock API calls inside sendToHumanInWorkflow run in an internal "use step" for retries and full Node.js access. Your workflow function should stay at the workflow level and call sendToHumanInWorkflow directly.

On this page