-
Notifications
You must be signed in to change notification settings - Fork 15.3k
fix multi‑agent heartbeats, sessions, and probes + health/status calls #1047
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
The Telegram webhook and monitor now accept and pass through accountId and config parameters, enabling routing and configuration per Telegram account. Tests have been updated to verify correct bot instantiation and DM routing based on accountId bindings.
- Align health/status with multi‑agent heartbeat enablement, per‑account probes, and per‑agent sessions. - Share heartbeat summary logic via heartbeat-runner, update status/health outputs, and TUI status rendering. - Add/adjust tests for heartbeat enablement, per‑account probe formatting, and multi‑agent sessions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR fixes multi-agent setup issues with health/status commands, heartbeat enablement logic, and Telegram account binding resolution. It ensures that multi-agent gateways correctly display per-agent information for heartbeats, sessions, and channel probes.
Changes:
- Fixed Telegram account-to-agent binding resolution to respect configured bindings instead of always defaulting to the first account
- Corrected heartbeat enablement logic so agents without explicit heartbeat blocks are disabled when other agents have explicit blocks
- Enhanced health and status commands to display per-agent session stores, heartbeats, and channel probes (especially in verbose/deep modes)
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/tui/tui-types.ts | Updated GatewayStatusSummary type to support multiple heartbeat agents and session paths |
| src/tui/tui-status-summary.ts | Updated formatting to display per-agent heartbeat and multiple session stores |
| src/telegram/bot.test.ts | Added test for group reply handling with requireMention enabled |
| src/telegram/accounts.ts | Added binding resolution logic to map default agent to correct Telegram account |
| src/infra/heartbeat-runner.ts | Added isHeartbeatEnabledForAgent and resolveHeartbeatSummaryForAgent functions |
| src/infra/heartbeat-runner.returns-default-unset.test.ts | Added tests for heartbeat enablement logic with explicit agents |
| src/gateway/server-methods/health.ts | Added probe parameter support to enable verbose health checks |
| src/commands/status.types.ts | Added HeartbeatStatus type and updated StatusSummary for multi-agent support |
| src/commands/status.test.ts | Added test for multi-agent session aggregation |
| src/commands/status.summary.ts | Refactored to aggregate sessions across all agents |
| src/commands/status.command.ts | Updated output formatting for multi-agent heartbeats and session stores |
| src/commands/health.ts | Extensive refactoring to support per-agent health snapshots and channel account probing |
| src/commands/health.test.ts | Added test for per-account probe timing formatting |
| src/commands/health.snapshot.test.ts | Added test for heartbeat disabling with explicit agent blocks |
| src/commands/health.command.coverage.test.ts | Updated test data to include new agent-related fields |
Comments suppressed due to low confidence (4)
src/commands/health.ts:1
- The fallback chain on lines 122-123 is redundant. If
mergedis defined (line 121), it already contains the merged values ofdefaultsandoverrides, so checkingdefaults?.everyandoverrides?.everyagain is unnecessary. Consider simplifying tomerged?.every ?? DEFAULT_HEARTBEAT_EVERY.
import { resolveDefaultAgentId } from "../agents/agent-scope.js";
src/commands/health.ts:1
- Similar to the previous comment, the fallback chain
defaults?.prompt ?? overrides?.promptis redundant sincemergedalready contains these values merged. Simplify tomerged?.prompt.
import { resolveDefaultAgentId } from "../agents/agent-scope.js";
src/commands/health.ts:1
- Same redundancy issue:
defaults?.target ?? overrides?.targetis unnecessary sincemergedalready contains the merged result. Simplify the fallback chain.
import { resolveDefaultAgentId } from "../agents/agent-scope.js";
src/commands/health.ts:1
- Same redundancy:
defaults?.ackMaxChars ?? overrides?.ackMaxCharsis unnecessary sincemergedalready contains these values. Simplify tomerged?.ackMaxChars ?? DEFAULT_HEARTBEAT_ACK_MAX_CHARS.
import { resolveDefaultAgentId } from "../agents/agent-scope.js";
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const every = | ||
| merged?.every ?? defaults?.every ?? overrides?.every ?? DEFAULT_HEARTBEAT_EVERY; | ||
| const everyMs = resolveHeartbeatIntervalMs(cfg, undefined, merged); | ||
| const prompt = resolveHeartbeatPromptText( | ||
| merged?.prompt ?? defaults?.prompt ?? overrides?.prompt, | ||
| ); | ||
| const target = merged?.target ?? defaults?.target ?? overrides?.target ?? DEFAULT_HEARTBEAT_TARGET; | ||
| const model = merged?.model ?? defaults?.model ?? overrides?.model; | ||
| const ackMaxChars = Math.max( | ||
| 0, | ||
| merged?.ackMaxChars ?? | ||
| defaults?.ackMaxChars ?? | ||
| overrides?.ackMaxChars ?? | ||
| DEFAULT_HEARTBEAT_ACK_MAX_CHARS, |
Copilot
AI
Jan 16, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Multiple fallback chains in this function have redundant checks for defaults and overrides after already computing merged which contains the spread of both. All these chains should be simplified to use only merged with the final default value.
| const every = | |
| merged?.every ?? defaults?.every ?? overrides?.every ?? DEFAULT_HEARTBEAT_EVERY; | |
| const everyMs = resolveHeartbeatIntervalMs(cfg, undefined, merged); | |
| const prompt = resolveHeartbeatPromptText( | |
| merged?.prompt ?? defaults?.prompt ?? overrides?.prompt, | |
| ); | |
| const target = merged?.target ?? defaults?.target ?? overrides?.target ?? DEFAULT_HEARTBEAT_TARGET; | |
| const model = merged?.model ?? defaults?.model ?? overrides?.model; | |
| const ackMaxChars = Math.max( | |
| 0, | |
| merged?.ackMaxChars ?? | |
| defaults?.ackMaxChars ?? | |
| overrides?.ackMaxChars ?? | |
| DEFAULT_HEARTBEAT_ACK_MAX_CHARS, | |
| const every = merged?.every ?? DEFAULT_HEARTBEAT_EVERY; | |
| const everyMs = resolveHeartbeatIntervalMs(cfg, undefined, merged); | |
| const prompt = resolveHeartbeatPromptText(merged?.prompt); | |
| const target = merged?.target ?? DEFAULT_HEARTBEAT_TARGET; | |
| const model = merged?.model; | |
| const ackMaxChars = Math.max( | |
| 0, | |
| merged?.ackMaxChars ?? DEFAULT_HEARTBEAT_ACK_MAX_CHARS, |
|
Landed on main via commits:
Closing this PR since the changes are already on main. Thanks @gumadeiras! |
Summary of Fixes and Behavior Changes
In fixing #1029 I realized the problem ran a little bit deeper.
Problem
In multi‑agent setups on a single gateway,
healthandstatusoutput was misleading:statusoutput showed the same issues ashealth.Root Causes
health/statussummaries only considered one account and one session store.Behavior Changes (What Changed)
Health
Status
Telegram Account Mapping
Heartbeat Enablement (Multi‑Agent)
Tests
current

clawdbot health --verbose→ wrong heartbeat duration; probing a random account instead of the one associated with default agent; missing session for other agents
new ones fix heartbeat reading; identifies the default account<>agent and others; sessions for other agents

new
clawdbot health --verbosecurrent
clawdbot status --deepnew

clawdbot status --deep