mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 19:44:30 +00:00
feat(heartbeat): add accountId config option for multi-agent routing (#8702)
* feat(heartbeat): add accountId config option for multi-agent routing Add optional accountId field to heartbeat configuration, allowing multi-agent setups to explicitly specify which Telegram account should be used for heartbeat delivery. Previously, heartbeat delivery would use the accountId from the session's deliveryContext. When a session had no prior conversation history, heartbeats would default to the first/primary account instead of the agent's intended bot. Changes: - Add accountId to HeartbeatSchema (zod-schema.agent-runtime.ts) - Use heartbeat.accountId with fallback to session accountId (targets.ts) Backward compatible: if accountId is not specified, behavior is unchanged. Closes #8695 * fix: improve heartbeat accountId routing (#8702) (thanks @lsh411) * fix: harden heartbeat accountId routing (#8702) (thanks @lsh411) * fix: expose heartbeat accountId in status (#8702) (thanks @lsh411) * chore: format status + heartbeat tests (#8702) (thanks @lsh411) --------- Co-authored-by: m1 16 512 <m116512@m1ui-MacBookAir-2.local> Co-authored-by: Gustavo Madeira Santana <gumadeiras@gmail.com>
This commit is contained in:
@@ -8,6 +8,7 @@ import type {
|
||||
} from "../../utils/message-channel.js";
|
||||
import { getChannelPlugin, normalizeChannelId } from "../../channels/plugins/index.js";
|
||||
import { formatCliCommand } from "../../cli/command-format.js";
|
||||
import { normalizeAccountId } from "../../routing/session-key.js";
|
||||
import { deliveryContextFromSession } from "../../utils/delivery-context.js";
|
||||
import {
|
||||
INTERNAL_MESSAGE_CHANNEL,
|
||||
@@ -207,11 +208,37 @@ export function resolveHeartbeatDeliveryTarget(params: {
|
||||
mode: "heartbeat",
|
||||
});
|
||||
|
||||
const heartbeatAccountId = heartbeat?.accountId?.trim();
|
||||
// Use explicit accountId from heartbeat config if provided, otherwise fall back to session
|
||||
let effectiveAccountId = heartbeatAccountId || resolvedTarget.accountId;
|
||||
|
||||
if (heartbeatAccountId && resolvedTarget.channel) {
|
||||
const plugin = getChannelPlugin(resolvedTarget.channel);
|
||||
const listAccountIds = plugin?.config.listAccountIds;
|
||||
const accountIds = listAccountIds ? listAccountIds(cfg) : [];
|
||||
if (accountIds.length > 0) {
|
||||
const normalizedAccountId = normalizeAccountId(heartbeatAccountId);
|
||||
const normalizedAccountIds = new Set(
|
||||
accountIds.map((accountId) => normalizeAccountId(accountId)),
|
||||
);
|
||||
if (!normalizedAccountIds.has(normalizedAccountId)) {
|
||||
return {
|
||||
channel: "none",
|
||||
reason: "unknown-account",
|
||||
accountId: normalizedAccountId,
|
||||
lastChannel: resolvedTarget.lastChannel,
|
||||
lastAccountId: resolvedTarget.lastAccountId,
|
||||
};
|
||||
}
|
||||
effectiveAccountId = normalizedAccountId;
|
||||
}
|
||||
}
|
||||
|
||||
if (!resolvedTarget.channel || !resolvedTarget.to) {
|
||||
return {
|
||||
channel: "none",
|
||||
reason: "no-target",
|
||||
accountId: resolvedTarget.accountId,
|
||||
accountId: effectiveAccountId,
|
||||
lastChannel: resolvedTarget.lastChannel,
|
||||
lastAccountId: resolvedTarget.lastAccountId,
|
||||
};
|
||||
@@ -221,14 +248,14 @@ export function resolveHeartbeatDeliveryTarget(params: {
|
||||
channel: resolvedTarget.channel,
|
||||
to: resolvedTarget.to,
|
||||
cfg,
|
||||
accountId: resolvedTarget.accountId,
|
||||
accountId: effectiveAccountId,
|
||||
mode: "heartbeat",
|
||||
});
|
||||
if (!resolved.ok) {
|
||||
return {
|
||||
channel: "none",
|
||||
reason: "no-target",
|
||||
accountId: resolvedTarget.accountId,
|
||||
accountId: effectiveAccountId,
|
||||
lastChannel: resolvedTarget.lastChannel,
|
||||
lastAccountId: resolvedTarget.lastAccountId,
|
||||
};
|
||||
@@ -241,7 +268,7 @@ export function resolveHeartbeatDeliveryTarget(params: {
|
||||
channel: resolvedTarget.channel,
|
||||
to: resolvedTarget.to,
|
||||
cfg,
|
||||
accountId: resolvedTarget.accountId,
|
||||
accountId: effectiveAccountId,
|
||||
mode: "explicit",
|
||||
});
|
||||
if (explicit.ok && explicit.to !== resolved.to) {
|
||||
@@ -253,7 +280,7 @@ export function resolveHeartbeatDeliveryTarget(params: {
|
||||
channel: resolvedTarget.channel,
|
||||
to: resolved.to,
|
||||
reason,
|
||||
accountId: resolvedTarget.accountId,
|
||||
accountId: effectiveAccountId,
|
||||
lastChannel: resolvedTarget.lastChannel,
|
||||
lastAccountId: resolvedTarget.lastAccountId,
|
||||
};
|
||||
@@ -301,11 +328,13 @@ export function resolveHeartbeatSenderContext(params: {
|
||||
}): HeartbeatSenderContext {
|
||||
const provider =
|
||||
params.delivery.channel !== "none" ? params.delivery.channel : params.delivery.lastChannel;
|
||||
const accountId =
|
||||
params.delivery.accountId ??
|
||||
(provider === params.delivery.lastChannel ? params.delivery.lastAccountId : undefined);
|
||||
const allowFrom = provider
|
||||
? (getChannelPlugin(provider)?.config.resolveAllowFrom?.({
|
||||
cfg: params.cfg,
|
||||
accountId:
|
||||
provider === params.delivery.lastChannel ? params.delivery.lastAccountId : undefined,
|
||||
accountId,
|
||||
}) ?? [])
|
||||
: [];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user