Notifications

Send contextual messages to the reviewer's channel without creating a new approval step. Use notify for updates while a request is pending, or to keep a conversation thread across multiple human steps.

Import

import { notify } from "@/lib/hitl-client";

notify

Signature

notify(notification: NotifyOptions): Promise<TimelineAnchor>

Options

NotifyOptions is a discriminated union of three shapes:

Anchor to a prior step (after)

notify({
  after: HumanPending | HumanBatchPending | HumanResult | TimelineAnchor,
  message: string,
  channel?: string,
  detail?: Record<string, unknown>,
})

Posts in the same chat thread as the referenced step. Most common pattern after requestHuman.

Anchor by id (on)

notify({
  on: string, // human request or batch id
  message: string,
  channel?: string,
  detail?: Record<string, unknown>,
})

Use when you have an id but not the full pending object (e.g. from stored context).

Standalone

notify({
  message: string,
  channel?: string,
  detail?: Record<string, unknown>,
})

Delivers to the default channel without threading.

FieldTypeDescription
messagestringNotification body shown in the channel
afterpending / result / anchorThread under this step
onstringRequest or batch id when after is unavailable
detailRecord<string, unknown>Opaque metadata (not shown to reviewer by default)
channelstringAdapter id or adapter_id:destination; defaults to first configured adapter

Returns

TimelineAnchor ({ id, externalRef }). Use as after on a subsequent requestHuman or waitForHuman call to keep threading.

Example

import { actions } from "@hitl-sdk/hitl";
import { requestHuman, notify, waitForHuman } from "@/lib/hitl-client";

const pending = await requestHuman({
  message: `Say hello to ${name}?`,
  actions: actions().approve({ label: "Approve" }).deny({ label: "Deny" }).build(),
});

await notify({
  after: pending,
  message: `Context for ${name}`,
  detail: { requestedAt: new Date().toISOString() },
});

const response = await waitForHuman(pending);

TimelineAnchor

Pending handles, resolved results, and notify return values all implement TimelineAnchor:

interface TimelineAnchor {
  id: string;
  externalRef: string;
}
FieldDescription
idHitl request or batch id
externalRefAdapter-native message ref (empty string when none)

Pass any anchor as after on requestHuman, waitForHuman, or notify to post in the same channel thread.

Thread chaining

Chain pending steps, notifications, and resolved results in one conversation thread.

While pending

Post context after creating a request, before waiting:

const pending = await requestHuman({ message: "Approve expense?", actions });
await notify({ after: pending, message: "Receipt attached in thread" });
const result = await waitForHuman(pending, { timeout: "72h" });

Multi-step approvals

Post a follow-up request in the same chat thread after a resolved step:

const first = await waitForHuman({ message: "Initial review?", actions });

const second = await requestHuman({
  message: "Follow-up: any changes needed?",
  actions,
  after: first,
});

const followUp = await waitForHuman(second);

After resolution

Notify after a resolved step, then start a follow-up request in the same thread:

const first = await waitForHuman({ message: "Approve draft?", actions });

await notify({
  after: first,
  message: "Draft was approved. Scheduling send for tomorrow.",
});

const second = await requestHuman({
  message: "Confirm send time?",
  actions,
  after: first,
});

See also