Notifications

Multi-channel HITL notification dispatch: Slack, Teams, Discord, Telegram, and webhooks.

Overview

@consensus-tools/notifications handles multi-channel human-in-the-loop notification dispatch. Send approval prompts, timeout warnings, and deadline expiry notices to Slack, Teams, Discord, Telegram, or a generic webhook. Automatically falls back to webhook when targeted delivery fails.

Installation

pnpm add @consensus-tools/notifications

Quick start

Send an approval prompt

import { sendHumanApprovalPrompt, nullCredentials } from "@consensus-tools/notifications";
import type { ChatPrompt } from "@consensus-tools/notifications";

const prompt: ChatPrompt = {
  boardId: "board-1",
  runId: "run-42",
  quorum: 0.6,
  risk: 0.85,
  threshold: 0.7,
  promptMode: "yes-no",
  timeoutSec: 300,
  chatTargets: [
    { subjectId: "user-1", adapter: "slack", handle: "U12345ABC" },
    { subjectId: "user-2", adapter: "discord", handle: "987654321" },
  ],
};

const result = await sendHumanApprovalPrompt(prompt, nullCredentials, "stdout");
// => { delivered: true, provider: "stdout", message: "...", promptMode: "yes-no", results: [...] }

Prompt modes: "yes-no" | "approve-reject-revise" | "acknowledge" | "vote"

API reference

Timeout and deadline notifications

import { sendTimeoutWarning, sendDeadlineExpired, nullCredentials } from "@consensus-tools/notifications";

// Warn approvers that time is running out
await sendTimeoutWarning(prompt, 120, nullCredentials); // 120 seconds remaining

// Notify that the deadline has passed with an auto-decision
await sendDeadlineExpired(prompt, "BLOCK", nullCredentials);

Direct channel adapters

import { sendSlackDM, sendDiscordDM, sendViaWebhook } from "@consensus-tools/notifications";

const target = { subjectId: "user-1", adapter: "slack", handle: "U12345ABC" };
const meta = { boardId: "board-1", runId: "run-42", type: "human_approval_request" };
const result = await sendSlackDM(target, "Please review run-42", meta, credentials);
// => { target, delivered: true, provider: "slack", messageId: "1234.5678" }

Credentials are resolved from a CredentialProvider (e.g. CredentialManager from @consensus-tools/secrets) or environment variables (SLACK_BOT_TOKEN, CHAT_WEBHOOK_URL).

Format mentions

import { formatMention } from "@consensus-tools/notifications";

formatMention("slack", "U12345ABC");   // "<@U12345ABC>"
formatMention("discord", "987654321"); // "<@987654321>"
formatMention("teams", "alice");       // "<at>alice</at>"
formatMention("telegram", "bob");      // "@bob"

Exports reference

ExportKindDescription
sendHumanApprovalPromptFunction(prompt, credentials, chatProvider?) => Promise<PromptResult>
sendTimeoutWarningFunction(prompt, remainingSec, credentials, chatProvider?) => Promise<PromptResult>
sendDeadlineExpiredFunction(prompt, autoDecision, credentials, chatProvider?) => Promise<PromptResult>
formatMentionFunction(adapter, handle) => string
sendSlackDMFunctionDirect Slack DM via Bot API
sendTeamsDMFunctionDirect Teams DM
sendDiscordDMFunctionDirect Discord DM
sendTelegramDMFunctionDirect Telegram DM
sendViaWebhookFunctionGeneric webhook POST
nullCredentialsObjectNo-op CredentialProvider for testing (stdout delivery)
ChatTargetType{ subjectId, adapter, handle }
ChatPromptTypeFull prompt config (boardId, runId, quorum, risk, targets, etc.)
DeliveryResultTypePer-target delivery outcome
PromptResultTypeAggregate result with all DeliveryResults
CredentialProviderType{ get(provider, keyName) => string | null }
  • workflows -- HITL nodes dispatch via this package
  • core -- HitlTracker tracks approval state; notifications send the prompts