UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

241 lines (240 loc) 10.8 kB
import { w as parseStrictPositiveInteger } from "./number-coercion-CLj0HTDM.js"; import { l as normalizeOptionalString } from "./string-coerce-CIXf7egm.js"; import { t as formatErrorMessage } from "./errors-Db3Ymjlb.js"; import { t as createSubsystemLogger } from "./subsystem-Dy2tqXOS.js"; import { t as resolveGatewayPublicOrigin } from "./gateway-public-origin-BcHLka2A.js"; import { t as buildChannelApprovalNativeTargetKey } from "./approval-native-target-key-uR5nEUEh.js"; import "./error-runtime-Bz9Tw57Z.js"; import "./runtime-env-0Q-gCyUb.js"; import "./number-runtime-Cy4drVnh.js"; import "./string-coerce-runtime-GQa0ehRA.js"; import { a as buildExecApprovalPendingReplyPayload, f as formatExecApprovalExpiresIn, n as buildApprovalPresentationFromActionDescriptors } from "./exec-approval-reply-ZdeEqz7J.js"; import { r as buildPluginApprovalPendingReplyPayload } from "./approval-renderers-DKlGmVsG.js"; import { r as createChannelApprovalNativeRuntimeAdapter } from "./approval-handler-runtime-BZs1zst-.js"; import "./approval-handler-runtime-BaeL6I-O.js"; import "./approval-native-runtime-DJtPnIU-.js"; import "./approval-reply-runtime-CaHYlGF_.js"; import { i as normalizeTelegramChatId, s as parseTelegramTarget } from "./topic-conversation-Cl4csGES.js"; import { a as isTelegramExecApprovalHandlerConfigured, l as shouldHandleTelegramExecApprovalRequest } from "./exec-approvals-CmtRI1wa.js"; import { N as escapeTelegramHtml } from "./text-chunk-limit-C3EsGj6Q.js"; import { o as buildTelegramApprovalCallbackData } from "./native-command-callback-data-C1RSVJRf.js"; import { r as resolveTelegramInlineButtons } from "./button-types-BNe7Hg2C.js"; import { b as editMessageTelegram, k as sendTypingTelegram, u as sendMessageTelegram, y as editMessageReplyMarkupTelegram } from "./send-BXHKghr-.js"; import { a as buildTelegramNativeResolvedApprovalText, i as buildTelegramNativeExpiredApprovalText } from "./approval-terminal-penH9HOv.js"; //#region extensions/telegram/src/approval-handler.runtime.ts const log = createSubsystemLogger("telegram/approvals"); const terminalizedSystemAgentApprovals = /* @__PURE__ */ new Set(); function resolveHandlerContext(params) { const context = params.context; const accountId = normalizeOptionalString(params.accountId) ?? ""; if (!context?.token || !accountId) return null; return { accountId, context }; } function buildPendingPayload(params) { if (params.approvalKind === "system-agent") { const view = params.view; if (view.approvalKind !== "system-agent") throw new Error("system-agent approval request and view kinds do not match"); const origin = resolveGatewayPublicOrigin(params.cfg); const reviewUrl = origin && params.cfg.gateway?.controlUi?.enabled !== false ? `${origin}${normalizeTelegramControlUiBasePath(params.cfg.gateway?.controlUi?.basePath)}/approve/${encodeURIComponent(params.request.id)}` : void 0; const lines = [ "🔒 OpenClaw change requires approval", `Change: ${view.operationSummary}`, `Agent: ${view.agentId ?? "unknown"}`, `Expires in: ${formatExecApprovalExpiresIn(params.request.expiresAtMs, params.nowMs)}` ]; const decisionButtons = view.actions.flatMap((action) => { const approvalAction = action.action; if (!approvalAction || approvalAction.type !== "approval") return []; const callbackData = buildTelegramApprovalCallbackData(approvalAction); const style = action.style === "danger" || action.style === "success" || action.style === "primary" ? action.style : void 0; return callbackData ? [{ text: action.label, callback_data: callbackData, ...style ? { style } : {} }] : []; }); return { text: lines.join("\n"), buttons: reviewUrl ? [[{ text: "Review in Control UI", url: reviewUrl }], ...decisionButtons.length > 0 ? [decisionButtons] : []] : decisionButtons.length > 0 ? [decisionButtons] : [] }; } return { text: (params.approvalKind === "plugin" ? buildPluginApprovalPendingReplyPayload({ request: params.request, nowMs: params.nowMs }) : buildExecApprovalPendingReplyPayload({ approvalId: params.request.id, approvalSlug: params.request.id.slice(0, 8), approvalCommandId: params.request.id, warningText: params.view.approvalKind === "exec" ? params.view.warningText ?? void 0 : void 0, command: params.view.approvalKind === "exec" ? params.view.commandText : "", cwd: params.view.approvalKind === "exec" ? params.view.cwd ?? void 0 : void 0, host: params.view.approvalKind === "exec" && params.view.host === "node" ? "node" : "gateway", nodeId: params.view.approvalKind === "exec" ? params.view.nodeId ?? void 0 : void 0, scope: params.view.approvalKind === "exec" ? params.view.scope ?? void 0 : void 0, allowedDecisions: params.view.actions.map((action) => action.decision), expiresAtMs: params.request.expiresAtMs, nowMs: params.nowMs })).text ?? "", buttons: resolveTelegramInlineButtons({ presentation: buildApprovalPresentationFromActionDescriptors(params.view.actions) }) }; } const telegramApprovalNativeRuntime = createChannelApprovalNativeRuntimeAdapter({ eventKinds: [ "exec", "plugin", "system-agent" ], availability: { isConfigured: (params) => { const resolved = resolveHandlerContext(params); return resolved ? isTelegramExecApprovalHandlerConfigured({ cfg: params.cfg, accountId: resolved.accountId }) : false; }, shouldHandle: (params) => { const resolved = resolveHandlerContext(params); return resolved ? shouldHandleTelegramExecApprovalRequest({ cfg: params.cfg, accountId: resolved.accountId, request: params.request }) : false; } }, presentation: { buildPendingPayload: ({ cfg, request, approvalKind, nowMs, view }) => buildPendingPayload({ cfg, request, approvalKind, nowMs, view }), buildResolvedResult: ({ view }) => ({ kind: "update", payload: { text: buildTelegramNativeResolvedApprovalText(view) } }), buildExpiredResult: ({ view }) => ({ kind: "update", payload: { text: buildTelegramNativeExpiredApprovalText(view) } }) }, transport: { prepareTarget: ({ plannedTarget }) => { const parsedTarget = parseTelegramTarget(plannedTarget.target.to); return { dedupeKey: buildChannelApprovalNativeTargetKey(plannedTarget.target), target: { chatId: parsedTarget.chatId, messageThreadId: typeof plannedTarget.target.threadId === "number" ? plannedTarget.target.threadId : parsedTarget.messageThreadId, directMessagesTopicId: parsedTarget.directMessagesTopicId } }; }, deliverPending: async ({ cfg, accountId, context, preparedTarget, pendingPayload }) => { const resolved = resolveHandlerContext({ cfg, accountId, context }); if (!resolved) return null; const sendTyping = resolved.context.deps?.sendTyping ?? sendTypingTelegram; const sendMessage = resolved.context.deps?.sendMessage ?? sendMessageTelegram; await sendTyping(preparedTarget.chatId, { cfg, token: resolved.context.token, accountId: resolved.accountId, ...preparedTarget.messageThreadId != null ? { messageThreadId: preparedTarget.messageThreadId } : {} }).catch(() => {}); const result = await sendMessage(preparedTarget.chatId, pendingPayload.text, { cfg, token: resolved.context.token, accountId: resolved.accountId, buttons: pendingPayload.buttons, ...preparedTarget.messageThreadId != null ? { messageThreadId: preparedTarget.messageThreadId } : {}, ...preparedTarget.directMessagesTopicId != null ? { directMessagesTopicId: preparedTarget.directMessagesTopicId } : {} }); return { chatId: result.chatId, messageId: result.messageId }; }, updateEntry: async ({ cfg, accountId, context, entry, payload, request, approvalKind }) => { const resolved = resolveHandlerContext({ cfg, accountId, context }); if (!resolved) return; const editMessage = resolved.context.deps?.editMessage ?? editMessageTelegram; let editError; try { await editMessage(entry.chatId, entry.messageId, escapeTelegramHtml(payload.text), { cfg, token: resolved.context.token, accountId: resolved.accountId, textMode: "html", buttons: [] }); } catch (error) { editError = error; } if (approvalKind === "system-agent" && request.request.turnSourceChannel?.trim().toLowerCase() === "telegram") { const originTarget = request.request.turnSourceTo?.trim(); const parsedOrigin = originTarget ? parseTelegramTarget(originTarget) : void 0; const originChatId = parsedOrigin ? normalizeTelegramChatId(parsedOrigin.chatId) : void 0; const originThreadId = parseStrictPositiveInteger(request.request.turnSourceThreadId) ?? parsedOrigin?.messageThreadId; const sourceAccountId = request.request.turnSourceAccountId?.trim(); const isSourceAccount = !sourceAccountId || sourceAccountId === resolved.accountId; if (originChatId && isSourceAccount && (entry.chatId !== originChatId || editError !== void 0)) { if (!terminalizedSystemAgentApprovals.has(request.id)) { await (resolved.context.deps?.sendMessage ?? sendMessageTelegram)(parsedOrigin?.directMessagesTopicId != null ? originTarget : originChatId, escapeTelegramHtml(payload.text), { cfg, token: resolved.context.token, accountId: resolved.accountId, textMode: "html", ...originThreadId != null ? { messageThreadId: originThreadId } : {} }); terminalizedSystemAgentApprovals.add(request.id); } } else if (originChatId && isSourceAccount) terminalizedSystemAgentApprovals.add(request.id); } if (editError !== void 0) throw editError instanceof Error ? editError : new Error(formatErrorMessage(editError)); } }, interactions: { clearPendingActions: async ({ cfg, accountId, context, entry }) => { const resolved = resolveHandlerContext({ cfg, accountId, context }); if (!resolved) return; await (resolved.context.deps?.editReplyMarkup ?? editMessageReplyMarkupTelegram)(entry.chatId, entry.messageId, [], { cfg, token: resolved.context.token, accountId: resolved.accountId }); } }, observe: { onDeliveryError: ({ error, request }) => { log.error(`telegram approvals: failed to send request ${request.id}: ${String(error)}`); }, onFinalized: ({ request, approvalKind }) => { if (approvalKind === "system-agent") terminalizedSystemAgentApprovals.delete(request.id); } } }); function normalizeTelegramControlUiBasePath(value) { const trimmed = value?.trim() ?? ""; if (!trimmed || trimmed === "/") return ""; const withSlash = trimmed.startsWith("/") ? trimmed : `/${trimmed}`; return withSlash.endsWith("/") ? withSlash.slice(0, -1) : withSlash; } //#endregion export { telegramApprovalNativeRuntime };