fix(telegram): preserve inline buttons for empty capabilities (#96468) · openclaw/openclaw@3217165
zhangguiping
·
2026-06-25
·
via Recent Commits to openclaw:main
| Original file line number | Diff line number | Diff line change |
|---|
@@ -90,6 +90,10 @@ export function mergeTelegramAccountConfig(
|
90 | 90 | baseAllowFrom: base.allowFrom, |
91 | 91 | accountAllowFrom: account.allowFrom, |
92 | 92 | }); |
| 93 | +const capabilities = |
| 94 | +Array.isArray(account.capabilities) && account.capabilities.length === 0 |
| 95 | + ? base.capabilities |
| 96 | + : (account.capabilities ?? base.capabilities); |
93 | 97 | |
94 | | -return { ...base, ...account, allowFrom, groups }; |
| 98 | +return { ...base, ...account, allowFrom, capabilities, groups }; |
95 | 99 | } |
| Original file line number | Diff line number | Diff line change |
|---|
@@ -1703,6 +1703,25 @@ describe("handleTelegramAction", () => {
|
1703 | 1703 | expect(sendMessageTelegram).toHaveBeenCalled(); |
1704 | 1704 | }); |
1705 | 1705 | |
| 1706 | +it("allows inline buttons when legacy capabilities are empty", async () => { |
| 1707 | +await handleTelegramAction( |
| 1708 | +{ |
| 1709 | +action: "sendMessage", |
| 1710 | +to: "@testchannel", |
| 1711 | +content: "Choose", |
| 1712 | +presentation: { |
| 1713 | +blocks: [{ type: "buttons", buttons: [{ label: "Ok", value: "cmd:ok" }] }], |
| 1714 | +}, |
| 1715 | +}, |
| 1716 | +telegramConfig({ capabilities: [] }), |
| 1717 | +); |
| 1718 | +const call = mockCall(sendMessageTelegram, 0, "empty legacy capabilities"); |
| 1719 | +expect(call[0]).toBe("@testchannel"); |
| 1720 | +expect(requireRecord(call[2], "empty legacy capabilities options").buttons).toEqual([ |
| 1721 | +[{ text: "Ok", callback_data: "cmd:ok" }], |
| 1722 | +]); |
| 1723 | +}); |
| 1724 | + |
1706 | 1725 | it("uses interactive button labels as fallback text when message text is omitted", async () => { |
1707 | 1726 | await handleTelegramAction( |
1708 | 1727 | { |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -43,6 +43,36 @@ describe("telegram actions contract", () => {
|
43 | 43 | expect(capabilities?.includes("richText")).toBe(expected); |
44 | 44 | }); |
45 | 45 | |
| 46 | +it("advertises inline buttons when legacy Telegram capabilities are empty", () => { |
| 47 | +const capabilities = telegramPlugin.agentPrompt?.messageToolCapabilities?.({ |
| 48 | +cfg: { |
| 49 | +channels: { |
| 50 | +telegram: { |
| 51 | +botToken: "123:telegram-test-token", |
| 52 | +capabilities: [], |
| 53 | +}, |
| 54 | +}, |
| 55 | +} as OpenClawConfig, |
| 56 | +}); |
| 57 | + |
| 58 | +expect(capabilities).toContain("inlineButtons"); |
| 59 | +}); |
| 60 | + |
| 61 | +it("does not advertise inline buttons for non-empty legacy Telegram capabilities without inlineButtons", () => { |
| 62 | +const capabilities = telegramPlugin.agentPrompt?.messageToolCapabilities?.({ |
| 63 | +cfg: { |
| 64 | +channels: { |
| 65 | +telegram: { |
| 66 | +botToken: "123:telegram-test-token", |
| 67 | +capabilities: ["vision"], |
| 68 | +}, |
| 69 | +}, |
| 70 | +} as OpenClawConfig, |
| 71 | +}); |
| 72 | + |
| 73 | +expect(capabilities).not.toContain("inlineButtons"); |
| 74 | +}); |
| 75 | + |
46 | 76 | it("uses the selected Telegram account's rich text setting", () => { |
47 | 77 | const capabilities = telegramPlugin.agentPrompt?.messageToolCapabilities?.({ |
48 | 78 | cfg: { |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -109,6 +109,39 @@ describe("resolveTelegramInlineButtonsScope (#75433 SecretRef tolerance)", () =>
|
109 | 109 | expect(isTelegramInlineButtonsEnabled({ cfg })).toBe(true); |
110 | 110 | }); |
111 | 111 | |
| 112 | +it("preserves the default inline-buttons scope when legacy capabilities are empty", () => { |
| 113 | +const cfg = { |
| 114 | +channels: { |
| 115 | +telegram: { |
| 116 | +botToken: { source: "exec", provider: "default", id: "telegram-token" }, |
| 117 | +capabilities: [], |
| 118 | +}, |
| 119 | +}, |
| 120 | +} as unknown as OpenClawConfig; |
| 121 | + |
| 122 | +expect(resolveTelegramInlineButtonsScope({ cfg })).toBe("allowlist"); |
| 123 | +expect(isTelegramInlineButtonsEnabled({ cfg })).toBe(true); |
| 124 | +}); |
| 125 | + |
| 126 | +it("inherits the channel scope when an account legacy capabilities array is empty", () => { |
| 127 | +const cfg = { |
| 128 | +channels: { |
| 129 | +telegram: { |
| 130 | +capabilities: { inlineButtons: "off" }, |
| 131 | +accounts: { |
| 132 | +ops: { |
| 133 | +botToken: "123:telegram-ops-token", |
| 134 | +capabilities: [], |
| 135 | +}, |
| 136 | +}, |
| 137 | +}, |
| 138 | +}, |
| 139 | +} as unknown as OpenClawConfig; |
| 140 | + |
| 141 | +expect(resolveTelegramInlineButtonsScope({ cfg, accountId: "ops" })).toBe("off"); |
| 142 | +expect(isTelegramInlineButtonsEnabled({ cfg, accountId: "ops" })).toBe(false); |
| 143 | +}); |
| 144 | + |
112 | 145 | it('preserves configured "off" when botToken is an unresolved SecretRef', () => { |
113 | 146 | const cfg = { |
114 | 147 | channels: { |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -47,6 +47,9 @@ export function resolveTelegramInlineButtonsScopeFromCapabilities(
|
47 | 47 | return DEFAULT_INLINE_BUTTONS_SCOPE; |
48 | 48 | } |
49 | 49 | if (Array.isArray(capabilities)) { |
| 50 | +if (capabilities.length === 0) { |
| 51 | +return DEFAULT_INLINE_BUTTONS_SCOPE; |
| 52 | +} |
50 | 53 | const enabled = capabilities.some( |
51 | 54 | (entry) => normalizeLowercaseStringOrEmpty(String(entry)) === "inlinebuttons", |
52 | 55 | ); |
|
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。