openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
630 lines (629 loc) • 25.6 kB
JavaScript
import { w as parseStrictPositiveInteger } from "./number-coercion-CLj0HTDM.js";
import { t as formatErrorMessage } from "./errors-Db3Ymjlb.js";
import { r as logVerbose, t as danger } from "./globals-CTaGxEqj.js";
import { b as fireAndForgetHook, t as getGlobalHookRunner } from "./hook-runner-global-0kfmMG4T.js";
import "./channel-outbound-Dw9bfhFK.js";
import { r as probeVideoDimensions } from "./media-probe-Dbs998-L.js";
import { f as normalizeMessagePresentation } from "./payload-DYE7bQ2k.js";
import { d as toPluginMessageSentEvent, l as toPluginMessageContext, o as toInternalMessageSentContext, t as buildCanonicalSentMessageHookContext } from "./message-hook-mappers-oV7hnRsq.js";
import { n as isSingleUseReplyToMode } from "./reply-reference-cLEWJ7Kr.js";
import { i as projectOutboundPayloadPlanForDelivery, t as createOutboundPayloadPlan } from "./payloads-DC1mf-yF.js";
import { n as createInternalHookEvent, u as triggerInternalHook } from "./internal-hooks-Dgwjgwuj.js";
import { n as loadWebMedia } from "./web-media-C9Ri3Aft.js";
import { t as buildOutboundMediaLoadOptions } from "./load-options-VzbF4ozo.js";
import "./runtime-env-0Q-gCyUb.js";
import "./number-runtime-Cy4drVnh.js";
import { i as isChannelPartialDeliveryError } from "./delivery-result-jWGDGh5u.js";
import "./reply-reference-CdV5SXbF.js";
import "./channel-inbound-DreWTphY.js";
import "./web-media-CbeT3HsJ.js";
import "./ssrf-runtime-Bum5C6NN.js";
import "./media-runtime--XhyE_WP.js";
import "./plugin-runtime-Cl_BX05Z.js";
import "./hook-runtime-mcMuhifZ.js";
import { c as resolveTelegramTargetChatType } from "./topic-conversation-Cl4csGES.js";
import { x as resolveTelegramReplyId } from "./helpers-C9zWfRKz.js";
import { O as buildInlineKeyboard, f as isTelegramEmptyContentError, r as TELEGRAM_RICH_TEXT_LIMIT } from "./text-chunk-limit-C3EsGj6Q.js";
import { r as resolveTelegramInlineButtons } from "./button-types-BNe7Hg2C.js";
import { n as resolveTelegramInteractiveTextFallback, t as canonicalizeTelegramPresentationPayload } from "./interactive-fallback-DOi9HmOl.js";
import { L as reportTelegramProviderDelivery, O as reactMessageTelegram, R as recordSentMessage, _ as isTelegramVoiceMessagesForbiddenError, d as createTelegramPreparedSender, f as createTelegramReplyRequest, g as isTelegramCaptionTooLongError, h as resolveTelegramOutboundMediaSenders, m as prepareTelegramOutboundMedia, rt as buildTelegramSendParams, x as planTelegramTextDeliveryPages } from "./send-BXHKghr-.js";
//#region extensions/telegram/src/bot/delivery.replies.ts
function markDelivered(progress) {
progress.hasDelivered = true;
progress.deliveredCount += 1;
}
function resolveReplyToForSend(params) {
return params.replyToId && (params.replyToMode === "all" || !params.progress.hasReplied) ? params.replyToId : void 0;
}
function markReplyApplied(progress, replyToId) {
if (replyToId && !progress.hasReplied) progress.hasReplied = true;
}
function filterEmptyTelegramTextChunks(chunks) {
return chunks.filter((chunk) => chunk.richMessage?.blocks.length || chunk.htmlText?.trim() || chunk.plainText.trim());
}
function resolveReplyQuoteForSend(params) {
if (params.replyToId != null) {
const mapped = params.replyQuoteByMessageId?.[String(params.replyToId)];
if (mapped?.text) {
const quote = {
messageId: params.replyToId,
text: mapped.text
};
if (typeof mapped.position === "number") quote.position = mapped.position;
if (mapped.entities) quote.entities = mapped.entities;
return quote;
}
}
const quote = {};
if (params.replyQuoteMessageId != null) quote.messageId = params.replyQuoteMessageId;
if (params.replyQuoteText != null) quote.text = params.replyQuoteText;
if (params.replyQuotePosition != null) quote.position = params.replyQuotePosition;
if (params.replyQuoteEntities != null) quote.entities = params.replyQuoteEntities;
return quote;
}
async function deliverTextReply(params) {
const chunks = filterEmptyTelegramTextChunks(params.chunkText(params.text));
const suppressReply = chunks.length > 1 && isSingleUseReplyToMode(params.replyToMode);
return (await params.sender.sendText({
pages: chunks,
context: params.richMessages ? "sendRichMessage" : "sendMessage",
tracking: {
invalidate: () => params.progress.promptContext?.invalidate(),
onRejected: (error) => params.runtime.error?.(danger(`telegram reply chunk rejected; continuing: ${formatErrorMessage(error)}`)),
onSilentSkip: (error) => params.runtime.log?.(`telegram reply chunk rendered empty; skipping: ${formatErrorMessage(error)}`)
},
preparePage: (_index, acceptedPages) => {
const first = acceptedPages === 0;
const replyToMessageId = suppressReply ? void 0 : resolveReplyToForSend(params);
const includeQuote = params.quoteOnlyOnFirstChunk !== true || first;
const base = buildTelegramSendParams({
replyToMessageId,
replyQuoteMessageId: includeQuote ? params.replyQuoteMessageId : void 0,
replyQuoteText: replyToMessageId && includeQuote ? params.replyQuoteText : void 0,
replyQuotePosition: includeQuote ? params.replyQuotePosition : void 0,
replyQuoteEntities: includeQuote ? params.replyQuoteEntities : void 0,
thread: params.thread,
silent: params.silent
});
return {
requestParams: (fallback) => {
const requestParams = { ...base };
if (fallback?.index) {
delete requestParams.reply_parameters;
delete requestParams.reply_to_message_id;
}
return {
...requestParams,
...params.linkPreview === false ? { link_preview_options: { is_disabled: true } } : {},
...first && params.replyMarkup && (!fallback || fallback.index === fallback.count - 1) ? { reply_markup: params.replyMarkup } : {}
};
},
delivered: () => {
markReplyApplied(params.progress, suppressReply && first ? params.replyToId : replyToMessageId);
markDelivered(params.progress);
}
};
},
observe: async ({ result, messageId, plainText }) => {
if (params.thread?.id !== void 0) await reportTelegramProviderDelivery({
message: result,
messageId,
fallbackChatId: params.chatId,
successfulSendThread: params.thread
});
params.runtime.log?.(`telegram text delivery ok chat=${params.chatId} message=${messageId}`);
params.recordMessageId(messageId);
await params.progress.promptContext?.accept({
messageId,
text: plainText
});
}
}))[0]?.messageId;
}
function resolveVoiceFallbackText(reply) {
if (reply.text?.trim()) return reply.text;
if (reply.spokenText?.trim()) return reply.spokenText;
}
async function deliverMediaReply(params) {
let firstDeliveredMessageId;
let visibleFallbackText;
let firstDeliveredCaption;
const mediaUrls = [];
const recordPromptContextMessage = async (message, text) => {
const promptContextMessage = {
messageId: message.message_id,
message,
...text ? { text } : {}
};
await params.progress.promptContext?.accept(promptContextMessage);
};
const deliverAcceptedMedia = async (options) => {
const delivery = await params.sender.sendMedia(options);
await params.sender.accept(delivery, async ({ result: message, messageId, plainText }) => {
mediaUrls.push(options.mediaUrl);
if (params.thread?.id !== void 0) await reportTelegramProviderDelivery({
message,
messageId,
fallbackChatId: params.chatId,
successfulSendThread: params.thread
});
firstDeliveredMessageId ??= messageId;
firstDeliveredCaption ??= plainText || void 0;
if (delivery.captionRemoved) visibleFallbackText = "";
params.recordMessageId(messageId);
await recordPromptContextMessage(message, plainText || void 0);
markDelivered(params.progress);
});
};
const createVoiceFallbackProgress = () => ({
hasReplied: false,
hasDelivered: false,
deliveredCount: 0,
...params.progress.promptContext ? { promptContext: params.progress.promptContext } : {}
});
for (const [index, mediaUrl] of params.mediaList.entries()) {
const isFirstMedia = index === 0;
const media = await params.mediaLoader(mediaUrl, buildOutboundMediaLoadOptions({
mediaLocalRoots: params.mediaLocalRoots,
maxBytes: params.mediaMaxBytes
}));
const mediaPlan = prepareTelegramOutboundMedia({
media,
text: isFirstMedia ? params.reply.text ?? void 0 : void 0,
textMode: params.textMode,
tableMode: params.tableMode,
preparedHtml: true
});
const { sender: mediaSender, documentSender } = resolveTelegramOutboundMediaSenders({
api: params.bot.api,
chatId: params.chatId,
media,
plan: mediaPlan,
asVoice: params.reply.audioAsVoice
});
const { htmlCaption, plainCaption, followUpText } = mediaPlan;
const replyToMessageId = resolveReplyToForSend({
replyToId: params.replyToId,
replyToMode: params.replyToMode,
progress: params.progress
});
const shouldAttachButtonsToMedia = isFirstMedia && params.replyMarkup && !followUpText;
const videoDimensions = mediaPlan.kind === "video" ? await probeVideoDimensions(media.buffer) : void 0;
const mediaParams = {
caption: htmlCaption,
...htmlCaption ? { parse_mode: "HTML" } : {},
...shouldAttachButtonsToMedia ? { reply_markup: params.replyMarkup } : {},
...videoDimensions ? {
width: videoDimensions.width,
height: videoDimensions.height
} : {},
...buildTelegramSendParams({
replyToMessageId,
replyQuoteMessageId: params.replyQuoteMessageId,
replyQuoteText: params.replyQuoteText,
replyQuotePosition: params.replyQuotePosition,
replyQuoteEntities: params.replyQuoteEntities,
thread: params.thread,
silent: params.silent
})
};
if (mediaSender.label === "voice") {
const sendVoiceMedia = async (requestParams) => {
const hasCaption = typeof requestParams.caption === "string";
await deliverAcceptedMedia({
sender: mediaSender,
mediaUrl,
requestParams,
plainCaption: hasCaption ? plainCaption : void 0
});
};
const sendVoiceFallbackText = async (text, options = {}) => await deliverTextReply({
sender: params.sender,
chatId: params.chatId,
runtime: params.runtime,
text,
chunkText: params.chunkText,
replyToId: options.replyToId,
...options.includeQuote ? {
replyQuoteMessageId: params.replyQuoteMessageId,
replyQuotePosition: params.replyQuotePosition,
replyQuoteEntities: params.replyQuoteEntities,
replyQuoteText: params.replyQuoteText
} : {},
thread: params.thread,
richMessages: params.richMessages,
linkPreview: params.linkPreview,
silent: params.silent,
replyMarkup: params.replyMarkup,
replyToMode: options.replyToMode ?? params.replyToMode,
progress: createVoiceFallbackProgress(),
recordMessageId: params.recordMessageId,
quoteOnlyOnFirstChunk: true
});
await params.onVoiceRecording?.();
try {
await sendVoiceMedia(mediaParams);
} catch (voiceErr) {
if (isChannelPartialDeliveryError(voiceErr)) throw voiceErr;
if (isTelegramVoiceMessagesForbiddenError(voiceErr)) {
const fallbackText = resolveVoiceFallbackText(params.reply);
if (!fallbackText || !fallbackText.trim()) throw voiceErr;
logVerbose("telegram sendVoice forbidden (recipient has voice messages blocked in privacy settings); falling back to text");
const voiceFallbackReplyTo = resolveReplyToForSend({
replyToId: params.replyToId,
replyToMode: params.replyToMode,
progress: params.progress
});
const fallbackMessageId = await sendVoiceFallbackText(fallbackText, {
replyToId: voiceFallbackReplyTo,
includeQuote: true
});
if (fallbackMessageId === void 0) throw voiceErr;
firstDeliveredMessageId ??= fallbackMessageId;
visibleFallbackText = fallbackText;
markReplyApplied(params.progress, voiceFallbackReplyTo);
markDelivered(params.progress);
continue;
}
if (isTelegramCaptionTooLongError(voiceErr)) {
logVerbose("telegram sendVoice caption too long; resending voice without caption + text separately");
const noCaptionParams = { ...mediaParams };
delete noCaptionParams.caption;
delete noCaptionParams.parse_mode;
await sendVoiceMedia(noCaptionParams);
const fallbackText = resolveVoiceFallbackText(params.reply);
if (fallbackText?.trim()) try {
if (await sendVoiceFallbackText(fallbackText, { replyToMode: "first" }) !== void 0) visibleFallbackText = fallbackText;
} catch (fallbackError) {
if (isChannelPartialDeliveryError(fallbackError) || !isTelegramEmptyContentError(fallbackError)) throw fallbackError;
visibleFallbackText = "";
}
markReplyApplied(params.progress, replyToMessageId);
continue;
}
throw voiceErr;
}
} else await deliverAcceptedMedia({
sender: mediaSender,
documentSender,
mediaUrl,
requestParams: mediaParams,
plainCaption
});
markReplyApplied(params.progress, replyToMessageId);
if (followUpText) try {
if (await deliverTextReply({
sender: params.sender,
chatId: params.chatId,
runtime: params.runtime,
thread: params.thread,
chunkText: params.chunkText,
text: followUpText,
replyMarkup: params.replyMarkup,
richMessages: params.richMessages,
linkPreview: params.linkPreview,
silent: params.silent,
replyToId: params.replyToId,
replyToMode: params.replyToMode,
progress: params.progress,
recordMessageId: params.recordMessageId
}) === void 0) visibleFallbackText = firstDeliveredCaption ?? "";
else visibleFallbackText = void 0;
} catch (error) {
if (isChannelPartialDeliveryError(error) || !isTelegramEmptyContentError(error)) throw error;
visibleFallbackText = firstDeliveredCaption ?? "";
if (params.replyMarkup && firstDeliveredMessageId !== void 0) await params.bot.api.editMessageReplyMarkup(params.chatId, firstDeliveredMessageId, { reply_markup: params.replyMarkup });
}
}
return {
firstDeliveredMessageId,
visibleFallbackText,
mediaUrls
};
}
async function maybePinFirstDeliveredMessage(params) {
if (!(params.pin === true || typeof params.pin === "object" && params.pin.enabled) || typeof params.firstDeliveredMessageId !== "number") return;
const notify = typeof params.pin === "object" && params.pin.notify === true;
try {
await params.bot.api.pinChatMessage(params.chatId, params.firstDeliveredMessageId, { disable_notification: !notify });
} catch (err) {
if (typeof params.pin === "object" && params.pin.required === true) throw err;
logVerbose(`telegram pinChatMessage failed chat=${params.chatId} message=${params.firstDeliveredMessageId}: ${formatErrorMessage(err)}`);
}
}
function buildTelegramSentHookContext(params) {
return buildCanonicalSentMessageHookContext({
to: params.chatId,
content: params.content,
success: params.success,
error: params.error,
channelId: "telegram",
accountId: params.accountId,
conversationId: params.chatId,
messageId: typeof params.messageId === "number" ? String(params.messageId) : void 0,
isGroup: params.isGroup,
groupId: params.groupId
});
}
function emitInternalMessageSentHook(params) {
if (!params.sessionKeyForInternalHooks) return;
const canonical = buildTelegramSentHookContext(params);
fireAndForgetHook(triggerInternalHook(createInternalHookEvent("message", "sent", params.sessionKeyForInternalHooks, toInternalMessageSentContext(canonical))), "telegram: message:sent internal hook failed");
}
function emitMessageSentHooks(params) {
if (!params.enabled && !params.sessionKeyForInternalHooks) return;
const canonical = buildTelegramSentHookContext(params);
if (params.enabled) fireAndForgetHook(Promise.resolve(params.hookRunner.runMessageSent(toPluginMessageSentEvent(canonical), toPluginMessageContext(canonical))), "telegram: message_sent plugin hook failed");
emitInternalMessageSentHook(params);
}
function emitTelegramMessageSentHooks(params) {
const hookRunner = getGlobalHookRunner();
emitMessageSentHooks({
...params,
hookRunner,
enabled: hookRunner?.hasHooks("message_sent") ?? false
});
}
async function deliverReplies(params) {
const progress = {
hasReplied: false,
hasDelivered: false,
deliveredCount: 0,
...params.promptContextSequence ? { promptContext: params.promptContextSequence } : {}
};
const recordMessageId = (messageId) => {
if (params.accountId || params.ownerAgentId) {
recordSentMessage(params.chatId, messageId, params.cfg, {
accountId: params.accountId,
agentId: params.ownerAgentId
});
return;
}
recordSentMessage(params.chatId, messageId, params.cfg);
};
const mediaLoader = params.mediaLoader ?? loadWebMedia;
const transcriptMirror = params.transcriptMirror;
const deliveredContents = [];
const hookRunner = getGlobalHookRunner();
const hasMessageSendingHooks = hookRunner?.hasHooks("message_sending") ?? false;
const hasMessageSentHooks = hookRunner?.hasHooks("message_sent") ?? false;
const chunkText = (text) => planTelegramTextDeliveryPages({
text,
maxChars: params.richMessages === true ? Math.min(params.textLimit, TELEGRAM_RICH_TEXT_LIMIT) : Math.min(params.textLimit, 4e3),
chunkMode: params.chunkMode ?? "length",
tableMode: params.tableMode,
richMessages: params.richMessages,
skipEntityDetection: params.linkPreview === false,
...params.textMode ? { textMode: params.textMode } : {}
});
const candidateReplies = [];
for (const reply of params.replies) {
if (!reply || typeof reply !== "object") {
params.runtime.error?.(danger("reply missing text/media"));
continue;
}
candidateReplies.push(reply);
}
const normalizedReplies = projectOutboundPayloadPlanForDelivery(createOutboundPayloadPlan(candidateReplies, {
cfg: params.cfg,
sessionKey: params.policySessionKey ?? params.sessionKeyForInternalHooks,
surface: "telegram"
}));
for (const originalReply of normalizedReplies) {
let reply = canonicalizeTelegramPresentationPayload(originalReply, {
allowWebAppButtons: resolveTelegramTargetChatType(params.chatId) === "direct",
richTables: params.richMessages === true && params.textMode !== "html"
});
const mediaList = reply?.mediaUrls?.length ? reply.mediaUrls : reply?.mediaUrl ? [reply.mediaUrl] : [];
const hasMedia = mediaList.length > 0;
const presentation = normalizeMessagePresentation(reply?.presentation);
const interactive = reply?.interactive;
const resolvedReplyText = resolveTelegramInteractiveTextFallback({
text: reply?.text,
interactive,
presentation
}) ?? reply?.text ?? "";
if (reply && resolvedReplyText !== (reply.text ?? "")) reply = {
...reply,
text: resolvedReplyText
};
const telegramData = reply.channelData?.telegram;
const reactionEmoji = typeof telegramData?.reaction?.emoji === "string" ? telegramData.reaction.emoji : void 0;
const replyToId = params.replyToMode === "off" ? void 0 : resolveTelegramReplyId(reply.replyToId);
const targetId = parseStrictPositiveInteger(telegramData?.reaction?.replyToId ?? replyToId);
if (reactionEmoji && typeof targetId !== "number") {
params.runtime.error?.(danger("Telegram reaction requires a reply target"));
continue;
}
if (!resolvedReplyText && !hasMedia && !reactionEmoji) {
if (reply?.audioAsVoice) {
logVerbose("telegram reply has audioAsVoice without media/text; skipping");
continue;
}
params.runtime.error?.(danger("reply missing text/media"));
continue;
}
const rawContent = resolvedReplyText;
const spokenHookContent = !rawContent && reply.audioAsVoice === true && reply.spokenText?.trim() ? reply.spokenText : void 0;
const hookContent = spokenHookContent ?? rawContent;
const replyQuote = resolveReplyQuoteForSend({
replyToId,
replyQuoteByMessageId: params.replyQuoteByMessageId,
replyQuoteMessageId: params.replyQuoteMessageId,
replyQuoteText: params.replyQuoteText,
replyQuotePosition: params.replyQuotePosition,
replyQuoteEntities: params.replyQuoteEntities
});
if (hasMessageSendingHooks) {
const hookResult = await hookRunner?.runMessageSending({
to: params.chatId,
content: hookContent,
replyToId,
threadId: params.thread?.id,
metadata: {
channel: "telegram",
mediaUrls: mediaList,
threadId: params.thread?.id
}
}, {
channelId: "telegram",
accountId: params.accountId,
conversationId: params.chatId
});
if (hookResult?.cancel) continue;
if (typeof hookResult?.content === "string" && hookResult.content !== hookContent) {
progress.promptContext?.detach();
reply = spokenHookContent ? {
...reply,
spokenText: hookResult.content
} : {
...reply,
text: hookResult.content
};
}
}
let contentForSentHook = reply.text || (reply.audioAsVoice === true ? resolveVoiceFallbackText(reply) : "") || "";
const sender = createTelegramPreparedSender({
api: params.bot.api,
chatId: params.chatId,
request: createTelegramReplyRequest(params.runtime),
warn: (message) => params.runtime.log?.(message),
beforeTextPage: params.onPlatformSendDispatch,
beforeMedia: params.onPlatformSendDispatch,
assertPlatformSendAuthorized: params.assertPlatformSendAuthorized
});
try {
const deliveredCountBeforeReply = progress.deliveredCount;
const replyMarkup = buildInlineKeyboard(resolveTelegramInlineButtons({
buttons: telegramData?.buttons,
presentation,
interactive
}));
let firstDeliveredMessageId;
let deliveredMediaUrls = [];
if (reactionEmoji && typeof targetId === "number") {
await params.onPlatformSendDispatch?.();
params.assertPlatformSendAuthorized?.();
const reactionResult = await reactMessageTelegram(params.chatId, targetId, reactionEmoji, {
cfg: params.cfg ?? { channels: { telegram: { botToken: params.token } } },
token: params.token,
accountId: params.accountId,
api: params.bot.api,
verbose: false
});
if (reactionResult.ok) {
progress.hasDelivered = true;
progress.deliveredCount += 1;
} else {
params.runtime.error?.(danger(reactionResult.warning));
continue;
}
}
if (mediaList.length === 0 && resolvedReplyText) firstDeliveredMessageId = await deliverTextReply({
sender,
chatId: params.chatId,
runtime: params.runtime,
thread: params.thread,
chunkText,
text: reply.text || "",
replyMarkup,
replyQuoteMessageId: replyQuote.messageId,
replyQuoteText: replyQuote.text,
replyQuotePosition: replyQuote.position,
replyQuoteEntities: replyQuote.entities,
richMessages: params.richMessages,
linkPreview: params.linkPreview,
silent: params.silent,
replyToId,
replyToMode: params.replyToMode,
progress,
recordMessageId
});
else if (mediaList.length > 0) {
const mediaDelivery = await deliverMediaReply({
sender,
reply,
mediaList,
bot: params.bot,
chatId: params.chatId,
runtime: params.runtime,
thread: params.thread,
tableMode: params.tableMode,
richMessages: params.richMessages,
mediaLocalRoots: params.mediaLocalRoots,
mediaMaxBytes: params.mediaMaxBytes,
chunkText,
mediaLoader,
onVoiceRecording: params.onVoiceRecording,
linkPreview: params.linkPreview,
silent: params.silent,
replyQuoteMessageId: replyQuote.messageId,
replyQuoteText: replyQuote.text,
replyQuotePosition: replyQuote.position,
replyQuoteEntities: replyQuote.entities,
replyMarkup,
replyToId,
replyToMode: params.replyToMode,
progress,
recordMessageId,
...params.textMode ? { textMode: params.textMode } : {}
});
firstDeliveredMessageId = mediaDelivery.firstDeliveredMessageId;
deliveredMediaUrls = mediaDelivery.mediaUrls;
if (mediaDelivery.visibleFallbackText !== void 0) contentForSentHook = mediaDelivery.visibleFallbackText;
}
await maybePinFirstDeliveredMessage({
pin: reply.delivery?.pin,
bot: params.bot,
chatId: params.chatId,
runtime: params.runtime,
firstDeliveredMessageId
});
if (progress.deliveredCount > deliveredCountBeforeReply && transcriptMirror) deliveredContents.push({
text: contentForSentHook,
mediaUrls: deliveredMediaUrls
});
emitMessageSentHooks({
hookRunner,
enabled: hasMessageSentHooks,
sessionKeyForInternalHooks: params.sessionKeyForInternalHooks,
chatId: params.chatId,
accountId: params.accountId,
content: contentForSentHook,
success: progress.deliveredCount > deliveredCountBeforeReply,
messageId: firstDeliveredMessageId,
isGroup: params.mirrorIsGroup,
groupId: params.mirrorGroupId
});
} catch (error) {
emitMessageSentHooks({
hookRunner,
enabled: hasMessageSentHooks,
sessionKeyForInternalHooks: params.sessionKeyForInternalHooks,
chatId: params.chatId,
accountId: params.accountId,
content: contentForSentHook,
success: false,
error: formatErrorMessage(error),
isGroup: params.mirrorIsGroup,
groupId: params.mirrorGroupId
});
sender.fail(error);
}
}
if (progress.hasDelivered && transcriptMirror) {
const text = deliveredContents.map((content) => content.text).filter(Boolean).join("\n\n");
const mediaUrls = deliveredContents.flatMap((content) => content.mediaUrls);
if (text || mediaUrls.length > 0) try {
await transcriptMirror({
text: text || void 0,
mediaUrls: mediaUrls.length > 0 ? mediaUrls : void 0
});
} catch (mirrorErr) {
logVerbose(`telegram transcriptMirror failed: ${formatErrorMessage(mirrorErr)}`);
}
}
return { delivered: progress.hasDelivered };
}
//#endregion
export { emitTelegramMessageSentHooks as n, deliverReplies as t };