diff --git a/src/telegram/accounts.test.ts b/src/telegram/accounts.test.ts index 919ca989f..9d6440db2 100644 --- a/src/telegram/accounts.test.ts +++ b/src/telegram/accounts.test.ts @@ -168,3 +168,104 @@ describe("resolveTelegramAccount allowFrom precedence", () => { expect(resolved.config.groupAllowFrom).toBeUndefined(); }); }); + +describe("resolveTelegramAccount groups inheritance (#30673)", () => { + it("inherits channel-level groups in single-account setup", () => { + const resolved = resolveTelegramAccount({ + cfg: { + channels: { + telegram: { + groups: { "-100123": { requireMention: false } }, + accounts: { + default: { botToken: "123:default" }, + }, + }, + }, + }, + accountId: "default", + }); + + expect(resolved.config.groups).toEqual({ "-100123": { requireMention: false } }); + }); + + it("does NOT inherit channel-level groups to secondary account in multi-account setup", () => { + const resolved = resolveTelegramAccount({ + cfg: { + channels: { + telegram: { + groups: { "-100123": { requireMention: false } }, + accounts: { + default: { botToken: "123:default" }, + dev: { botToken: "456:dev" }, + }, + }, + }, + }, + accountId: "dev", + }); + + expect(resolved.config.groups).toBeUndefined(); + }); + + it("does NOT inherit channel-level groups to default account in multi-account setup", () => { + const resolved = resolveTelegramAccount({ + cfg: { + channels: { + telegram: { + groups: { "-100123": { requireMention: false } }, + accounts: { + default: { botToken: "123:default" }, + dev: { botToken: "456:dev" }, + }, + }, + }, + }, + accountId: "default", + }); + + expect(resolved.config.groups).toBeUndefined(); + }); + + it("uses account-level groups even in multi-account setup", () => { + const resolved = resolveTelegramAccount({ + cfg: { + channels: { + telegram: { + groups: { "-100999": { requireMention: true } }, + accounts: { + default: { + botToken: "123:default", + groups: { "-100123": { requireMention: false } }, + }, + dev: { botToken: "456:dev" }, + }, + }, + }, + }, + accountId: "default", + }); + + expect(resolved.config.groups).toEqual({ "-100123": { requireMention: false } }); + }); + + it("account-level groups takes priority over channel-level in single-account setup", () => { + const resolved = resolveTelegramAccount({ + cfg: { + channels: { + telegram: { + groups: { "-100999": { requireMention: true } }, + accounts: { + default: { + botToken: "123:default", + groups: { "-100123": { requireMention: false } }, + }, + }, + }, + }, + }, + accountId: "default", + }); + + expect(resolved.config.groups).toEqual({ "-100123": { requireMention: false } }); + }); +}); diff --git a/src/telegram/accounts.ts b/src/telegram/accounts.ts index 9df297180..5350baae8 100644 --- a/src/telegram/accounts.ts +++ b/src/telegram/accounts.ts @@ -84,10 +84,22 @@ function resolveAccountConfig( } function mergeTelegramAccountConfig(cfg: OpenClawConfig, accountId: string): TelegramAccountConfig { - const { accounts: _ignored, ...base } = (cfg.channels?.telegram ?? + const { accounts: _ignored, groups: channelGroups, ...base } = (cfg.channels?.telegram ?? {}) as TelegramAccountConfig & { accounts?: unknown }; const account = resolveAccountConfig(cfg, accountId) ?? {}; - return { ...base, ...account }; + + // In multi-account setups, channel-level `groups` must NOT be inherited by + // accounts that don't have their own `groups` config. A bot that is not a + // member of a configured group will fail when handling group messages, and + // this failure disrupts message delivery for *all* accounts. + // Single-account setups keep backward compat: channel-level groups still + // applies when the account has no override. + // See: https://github.com/openclaw/openclaw/issues/30673 + const configuredAccountIds = Object.keys(cfg.channels?.telegram?.accounts ?? {}); + const isMultiAccount = configuredAccountIds.length > 1; + const groups = account.groups ?? (isMultiAccount ? undefined : channelGroups); + + return { ...base, ...account, groups }; } export function createTelegramActionGate(params: {