From e913de072048414bacf10227347fdd7ed1d6aec8 Mon Sep 17 00:00:00 2001 From: jasonsschin Date: Sat, 31 Jan 2026 11:48:38 +1100 Subject: [PATCH] Fix Telegram token resolution for non-normalized accountId keys --- src/telegram/token.test.ts | 18 ++++++++++++++++++ src/telegram/token.ts | 21 +++++++++++++++++---- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/telegram/token.test.ts b/src/telegram/token.test.ts index 9f469721b..8be3fd6a6 100644 --- a/src/telegram/token.test.ts +++ b/src/telegram/token.test.ts @@ -70,4 +70,22 @@ describe("resolveTelegramToken", () => { expect(res.source).toBe("none"); fs.rmSync(dir, { recursive: true, force: true }); }); + + it("resolves per-account tokens when the config account key casing doesn't match routing normalization", () => { + vi.stubEnv("TELEGRAM_BOT_TOKEN", ""); + const cfg = { + channels: { + telegram: { + accounts: { + // Note the mixed-case key; runtime accountId is normalized. + careyNotifications: { botToken: "acct-token" }, + }, + }, + }, + } as OpenClawConfig; + + const res = resolveTelegramToken(cfg, { accountId: "careynotifications" }); + expect(res.token).toBe("acct-token"); + expect(res.source).toBe("config"); + }); }); diff --git a/src/telegram/token.ts b/src/telegram/token.ts index d830c7761..fe3b7bc36 100644 --- a/src/telegram/token.ts +++ b/src/telegram/token.ts @@ -22,10 +22,23 @@ export function resolveTelegramToken( ): TelegramTokenResolution { const accountId = normalizeAccountId(opts.accountId); const telegramCfg = cfg?.channels?.telegram; - const accountCfg = - accountId !== DEFAULT_ACCOUNT_ID - ? telegramCfg?.accounts?.[accountId] - : telegramCfg?.accounts?.[DEFAULT_ACCOUNT_ID]; + + // Account IDs are normalized for routing (e.g. lowercased). Config keys may not + // be normalized, so resolve per-account config by matching normalized IDs. + const resolveAccountCfg = (id: string) => { + const accounts = telegramCfg?.accounts; + if (!accounts || typeof accounts !== "object") return undefined; + // Direct hit (already normalized key) + const direct = (accounts as any)[id]; + if (direct) return direct as any; + // Fallback: match by normalized key + const matchKey = Object.keys(accounts).find((k) => normalizeAccountId(k) === id); + return matchKey ? ((accounts as any)[matchKey] as any) : undefined; + }; + + const accountCfg = resolveAccountCfg( + accountId !== DEFAULT_ACCOUNT_ID ? accountId : DEFAULT_ACCOUNT_ID, + ); const accountTokenFile = accountCfg?.tokenFile?.trim(); if (accountTokenFile) { if (!fs.existsSync(accountTokenFile)) {