feat(heartbeat): add configurable visibility for heartbeat responses

Add per-channel and per-account heartbeat visibility settings:
- showOk: hide/show HEARTBEAT_OK messages (default: false)
- showAlerts: hide/show alert messages (default: true)
- useIndicator: emit typing indicator events (default: true)

Config precedence: per-account > per-channel > channel-defaults > global

This allows silencing routine heartbeat acks while still surfacing
alerts when something needs attention.
This commit is contained in:
Dave Lauer
2026-01-22 10:54:07 -05:00
committed by Peter Steinberger
parent 9b12275fe1
commit f9cf508cff
18 changed files with 695 additions and 6 deletions

View File

@@ -0,0 +1,58 @@
import type { ClawdbotConfig } from "../config/config.js";
import type { ChannelHeartbeatVisibilityConfig } from "../config/types.channels.js";
import type { DeliverableMessageChannel } from "../utils/message-channel.js";
export type ResolvedHeartbeatVisibility = {
showOk: boolean;
showAlerts: boolean;
useIndicator: boolean;
};
const DEFAULT_VISIBILITY: ResolvedHeartbeatVisibility = {
showOk: false, // Silent by default
showAlerts: true, // Show content messages
useIndicator: true, // Emit indicator events
};
export function resolveHeartbeatVisibility(params: {
cfg: ClawdbotConfig;
channel: DeliverableMessageChannel;
accountId?: string;
}): ResolvedHeartbeatVisibility {
const { cfg, channel, accountId } = params;
// Layer 1: Global channel defaults
const channelDefaults = cfg.channels?.defaults?.heartbeat;
// Layer 2: Per-channel config (at channel root level)
const channelCfg = cfg.channels?.[channel] as
| {
heartbeat?: ChannelHeartbeatVisibilityConfig;
accounts?: Record<string, { heartbeat?: ChannelHeartbeatVisibilityConfig }>;
}
| undefined;
const perChannel = channelCfg?.heartbeat;
// Layer 3: Per-account config (most specific)
const accountCfg = accountId ? channelCfg?.accounts?.[accountId] : undefined;
const perAccount = accountCfg?.heartbeat;
// Precedence: per-account > per-channel > channel-defaults > global defaults
return {
showOk:
perAccount?.showOk ??
perChannel?.showOk ??
channelDefaults?.showOk ??
DEFAULT_VISIBILITY.showOk,
showAlerts:
perAccount?.showAlerts ??
perChannel?.showAlerts ??
channelDefaults?.showAlerts ??
DEFAULT_VISIBILITY.showAlerts,
useIndicator:
perAccount?.useIndicator ??
perChannel?.useIndicator ??
channelDefaults?.useIndicator ??
DEFAULT_VISIBILITY.useIndicator,
};
}