Files
openclaw/extensions/telegram/src/approval-native.ts
Gustavo Madeira Santana c87c8e66bf Refactor channel approval capability seams (#58634)
Merged via squash.

Prepared head SHA: c9ad4e4706
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-04-01 17:10:25 -04:00

111 lines
4.3 KiB
TypeScript

import {
createChannelApproverDmTargetResolver,
createChannelNativeOriginTargetResolver,
createApproverRestrictedNativeApprovalCapability,
splitChannelApprovalCapability,
} from "openclaw/plugin-sdk/approval-runtime";
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
import type { ExecApprovalRequest, PluginApprovalRequest } from "openclaw/plugin-sdk/infra-runtime";
import { listTelegramAccountIds } from "./accounts.js";
import {
getTelegramExecApprovalApprovers,
isTelegramExecApprovalApprover,
isTelegramExecApprovalAuthorizedSender,
isTelegramExecApprovalClientEnabled,
resolveTelegramExecApprovalTarget,
shouldHandleTelegramExecApprovalRequest,
} from "./exec-approvals.js";
import { normalizeTelegramChatId, parseTelegramTarget } from "./targets.js";
type ApprovalRequest = ExecApprovalRequest | PluginApprovalRequest;
type TelegramOriginTarget = { to: string; threadId?: number };
function resolveTurnSourceTelegramOriginTarget(
request: ApprovalRequest,
): TelegramOriginTarget | null {
const turnSourceChannel = request.request.turnSourceChannel?.trim().toLowerCase() || "";
const rawTurnSourceTo = request.request.turnSourceTo?.trim() || "";
const parsedTurnSourceTarget = rawTurnSourceTo ? parseTelegramTarget(rawTurnSourceTo) : null;
const turnSourceTo = normalizeTelegramChatId(parsedTurnSourceTarget?.chatId ?? rawTurnSourceTo);
if (turnSourceChannel !== "telegram" || !turnSourceTo) {
return null;
}
const rawThreadId =
request.request.turnSourceThreadId ?? parsedTurnSourceTarget?.messageThreadId ?? undefined;
const threadId =
typeof rawThreadId === "number"
? rawThreadId
: typeof rawThreadId === "string"
? Number.parseInt(rawThreadId, 10)
: undefined;
return {
to: turnSourceTo,
threadId: Number.isFinite(threadId) ? threadId : undefined,
};
}
function resolveSessionTelegramOriginTarget(sessionTarget: {
to: string;
threadId?: number | null;
}): TelegramOriginTarget {
return {
to: normalizeTelegramChatId(sessionTarget.to) ?? sessionTarget.to,
threadId: sessionTarget.threadId ?? undefined,
};
}
function telegramTargetsMatch(a: TelegramOriginTarget, b: TelegramOriginTarget): boolean {
const normalizedA = normalizeTelegramChatId(a.to) ?? a.to;
const normalizedB = normalizeTelegramChatId(b.to) ?? b.to;
return normalizedA === normalizedB && a.threadId === b.threadId;
}
const resolveTelegramOriginTarget = createChannelNativeOriginTargetResolver({
channel: "telegram",
shouldHandleRequest: ({ cfg, accountId, request }) =>
shouldHandleTelegramExecApprovalRequest({
cfg,
accountId,
request,
}),
resolveTurnSourceTarget: resolveTurnSourceTelegramOriginTarget,
resolveSessionTarget: resolveSessionTelegramOriginTarget,
targetsMatch: telegramTargetsMatch,
});
const resolveTelegramApproverDmTargets = createChannelApproverDmTargetResolver({
shouldHandleRequest: ({ cfg, accountId, request }) =>
shouldHandleTelegramExecApprovalRequest({
cfg,
accountId,
request,
}),
resolveApprovers: getTelegramExecApprovalApprovers,
mapApprover: (approver) => ({ to: approver }),
});
export const telegramApprovalCapability = createApproverRestrictedNativeApprovalCapability({
channel: "telegram",
channelLabel: "Telegram",
listAccountIds: listTelegramAccountIds,
hasApprovers: ({ cfg, accountId }) =>
getTelegramExecApprovalApprovers({ cfg, accountId }).length > 0,
isExecAuthorizedSender: ({ cfg, accountId, senderId }) =>
isTelegramExecApprovalAuthorizedSender({ cfg, accountId, senderId }),
isPluginAuthorizedSender: ({ cfg, accountId, senderId }) =>
isTelegramExecApprovalApprover({ cfg, accountId, senderId }),
isNativeDeliveryEnabled: ({ cfg, accountId }) =>
isTelegramExecApprovalClientEnabled({ cfg, accountId }),
resolveNativeDeliveryMode: ({ cfg, accountId }) =>
resolveTelegramExecApprovalTarget({ cfg, accountId }),
requireMatchingTurnSourceChannel: true,
resolveSuppressionAccountId: ({ target, request }) =>
target.accountId?.trim() || request.request.turnSourceAccountId?.trim() || undefined,
resolveOriginTarget: resolveTelegramOriginTarget,
resolveApproverDmTargets: resolveTelegramApproverDmTargets,
});
export const telegramNativeApprovalAdapter = splitChannelApprovalCapability(
telegramApprovalCapability,
);