mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 20:38:27 +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:
@@ -25,7 +25,10 @@ import {
|
||||
resolveHeartbeatPrompt,
|
||||
runHeartbeatOnce,
|
||||
} from "./heartbeat-runner.js";
|
||||
import { resolveHeartbeatDeliveryTarget } from "./outbound/targets.js";
|
||||
import {
|
||||
resolveHeartbeatDeliveryTarget,
|
||||
resolveHeartbeatSenderContext,
|
||||
} from "./outbound/targets.js";
|
||||
|
||||
// Avoid pulling optional runtime deps during isolated runs.
|
||||
vi.mock("jiti", () => ({ createJiti: () => () => ({}) }));
|
||||
@@ -264,6 +267,42 @@ describe("resolveHeartbeatDeliveryTarget", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("uses explicit heartbeat accountId when provided", () => {
|
||||
const cfg: OpenClawConfig = {
|
||||
agents: {
|
||||
defaults: {
|
||||
heartbeat: { target: "telegram", to: "123", accountId: "work" },
|
||||
},
|
||||
},
|
||||
channels: { telegram: { accounts: { work: { botToken: "token" } } } },
|
||||
};
|
||||
expect(resolveHeartbeatDeliveryTarget({ cfg, entry: baseEntry })).toEqual({
|
||||
channel: "telegram",
|
||||
to: "123",
|
||||
accountId: "work",
|
||||
lastChannel: undefined,
|
||||
lastAccountId: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it("skips when explicit heartbeat accountId is unknown", () => {
|
||||
const cfg: OpenClawConfig = {
|
||||
agents: {
|
||||
defaults: {
|
||||
heartbeat: { target: "telegram", to: "123", accountId: "missing" },
|
||||
},
|
||||
},
|
||||
channels: { telegram: { accounts: { work: { botToken: "token" } } } },
|
||||
};
|
||||
expect(resolveHeartbeatDeliveryTarget({ cfg, entry: baseEntry })).toEqual({
|
||||
channel: "none",
|
||||
reason: "unknown-account",
|
||||
accountId: "missing",
|
||||
lastChannel: undefined,
|
||||
lastAccountId: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it("prefers per-agent heartbeat overrides when provided", () => {
|
||||
const cfg: OpenClawConfig = {
|
||||
agents: { defaults: { heartbeat: { target: "telegram", to: "123" } } },
|
||||
@@ -285,6 +324,39 @@ describe("resolveHeartbeatDeliveryTarget", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("resolveHeartbeatSenderContext", () => {
|
||||
it("prefers delivery accountId for allowFrom resolution", () => {
|
||||
const cfg: OpenClawConfig = {
|
||||
channels: {
|
||||
telegram: {
|
||||
allowFrom: ["111"],
|
||||
accounts: {
|
||||
work: { allowFrom: ["222"], botToken: "token" },
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
const entry = {
|
||||
sessionId: "sid",
|
||||
updatedAt: Date.now(),
|
||||
lastChannel: "telegram" as const,
|
||||
lastTo: "111",
|
||||
lastAccountId: "default",
|
||||
};
|
||||
const delivery = {
|
||||
channel: "telegram" as const,
|
||||
to: "999",
|
||||
accountId: "work",
|
||||
lastChannel: "telegram" as const,
|
||||
lastAccountId: "default",
|
||||
};
|
||||
|
||||
const ctx = resolveHeartbeatSenderContext({ cfg, entry, delivery });
|
||||
|
||||
expect(ctx.allowFrom).toEqual(["222"]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("runHeartbeatOnce", () => {
|
||||
it("skips when agent heartbeat is not enabled", async () => {
|
||||
const cfg: OpenClawConfig = {
|
||||
|
||||
Reference in New Issue
Block a user