Telegram: move group policy behind plugin boundary
This commit is contained in:
parent
a34944c918
commit
7ba8dd112f
@ -3,6 +3,7 @@ export * from "./src/accounts.js";
|
||||
export * from "./src/allow-from.js";
|
||||
export * from "./src/api-fetch.js";
|
||||
export * from "./src/exec-approvals.js";
|
||||
export * from "./src/group-policy.js";
|
||||
export * from "./src/inline-buttons.js";
|
||||
export * from "./src/model-buttons.js";
|
||||
export * from "./src/normalize.js";
|
||||
|
||||
@ -154,6 +154,42 @@ afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe("telegramPlugin groups", () => {
|
||||
it("uses plugin-owned group policy resolvers", () => {
|
||||
const cfg = {
|
||||
channels: {
|
||||
telegram: {
|
||||
botToken: "telegram-test",
|
||||
groups: {
|
||||
"-1001": {
|
||||
requireMention: true,
|
||||
tools: { allow: ["message.send"] },
|
||||
topics: {
|
||||
"77": {
|
||||
requireMention: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
|
||||
expect(
|
||||
telegramPlugin.groups?.resolveRequireMention?.({
|
||||
cfg,
|
||||
groupId: "-1001:topic:77",
|
||||
}),
|
||||
).toBe(false);
|
||||
expect(
|
||||
telegramPlugin.groups?.resolveToolPolicy?.({
|
||||
cfg,
|
||||
groupId: "-1001:topic:77",
|
||||
}),
|
||||
).toEqual({ allow: ["message.send"] });
|
||||
});
|
||||
});
|
||||
|
||||
describe("telegramPlugin duplicate token guard", () => {
|
||||
it("marks secondary account as not configured when token is shared", async () => {
|
||||
const cfg = createCfg();
|
||||
|
||||
@ -20,8 +20,6 @@ import {
|
||||
PAIRING_APPROVED_MESSAGE,
|
||||
projectCredentialSnapshotFields,
|
||||
resolveConfiguredFromCredentialStatuses,
|
||||
resolveTelegramGroupRequireMention,
|
||||
resolveTelegramGroupToolPolicy,
|
||||
type ChannelPlugin,
|
||||
type ChannelMessageActionAdapter,
|
||||
type OpenClawConfig,
|
||||
@ -38,6 +36,10 @@ import {
|
||||
isTelegramExecApprovalClientEnabled,
|
||||
resolveTelegramExecApprovalTarget,
|
||||
} from "./exec-approvals.js";
|
||||
import {
|
||||
resolveTelegramGroupRequireMention,
|
||||
resolveTelegramGroupToolPolicy,
|
||||
} from "./group-policy.js";
|
||||
import { monitorTelegramProvider } from "./monitor.js";
|
||||
import { looksLikeTelegramTargetId, normalizeTelegramMessagingTarget } from "./normalize.js";
|
||||
import { sendTelegramPayloadMessages } from "./outbound-adapter.js";
|
||||
|
||||
40
extensions/telegram/src/group-policy.test.ts
Normal file
40
extensions/telegram/src/group-policy.test.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
resolveTelegramGroupRequireMention,
|
||||
resolveTelegramGroupToolPolicy,
|
||||
} from "./group-policy.js";
|
||||
|
||||
describe("telegram group policy", () => {
|
||||
it("resolves topic-level requireMention and chat-level tools for topic ids", () => {
|
||||
const telegramCfg = {
|
||||
channels: {
|
||||
telegram: {
|
||||
botToken: "telegram-test",
|
||||
groups: {
|
||||
"-1001": {
|
||||
requireMention: true,
|
||||
tools: { allow: ["message.send"] },
|
||||
topics: {
|
||||
"77": {
|
||||
requireMention: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
"*": {
|
||||
requireMention: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
} as any;
|
||||
expect(
|
||||
resolveTelegramGroupRequireMention({ cfg: telegramCfg, groupId: "-1001:topic:77" }),
|
||||
).toBe(false);
|
||||
expect(resolveTelegramGroupToolPolicy({ cfg: telegramCfg, groupId: "-1001:topic:77" })).toEqual(
|
||||
{
|
||||
allow: ["message.send"],
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
91
extensions/telegram/src/group-policy.ts
Normal file
91
extensions/telegram/src/group-policy.ts
Normal file
@ -0,0 +1,91 @@
|
||||
import {
|
||||
resolveChannelGroupRequireMention,
|
||||
resolveChannelGroupToolsPolicy,
|
||||
type GroupToolPolicyConfig,
|
||||
} from "openclaw/plugin-sdk/channel-policy";
|
||||
import { type ChannelGroupContext } from "openclaw/plugin-sdk/channel-runtime";
|
||||
|
||||
function parseTelegramGroupId(value?: string | null) {
|
||||
const raw = value?.trim() ?? "";
|
||||
if (!raw) {
|
||||
return { chatId: undefined, topicId: undefined };
|
||||
}
|
||||
const parts = raw.split(":").filter(Boolean);
|
||||
if (
|
||||
parts.length >= 3 &&
|
||||
parts[1] === "topic" &&
|
||||
/^-?\d+$/.test(parts[0]) &&
|
||||
/^\d+$/.test(parts[2])
|
||||
) {
|
||||
return { chatId: parts[0], topicId: parts[2] };
|
||||
}
|
||||
if (parts.length >= 2 && /^-?\d+$/.test(parts[0]) && /^\d+$/.test(parts[1])) {
|
||||
return { chatId: parts[0], topicId: parts[1] };
|
||||
}
|
||||
return { chatId: raw, topicId: undefined };
|
||||
}
|
||||
|
||||
function resolveTelegramRequireMention(params: {
|
||||
cfg: ChannelGroupContext["cfg"];
|
||||
chatId?: string;
|
||||
topicId?: string;
|
||||
}): boolean | undefined {
|
||||
const { cfg, chatId, topicId } = params;
|
||||
if (!chatId) {
|
||||
return undefined;
|
||||
}
|
||||
const groupConfig = cfg.channels?.telegram?.groups?.[chatId];
|
||||
const groupDefault = cfg.channels?.telegram?.groups?.["*"];
|
||||
const topicConfig = topicId && groupConfig?.topics ? groupConfig.topics[topicId] : undefined;
|
||||
const defaultTopicConfig =
|
||||
topicId && groupDefault?.topics ? groupDefault.topics[topicId] : undefined;
|
||||
if (typeof topicConfig?.requireMention === "boolean") {
|
||||
return topicConfig.requireMention;
|
||||
}
|
||||
if (typeof defaultTopicConfig?.requireMention === "boolean") {
|
||||
return defaultTopicConfig.requireMention;
|
||||
}
|
||||
if (typeof groupConfig?.requireMention === "boolean") {
|
||||
return groupConfig.requireMention;
|
||||
}
|
||||
if (typeof groupDefault?.requireMention === "boolean") {
|
||||
return groupDefault.requireMention;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function resolveTelegramGroupRequireMention(
|
||||
params: ChannelGroupContext,
|
||||
): boolean | undefined {
|
||||
const { chatId, topicId } = parseTelegramGroupId(params.groupId);
|
||||
const requireMention = resolveTelegramRequireMention({
|
||||
cfg: params.cfg,
|
||||
chatId,
|
||||
topicId,
|
||||
});
|
||||
if (typeof requireMention === "boolean") {
|
||||
return requireMention;
|
||||
}
|
||||
return resolveChannelGroupRequireMention({
|
||||
cfg: params.cfg,
|
||||
channel: "telegram",
|
||||
groupId: chatId ?? params.groupId,
|
||||
accountId: params.accountId,
|
||||
});
|
||||
}
|
||||
|
||||
export function resolveTelegramGroupToolPolicy(
|
||||
params: ChannelGroupContext,
|
||||
): GroupToolPolicyConfig | undefined {
|
||||
const { chatId } = parseTelegramGroupId(params.groupId);
|
||||
return resolveChannelGroupToolsPolicy({
|
||||
cfg: params.cfg,
|
||||
channel: "telegram",
|
||||
groupId: chatId ?? params.groupId,
|
||||
accountId: params.accountId,
|
||||
senderId: params.senderId,
|
||||
senderName: params.senderName,
|
||||
senderUsername: params.senderUsername,
|
||||
senderE164: params.senderE164,
|
||||
});
|
||||
}
|
||||
@ -4,45 +4,8 @@ import {
|
||||
resolveBlueBubblesGroupToolPolicy,
|
||||
resolveLineGroupRequireMention,
|
||||
resolveLineGroupToolPolicy,
|
||||
resolveTelegramGroupRequireMention,
|
||||
resolveTelegramGroupToolPolicy,
|
||||
} from "./group-mentions.js";
|
||||
|
||||
describe("group mentions (telegram)", () => {
|
||||
it("resolves topic-level requireMention and chat-level tools for topic ids", () => {
|
||||
const telegramCfg = {
|
||||
channels: {
|
||||
telegram: {
|
||||
botToken: "telegram-test",
|
||||
groups: {
|
||||
"-1001": {
|
||||
requireMention: true,
|
||||
tools: { allow: ["message.send"] },
|
||||
topics: {
|
||||
"77": {
|
||||
requireMention: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
"*": {
|
||||
requireMention: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
} as any;
|
||||
expect(
|
||||
resolveTelegramGroupRequireMention({ cfg: telegramCfg, groupId: "-1001:topic:77" }),
|
||||
).toBe(false);
|
||||
expect(resolveTelegramGroupToolPolicy({ cfg: telegramCfg, groupId: "-1001:topic:77" })).toEqual(
|
||||
{
|
||||
allow: ["message.send"],
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("group mentions (bluebubbles)", () => {
|
||||
it("uses generic channel group policy helpers", () => {
|
||||
const blueBubblesCfg = {
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import {
|
||||
resolveChannelGroupRequireMention,
|
||||
resolveChannelGroupToolsPolicy,
|
||||
@ -9,55 +8,6 @@ import type { ChannelGroupContext } from "./types.js";
|
||||
|
||||
type GroupMentionParams = ChannelGroupContext;
|
||||
|
||||
function parseTelegramGroupId(value?: string | null) {
|
||||
const raw = value?.trim() ?? "";
|
||||
if (!raw) {
|
||||
return { chatId: undefined, topicId: undefined };
|
||||
}
|
||||
const parts = raw.split(":").filter(Boolean);
|
||||
if (
|
||||
parts.length >= 3 &&
|
||||
parts[1] === "topic" &&
|
||||
/^-?\d+$/.test(parts[0]) &&
|
||||
/^\d+$/.test(parts[2])
|
||||
) {
|
||||
return { chatId: parts[0], topicId: parts[2] };
|
||||
}
|
||||
if (parts.length >= 2 && /^-?\d+$/.test(parts[0]) && /^\d+$/.test(parts[1])) {
|
||||
return { chatId: parts[0], topicId: parts[1] };
|
||||
}
|
||||
return { chatId: raw, topicId: undefined };
|
||||
}
|
||||
|
||||
function resolveTelegramRequireMention(params: {
|
||||
cfg: OpenClawConfig;
|
||||
chatId?: string;
|
||||
topicId?: string;
|
||||
}): boolean | undefined {
|
||||
const { cfg, chatId, topicId } = params;
|
||||
if (!chatId) {
|
||||
return undefined;
|
||||
}
|
||||
const groupConfig = cfg.channels?.telegram?.groups?.[chatId];
|
||||
const groupDefault = cfg.channels?.telegram?.groups?.["*"];
|
||||
const topicConfig = topicId && groupConfig?.topics ? groupConfig.topics[topicId] : undefined;
|
||||
const defaultTopicConfig =
|
||||
topicId && groupDefault?.topics ? groupDefault.topics[topicId] : undefined;
|
||||
if (typeof topicConfig?.requireMention === "boolean") {
|
||||
return topicConfig.requireMention;
|
||||
}
|
||||
if (typeof defaultTopicConfig?.requireMention === "boolean") {
|
||||
return defaultTopicConfig.requireMention;
|
||||
}
|
||||
if (typeof groupConfig?.requireMention === "boolean") {
|
||||
return groupConfig.requireMention;
|
||||
}
|
||||
if (typeof groupDefault?.requireMention === "boolean") {
|
||||
return groupDefault.requireMention;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
type ChannelGroupPolicyChannel =
|
||||
| "telegram"
|
||||
| "whatsapp"
|
||||
@ -96,26 +46,6 @@ function resolveChannelToolPolicyForSender(
|
||||
});
|
||||
}
|
||||
|
||||
export function resolveTelegramGroupRequireMention(
|
||||
params: GroupMentionParams,
|
||||
): boolean | undefined {
|
||||
const { chatId, topicId } = parseTelegramGroupId(params.groupId);
|
||||
const requireMention = resolveTelegramRequireMention({
|
||||
cfg: params.cfg,
|
||||
chatId,
|
||||
topicId,
|
||||
});
|
||||
if (typeof requireMention === "boolean") {
|
||||
return requireMention;
|
||||
}
|
||||
return resolveChannelGroupRequireMention({
|
||||
cfg: params.cfg,
|
||||
channel: "telegram",
|
||||
groupId: chatId ?? params.groupId,
|
||||
accountId: params.accountId,
|
||||
});
|
||||
}
|
||||
|
||||
export function resolveWhatsAppGroupRequireMention(params: GroupMentionParams): boolean {
|
||||
return resolveChannelRequireMention(params, "whatsapp");
|
||||
}
|
||||
@ -138,13 +68,6 @@ export function resolveBlueBubblesGroupRequireMention(params: GroupMentionParams
|
||||
return resolveChannelRequireMention(params, "bluebubbles");
|
||||
}
|
||||
|
||||
export function resolveTelegramGroupToolPolicy(
|
||||
params: GroupMentionParams,
|
||||
): GroupToolPolicyConfig | undefined {
|
||||
const { chatId } = parseTelegramGroupId(params.groupId);
|
||||
return resolveChannelToolPolicyForSender(params, "telegram", chatId ?? params.groupId);
|
||||
}
|
||||
|
||||
export function resolveWhatsAppGroupToolPolicy(
|
||||
params: GroupMentionParams,
|
||||
): GroupToolPolicyConfig | undefined {
|
||||
|
||||
@ -14,7 +14,11 @@ export {
|
||||
collectOpenProviderGroupPolicyWarnings,
|
||||
} from "../channels/plugins/group-policy-warnings.js";
|
||||
export { buildAccountScopedDmSecurityPolicy } from "../channels/plugins/helpers.js";
|
||||
export { resolveChannelGroupRequireMention, resolveToolsBySender } from "../config/group-policy.js";
|
||||
export {
|
||||
resolveChannelGroupRequireMention,
|
||||
resolveChannelGroupToolsPolicy,
|
||||
resolveToolsBySender,
|
||||
} from "../config/group-policy.js";
|
||||
export {
|
||||
DM_GROUP_ACCESS_REASON,
|
||||
readStoreAllowFromForDmPolicy,
|
||||
|
||||
@ -57,7 +57,7 @@ export {
|
||||
export {
|
||||
resolveTelegramGroupRequireMention,
|
||||
resolveTelegramGroupToolPolicy,
|
||||
} from "../channels/plugins/group-mentions.js";
|
||||
} from "../../extensions/telegram/src/group-policy.js";
|
||||
export { TelegramConfigSchema } from "../config/zod-schema.providers-core.js";
|
||||
|
||||
export { buildTokenChannelStatusSummary } from "./status-helpers.js";
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user