mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 21:58:26 +00:00
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
250
src/infra/heartbeat-visibility.test.ts
Normal file
250
src/infra/heartbeat-visibility.test.ts
Normal file
@@ -0,0 +1,250 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import type { ClawdbotConfig } from "../config/config.js";
|
||||
import { resolveHeartbeatVisibility } from "./heartbeat-visibility.js";
|
||||
|
||||
describe("resolveHeartbeatVisibility", () => {
|
||||
it("returns default values when no config is provided", () => {
|
||||
const cfg = {} as ClawdbotConfig;
|
||||
const result = resolveHeartbeatVisibility({ cfg, channel: "telegram" });
|
||||
|
||||
expect(result).toEqual({
|
||||
showOk: false,
|
||||
showAlerts: true,
|
||||
useIndicator: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("uses channel defaults when provided", () => {
|
||||
const cfg = {
|
||||
channels: {
|
||||
defaults: {
|
||||
heartbeat: {
|
||||
showOk: true,
|
||||
showAlerts: false,
|
||||
useIndicator: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
|
||||
const result = resolveHeartbeatVisibility({ cfg, channel: "telegram" });
|
||||
|
||||
expect(result).toEqual({
|
||||
showOk: true,
|
||||
showAlerts: false,
|
||||
useIndicator: false,
|
||||
});
|
||||
});
|
||||
|
||||
it("per-channel config overrides channel defaults", () => {
|
||||
const cfg = {
|
||||
channels: {
|
||||
defaults: {
|
||||
heartbeat: {
|
||||
showOk: false,
|
||||
showAlerts: true,
|
||||
useIndicator: true,
|
||||
},
|
||||
},
|
||||
telegram: {
|
||||
heartbeat: {
|
||||
showOk: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
|
||||
const result = resolveHeartbeatVisibility({ cfg, channel: "telegram" });
|
||||
|
||||
expect(result).toEqual({
|
||||
showOk: true,
|
||||
showAlerts: true,
|
||||
useIndicator: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("per-account config overrides per-channel config", () => {
|
||||
const cfg = {
|
||||
channels: {
|
||||
defaults: {
|
||||
heartbeat: {
|
||||
showOk: false,
|
||||
showAlerts: true,
|
||||
useIndicator: true,
|
||||
},
|
||||
},
|
||||
telegram: {
|
||||
heartbeat: {
|
||||
showOk: false,
|
||||
showAlerts: false,
|
||||
},
|
||||
accounts: {
|
||||
primary: {
|
||||
heartbeat: {
|
||||
showOk: true,
|
||||
showAlerts: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
|
||||
const result = resolveHeartbeatVisibility({
|
||||
cfg,
|
||||
channel: "telegram",
|
||||
accountId: "primary",
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
showOk: true,
|
||||
showAlerts: true,
|
||||
useIndicator: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("falls through to defaults when account has no heartbeat config", () => {
|
||||
const cfg = {
|
||||
channels: {
|
||||
defaults: {
|
||||
heartbeat: {
|
||||
showOk: false,
|
||||
},
|
||||
},
|
||||
telegram: {
|
||||
heartbeat: {
|
||||
showAlerts: false,
|
||||
},
|
||||
accounts: {
|
||||
primary: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
|
||||
const result = resolveHeartbeatVisibility({
|
||||
cfg,
|
||||
channel: "telegram",
|
||||
accountId: "primary",
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
showOk: false,
|
||||
showAlerts: false,
|
||||
useIndicator: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("handles missing accountId gracefully", () => {
|
||||
const cfg = {
|
||||
channels: {
|
||||
telegram: {
|
||||
heartbeat: {
|
||||
showOk: true,
|
||||
},
|
||||
accounts: {
|
||||
primary: {
|
||||
heartbeat: {
|
||||
showOk: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
|
||||
const result = resolveHeartbeatVisibility({ cfg, channel: "telegram" });
|
||||
|
||||
expect(result.showOk).toBe(true);
|
||||
});
|
||||
|
||||
it("handles non-existent account gracefully", () => {
|
||||
const cfg = {
|
||||
channels: {
|
||||
telegram: {
|
||||
heartbeat: {
|
||||
showOk: true,
|
||||
},
|
||||
accounts: {
|
||||
primary: {
|
||||
heartbeat: {
|
||||
showOk: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
|
||||
const result = resolveHeartbeatVisibility({
|
||||
cfg,
|
||||
channel: "telegram",
|
||||
accountId: "nonexistent",
|
||||
});
|
||||
|
||||
expect(result.showOk).toBe(true);
|
||||
});
|
||||
|
||||
it("works with whatsapp channel", () => {
|
||||
const cfg = {
|
||||
channels: {
|
||||
whatsapp: {
|
||||
heartbeat: {
|
||||
showOk: true,
|
||||
showAlerts: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
|
||||
const result = resolveHeartbeatVisibility({ cfg, channel: "whatsapp" });
|
||||
|
||||
expect(result).toEqual({
|
||||
showOk: true,
|
||||
showAlerts: false,
|
||||
useIndicator: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("works with discord channel", () => {
|
||||
const cfg = {
|
||||
channels: {
|
||||
discord: {
|
||||
heartbeat: {
|
||||
useIndicator: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
|
||||
const result = resolveHeartbeatVisibility({ cfg, channel: "discord" });
|
||||
|
||||
expect(result).toEqual({
|
||||
showOk: false,
|
||||
showAlerts: true,
|
||||
useIndicator: false,
|
||||
});
|
||||
});
|
||||
|
||||
it("works with slack channel", () => {
|
||||
const cfg = {
|
||||
channels: {
|
||||
slack: {
|
||||
heartbeat: {
|
||||
showOk: true,
|
||||
showAlerts: true,
|
||||
useIndicator: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
|
||||
const result = resolveHeartbeatVisibility({ cfg, channel: "slack" });
|
||||
|
||||
expect(result).toEqual({
|
||||
showOk: true,
|
||||
showAlerts: true,
|
||||
useIndicator: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user