From e702a9eb52a2aa617eee491ebc0b0b590b330c86 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Wed, 18 Feb 2026 17:39:05 +0000 Subject: [PATCH] refactor(channels): share account action gate resolution --- .../plugins/account-action-gate.test.ts | 34 +++++++++++++++++++ src/channels/plugins/account-action-gate.ts | 21 ++++++++++++ src/discord/accounts.ts | 18 +++------- src/telegram/accounts.ts | 18 +++------- 4 files changed, 65 insertions(+), 26 deletions(-) create mode 100644 src/channels/plugins/account-action-gate.test.ts create mode 100644 src/channels/plugins/account-action-gate.ts diff --git a/src/channels/plugins/account-action-gate.test.ts b/src/channels/plugins/account-action-gate.test.ts new file mode 100644 index 0000000000..ac292993d7 --- /dev/null +++ b/src/channels/plugins/account-action-gate.test.ts @@ -0,0 +1,34 @@ +import { describe, expect, it } from "vitest"; +import { createAccountActionGate } from "./account-action-gate.js"; + +type TestActions = { + send?: boolean; + reactions?: boolean; +}; + +describe("createAccountActionGate", () => { + it("prefers account action values over base values", () => { + const gate = createAccountActionGate({ + baseActions: { send: false, reactions: true }, + accountActions: { send: true }, + }); + expect(gate("send")).toBe(true); + }); + + it("falls back to base actions when account actions are unset", () => { + const gate = createAccountActionGate({ + baseActions: { reactions: false }, + accountActions: {}, + }); + expect(gate("reactions")).toBe(false); + }); + + it("uses default value when neither account nor base defines the key", () => { + const gate = createAccountActionGate({ + baseActions: {}, + accountActions: {}, + }); + expect(gate("send", false)).toBe(false); + expect(gate("send")).toBe(true); + }); +}); diff --git a/src/channels/plugins/account-action-gate.ts b/src/channels/plugins/account-action-gate.ts new file mode 100644 index 0000000000..d90f454bd8 --- /dev/null +++ b/src/channels/plugins/account-action-gate.ts @@ -0,0 +1,21 @@ +export type ActionGate> = ( + key: keyof T, + defaultValue?: boolean, +) => boolean; + +export function createAccountActionGate>(params: { + baseActions?: T; + accountActions?: T; +}): ActionGate { + return (key, defaultValue = true) => { + const accountValue = params.accountActions?.[key]; + if (accountValue !== undefined) { + return accountValue; + } + const baseValue = params.baseActions?.[key]; + if (baseValue !== undefined) { + return baseValue; + } + return defaultValue; + }; +} diff --git a/src/discord/accounts.ts b/src/discord/accounts.ts index 2f5729114c..a5810de247 100644 --- a/src/discord/accounts.ts +++ b/src/discord/accounts.ts @@ -1,3 +1,4 @@ +import { createAccountActionGate } from "../channels/plugins/account-action-gate.js"; import { createAccountListHelpers } from "../channels/plugins/account-helpers.js"; import type { OpenClawConfig } from "../config/config.js"; import type { DiscordAccountConfig, DiscordActionConfig } from "../config/types.js"; @@ -41,19 +42,10 @@ export function createDiscordActionGate(params: { accountId?: string | null; }): (key: keyof DiscordActionConfig, defaultValue?: boolean) => boolean { const accountId = normalizeAccountId(params.accountId); - const baseActions = params.cfg.channels?.discord?.actions; - const accountActions = resolveAccountConfig(params.cfg, accountId)?.actions; - return (key, defaultValue = true) => { - const accountValue = accountActions?.[key]; - if (accountValue !== undefined) { - return accountValue; - } - const baseValue = baseActions?.[key]; - if (baseValue !== undefined) { - return baseValue; - } - return defaultValue; - }; + return createAccountActionGate({ + baseActions: params.cfg.channels?.discord?.actions, + accountActions: resolveAccountConfig(params.cfg, accountId)?.actions, + }); } export function resolveDiscordAccount(params: { diff --git a/src/telegram/accounts.ts b/src/telegram/accounts.ts index ce7f2d1bf6..e0bfcf7919 100644 --- a/src/telegram/accounts.ts +++ b/src/telegram/accounts.ts @@ -1,3 +1,4 @@ +import { createAccountActionGate } from "../channels/plugins/account-action-gate.js"; import type { OpenClawConfig } from "../config/config.js"; import type { TelegramAccountConfig, TelegramActionConfig } from "../config/types.js"; import { isTruthyEnvValue } from "../infra/env.js"; @@ -87,19 +88,10 @@ export function createTelegramActionGate(params: { accountId?: string | null; }): (key: keyof TelegramActionConfig, defaultValue?: boolean) => boolean { const accountId = normalizeAccountId(params.accountId); - const baseActions = params.cfg.channels?.telegram?.actions; - const accountActions = resolveAccountConfig(params.cfg, accountId)?.actions; - return (key, defaultValue = true) => { - const accountValue = accountActions?.[key]; - if (accountValue !== undefined) { - return accountValue; - } - const baseValue = baseActions?.[key]; - if (baseValue !== undefined) { - return baseValue; - } - return defaultValue; - }; + return createAccountActionGate({ + baseActions: params.cfg.channels?.telegram?.actions, + accountActions: resolveAccountConfig(params.cfg, accountId)?.actions, + }); } export function resolveTelegramAccount(params: {