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:
committed by
Peter Steinberger
parent
9b12275fe1
commit
f9cf508cff
@@ -7,8 +7,19 @@ import type { TelegramConfig } from "./types.telegram.js";
|
||||
import type { WhatsAppConfig } from "./types.whatsapp.js";
|
||||
import type { GroupPolicy } from "./types.base.js";
|
||||
|
||||
export type ChannelHeartbeatVisibilityConfig = {
|
||||
/** Show HEARTBEAT_OK acknowledgments in chat (default: false). */
|
||||
showOk?: boolean;
|
||||
/** Show heartbeat alerts with actual content (default: true). */
|
||||
showAlerts?: boolean;
|
||||
/** Emit indicator events for UI status display (default: true). */
|
||||
useIndicator?: boolean;
|
||||
};
|
||||
|
||||
export type ChannelDefaultsConfig = {
|
||||
groupPolicy?: GroupPolicy;
|
||||
/** Default heartbeat visibility for all channels. */
|
||||
heartbeat?: ChannelHeartbeatVisibilityConfig;
|
||||
};
|
||||
|
||||
export type ChannelsConfig = {
|
||||
|
||||
@@ -6,6 +6,7 @@ import type {
|
||||
OutboundRetryConfig,
|
||||
ReplyToMode,
|
||||
} from "./types.base.js";
|
||||
import type { ChannelHeartbeatVisibilityConfig } from "./types.channels.js";
|
||||
import type { DmConfig, ProviderCommandsConfig } from "./types.messages.js";
|
||||
import type { GroupToolPolicyConfig } from "./types.tools.js";
|
||||
|
||||
@@ -121,6 +122,8 @@ export type DiscordAccountConfig = {
|
||||
dm?: DiscordDmConfig;
|
||||
/** New per-guild config keyed by guild id or slug. */
|
||||
guilds?: Record<string, DiscordGuildEntry>;
|
||||
/** Heartbeat visibility settings for this channel. */
|
||||
heartbeat?: ChannelHeartbeatVisibilityConfig;
|
||||
};
|
||||
|
||||
export type DiscordConfig = {
|
||||
|
||||
@@ -4,6 +4,7 @@ import type {
|
||||
GroupPolicy,
|
||||
MarkdownConfig,
|
||||
} from "./types.base.js";
|
||||
import type { ChannelHeartbeatVisibilityConfig } from "./types.channels.js";
|
||||
import type { DmConfig } from "./types.messages.js";
|
||||
import type { GroupToolPolicyConfig } from "./types.tools.js";
|
||||
|
||||
@@ -63,6 +64,8 @@ export type IMessageAccountConfig = {
|
||||
tools?: GroupToolPolicyConfig;
|
||||
}
|
||||
>;
|
||||
/** Heartbeat visibility settings for this channel. */
|
||||
heartbeat?: ChannelHeartbeatVisibilityConfig;
|
||||
};
|
||||
|
||||
export type IMessageConfig = {
|
||||
|
||||
@@ -4,6 +4,7 @@ import type {
|
||||
GroupPolicy,
|
||||
MarkdownConfig,
|
||||
} from "./types.base.js";
|
||||
import type { ChannelHeartbeatVisibilityConfig } from "./types.channels.js";
|
||||
import type { DmConfig } from "./types.messages.js";
|
||||
import type { GroupToolPolicyConfig } from "./types.tools.js";
|
||||
|
||||
@@ -94,4 +95,6 @@ export type MSTeamsConfig = {
|
||||
mediaMaxMb?: number;
|
||||
/** SharePoint site ID for file uploads in group chats/channels (e.g., "contoso.sharepoint.com,guid1,guid2"). */
|
||||
sharePointSiteId?: string;
|
||||
/** Heartbeat visibility settings for this channel. */
|
||||
heartbeat?: ChannelHeartbeatVisibilityConfig;
|
||||
};
|
||||
|
||||
@@ -4,6 +4,7 @@ import type {
|
||||
GroupPolicy,
|
||||
MarkdownConfig,
|
||||
} from "./types.base.js";
|
||||
import type { ChannelHeartbeatVisibilityConfig } from "./types.channels.js";
|
||||
import type { DmConfig } from "./types.messages.js";
|
||||
|
||||
export type SignalReactionNotificationMode = "off" | "own" | "all" | "allowlist";
|
||||
@@ -63,6 +64,8 @@ export type SignalAccountConfig = {
|
||||
reactionNotifications?: SignalReactionNotificationMode;
|
||||
/** Allowlist for reaction notifications when mode is allowlist. */
|
||||
reactionAllowlist?: Array<string | number>;
|
||||
/** Heartbeat visibility settings for this channel. */
|
||||
heartbeat?: ChannelHeartbeatVisibilityConfig;
|
||||
};
|
||||
|
||||
export type SignalConfig = {
|
||||
|
||||
@@ -5,6 +5,7 @@ import type {
|
||||
MarkdownConfig,
|
||||
ReplyToMode,
|
||||
} from "./types.base.js";
|
||||
import type { ChannelHeartbeatVisibilityConfig } from "./types.channels.js";
|
||||
import type { DmConfig, ProviderCommandsConfig } from "./types.messages.js";
|
||||
import type { GroupToolPolicyConfig } from "./types.tools.js";
|
||||
|
||||
@@ -136,6 +137,8 @@ export type SlackAccountConfig = {
|
||||
slashCommand?: SlackSlashCommandConfig;
|
||||
dm?: SlackDmConfig;
|
||||
channels?: Record<string, SlackChannelConfig>;
|
||||
/** Heartbeat visibility settings for this channel. */
|
||||
heartbeat?: ChannelHeartbeatVisibilityConfig;
|
||||
};
|
||||
|
||||
export type SlackConfig = {
|
||||
|
||||
@@ -7,6 +7,7 @@ import type {
|
||||
OutboundRetryConfig,
|
||||
ReplyToMode,
|
||||
} from "./types.base.js";
|
||||
import type { ChannelHeartbeatVisibilityConfig } from "./types.channels.js";
|
||||
import type { DmConfig, ProviderCommandsConfig } from "./types.messages.js";
|
||||
import type { GroupToolPolicyConfig } from "./types.tools.js";
|
||||
|
||||
@@ -113,6 +114,8 @@ export type TelegramAccountConfig = {
|
||||
* - "extensive": agent can react liberally when appropriate
|
||||
*/
|
||||
reactionLevel?: "off" | "ack" | "minimal" | "extensive";
|
||||
/** Heartbeat visibility settings for this channel. */
|
||||
heartbeat?: ChannelHeartbeatVisibilityConfig;
|
||||
};
|
||||
|
||||
export type TelegramTopicConfig = {
|
||||
|
||||
@@ -4,6 +4,7 @@ import type {
|
||||
GroupPolicy,
|
||||
MarkdownConfig,
|
||||
} from "./types.base.js";
|
||||
import type { ChannelHeartbeatVisibilityConfig } from "./types.channels.js";
|
||||
import type { DmConfig } from "./types.messages.js";
|
||||
import type { GroupToolPolicyConfig } from "./types.tools.js";
|
||||
|
||||
@@ -86,6 +87,8 @@ export type WhatsAppConfig = {
|
||||
};
|
||||
/** Debounce window (ms) for batching rapid consecutive messages from the same sender (0 to disable). */
|
||||
debounceMs?: number;
|
||||
/** Heartbeat visibility settings for this channel. */
|
||||
heartbeat?: ChannelHeartbeatVisibilityConfig;
|
||||
};
|
||||
|
||||
export type WhatsAppAccountConfig = {
|
||||
@@ -147,4 +150,6 @@ export type WhatsAppAccountConfig = {
|
||||
};
|
||||
/** Debounce window (ms) for batching rapid consecutive messages from the same sender (0 to disable). */
|
||||
debounceMs?: number;
|
||||
/** Heartbeat visibility settings for this account. */
|
||||
heartbeat?: ChannelHeartbeatVisibilityConfig;
|
||||
};
|
||||
|
||||
10
src/config/zod-schema.channels.ts
Normal file
10
src/config/zod-schema.channels.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const ChannelHeartbeatVisibilitySchema = z
|
||||
.object({
|
||||
showOk: z.boolean().optional(),
|
||||
showAlerts: z.boolean().optional(),
|
||||
useIndicator: z.boolean().optional(),
|
||||
})
|
||||
.strict()
|
||||
.optional();
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
requireOpenAllowFrom,
|
||||
} from "./zod-schema.core.js";
|
||||
import { ToolPolicySchema } from "./zod-schema.agent-runtime.js";
|
||||
import { ChannelHeartbeatVisibilitySchema } from "./zod-schema.channels.js";
|
||||
import {
|
||||
normalizeTelegramCommandDescription,
|
||||
normalizeTelegramCommandName,
|
||||
@@ -122,6 +123,7 @@ export const TelegramAccountSchemaBase = z
|
||||
.optional(),
|
||||
reactionNotifications: z.enum(["off", "own", "all"]).optional(),
|
||||
reactionLevel: z.enum(["off", "ack", "minimal", "extensive"]).optional(),
|
||||
heartbeat: ChannelHeartbeatVisibilitySchema,
|
||||
})
|
||||
.strict();
|
||||
|
||||
@@ -241,6 +243,7 @@ export const DiscordAccountSchema = z
|
||||
replyToMode: ReplyToModeSchema.optional(),
|
||||
dm: DiscordDmSchema.optional(),
|
||||
guilds: z.record(z.string(), DiscordGuildSchema.optional()).optional(),
|
||||
heartbeat: ChannelHeartbeatVisibilitySchema,
|
||||
})
|
||||
.strict();
|
||||
|
||||
@@ -351,6 +354,7 @@ export const SlackAccountSchema = z
|
||||
.optional(),
|
||||
dm: SlackDmSchema.optional(),
|
||||
channels: z.record(z.string(), SlackChannelSchema.optional()).optional(),
|
||||
heartbeat: ChannelHeartbeatVisibilitySchema,
|
||||
})
|
||||
.strict();
|
||||
|
||||
@@ -416,6 +420,7 @@ export const SignalAccountSchemaBase = z
|
||||
mediaMaxMb: z.number().int().positive().optional(),
|
||||
reactionNotifications: z.enum(["off", "own", "all", "allowlist"]).optional(),
|
||||
reactionAllowlist: z.array(z.union([z.string(), z.number()])).optional(),
|
||||
heartbeat: ChannelHeartbeatVisibilitySchema,
|
||||
})
|
||||
.strict();
|
||||
|
||||
@@ -477,6 +482,7 @@ export const IMessageAccountSchemaBase = z
|
||||
.optional(),
|
||||
)
|
||||
.optional(),
|
||||
heartbeat: ChannelHeartbeatVisibilitySchema,
|
||||
})
|
||||
.strict();
|
||||
|
||||
@@ -553,6 +559,7 @@ export const BlueBubblesAccountSchemaBase = z
|
||||
blockStreaming: z.boolean().optional(),
|
||||
blockStreamingCoalesce: BlockStreamingCoalesceSchema.optional(),
|
||||
groups: z.record(z.string(), BlueBubblesGroupConfigSchema.optional()).optional(),
|
||||
heartbeat: ChannelHeartbeatVisibilitySchema,
|
||||
})
|
||||
.strict();
|
||||
|
||||
@@ -630,6 +637,7 @@ export const MSTeamsConfigSchema = z
|
||||
mediaMaxMb: z.number().positive().optional(),
|
||||
/** SharePoint site ID for file uploads in group chats/channels (e.g., "contoso.sharepoint.com,guid1,guid2") */
|
||||
sharePointSiteId: z.string().optional(),
|
||||
heartbeat: ChannelHeartbeatVisibilitySchema,
|
||||
})
|
||||
.strict()
|
||||
.superRefine((value, ctx) => {
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
MarkdownConfigSchema,
|
||||
} from "./zod-schema.core.js";
|
||||
import { ToolPolicySchema } from "./zod-schema.agent-runtime.js";
|
||||
import { ChannelHeartbeatVisibilitySchema } from "./zod-schema.channels.js";
|
||||
|
||||
export const WhatsAppAccountSchema = z
|
||||
.object({
|
||||
@@ -53,6 +54,7 @@ export const WhatsAppAccountSchema = z
|
||||
.strict()
|
||||
.optional(),
|
||||
debounceMs: z.number().int().nonnegative().optional().default(0),
|
||||
heartbeat: ChannelHeartbeatVisibilitySchema,
|
||||
})
|
||||
.strict()
|
||||
.superRefine((value, ctx) => {
|
||||
@@ -115,6 +117,7 @@ export const WhatsAppConfigSchema = z
|
||||
.strict()
|
||||
.optional(),
|
||||
debounceMs: z.number().int().nonnegative().optional().default(0),
|
||||
heartbeat: ChannelHeartbeatVisibilitySchema,
|
||||
})
|
||||
.strict()
|
||||
.superRefine((value, ctx) => {
|
||||
|
||||
@@ -11,15 +11,18 @@ import {
|
||||
} from "./zod-schema.providers-core.js";
|
||||
import { WhatsAppConfigSchema } from "./zod-schema.providers-whatsapp.js";
|
||||
import { GroupPolicySchema } from "./zod-schema.core.js";
|
||||
import { ChannelHeartbeatVisibilitySchema } from "./zod-schema.channels.js";
|
||||
|
||||
export * from "./zod-schema.providers-core.js";
|
||||
export * from "./zod-schema.providers-whatsapp.js";
|
||||
export { ChannelHeartbeatVisibilitySchema } from "./zod-schema.channels.js";
|
||||
|
||||
export const ChannelsSchema = z
|
||||
.object({
|
||||
defaults: z
|
||||
.object({
|
||||
groupPolicy: GroupPolicySchema.optional(),
|
||||
heartbeat: ChannelHeartbeatVisibilitySchema,
|
||||
})
|
||||
.strict()
|
||||
.optional(),
|
||||
|
||||
Reference in New Issue
Block a user