RobotRock

Updates

Updates are short status messages (1-2 sentences) attached to a thread. They show in a status bar at the top of the task detail view in the inbox, with an icon and color driven by an optional lifecycle status. Every update is logged, so reviewers can expand the full update history for a thread.

Use updates to keep a human reviewer informed about long-running work without creating a new task—for example, an agent reporting running, then succeeded or failed against the same thread it created.

How it works

  1. Updates are scoped to a threadId. Send them for any thread that already has at least one task in your tenant.
  2. Each update has a message and an optional status. The newest update renders as a status bar; older updates appear in an expandable log.
  3. You can send updates two ways: standalone with sendUpdate, or inline when you create a task with the update field.

Send a standalone update

Use client.sendUpdate with the thread's threadId (returned on task.threadId when you create a task).

import { robotrock } from "@/lib/robotrock";

await robotrock.sendUpdate({
  threadId: "thread_123",
  message: "Deployment started, running smoke tests.",
  status: "running",
});

sendUpdate returns the created update:

const update = await robotrock.sendUpdate({
  threadId,
  message: "All checks passed.",
  status: "succeeded",
});

console.log(update.id, update.status, update.createdAt);

If no task exists for the threadId in your tenant, the API returns 404.

Send an update when creating a task

Pass update to sendToHuman (or createTask) to log an initial update against the new task's thread:

await robotrock.sendToHuman({
  type: "deploy-approval",
  name: "Approve production rollout",
  threadId: `deploy_${deploymentId}`,
  update: { message: "Build finished, awaiting approval.", status: "waiting" },
  actions: [{ id: "approve", title: "Approve" }],
});

update is a top-level field—like threadId and assignTo, it is not part of context.

Status values

status is optional and defaults to info. Each value maps to an icon and color in the status bar:

StatusMeaning
infoNeutral informational message (default)
queuedWork is queued and not started yet
runningWork is in progress
waitingBlocked or waiting on input
succeededCompleted successfully
failedErrored or failed
cancelledAborted or cancelled

Field reference

FieldTypeNotes
threadIdstringThe thread to log against. Required for sendUpdate.
messagestring1-2 sentences. Max 500 characters.
statusenum (optional)One of the values above. Defaults to info.

Inbox behavior

  • The newest update shows as a status bar at the top of the task detail view, with the status icon and color.
  • When a thread has more than one update, the bar shows an "N updates" toggle that expands the full log, newest first.
  • For multi-task threads, the status bar and log render once at the top of the stacked thread view.

Integrations

sendUpdate is fire-and-forget (no human wait), so the integration packages wrap it differently from sendToHuman.

Vercel Workflow

Inside a "use workflow" function, network calls must run in a step. sendUpdateInWorkflow() wraps sendUpdate in a durable, retried step:

import { sendToHumanInWorkflow, sendUpdateInWorkflow } from "robotrock/workflow";

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

  const threadId = `deploy_${version}`;

  await sendUpdateInWorkflow({ threadId, message: "Build started.", status: "running" });

  const result = await sendToHumanInWorkflow({
    type: "deploy-approval",
    name: `Deploy ${version}`,
    threadId,
    actions: [{ id: "approve", title: "Deploy" }] as const,
  });

  await sendUpdateInWorkflow({
    threadId,
    message: result.actionId === "approve" ? "Deploying." : "Blocked.",
    status: result.actionId === "approve" ? "succeeded" : "cancelled",
  });
}

Vercel AI SDK

Give an agent a tool to report progress on the thread it is working on. The tool resolves the thread from the model-supplied threadId, or a session threadId you configure:

import { createSendUpdateTool } from "robotrock/ai";

const sendUpdate = createSendUpdateTool(robotrock, { threadId: "thread_123" });

Or build the whole tool set with a shared session thread so tasks and updates auto-thread together:

import { createRobotRockAiTools } from "robotrock/ai";

const tools = createRobotRockAiTools({ client: robotrock, threadId: "session_42" });

const result = await generateText({
  model: "anthropic/claude-sonnet-4",
  tools: {
    sendToHuman: tools.sendToHuman({ actions: [{ id: "ack", title: "Acknowledge" }] }),
    sendUpdate: tools.sendUpdate(),
  },
  prompt: "Work the task and post progress updates as you go.",
});

For Trigger.dev or Workflow, pass a durable context instead of a client: createSendUpdateTool({ mode: "workflow", app: "my-agent" }).

Because updates are fire-and-forget, the tool never aborts the agent loop when the thread has no task yet. Instead of throwing, it returns { posted: false, reason: "thread_not_found" } so the model can create a task first and keep going. Successful posts return { posted: true, update }. Genuine failures (auth, validation, server errors) still throw.

Trigger.dev

sendUpdate returns immediately, so it needs no wait token. Call the SDK directly inside any task:

import { task } from "@trigger.dev/sdk";
import { createClient } from "robotrock";

export const reportProgress = task({
  id: "report-progress",
  run: async ({ threadId }: { threadId: string }) => {
    const robotrock = createClient({ apiKey: process.env.ROBOTROCK_API_KEY! });
    await robotrock.sendUpdate({ threadId, message: "Job running.", status: "running" });
  },
});

On this page