refactor: deduplicate channel runtime helpers

This commit is contained in:
Peter Steinberger
2026-03-18 16:36:09 +00:00
parent 3e02635df3
commit 27f655ed11
47 changed files with 2595 additions and 1151 deletions

View File

@@ -1,11 +1,17 @@
import { buildAccountScopedAllowlistConfigEditor } from "openclaw/plugin-sdk/allowlist-config-edit";
import {
collectAllowlistProviderGroupPolicyWarnings,
collectOpenGroupPolicyRouteAllowlistWarnings,
createScopedDmSecurityResolver,
} from "openclaw/plugin-sdk/channel-config-helpers";
import { type OutboundSendDeps, resolveOutboundSendDep } from "openclaw/plugin-sdk/channel-runtime";
import { normalizeMessageChannel } from "openclaw/plugin-sdk/channel-runtime";
buildDmGroupAccountAllowlistAdapter,
createNestedAllowlistOverrideResolver,
} from "openclaw/plugin-sdk/allowlist-config-edit";
import { createScopedDmSecurityResolver } from "openclaw/plugin-sdk/channel-config-helpers";
import { createAllowlistProviderRouteAllowlistWarningCollector } from "openclaw/plugin-sdk/channel-policy";
import {
createChannelDirectoryAdapter,
createPairingPrefixStripper,
createTextPairingAdapter,
normalizeMessageChannel,
type OutboundSendDeps,
resolveOutboundSendDep,
} from "openclaw/plugin-sdk/channel-runtime";
import { buildOutboundBaseSessionKey, normalizeOutboundThreadId } from "openclaw/plugin-sdk/core";
import { resolveExecApprovalCommandDisplay } from "openclaw/plugin-sdk/infra-runtime";
import { buildExecApprovalPendingReplyPayload } from "openclaw/plugin-sdk/infra-runtime";
@@ -273,65 +279,66 @@ const resolveTelegramDmPolicy = createScopedDmSecurityResolver<ResolvedTelegramA
normalizeEntry: (raw) => raw.replace(/^(telegram|tg):/i, ""),
});
function readTelegramAllowlistConfig(account: ResolvedTelegramAccount) {
const groupOverrides: Array<{ label: string; entries: string[] }> = [];
for (const [groupId, groupCfg] of Object.entries(account.config.groups ?? {})) {
const entries = (groupCfg?.allowFrom ?? []).map(String).filter(Boolean);
if (entries.length > 0) {
groupOverrides.push({ label: groupId, entries });
}
for (const [topicId, topicCfg] of Object.entries(groupCfg?.topics ?? {})) {
const topicEntries = (topicCfg?.allowFrom ?? []).map(String).filter(Boolean);
if (topicEntries.length > 0) {
groupOverrides.push({ label: `${groupId} topic ${topicId}`, entries: topicEntries });
}
}
}
return {
dmAllowFrom: (account.config.allowFrom ?? []).map(String),
groupAllowFrom: (account.config.groupAllowFrom ?? []).map(String),
dmPolicy: account.config.dmPolicy,
groupPolicy: account.config.groupPolicy,
groupOverrides,
};
}
const resolveTelegramAllowlistGroupOverrides = createNestedAllowlistOverrideResolver({
resolveRecord: (account: ResolvedTelegramAccount) => account.config.groups,
outerLabel: (groupId) => groupId,
resolveOuterEntries: (groupCfg) => groupCfg?.allowFrom,
resolveChildren: (groupCfg) => groupCfg?.topics,
innerLabel: (groupId, topicId) => `${groupId} topic ${topicId}`,
resolveInnerEntries: (topicCfg) => topicCfg?.allowFrom,
});
const collectTelegramSecurityWarnings =
createAllowlistProviderRouteAllowlistWarningCollector<ResolvedTelegramAccount>({
providerConfigPresent: (cfg) => cfg.channels?.telegram !== undefined,
resolveGroupPolicy: (account) => account.config.groupPolicy,
resolveRouteAllowlistConfigured: (account) =>
Boolean(account.config.groups) && Object.keys(account.config.groups ?? {}).length > 0,
restrictSenders: {
surface: "Telegram groups",
openScope: "any member in allowed groups",
groupPolicyPath: "channels.telegram.groupPolicy",
groupAllowFromPath: "channels.telegram.groupAllowFrom",
},
noRouteAllowlist: {
surface: "Telegram groups",
routeAllowlistPath: "channels.telegram.groups",
routeScope: "group",
groupPolicyPath: "channels.telegram.groupPolicy",
groupAllowFromPath: "channels.telegram.groupAllowFrom",
},
});
export const telegramPlugin: ChannelPlugin<ResolvedTelegramAccount, TelegramProbe> = {
...createTelegramPluginBase({
setupWizard: telegramSetupWizard,
setup: telegramSetupAdapter,
}),
pairing: {
pairing: createTextPairingAdapter({
idLabel: "telegramUserId",
normalizeAllowEntry: (entry) => entry.replace(/^(telegram|tg):/i, ""),
notifyApproval: async ({ cfg, id }) => {
message: PAIRING_APPROVED_MESSAGE,
normalizeAllowEntry: createPairingPrefixStripper(/^(telegram|tg):/i),
notify: async ({ cfg, id, message }) => {
const { token } = getTelegramRuntime().channel.telegram.resolveTelegramToken(cfg);
if (!token) {
throw new Error("telegram token not configured");
}
await getTelegramRuntime().channel.telegram.sendMessageTelegram(
id,
PAIRING_APPROVED_MESSAGE,
{
token,
},
);
await getTelegramRuntime().channel.telegram.sendMessageTelegram(id, message, {
token,
});
},
},
allowlist: {
supportsScope: ({ scope }) => scope === "dm" || scope === "group" || scope === "all",
readConfig: ({ cfg, accountId }) =>
readTelegramAllowlistConfig(resolveTelegramAccount({ cfg, accountId })),
applyConfigEdit: buildAccountScopedAllowlistConfigEditor({
channelId: "telegram",
normalize: ({ cfg, accountId, values }) =>
telegramConfigAdapter.formatAllowFrom!({ cfg, accountId, allowFrom: values }),
resolvePaths: (scope) => ({
readPaths: [[scope === "dm" ? "allowFrom" : "groupAllowFrom"]],
writePath: [scope === "dm" ? "allowFrom" : "groupAllowFrom"],
}),
}),
},
}),
allowlist: buildDmGroupAccountAllowlistAdapter({
channelId: "telegram",
resolveAccount: ({ cfg, accountId }) => resolveTelegramAccount({ cfg, accountId }),
normalize: ({ cfg, accountId, values }) =>
telegramConfigAdapter.formatAllowFrom!({ cfg, accountId, allowFrom: values }),
resolveDmAllowFrom: (account) => account.config.allowFrom,
resolveGroupAllowFrom: (account) => account.config.groupAllowFrom,
resolveDmPolicy: (account) => account.config.dmPolicy,
resolveGroupPolicy: (account) => account.config.groupPolicy,
resolveGroupOverrides: resolveTelegramAllowlistGroupOverrides,
}),
bindings: {
compileConfiguredBinding: ({ conversationId }) =>
normalizeTelegramAcpConversationId(conversationId),
@@ -344,33 +351,7 @@ export const telegramPlugin: ChannelPlugin<ResolvedTelegramAccount, TelegramProb
},
security: {
resolveDmPolicy: resolveTelegramDmPolicy,
collectWarnings: ({ account, cfg }) => {
const groupAllowlistConfigured =
account.config.groups && Object.keys(account.config.groups).length > 0;
return collectAllowlistProviderGroupPolicyWarnings({
cfg,
providerConfigPresent: cfg.channels?.telegram !== undefined,
configuredGroupPolicy: account.config.groupPolicy,
collect: (groupPolicy) =>
collectOpenGroupPolicyRouteAllowlistWarnings({
groupPolicy,
routeAllowlistConfigured: Boolean(groupAllowlistConfigured),
restrictSenders: {
surface: "Telegram groups",
openScope: "any member in allowed groups",
groupPolicyPath: "channels.telegram.groupPolicy",
groupAllowFromPath: "channels.telegram.groupAllowFrom",
},
noRouteAllowlist: {
surface: "Telegram groups",
routeAllowlistPath: "channels.telegram.groups",
routeScope: "group",
groupPolicyPath: "channels.telegram.groupPolicy",
groupAllowFromPath: "channels.telegram.groupAllowFrom",
},
}),
});
},
collectWarnings: collectTelegramSecurityWarnings,
},
groups: {
resolveRequireMention: resolveTelegramGroupRequireMention,
@@ -471,11 +452,10 @@ export const telegramPlugin: ChannelPlugin<ResolvedTelegramAccount, TelegramProb
}).catch(() => {});
},
},
directory: {
self: async () => null,
directory: createChannelDirectoryAdapter({
listPeers: async (params) => listTelegramDirectoryPeersFromConfig(params),
listGroups: async (params) => listTelegramDirectoryGroupsFromConfig(params),
},
}),
actions: telegramMessageActions,
setup: telegramSetupAdapter,
outbound: {

View File

@@ -1,24 +1,20 @@
import { mapAllowFromEntries } from "openclaw/plugin-sdk/channel-config-helpers";
import {
applyDirectoryQueryAndLimit,
collectNormalizedDirectoryIds,
listDirectoryGroupEntriesFromMapKeys,
toDirectoryEntries,
listInspectedDirectoryEntriesFromSources,
type DirectoryConfigParams,
} from "openclaw/plugin-sdk/directory-runtime";
import { inspectTelegramAccount, type InspectedTelegramAccount } from "../api.js";
export async function listTelegramDirectoryPeersFromConfig(params: DirectoryConfigParams) {
const account: InspectedTelegramAccount = inspectTelegramAccount({
cfg: params.cfg,
accountId: params.accountId,
});
if (!account.config) {
return [];
}
const ids = collectNormalizedDirectoryIds({
sources: [mapAllowFromEntries(account.config.allowFrom), Object.keys(account.config.dms ?? {})],
return listInspectedDirectoryEntriesFromSources({
...params,
kind: "user",
inspectAccount: (cfg, accountId) =>
inspectTelegramAccount({ cfg, accountId }) as InspectedTelegramAccount | null,
resolveSources: (account) => [
mapAllowFromEntries(account.config.allowFrom),
Object.keys(account.config.dms ?? {}),
],
normalizeId: (entry) => {
const trimmed = entry.replace(/^(telegram|tg):/i, "").trim();
if (!trimmed) {
@@ -30,20 +26,15 @@ export async function listTelegramDirectoryPeersFromConfig(params: DirectoryConf
return trimmed.startsWith("@") ? trimmed : `@${trimmed}`;
},
});
return toDirectoryEntries("user", applyDirectoryQueryAndLimit(ids, params));
}
export async function listTelegramDirectoryGroupsFromConfig(params: DirectoryConfigParams) {
const account: InspectedTelegramAccount = inspectTelegramAccount({
cfg: params.cfg,
accountId: params.accountId,
});
if (!account.config) {
return [];
}
return listDirectoryGroupEntriesFromMapKeys({
groups: account.config.groups,
query: params.query,
limit: params.limit,
return listInspectedDirectoryEntriesFromSources({
...params,
kind: "group",
inspectAccount: (cfg, accountId) =>
inspectTelegramAccount({ cfg, accountId }) as InspectedTelegramAccount | null,
resolveSources: (account) => [Object.keys(account.config.groups ?? {})],
normalizeId: (entry) => entry.trim() || null,
});
}