feat: add heartbeat visibility filtering for webchat

- Add isHeartbeat to AgentRunContext to track heartbeat runs
- Pass isHeartbeat flag through agent runner execution
- Suppress webchat broadcast (deltas + final) for heartbeat runs when showOk is false
- Webchat uses channels.defaults.heartbeat settings (no per-channel config)
- Default behavior: hide HEARTBEAT_OK from webchat (matches other channels)

This allows users to control whether heartbeat responses appear in
the webchat UI via channels.defaults.heartbeat.showOk (defaults to false).
This commit is contained in:
Dave Lauer
2026-01-26 16:03:59 -05:00
committed by Vignesh
parent b3a60af71c
commit 2807f5afbc
5 changed files with 104 additions and 4 deletions

View File

@@ -1,6 +1,6 @@
import type { ClawdbotConfig } from "../config/config.js";
import type { ChannelHeartbeatVisibilityConfig } from "../config/types.channels.js";
import type { DeliverableMessageChannel } from "../utils/message-channel.js";
import type { DeliverableMessageChannel, GatewayMessageChannel } from "../utils/message-channel.js";
export type ResolvedHeartbeatVisibility = {
showOk: boolean;
@@ -14,13 +14,28 @@ const DEFAULT_VISIBILITY: ResolvedHeartbeatVisibility = {
useIndicator: true, // Emit indicator events
};
/**
* Resolve heartbeat visibility settings for a channel.
* Supports both deliverable channels (telegram, signal, etc.) and webchat.
* For webchat, uses channels.defaults.heartbeat since webchat doesn't have per-channel config.
*/
export function resolveHeartbeatVisibility(params: {
cfg: ClawdbotConfig;
channel: DeliverableMessageChannel;
channel: GatewayMessageChannel;
accountId?: string;
}): ResolvedHeartbeatVisibility {
const { cfg, channel, accountId } = params;
// Webchat uses channel defaults only (no per-channel or per-account config)
if (channel === "webchat") {
const channelDefaults = cfg.channels?.defaults?.heartbeat;
return {
showOk: channelDefaults?.showOk ?? DEFAULT_VISIBILITY.showOk,
showAlerts: channelDefaults?.showAlerts ?? DEFAULT_VISIBILITY.showAlerts,
useIndicator: channelDefaults?.useIndicator ?? DEFAULT_VISIBILITY.useIndicator,
};
}
// Layer 1: Global channel defaults
const channelDefaults = cfg.channels?.defaults?.heartbeat;