aborted: res.aborted,
				runIds: res.runIds
			});
			return;
		}
		const active = context.chatAbortControllers.get(runId);
		if (!active) {
			respond(true, {
				ok: true,
				aborted: false,
				runIds: []
			});
			return;
		}
		if (active.sessionKey !== rawSessionKey) {
			respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "runId does not match sessionKey"));
			return;
		}
		const partialText = context.chatRunBuffers.get(runId);
		const res = abortChatRunById(ops, {
			runId,
			sessionKey: rawSessionKey,
			stopReason: "rpc"
		});
		if (res.aborted && partialText && partialText.trim()) persistAbortedPartials({
			context,
			sessionKey: rawSessionKey,
			snapshots: [{
				runId,
				sessionId: active.sessionId,
				text: partialText,
				abortOrigin: "rpc"
			}]
		});
		respond(true, {
			ok: true,
			aborted: res.aborted,
			runIds: res.aborted ? [runId] : []
		});
	},
	"chat.send": async ({ params, respond, context, client }) => {
		if (!validateChatSendParams(params)) {
			respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `invalid chat.send params: ${formatValidationErrors(validateChatSendParams.errors)}`));
			return;
		}
		const p = params;
		const sanitizedMessageResult = sanitizeChatSendMessageInput(p.message);
		if (!sanitizedMessageResult.ok) {
			respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, sanitizedMessageResult.error));
			return;
		}
		const inboundMessage = sanitizedMessageResult.message;
		const stopCommand = isChatStopCommandText(inboundMessage);
		const normalizedAttachments = normalizeRpcAttachmentsToChatAttachments(p.attachments);
		if (!inboundMessage.trim() && normalizedAttachments.length === 0) {
			respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "message or attachment required"));
			return;
		}
		let parsedMessage = inboundMessage;
		let parsedImages = [];
		if (normalizedAttachments.length > 0) try {
			const parsed = await parseMessageWithAttachments(inboundMessage, normalizedAttachments, {
				maxBytes: 5e6,
				log: context.logGateway
			});
			parsedMessage = parsed.message;
			parsedImages = parsed.images;
		} catch (err) {
			respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, String(err)));
			return;
		}
		const rawSessionKey = p.sessionKey;
		const { cfg, entry, canonicalKey: sessionKey } = loadSessionEntry(rawSessionKey);
		const timeoutMs = resolveAgentTimeoutMs({
			cfg,
			overrideMs: p.timeoutMs
		});
		const now = Date.now();
		const clientRunId = p.idempotencyKey;
		if (resolveSendPolicy({
			cfg,
			entry,
			sessionKey,
			channel: entry?.channel,
			chatType: entry?.chatType
		}) === "deny") {
			respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "send blocked by session policy"));
			return;
		}
		if (stopCommand) {
			const res = abortChatRunsForSessionKeyWithPartials({
				context,
				ops: createChatAbortOps(context),
				sessionKey: rawSessionKey,
				abortOrigin: "stop-command",
				stopReason: "stop"
			});
			respond(true, {
				ok: true,
				aborted: res.aborted,
				runIds: res.runIds
			});
			return;
		}
		const cached = context.dedupe.get(`chat:${clientRunId}`);
		if (cached) {
			respond(cached.ok, cached.payload, cached.error, { cached: true });
			return;
		}
		if (context.chatAbortControllers.get(clientRunId)) {
			respond(true, {
				runId: clientRunId,
				status: "in_flight"
			}, void 0, {
				cached: true,
				runId: clientRunId
			});
			return;
		}
		try {
			const abortController = new AbortController();
			context.chatAbortControllers.set(clientRunId, {
				controller: abortController,
				sessionId: entry?.sessionId ?? clientRunId,
				sessionKey: rawSessionKey,
				startedAtMs: now,
				expiresAtMs: resolveChatRunExpiresAtMs({
					now,
					timeoutMs
				})
			});
			respond(true, {
				runId: clientRunId,
				status: "started"
			}, void 0, { runId: clientRunId });
			const trimmedMessage = parsedMessage.trim();
			const commandBody = Boolean(p.thinking && trimmedMessage && !trimmedMessage.startsWith("/")) ? `/think ${p.thinking} ${parsedMessage}` : parsedMessage;
			const clientInfo = client?.connect?.client;
			const routeChannelCandidate = normalizeMessageChannel(entry?.deliveryContext?.channel ?? entry?.lastChannel);
			const routeToCandidate = entry?.deliveryContext?.to ?? entry?.lastTo;
			const routeAccountIdCandidate = entry?.deliveryContext?.accountId ?? entry?.lastAccountId ?? void 0;
			const routeThreadIdCandidate = entry?.deliveryContext?.threadId ?? entry?.lastThreadId;
			const hasDeliverableRoute = routeChannelCandidate && routeChannelCandidate !== INTERNAL_MESSAGE_CHANNEL && typeof routeToCandidate === "string" && routeToCandidate.trim().length > 0;
			const originatingChannel = hasDeliverableRoute ? routeChannelCandidate : INTERNAL_MESSAGE_CHANNEL;
			const originatingTo = hasDeliverableRoute ? routeToCandidate : void 0;
			const accountId = hasDeliverableRoute ? routeAccountIdCandidate : void 0;
			const messageThreadId = hasDeliverableRoute ? routeThreadIdCandidate : void 0;
			const stampedMessage = injectTimestamp(parsedMessage, timestampOptsFromConfig(cfg));
			const ctx = {
				Body: parsedMessage,
				BodyForAgent: stampedMessage,
				BodyForCommands: commandBody,
				RawBody: parsedMessage,
				CommandBody: commandBody,
				SessionKey: sessionKey,
				Provider: INTERNAL_MESSAGE_CHANNEL,
				Surface: INTERNAL_MESSAGE_CHANNEL,
				OriginatingChannel: originatingChannel,
				OriginatingTo: originatingTo,
				AccountId: accountId,
				MessageThreadId: messageThreadId,
				ChatType: "direct",
				CommandAuthorized: true,
				MessageSid: clientRunId,
				SenderId: clientInfo?.id,
				SenderName: clientInfo?.displayName,
				SenderUsername: clientInfo?.displayName,
				GatewayClientScopes: client?.connect?.scopes
			};
			const agentId = resolveSessionAgentId({
				sessionKey,
				config: cfg
			});
			const { onModelSelected, ...prefixOptions } = createReplyPrefixOptions({
				cfg,
				agentId,
				channel: INTERNAL_MESSAGE_CHANNEL
			});
			const finalReplyParts = [];
			const dispatcher = createReplyDispatcher({
				...prefixOptions,
				onError: (err) => {
					context.logGateway.warn(`webchat dispatch failed: ${formatForLog(err)}`);
				},
				deliver: async (payload, info) => {
					if (info.kind !== "final") return;
					const text = payload.text?.trim() ?? "";
					if (!text) return;
					finalReplyParts.push(text);
				}
			});
			let agentRunStarted = false;
			dispatchInboundMessage({
				ctx,
				cfg,
				dispatcher,
				replyOptions: {
					runId: clientRunId,
					abortSignal: abortController.signal,
					images: parsedImages.length > 0 ? parsedImages : void 0,
					onAgentRunStart: (runId) => {


exec

sed -n '13640,13850p' /usr/lib/node_modules/openclaw/dist/gateway-cli-CuFEx2ht.js


if (!inflight) {
		inflight = /* @__PURE__ */ new Map();
		inflightByContext.set(context, inflight);
	}
	return inflight;
};
async function resolveRequestedChannel(params) {
	const channelInput = typeof params.requestChannel === "string" ? params.requestChannel : void 0;
	const normalizedChannel = channelInput ? normalizeChannelId(channelInput) : null;
	if (channelInput && !normalizedChannel) {
		const normalizedInput = channelInput.trim().toLowerCase();
		if (params.rejectWebchatAsInternalOnly && normalizedInput === "webchat") return { error: errorShape(ErrorCodes.INVALID_REQUEST, "unsupported channel: webchat (internal-only). Use `chat.send` for WebChat UI messages or choose a deliverable channel.") };
		return { error: errorShape(ErrorCodes.INVALID_REQUEST, params.unsupportedMessage(channelInput)) };
	}
	const cfg = loadConfig();
	let channel = normalizedChannel;
	if (!channel) try {
		channel = (await resolveMessageChannelSelection({ cfg })).channel;
	} catch (err) {
		return { error: errorShape(ErrorCodes.INVALID_REQUEST, String(err)) };
	}
	return {
		cfg,
		channel
	};
}
const sendHandlers = {
	send: async ({ params, respond, context }) => {
		const p = params;
		if (!validateSendParams(p)) {
			respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `invalid send params: ${formatValidationErrors(validateSendParams.errors)}`));
			return;
		}
		const request = p;
		const idem = request.idempotencyKey;
		const dedupeKey = `send:${idem}`;
		const cached = context.dedupe.get(dedupeKey);
		if (cached) {
			respond(cached.ok, cached.payload, cached.error, { cached: true });
			return;
		}
		const inflightMap = getInflightMap(context);
		const inflight = inflightMap.get(dedupeKey);
		if (inflight) {
			const result = await inflight;
			const meta = result.meta ? {
				...result.meta,
				cached: true
			} : { cached: true };
			respond(result.ok, result.payload, result.error, meta);
			return;
		}
		const to = request.to.trim();
		const message = typeof request.message === "string" ? request.message.trim() : "";
		const mediaUrl = typeof request.mediaUrl === "string" && request.mediaUrl.trim().length > 0 ? request.mediaUrl.trim() : void 0;
		const mediaUrls = Array.isArray(request.mediaUrls) ? request.mediaUrls.map((entry) => typeof entry === "string" ? entry.trim() : "").filter((entry) => entry.length > 0) : void 0;
		if (!message && !mediaUrl && (mediaUrls?.length ?? 0) === 0) {
			respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "invalid send params: text or media is required"));
			return;
		}
		const resolvedChannel = await resolveRequestedChannel({
			requestChannel: request.channel,
			unsupportedMessage: (input) => `unsupported channel: ${input}`,
			rejectWebchatAsInternalOnly: true
		});
		if ("error" in resolvedChannel) {
			respond(false, void 0, resolvedChannel.error);
			return;
		}
		const { cfg, channel } = resolvedChannel;
		const accountId = typeof request.accountId === "string" && request.accountId.trim().length ? request.accountId.trim() : void 0;
		const threadId = typeof request.threadId === "string" && request.threadId.trim().length ? request.threadId.trim() : void 0;
		const outboundChannel = channel;
		if (!resolveOutboundChannelPlugin({
			channel,
			cfg
		})) {
			respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `unsupported channel: ${channel}`));
			return;
		}
		const work = (async () => {
			try {
				const resolved = resolveOutboundTarget({
					channel: outboundChannel,
					to,
					cfg,
					accountId,
					mode: "explicit"
				});
				if (!resolved.ok) return {
					ok: false,
					error: errorShape(ErrorCodes.INVALID_REQUEST, String(resolved.error)),
					meta: { channel }
				};
				const outboundDeps = context.deps ? createOutboundSendDeps$1(context.deps) : void 0;
				const mirrorPayloads = normalizeReplyPayloadsForDelivery([{
					text: message,
					mediaUrl,
					mediaUrls
				}]);
				const mirrorText = mirrorPayloads.map((payload) => payload.text).filter(Boolean).join("\n");
				const mirrorMediaUrls = mirrorPayloads.flatMap((payload) => payload.mediaUrls ?? (payload.mediaUrl ? [payload.mediaUrl] : []));
				const providedSessionKey = typeof request.sessionKey === "string" && request.sessionKey.trim() ? request.sessionKey.trim().toLowerCase() : void 0;
				const explicitAgentId = typeof request.agentId === "string" && request.agentId.trim() ? request.agentId.trim() : void 0;
				const sessionAgentId = providedSessionKey ? resolveSessionAgentId({
					sessionKey: providedSessionKey,
					config: cfg
				}) : void 0;
				const defaultAgentId = resolveSessionAgentId({ config: cfg });
				const effectiveAgentId = explicitAgentId ?? sessionAgentId ?? defaultAgentId;
				const derivedRoute = !providedSessionKey ? await resolveOutboundSessionRoute({
					cfg,
					channel,
					agentId: effectiveAgentId,
					accountId,
					target: resolved.to,
					threadId
				}) : null;
				if (derivedRoute) await ensureOutboundSessionEntry({
					cfg,
					agentId: effectiveAgentId,
					channel,
					accountId,
					route: derivedRoute
				});
				const outboundSession = buildOutboundSessionContext({
					cfg,
					agentId: effectiveAgentId,
					sessionKey: providedSessionKey ?? derivedRoute?.sessionKey
				});
				const result = (await deliverOutboundPayloads({
					cfg,
					channel: outboundChannel,
					to: resolved.to,
					accountId,
					payloads: [{
						text: message,
						mediaUrl,
						mediaUrls
					}],
					session: outboundSession,
					gifPlayback: request.gifPlayback,
					threadId: threadId ?? null,
					deps: outboundDeps,
					mirror: providedSessionKey ? {
						sessionKey: providedSessionKey,
						agentId: effectiveAgentId,
						text: mirrorText || message,
						mediaUrls: mirrorMediaUrls.length > 0 ? mirrorMediaUrls : void 0
					} : derivedRoute ? {
						sessionKey: derivedRoute.sessionKey,
						agentId: effectiveAgentId,
						text: mirrorText || message,
						mediaUrls: mirrorMediaUrls.length > 0 ? mirrorMediaUrls : void 0
					} : void 0
				})).at(-1);
				if (!result) throw new Error("No delivery result");
				const payload = {
					runId: idem,
					messageId: result.messageId,
					channel
				};
				if ("chatId" in result) payload.chatId = result.chatId;
				if ("channelId" in result) payload.channelId = result.channelId;
				if ("toJid" in result) payload.toJid = result.toJid;
				if ("conversationId" in result) payload.conversationId = result.conversationId;
				context.dedupe.set(dedupeKey, {
					ts: Date.now(),
					ok: true,
					payload
				});
				return {
					ok: true,
					payload,
					meta: { channel }
				};
			} catch (err) {
				const error = errorShape(ErrorCodes.UNAVAILABLE, String(err));
				context.dedupe.set(dedupeKey, {
					ts: Date.now(),
					ok: false,
					error
				});
				return {
					ok: false,
					error,
					meta: {
						channel,
						error: formatForLog(err)
					}
				};
			}
		})();
		inflightMap.set(dedupeKey, work);
		try {
			const result = await work;
			respond(result.ok, result.payload, result.error, result.meta);
		} finally {
			inflightMap.delete(dedupeKey);
		}
	},
	poll: async ({ params, respond, context }) => {
		const p = params;
		if (!validatePollParams(p)) {
			respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `invalid poll params: ${formatValidationErrors(validatePollParams.errors)}`));
			return;
		}
		const request = p;
		const idem = request.idempotencyKey;
		const cached = context.dedupe.get(`poll:${idem}`);
		if (cached) {


grep -RIn "update_id\|getUpdates\|telegram.*inbound\|on\('message'\)|processUpdate\|ctx.update\|message_id" /usr/lib/node_modules/openclaw/dist/plugins-Co0ormRA.js /usr/lib/node_modules/openclaw/dist/gateway-cli-CuFEx2ht.js /usr/lib/node_modules/openclaw/dist/send-BfbOwTR-.js 2>/dev/null | head -300


/usr/lib/node_modules/openclaw/dist/send-BfbOwTR-.js:915:		id: replyLike?.message_id ? String(replyLike.message_id) : void 0,
/usr/lib/node_modules/openclaw/dist/send-BfbOwTR-.js:1008:			messageId: origin.message_id
/usr/lib/node_modules/openclaw/dist/send-BfbOwTR-.js:1942:	if (typeof result?.message_id === "number" && Number.isFinite(result.message_id)) return Math.trunc(result.message_id);
/usr/lib/node_modules/openclaw/dist/send-BfbOwTR-.js:1943:	throw new Error(`Telegram ${context} returned no message_id`);
/usr/lib/node_modules/openclaw/dist/send-BfbOwTR-.js:2046:			message_id: replyToMessageId,
/usr/lib/node_modules/openclaw/dist/send-BfbOwTR-.js:2049:		else threadParams.reply_to_message_id = replyToMessageId;


grep -RIn "MessageSid:\|dispatchInboundMessage\(|Provider:\s*\"telegram\"\|Surface:\s*\"telegram\"\|updateId\|update_id" /usr/lib/node_modules/openclaw/dist/gateway-cli-CuFEx2ht.js /usr/lib/node_modules/openclaw/dist/plugins-Co0ormRA.js /usr/lib/node_modules/openclaw/dist/send-BfbOwTR-.js 2>/dev/null | head -400


(no output)


grep -RIn "MessageSid" /usr/lib/node_modules/openclaw/dist | head -200


/usr/lib/node_modules/openclaw/dist/gateway-cli-CuFEx2ht.js:11303:				MessageSid: clientRunId,
/usr/lib/node_modules/openclaw/dist/deliver-FEreRY0J.js:650:		messageId: overrides?.messageId ?? ctx.MessageSidFull ?? ctx.MessageSid ?? ctx.MessageSidFirst ?? ctx.MessageSidLast,
/usr/lib/node_modules/openclaw/dist/channel-web-k1Tb8tGz.js:1668:		MessageSid: params.msg.id,
/usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js:6807:	const messageSid = typeof ctx.MessageSidFull === "string" && ctx.MessageSidFull.trim() || typeof ctx.MessageSid === "string" && ctx.MessageSid.trim() || void 0;
/usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js:6817:	const messageSid = entry.abortCutoffMessageSid?.trim() || void 0;
/usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js:6829:	entry.abortCutoffMessageSid = cutoff?.messageSid;
/usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js:6847:function toNumericMessageSid(value) {
/usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js:6857:	const cutoffSid = params.cutoffMessageSid?.trim();
/usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js:6860:		const cutoffNumeric = toNumericMessageSid(cutoffSid);
/usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js:6861:		const currentNumeric = toNumericMessageSid(currentSid);
/usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js:9245:	const value = params.ctx.MessageSidFull ?? params.ctx.MessageSid ?? params.ctx.MessageSidFirst ?? params.ctx.MessageSidLast;
/usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js:38166:			cutoffMessageSid: cutoff.messageSid,
/usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js:39222:	const currentMessageId = sessionCtx.MessageSidFull ?? sessionCtx.MessageSid;
/usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js:39934:						currentMessageId: params.sessionCtx.MessageSidFull ?? params.sessionCtx.MessageSid,
/usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js:41854:			currentMessageId: sessionCtx.MessageSidFull ?? sessionCtx.MessageSid,
/usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js:42121:	const messageId = safeTrim(ctx.MessageSid);
/usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js:42122:	const messageIdFull = safeTrim(ctx.MessageSidFull);
/usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js:42464:		messageId: sessionCtx.MessageSidFull ?? sessionCtx.MessageSid,
/usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js:44674:	const id = ctx.MessageSidFull ?? ctx.MessageSid ?? ctx.MessageSidFirst ?? ctx.MessageSidLast;
/usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js:44904:	const messageId = ctx.MessageSid?.trim();
/usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js:44961:	const messageId = ctx.MessageSid ?? ctx.MessageSidFirst ?? ctx.MessageSidLast;
/usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js:45011:	const hookContext = deriveInboundMessageHookContext(ctx, { messageId: ctx.MessageSidFull ?? ctx.MessageSid ?? ctx.MessageSidFirst ?? ctx.MessageSidLast });
/usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js:51178:		MessageSid: message.id,
/usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js:51547:					ctxBatch.MessageSids = ids;
/usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js:51548:					ctxBatch.MessageSidFirst = ids[0];
/usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js:51549:					ctxBatch.MessageSidLast = ids[ids.length - 1];
/usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js:53229:		MessageSid: interactionId,
/usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js:56012:		MessageSid: interaction.rawData.id,
/usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js:59193:			MessageSid: params.message.id ? String(params.message.id) : void 0,
/usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js:60042:		MessageSid: params.messageSid,
/usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js:61792:			MessageSid: entry.messageId,
/usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js:65538:		MessageSid: message.ts,
/usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js:65774:					prepared.ctxPayload.MessageSids = ids;
/usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js:65775:					prepared.ctxPayload.MessageSidFirst = ids[0];
/usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js:65776:					prepared.ctxPayload.MessageSidLast = ids[ids.length - 1];
/usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js:66359:				MessageSid: command.trigger_id,
/usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js:69497:		MessageSid: options?.messageIdOverride ?? String(msg.message_id),
/usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js:71031:					MessageSid: String(msg.message_id),
/usr/lib/node_modules/openclaw/dist/deliver-DCtqEVTU.js:660:		messageId: overrides?.messageId ?? ctx.MessageSidFull ?? ctx.MessageSid ?? ctx.MessageSidFirst ?? ctx.MessageSidLast,
/usr/lib/node_modules/openclaw/dist/pi-embedded-CtM2Mrrj.js:13093:	const messageSid = typeof ctx.MessageSidFull === "string" && ctx.MessageSidFull.trim() || typeof ctx.MessageSid === "string" && ctx.MessageSid.trim() || void 0;
/usr/lib/node_modules/openclaw/dist/pi-embedded-CtM2Mrrj.js:13103:	const messageSid = entry.abortCutoffMessageSid?.trim() || void 0;
/usr/lib/node_modules/openclaw/dist/pi-embedded-CtM2Mrrj.js:13115:	entry.abortCutoffMessageSid = cutoff?.messageSid;
/usr/lib/node_modules/openclaw/dist/pi-embedded-CtM2Mrrj.js:13133:function toNumericMessageSid(value) {
/usr/lib/node_modules/openclaw/dist/pi-embedded-CtM2Mrrj.js:13143:	const cutoffSid = params.cutoffMessageSid?.trim();
/usr/lib/node_modules/openclaw/dist/pi-embedded-CtM2Mrrj.js:13146:		const cutoffNumeric = toNumericMessageSid(cutoffSid);
/usr/lib/node_modules/openclaw/dist/pi-embedded-CtM2Mrrj.js:13147:		const currentNumeric = toNumericMessageSid(currentSid);
/usr/lib/node_modules/openclaw/dist/pi-embedded-CtM2Mrrj.js:15293:	const value = params.ctx.MessageSidFull ?? params.ctx.MessageSid ?? params.ctx.MessageSidFirst ?? params.ctx.MessageSidLast;
/usr/lib/node_modules/openclaw/dist/pi-embedded-CtM2Mrrj.js:45303:			cutoffMessageSid: cutoff.messageSid,
/usr/lib/node_modules/openclaw/dist/pi-embedded-CtM2Mrrj.js:46359:	const currentMessageId = sessionCtx.MessageSidFull ?? sessionCtx.MessageSid;
/usr/lib/node_modules/openclaw/dist/pi-embedded-CtM2Mrrj.js:47071:						currentMessageId: params.sessionCtx.MessageSidFull ?? params.sessionCtx.MessageSid,
/usr/lib/node_modules/openclaw/dist/pi-embedded-CtM2Mrrj.js:48985:			currentMessageId: sessionCtx.MessageSidFull ?? sessionCtx.MessageSid,
/usr/lib/node_modules/openclaw/dist/pi-embedded-CtM2Mrrj.js:49252:	const messageId = safeTrim(ctx.MessageSid);
/usr/lib/node_modules/openclaw/dist/pi-embedded-CtM2Mrrj.js:49253:	const messageIdFull = safeTrim(ctx.MessageSidFull);
/usr/lib/node_modules/openclaw/dist/pi-embedded-CtM2Mrrj.js:49595:		messageId: sessionCtx.MessageSidFull ?? sessionCtx.MessageSid,
/usr/lib/node_modules/openclaw/dist/pi-embedded-CtM2Mrrj.js:51805:	const id = ctx.MessageSidFull ?? ctx.MessageSid ?? ctx.MessageSidFirst ?? ctx.MessageSidLast;
/usr/lib/node_modules/openclaw/dist/pi-embedded-CtM2Mrrj.js:52035:	const messageId = ctx.MessageSid?.trim();
/usr/lib/node_modules/openclaw/dist/pi-embedded-CtM2Mrrj.js:52092:	const messageId = ctx.MessageSid ?? ctx.MessageSidFirst ?? ctx.MessageSidLast;
/usr/lib/node_modules/openclaw/dist/pi-embedded-CtM2Mrrj.js:52142:	const hookContext = deriveInboundMessageHookContext(ctx, { messageId: ctx.MessageSidFull ?? ctx.MessageSid ?? ctx.MessageSidFirst ?? ctx.MessageSidLast });
/usr/lib/node_modules/openclaw/dist/pi-embedded-CtM2Mrrj.js:58491:		MessageSid: message.id,
/usr/lib/node_modules/openclaw/dist/pi-embedded-CtM2Mrrj.js:58860:					ctxBatch.MessageSids = ids;
/usr/lib/node_modules/openclaw/dist/pi-embedded-CtM2Mrrj.js:58861:					ctxBatch.MessageSidFirst = ids[0];
/usr/lib/node_modules/openclaw/dist/pi-embedded-CtM2Mrrj.js:58862:					ctxBatch.MessageSidLast = ids[ids.length - 1];
/usr/lib/node_modules/openclaw/dist/pi-embedded-CtM2Mrrj.js:60542:		MessageSid: interactionId,
/usr/lib/node_modules/openclaw/dist/pi-embedded-CtM2Mrrj.js:65760:		MessageSid: interaction.rawData.id,
/usr/lib/node_modules/openclaw/dist/pi-embedded-CtM2Mrrj.js:68966:			MessageSid: params.message.id ? String(params.message.id) : void 0,
/usr/lib/node_modules/openclaw/dist/pi-embedded-CtM2Mrrj.js:69821:		MessageSid: params.messageSid,
/usr/lib/node_modules/openclaw/dist/pi-embedded-CtM2Mrrj.js:71571:			MessageSid: entry.messageId,
/usr/lib/node_modules/openclaw/dist/pi-embedded-CtM2Mrrj.js:75310:		MessageSid: message.ts,
/usr/lib/node_modules/openclaw/dist/pi-embedded-CtM2Mrrj.js:75546:					prepared.ctxPayload.MessageSids = ids;
/usr/lib/node_modules/openclaw/dist/pi-embedded-CtM2Mrrj.js:75547:					prepared.ctxPayload.MessageSidFirst = ids[0];
/usr/lib/node_modules/openclaw/dist/pi-embedded-CtM2Mrrj.js:75548:					prepared.ctxPayload.MessageSidLast = ids[ids.length - 1];
/usr/lib/node_modules/openclaw/dist/pi-embedded-CtM2Mrrj.js:76131:				MessageSid: command.trigger_id,
/usr/lib/node_modules/openclaw/dist/pi-embedded-CtM2Mrrj.js:79269:		MessageSid: options?.messageIdOverride ?? String(msg.message_id),
/usr/lib/node_modules/openclaw/dist/pi-embedded-CtM2Mrrj.js:80803:					MessageSid: String(msg.message_id),
/usr/lib/node_modules/openclaw/dist/web-CSq0l9pG.js:1713:		MessageSid: params.msg.id,
/usr/lib/node_modules/openclaw/dist/channel-web-sl83aqDv.js:1667:		MessageSid: params.msg.id,
/usr/lib/node_modules/openclaw/dist/deliver-xtu58uBi.js:649:		messageId: overrides?.messageId ?? ctx.MessageSidFull ?? ctx.MessageSid ?? ctx.MessageSidFirst ?? ctx.MessageSidLast,
/usr/lib/node_modules/openclaw/dist/deliver-DPAduhp1.js:461:		messageId: overrides?.messageId ?? ctx.MessageSidFull ?? ctx.MessageSid ?? ctx.MessageSidFirst ?? ctx.MessageSidLast,
/usr/lib/node_modules/openclaw/dist/plugin-sdk/telegram/bot-message-context.d.ts:91:        MessageSid: string;
/usr/lib/node_modules/openclaw/dist/plugin-sdk/channel-web-Doc1Kr8O.js:1726:		MessageSid: params.msg.id,
/usr/lib/node_modules/openclaw/dist/plugin-sdk/auto-reply/reply/abort-cutoff.d.ts:7:type SessionAbortCutoffEntry = Pick<SessionEntry, "abortCutoffMessageSid" | "abortCutoffTimestamp">;
/usr/lib/node_modules/openclaw/dist/plugin-sdk/auto-reply/reply/abort-cutoff.d.ts:19:    cutoffMessageSid?: string;
/usr/lib/node_modules/openclaw/dist/plugin-sdk/auto-reply/templating.d.ts:45:    MessageSid?: string;
/usr/lib/node_modules/openclaw/dist/plugin-sdk/auto-reply/templating.d.ts:46:    /** Provider-specific full message id when MessageSid is a shortened alias. */
/usr/lib/node_modules/openclaw/dist/plugin-sdk/auto-reply/templating.d.ts:47:    MessageSidFull?: string;
/usr/lib/node_modules/openclaw/dist/plugin-sdk/auto-reply/templating.d.ts:48:    MessageSids?: string[];
/usr/lib/node_modules/openclaw/dist/plugin-sdk/auto-reply/templating.d.ts:49:    MessageSidFirst?: string;
/usr/lib/node_modules/openclaw/dist/plugin-sdk/auto-reply/templating.d.ts:50:    MessageSidLast?: string;
/usr/lib/node_modules/openclaw/dist/plugin-sdk/deliver-IzcbcFd0.js:662:		messageId: overrides?.messageId ?? ctx.MessageSidFull ?? ctx.MessageSid ?? ctx.MessageSidFirst ?? ctx.MessageSidLast,
/usr/lib/node_modules/openclaw/dist/plugin-sdk/config/sessions/types.d.ts:81:    abortCutoffMessageSid?: string;
/usr/lib/node_modules/openclaw/dist/plugin-sdk/config/sessions/types.d.ts:82:    /** Epoch ms cutoff paired with abortCutoffMessageSid when available. */
/usr/lib/node_modules/openclaw/dist/plugin-sdk/line/bot-message-context.d.ts:47:        MessageSid: string;
/usr/lib/node_modules/openclaw/dist/plugin-sdk/line/bot-message-context.d.ts:97:        MessageSid: string;
/usr/lib/node_modules/openclaw/dist/plugin-sdk/reply-DFFRlayb.js:10609:	const value = params.ctx.MessageSidFull ?? params.ctx.MessageSid ?? params.ctx.MessageSidFirst ?? params.ctx.MessageSidLast;
/usr/lib/node_modules/openclaw/dist/plugin-sdk/reply-DFFRlayb.js:24991:	const messageSid = typeof ctx.MessageSidFull === "string" && ctx.MessageSidFull.trim() || typeof ctx.MessageSid === "string" && ctx.MessageSid.trim() || void 0;
/usr/lib/node_modules/openclaw/dist/plugin-sdk/reply-DFFRlayb.js:25001:	const messageSid = entry.abortCutoffMessageSid?.trim() || void 0;
/usr/lib/node_modules/openclaw/dist/plugin-sdk/reply-DFFRlayb.js:25013:	entry.abortCutoffMessageSid = cutoff?.messageSid;
/usr/lib/node_modules/openclaw/dist/plugin-sdk/reply-DFFRlayb.js:25031:function toNumericMessageSid(value) {
/usr/lib/node_modules/openclaw/dist/plugin-sdk/reply-DFFRlayb.js:25041:	const cutoffSid = params.cutoffMessageSid?.trim();
/usr/lib/node_modules/openclaw/dist/plugin-sdk/reply-DFFRlayb.js:25044:		const cutoffNumeric = toNumericMessageSid(cutoffSid);
/usr/lib/node_modules/openclaw/dist/plugin-sdk/reply-DFFRlayb.js:25045:		const currentNumeric = toNumericMessageSid(currentSid);
/usr/lib/node_modules/openclaw/dist/plugin-sdk/reply-DFFRlayb.js:29609:	const id = ctx.MessageSidFull ?? ctx.MessageSid ?? ctx.MessageSidFirst ?? ctx.MessageSidLast;
/usr/lib/node_modules/openclaw/dist/plugin-sdk/reply-DFFRlayb.js:29774:	const messageId = ctx.MessageSid?.trim();
/usr/lib/node_modules/openclaw/dist/plugin-sdk/reply-DFFRlayb.js:29841:	const messageId = ctx.MessageSid ?? ctx.MessageSidFirst ?? ctx.MessageSidLast;
/usr/lib/node_modules/openclaw/dist/plugin-sdk/reply-DFFRlayb.js:29891:	const hookContext = deriveInboundMessageHookContext(ctx, { messageId: ctx.MessageSidFull ?? ctx.MessageSid ?? ctx.MessageSidFirst ?? ctx.MessageSidLast });
/usr/lib/node_modules/openclaw/dist/plugin-sdk/reply-DFFRlayb.js:35668:		MessageSid: message.id,
/usr/lib/node_modules/openclaw/dist/plugin-sdk/reply-DFFRlayb.js:36037:					ctxBatch.MessageSids = ids;
/usr/lib/node_modules/openclaw/dist/plugin-sdk/reply-DFFRlayb.js:36038:					ctxBatch.MessageSidFirst = ids[0];
/usr/lib/node_modules/openclaw/dist/plugin-sdk/reply-DFFRlayb.js:36039:					ctxBatch.MessageSidLast = ids[ids.length - 1];
/usr/lib/node_modules/openclaw/dist/plugin-sdk/reply-DFFRlayb.js:38897:		MessageSid: interactionId,
/usr/lib/node_modules/openclaw/dist/plugin-sdk/reply-DFFRlayb.js:46014:		MessageSid: interaction.rawData.id,
/usr/lib/node_modules/openclaw/dist/plugin-sdk/reply-DFFRlayb.js:48872:			MessageSid: params.message.id ? String(params.message.id) : void 0,
/usr/lib/node_modules/openclaw/dist/plugin-sdk/reply-DFFRlayb.js:49683:		MessageSid: params.messageSid,
/usr/lib/node_modules/openclaw/dist/plugin-sdk/reply-DFFRlayb.js:51173:			MessageSid: entry.messageId,
/usr/lib/node_modules/openclaw/dist/plugin-sdk/reply-DFFRlayb.js:54827:		MessageSid: message.ts,
/usr/lib/node_modules/openclaw/dist/plugin-sdk/reply-DFFRlayb.js:55063:					prepared.ctxPayload.MessageSids = ids;
/usr/lib/node_modules/openclaw/dist/plugin-sdk/reply-DFFRlayb.js:55064:					prepared.ctxPayload.MessageSidFirst = ids[0];
/usr/lib/node_modules/openclaw/dist/plugin-sdk/reply-DFFRlayb.js:55065:					prepared.ctxPayload.MessageSidLast = ids[ids.length - 1];
/usr/lib/node_modules/openclaw/dist/plugin-sdk/reply-DFFRlayb.js:55648:				MessageSid: command.trigger_id,
/usr/lib/node_modules/openclaw/dist/plugin-sdk/reply-DFFRlayb.js:61217:		MessageSid: options?.messageIdOverride ?? String(msg.message_id),
/usr/lib/node_modules/openclaw/dist/plugin-sdk/reply-DFFRlayb.js:62751:					MessageSid: String(msg.message_id),
/usr/lib/node_modules/openclaw/dist/plugin-sdk/reply-DFFRlayb.js:91151:			cutoffMessageSid: cutoff.messageSid,
/usr/lib/node_modules/openclaw/dist/plugin-sdk/reply-DFFRlayb.js:91384:	const currentMessageId = sessionCtx.MessageSidFull ?? sessionCtx.MessageSid;
/usr/lib/node_modules/openclaw/dist/plugin-sdk/reply-DFFRlayb.js:91841:						currentMessageId: params.sessionCtx.MessageSidFull ?? params.sessionCtx.MessageSid,
/usr/lib/node_modules/openclaw/dist/plugin-sdk/reply-DFFRlayb.js:93115:			currentMessageId: sessionCtx.MessageSidFull ?? sessionCtx.MessageSid,
/usr/lib/node_modules/openclaw/dist/plugin-sdk/reply-DFFRlayb.js:93359:	const messageId = safeTrim(ctx.MessageSid);
/usr/lib/node_modules/openclaw/dist/plugin-sdk/reply-DFFRlayb.js:93360:	const messageIdFull = safeTrim(ctx.MessageSidFull);
/usr/lib/node_modules/openclaw/dist/plugin-sdk/reply-DFFRlayb.js:93692:		messageId: sessionCtx.MessageSidFull ?? sessionCtx.MessageSid,
/usr/lib/node_modules/openclaw/dist/reply-DhtejUNZ.js:4138:	const value = params.ctx.MessageSidFull ?? params.ctx.MessageSid ?? params.ctx.MessageSidFirst ?? params.ctx.MessageSidLast;
/usr/lib/node_modules/openclaw/dist/reply-DhtejUNZ.js:17998:	const messageSid = typeof ctx.MessageSidFull === "string" && ctx.MessageSidFull.trim() || typeof ctx.MessageSid === "string" && ctx.MessageSid.trim() || void 0;
/usr/lib/node_modules/openclaw/dist/reply-DhtejUNZ.js:18008:	const messageSid = entry.abortCutoffMessageSid?.trim() || void 0;
/usr/lib/node_modules/openclaw/dist/reply-DhtejUNZ.js:18020:	entry.abortCutoffMessageSid = cutoff?.messageSid;
/usr/lib/node_modules/openclaw/dist/reply-DhtejUNZ.js:18038:function toNumericMessageSid(value) {
/usr/lib/node_modules/openclaw/dist/reply-DhtejUNZ.js:18048:	const cutoffSid = params.cutoffMessageSid?.trim();
/usr/lib/node_modules/openclaw/dist/reply-DhtejUNZ.js:18051:		const cutoffNumeric = toNumericMessageSid(cutoffSid);
/usr/lib/node_modules/openclaw/dist/reply-DhtejUNZ.js:18052:		const currentNumeric = toNumericMessageSid(currentSid);
/usr/lib/node_modules/openclaw/dist/reply-DhtejUNZ.js:22435:	const id = ctx.MessageSidFull ?? ctx.MessageSid ?? ctx.MessageSidFirst ?? ctx.MessageSidLast;
/usr/lib/node_modules/openclaw/dist/reply-DhtejUNZ.js:22665:	const messageId = ctx.MessageSid?.trim();
/usr/lib/node_modules/openclaw/dist/reply-DhtejUNZ.js:22732:	const messageId = ctx.MessageSid ?? ctx.MessageSidFirst ?? ctx.MessageSidLast;
/usr/lib/node_modules/openclaw/dist/reply-DhtejUNZ.js:22782:	const hookContext = deriveInboundMessageHookContext(ctx, { messageId: ctx.MessageSidFull ?? ctx.MessageSid ?? ctx.MessageSidFirst ?? ctx.MessageSidLast });
/usr/lib/node_modules/openclaw/dist/reply-DhtejUNZ.js:30420:		MessageSid: message.id,
/usr/lib/node_modules/openclaw/dist/reply-DhtejUNZ.js:30789:					ctxBatch.MessageSids = ids;
/usr/lib/node_modules/openclaw/dist/reply-DhtejUNZ.js:30790:					ctxBatch.MessageSidFirst = ids[0];
/usr/lib/node_modules/openclaw/dist/reply-DhtejUNZ.js:30791:					ctxBatch.MessageSidLast = ids[ids.length - 1];
/usr/lib/node_modules/openclaw/dist/reply-DhtejUNZ.js:33649:		MessageSid: interactionId,
/usr/lib/node_modules/openclaw/dist/reply-DhtejUNZ.js:38254:		MessageSid: interaction.rawData.id,
/usr/lib/node_modules/openclaw/dist/reply-DhtejUNZ.js:41435:			MessageSid: params.message.id ? String(params.message.id) : void 0,
/usr/lib/node_modules/openclaw/dist/reply-DhtejUNZ.js:42284:		MessageSid: params.messageSid,
/usr/lib/node_modules/openclaw/dist/reply-DhtejUNZ.js:44034:			MessageSid: entry.messageId,
/usr/lib/node_modules/openclaw/dist/reply-DhtejUNZ.js:47780:		MessageSid: message.ts,
/usr/lib/node_modules/openclaw/dist/reply-DhtejUNZ.js:48016:					prepared.ctxPayload.MessageSids = ids;
/usr/lib/node_modules/openclaw/dist/reply-DhtejUNZ.js:48017:					prepared.ctxPayload.MessageSidFirst = ids[0];
/usr/lib/node_modules/openclaw/dist/reply-DhtejUNZ.js:48018:					prepared.ctxPayload.MessageSidLast = ids[ids.length - 1];
/usr/lib/node_modules/openclaw/dist/reply-DhtejUNZ.js:48601:				MessageSid: command.trigger_id,
/usr/lib/node_modules/openclaw/dist/reply-DhtejUNZ.js:54158:		MessageSid: options?.messageIdOverride ?? String(msg.message_id),
/usr/lib/node_modules/openclaw/dist/reply-DhtejUNZ.js:55692:					MessageSid: String(msg.message_id),
/usr/lib/node_modules/openclaw/dist/reply-DhtejUNZ.js:82738:			cutoffMessageSid: cutoff.messageSid,
/usr/lib/node_modules/openclaw/dist/reply-DhtejUNZ.js:82971:	const currentMessageId = sessionCtx.MessageSidFull ?? sessionCtx.MessageSid;
/usr/lib/node_modules/openclaw/dist/reply-DhtejUNZ.js:83428:						currentMessageId: params.sessionCtx.MessageSidFull ?? params.sessionCtx.MessageSid,
/usr/lib/node_modules/openclaw/dist/reply-DhtejUNZ.js:84721:			currentMessageId: sessionCtx.MessageSidFull ?? sessionCtx.MessageSid,
/usr/lib/node_modules/openclaw/dist/reply-DhtejUNZ.js:84965:	const messageId = safeTrim(ctx.MessageSid);
/usr/lib/node_modules/openclaw/dist/reply-DhtejUNZ.js:84966:	const messageIdFull = safeTrim(ctx.MessageSidFull);
/usr/lib/node_modules/openclaw/dist/reply-DhtejUNZ.js:85298:		messageId: sessionCtx.MessageSidFull ?? sessionCtx.MessageSid,
/usr/lib/node_modules/openclaw/dist/gateway-cli-vk3t7zJU.js:11301:				MessageSid: clientRunId,
/usr/lib/node_modules/openclaw/dist/web-pFdwPQ7y.js:1709:		MessageSid: params.msg.id,
/usr/lib/node_modules/openclaw/dist/pi-embedded-DgYXShcG.js:13089:	const messageSid = typeof ctx.MessageSidFull === "string" && ctx.MessageSidFull.trim() || typeof ctx.MessageSid === "string" && ctx.MessageSid.trim() || void 0;
/usr/lib/node_modules/openclaw/dist/pi-embedded-DgYXShcG.js:13099:	const messageSid = entry.abortCutoffMessageSid?.trim() || void 0;
/usr/lib/node_modules/openclaw/dist/pi-embedded-DgYXShcG.js:13111:	entry.abortCutoffMessageSid = cutoff?.messageSid;
/usr/lib/node_modules/openclaw/dist/pi-embedded-DgYXShcG.js:13129:function toNumericMessageSid(value) {
/usr/lib/node_modules/openclaw/dist/pi-embedded-DgYXShcG.js:13139:	const cutoffSid = params.cutoffMessageSid?.trim();
/usr/lib/node_modules/openclaw/dist/pi-embedded-DgYXShcG.js:13142:		const cutoffNumeric = toNumericMessageSid(cutoffSid);
/usr/lib/node_modules/openclaw/dist/pi-embedded-DgYXShcG.js:13143:		const currentNumeric = toNumericMessageSid(currentSid);
/usr/lib/node_modules/openclaw/dist/pi-embedded-DgYXShcG.js:15289:	const value = params.ctx.MessageSidFull ?? params.ctx.MessageSid ?? params.ctx.MessageSidFirst ?? params.ctx.MessageSidLast;
/usr/lib/node_modules/openclaw/dist/pi-embedded-DgYXShcG.js:45299:			cutoffMessageSid: cutoff.messageSid,
/usr/lib/node_modules/openclaw/dist/pi-embedded-DgYXShcG.js:46355:	const currentMessageId = sessionCtx.MessageSidFull ?? sessionCtx.MessageSid;
/usr/lib/node_modules/openclaw/dist/pi-embedded-DgYXShcG.js:47067:						currentMessageId: params.sessionCtx.MessageSidFull ?? params.sessionCtx.MessageSid,
/usr/lib/node_modules/openclaw/dist/pi-embedded-DgYXShcG.js:48981:			currentMessageId: sessionCtx.MessageSidFull ?? sessionCtx.MessageSid,
/usr/lib/node_modules/openclaw/dist/pi-embedded-DgYXShcG.js:49248:	const messageId = safeTrim(ctx.MessageSid);
/usr/lib/node_modules/openclaw/dist/pi-embedded-DgYXShcG.js:49249:	const messageIdFull = safeTrim(ctx.MessageSidFull);
/usr/lib/node_modules/openclaw/dist/pi-embedded-DgYXShcG.js:49591:		messageId: sessionCtx.MessageSidFull ?? sessionCtx.MessageSid,
/usr/lib/node_modules/openclaw/dist/pi-embedded-DgYXShcG.js:51801:	const id = ctx.MessageSidFull ?? ctx.MessageSid ?? ctx.MessageSidFirst ?? ctx.MessageSidLast;
/usr/lib/node_modules/openclaw/dist/pi-embedded-DgYXShcG.js:52031:	const messageId = ctx.MessageSid?.trim();
/usr/lib/node_modules/openclaw/dist/pi-embedded-DgYXShcG.js:52088:	const messageId = ctx.MessageSid ?? ctx.MessageSidFirst ?? ctx.MessageSidLast;
/usr/lib/node_modules/openclaw/dist/pi-embedded-DgYXShcG.js:52138:	const hookContext = deriveInboundMessageHookContext(ctx, { messageId: ctx.MessageSidFull ?? ctx.MessageSid ?? ctx.MessageSidFirst ?? ctx.MessageSidLast });
/usr/lib/node_modules/openclaw/dist/pi-embedded-DgYXShcG.js:58487:		MessageSid: message.id,
/usr/lib/node_modules/openclaw/dist/pi-embedded-DgYXShcG.js:58856:					ctxBatch.MessageSids = ids;
/usr/lib/node_modules/openclaw/dist/pi-embedded-DgYXShcG.js:58857:					ctxBatch.MessageSidFirst = ids[0];
/usr/lib/node_modules/openclaw/dist/pi-embedded-DgYXShcG.js:58858:					ctxBatch.MessageSidLast = ids[ids.length - 1];
/usr/lib/node_modules/openclaw/dist/pi-embedded-DgYXShcG.js:60538:		MessageSid: interactionId,
/usr/lib/node_modules/openclaw/dist/pi-embedded-DgYXShcG.js:65750:		MessageSid: interaction.rawData.id,
/usr/lib/node_modules/openclaw/dist/pi-embedded-DgYXShcG.js:68956:			MessageSid: params.message.id ? String(params.message.id) : void 0,
/usr/lib/node_modules/openclaw/dist/pi-embedded-DgYXShcG.js:69811:		MessageSid: params.messageSid,
/usr/lib/node_modules/openclaw/dist/pi-embedded-DgYXShcG.js:71561:			MessageSid: entry.messageId,
/usr/lib/node_modules/openclaw/dist/pi-embedded-DgYXShcG.js:75300:		MessageSid: message.ts,
/usr/lib/node_modules/openclaw/dist/pi-embedded-DgYXShcG.js:75536:					prepared.ctxPayload.MessageSids = ids;
/usr/lib/node_modules/openclaw/dist/pi-embedded-DgYXShcG.js:75537:					prepared.ctxPayload.MessageSidFirst = ids[0];
/usr/lib/node_modules/openclaw/dist/pi-embedded-DgYXShcG.js:75538:					prepared.ctxPayload.MessageSidLast = ids[ids.length - 1];
/usr/lib/node_modules/openclaw/dist/pi-embedded-DgYXShcG.js:76121:				MessageSid: command.trigger_id,
/usr/lib/node_modules/openclaw/dist/pi-embedded-DgYXShcG.js:79259:		MessageSid: options?.messageIdOverride ?? String(msg.message_id),
/usr/lib/node_modules/openclaw/dist/pi-embedded-DgYXShcG.js:80793:					MessageSid: String(msg.message_id),


ls /usr/lib/node_modules/openclaw | sed -n '1,120p' && find /usr/lib/node_modules/openclaw -maxdepth 2 -type d | head -80


CHANGELOG.md
LICENSE
README.md
assets
dist
docs
extensions
node_modules
openclaw.mjs
package.json
skills
/usr/lib/node_modules/openclaw
/usr/lib/node_modules/openclaw/assets
/usr/lib/node_modules/openclaw/assets/chrome-extension
/usr/lib/node_modules/openclaw/dist
/usr/lib/node_modules/openclaw/dist/control-ui
/usr/lib/node_modules/openclaw/dist/export-html
/usr/lib/node_modules/openclaw/dist/bundled
/usr/lib/node_modules/openclaw/dist/plugin-sdk
/usr/lib/node_modules/openclaw/dist/cli
/usr/lib/node_modules/openclaw/dist/canvas-host
/usr/lib/node_modules/openclaw/node_modules
/usr/lib/node_modules/openclaw/node_modules/merge-descriptors
/usr/lib/node_modules/openclaw/node_modules/proper-lockfile
/usr/lib/node_modules/openclaw/node_modules/tslib
/usr/lib/node_modules/openclaw/node_modules/is-unicode-supported
/usr/lib/node_modules/openclaw/node_modules/strnum
/usr/lib/node_modules/openclaw/node_modules/path-is-absolute
/usr/lib/node_modules/openclaw/node_modules/strtok3
/usr/lib/node_modules/openclaw/node_modules/wrap-ansi-cjs
/usr/lib/node_modules/openclaw/node_modules/ipull
/usr/lib/node_modules/openclaw/node_modules/is-promise
/usr/lib/node_modules/openclaw/node_modules/jsonwebtoken
/usr/lib/node_modules/openclaw/node_modules/@babel
/usr/lib/node_modules/openclaw/node_modules/real-require
/usr/lib/node_modules/openclaw/node_modules/json-with-bigint
/usr/lib/node_modules/openclaw/node_modules/core-util-is
/usr/lib/node_modules/openclaw/node_modules/hasown
/usr/lib/node_modules/openclaw/node_modules/fast-xml-parser
/usr/lib/node_modules/openclaw/node_modules/diff
/usr/lib/node_modules/openclaw/node_modules/extend
/usr/lib/node_modules/openclaw/node_modules/es-define-property
/usr/lib/node_modules/openclaw/node_modules/json-schema-traverse
/usr/lib/node_modules/openclaw/node_modules/mz
/usr/lib/node_modules/openclaw/node_modules/ci-info
/usr/lib/node_modules/openclaw/node_modules/@img
/usr/lib/node_modules/openclaw/node_modules/pino
/usr/lib/node_modules/openclaw/node_modules/quick-format-unescaped
/usr/lib/node_modules/openclaw/node_modules/raw-body
/usr/lib/node_modules/openclaw/node_modules/sleep-promise
/usr/lib/node_modules/openclaw/node_modules/@mistralai
/usr/lib/node_modules/openclaw/node_modules/ora
/usr/lib/node_modules/openclaw/node_modules/get-stream
/usr/lib/node_modules/openclaw/node_modules/thenify-all
/usr/lib/node_modules/openclaw/node_modules/lodash.debounce
/usr/lib/node_modules/openclaw/node_modules/delayed-stream
/usr/lib/node_modules/openclaw/node_modules/proxy-agent
/usr/lib/node_modules/openclaw/node_modules/deep-extend
/usr/lib/node_modules/openclaw/node_modules/supports-color
/usr/lib/node_modules/openclaw/node_modules/@protobufjs
/usr/lib/node_modules/openclaw/node_modules/emoji-regex
/usr/lib/node_modules/openclaw/node_modules/qrcode-terminal
/usr/lib/node_modules/openclaw/node_modules/lodash.includes
/usr/lib/node_modules/openclaw/node_modules/proxy-addr
/usr/lib/node_modules/openclaw/node_modules/lodash.merge
/usr/lib/node_modules/openclaw/node_modules/partial-json
/usr/lib/node_modules/openclaw/node_modules/https-proxy-agent
/usr/lib/node_modules/openclaw/node_modules/safe-buffer
/usr/lib/node_modules/openclaw/node_modules/p-retry
/usr/lib/node_modules/openclaw/node_modules/@smithy
/usr/lib/node_modules/openclaw/node_modules/lodash.isboolean
/usr/lib/node_modules/openclaw/node_modules/sisteransi
/usr/lib/node_modules/openclaw/node_modules/inherits
/usr/lib/node_modules/openclaw/node_modules/path-to-regexp
/usr/lib/node_modules/openclaw/node_modules/grammy
/usr/lib/node_modules/openclaw/node_modules/isexe
/usr/lib/node_modules/openclaw/node_modules/has-symbols
/usr/lib/node_modules/openclaw/node_modules/pdfjs-dist
/usr/lib/node_modules/openclaw/node_modules/content-disposition
/usr/lib/node_modules/openclaw/node_modules/pino-abstract-transport
/usr/lib/node_modules/openclaw/node_modules/punycode.js
/usr/lib/node_modules/openclaw/node_modules/stdout-update
/usr/lib/node_modules/openclaw/node_modules/debug
/usr/lib/node_modules/openclaw/node_modules/log-symbols
/usr/lib/node_modules/openclaw/node_modules/buffer-equal-constant-time
/usr/lib/node_modules/openclaw/node_modules/lowdb
/usr/lib/node_modules/openclaw/node_modules/yauzl
/usr/lib/node_modules/openclaw/node_modules/simple-git
/usr/lib/node_modules/openclaw/node_modules/side-channel-weakmap
/usr/lib/node_modules/openclaw/node_modules/argparse
/usr/lib/node_modules/openclaw/node_modules/es-set-tostringtag


sed -n '69380,69620p' /usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js


const statusReactionVariantsByEmoji = buildTelegramStatusReactionVariants(resolvedStatusReactionEmojis);
	let allowedStatusReactionEmojisPromise = null;
	const statusReactionController = statusReactionsEnabled && msg.message_id ? createStatusReactionController({
		enabled: true,
		adapter: { setReaction: async (emoji) => {
			if (reactionApi) {
				if (!allowedStatusReactionEmojisPromise) allowedStatusReactionEmojisPromise = resolveTelegramAllowedEmojiReactions({
					chat: msg.chat,
					chatId,
					getChat: getChatApi ?? void 0
				}).catch((err) => {
					logVerbose(`telegram status-reaction available_reactions lookup failed for chat ${chatId}: ${String(err)}`);
					return null;
				});
				const resolvedEmoji = resolveTelegramReactionVariant({
					requestedEmoji: emoji,
					variantsByRequestedEmoji: statusReactionVariantsByEmoji,
					allowedEmojiReactions: await allowedStatusReactionEmojisPromise
				});
				if (!resolvedEmoji) return;
				await reactionApi(chatId, msg.message_id, [{
					type: "emoji",
					emoji: resolvedEmoji
				}]);
			}
		} },
		initialEmoji: ackReaction,
		emojis: resolvedStatusReactionEmojis,
		timing: statusReactionsConfig?.timing,
		onError: (err) => {
			logVerbose(`telegram status-reaction error for chat ${chatId}: ${String(err)}`);
		}
	}) : null;
	const ackReactionPromise = statusReactionController ? shouldAckReaction$1() ? Promise.resolve(statusReactionController.setQueued()).then(() => true, () => false) : null : shouldAckReaction$1() && msg.message_id && reactionApi ? withTelegramApiErrorLogging({
		operation: "setMessageReaction",
		fn: () => reactionApi(chatId, msg.message_id, [{
			type: "emoji",
			emoji: ackReaction
		}])
	}).then(() => true, (err) => {
		logVerbose(`telegram react failed for chat ${chatId}: ${String(err)}`);
		return false;
	}) : null;
	const replyTarget = describeReplyTarget(msg);
	const forwardOrigin = normalizeForwardedContext(msg);
	const replyForwardAnnotation = replyTarget?.forwardedFrom ? `[Forwarded from ${replyTarget.forwardedFrom.from}${replyTarget.forwardedFrom.date ? ` at ${(/* @__PURE__ */ new Date(replyTarget.forwardedFrom.date * 1e3)).toISOString()}` : ""}]\n` : "";
	const replySuffix = replyTarget ? replyTarget.kind === "quote" ? `\n\n[Quoting ${replyTarget.sender}${replyTarget.id ? ` id:${replyTarget.id}` : ""}]\n${replyForwardAnnotation}"${replyTarget.body}"\n[/Quoting]` : `\n\n[Replying to ${replyTarget.sender}${replyTarget.id ? ` id:${replyTarget.id}` : ""}]\n${replyForwardAnnotation}${replyTarget.body}\n[/Replying]` : "";
	const forwardPrefix = forwardOrigin ? `[Forwarded from ${forwardOrigin.from}${forwardOrigin.date ? ` at ${(/* @__PURE__ */ new Date(forwardOrigin.date * 1e3)).toISOString()}` : ""}]\n` : "";
	const groupLabel = isGroup ? buildGroupLabel(msg, chatId, resolvedThreadId) : void 0;
	const senderName = buildSenderName(msg);
	const conversationLabel = isGroup ? groupLabel ?? `group:${chatId}` : buildSenderLabel(msg, senderId || chatId);
	const storePath = resolveStorePath(cfg.session?.store, { agentId: route.agentId });
	const envelopeOptions = resolveEnvelopeFormatOptions(cfg);
	const previousTimestamp = readSessionUpdatedAt({
		storePath,
		sessionKey
	});
	const body = formatInboundEnvelope({
		channel: "Telegram",
		from: conversationLabel,
		timestamp: msg.date ? msg.date * 1e3 : void 0,
		body: `${forwardPrefix}${bodyText}${replySuffix}`,
		chatType: isGroup ? "group" : "direct",
		sender: {
			name: senderName,
			username: senderUsername || void 0,
			id: senderId || void 0
		},
		previousTimestamp,
		envelope: envelopeOptions
	});
	let combinedBody = body;
	if (isGroup && historyKey && historyLimit > 0) combinedBody = buildPendingHistoryContextFromMap({
		historyMap: groupHistories,
		historyKey,
		limit: historyLimit,
		currentMessage: combinedBody,
		formatEntry: (entry) => formatInboundEnvelope({
			channel: "Telegram",
			from: groupLabel ?? `group:${chatId}`,
			timestamp: entry.timestamp,
			body: `${entry.body} [id:${entry.messageId ?? "unknown"} chat:${chatId}]`,
			chatType: "group",
			senderLabel: entry.sender,
			envelope: envelopeOptions
		})
	});
	const { skillFilter, groupSystemPrompt } = resolveTelegramGroupPromptSettings({
		groupConfig,
		topicConfig
	});
	const commandBody = normalizeCommandBody(rawBody, { botUsername });
	const inboundHistory = isGroup && historyKey && historyLimit > 0 ? (groupHistories.get(historyKey) ?? []).map((entry) => ({
		sender: entry.sender,
		body: entry.body,
		timestamp: entry.timestamp
	})) : void 0;
	const contextMedia = [...stickerCacheHit ? [] : allMedia, ...replyMedia];
	const ctxPayload = finalizeInboundContext({
		Body: combinedBody,
		BodyForAgent: bodyText,
		InboundHistory: inboundHistory,
		RawBody: rawBody,
		CommandBody: commandBody,
		From: isGroup ? buildTelegramGroupFrom(chatId, resolvedThreadId) : `telegram:${chatId}`,
		To: `telegram:${chatId}`,
		SessionKey: sessionKey,
		AccountId: route.accountId,
		ChatType: isGroup ? "group" : "direct",
		ConversationLabel: conversationLabel,
		GroupSubject: isGroup ? msg.chat.title ?? void 0 : void 0,
		GroupSystemPrompt: isGroup || !isGroup && groupConfig ? groupSystemPrompt : void 0,
		SenderName: senderName,
		SenderId: senderId || void 0,
		SenderUsername: senderUsername || void 0,
		Provider: "telegram",
		Surface: "telegram",
		MessageSid: options?.messageIdOverride ?? String(msg.message_id),
		ReplyToId: replyTarget?.id,
		ReplyToBody: replyTarget?.body,
		ReplyToSender: replyTarget?.sender,
		ReplyToIsQuote: replyTarget?.kind === "quote" ? true : void 0,
		ReplyToForwardedFrom: replyTarget?.forwardedFrom?.from,
		ReplyToForwardedFromType: replyTarget?.forwardedFrom?.fromType,
		ReplyToForwardedFromId: replyTarget?.forwardedFrom?.fromId,
		ReplyToForwardedFromUsername: replyTarget?.forwardedFrom?.fromUsername,
		ReplyToForwardedFromTitle: replyTarget?.forwardedFrom?.fromTitle,
		ReplyToForwardedDate: replyTarget?.forwardedFrom?.date ? replyTarget.forwardedFrom.date * 1e3 : void 0,
		ForwardedFrom: forwardOrigin?.from,
		ForwardedFromType: forwardOrigin?.fromType,
		ForwardedFromId: forwardOrigin?.fromId,
		ForwardedFromUsername: forwardOrigin?.fromUsername,
		ForwardedFromTitle: forwardOrigin?.fromTitle,
		ForwardedFromSignature: forwardOrigin?.fromSignature,
		ForwardedFromChatType: forwardOrigin?.fromChatType,
		ForwardedFromMessageId: forwardOrigin?.fromMessageId,
		ForwardedDate: forwardOrigin?.date ? forwardOrigin.date * 1e3 : void 0,
		Timestamp: msg.date ? msg.date * 1e3 : void 0,
		WasMentioned: isGroup ? effectiveWasMentioned : void 0,
		MediaPath: contextMedia.length > 0 ? contextMedia[0]?.path : void 0,
		MediaType: contextMedia.length > 0 ? contextMedia[0]?.contentType : void 0,
		MediaUrl: contextMedia.length > 0 ? contextMedia[0]?.path : void 0,
		MediaPaths: contextMedia.length > 0 ? contextMedia.map((m) => m.path) : void 0,
		MediaUrls: contextMedia.length > 0 ? contextMedia.map((m) => m.path) : void 0,
		MediaTypes: contextMedia.length > 0 ? contextMedia.map((m) => m.contentType).filter(Boolean) : void 0,
		Sticker: allMedia[0]?.stickerMetadata,
		StickerMediaIncluded: allMedia[0]?.stickerMetadata ? !stickerCacheHit : void 0,
		...locationData ? toLocationContext(locationData) : void 0,
		CommandAuthorized: commandAuthorized,
		MessageThreadId: threadSpec.id,
		IsForum: isForum,
		OriginatingChannel: "telegram",
		OriginatingTo: `telegram:${chatId}`
	});
	const pinnedMainDmOwner = !isGroup ? resolvePinnedMainDmOwnerFromAllowlist({
		dmScope: cfg.session?.dmScope,
		allowFrom: dmAllowFrom,
		normalizeEntry: (entry) => normalizeAllowFrom$2([entry]).entries[0]
	}) : null;
	await recordInboundSession({
		storePath,
		sessionKey: ctxPayload.SessionKey ?? sessionKey,
		ctx: ctxPayload,
		updateLastRoute: !isGroup ? {
			sessionKey: route.mainSessionKey,
			channel: "telegram",
			to: `telegram:${chatId}`,
			accountId: route.accountId,
			threadId: dmThreadId != null ? String(dmThreadId) : void 0,
			mainDmOwnerPin: pinnedMainDmOwner && senderId ? {
				ownerRecipient: pinnedMainDmOwner,
				senderRecipient: senderId,
				onSkip: ({ ownerRecipient, senderRecipient }) => {
					logVerbose(`telegram: skip main-session last route for ${senderRecipient} (pinned owner ${ownerRecipient})`);
				}
			} : void 0
		} : void 0,
		onRecordError: (err) => {
			logVerbose(`telegram: failed updating session meta: ${String(err)}`);
		}
	});
	if (replyTarget && shouldLogVerbose()) {
		const preview = replyTarget.body.replace(/\s+/g, " ").slice(0, 120);
		logVerbose(`telegram reply-context: replyToId=${replyTarget.id} replyToSender=${replyTarget.sender} replyToBody="${preview}"`);
	}
	if (forwardOrigin && shouldLogVerbose()) logVerbose(`telegram forward-context: forwardedFrom="${forwardOrigin.from}" type=${forwardOrigin.fromType}`);
	if (shouldLogVerbose()) {
		const preview = body.slice(0, 200).replace(/\n/g, "\\n");
		const mediaInfo = allMedia.length > 1 ? ` mediaCount=${allMedia.length}` : "";
		const topicInfo = resolvedThreadId != null ? ` topic=${resolvedThreadId}` : "";
		logVerbose(`telegram inbound: chatId=${chatId} from=${ctxPayload.From} len=${body.length}${mediaInfo}${topicInfo} preview="${preview}"`);
	}
	return {
		ctxPayload,
		primaryCtx,
		msg,
		chatId,
		isGroup,
		resolvedThreadId,
		threadSpec,
		replyThreadId,
		isForum,
		historyKey,
		historyLimit,
		groupHistories,
		route,
		skillFilter,
		sendTyping,
		sendRecordVoice,
		ackReactionPromise,
		reactionApi,
		removeAckAfterReply,
		statusReactionController,
		accountId: account.accountId
	};
};

//#endregion
//#region src/telegram/draft-stream.ts
const TELEGRAM_STREAM_MAX_CHARS = 4096;
const DEFAULT_THROTTLE_MS = 1e3;
const TELEGRAM_DRAFT_ID_MAX = 2147483647;
const THREAD_NOT_FOUND_RE = /400:\s*Bad Request:\s*message thread not found/i;
const DRAFT_METHOD_UNAVAILABLE_RE = /(unknown method|method .*not (found|available|supported)|unsupported)/i;
const DRAFT_CHAT_UNSUPPORTED_RE = /(can't be used|can be used only)/i;
let nextDraftId = 0;
function allocateTelegramDraftId() {
	nextDraftId = nextDraftId >= TELEGRAM_DRAFT_ID_MAX ? 1 : nextDraftId + 1;
	return nextDraftId;
}
function resolveSendMessageDraftApi(api) {
	const sendMessageDraft = api.sendMessageDraft;
	if (typeof sendMessageDraft !== "function") return;
	return sendMessageDraft.bind(api);
}
function shouldFallbackFromDraftTransport(err) {
	const text = typeof err === "string" ? err : err instanceof Error ? err.message : typeof err === "object" && err && "description" in err ? typeof err.description === "string" ? err.description : "" : "";
	if (!/sendMessageDraft/i.test(text)) return false;
	return DRAFT_METHOD_UNAVAILABLE_RE.test(text) || DRAFT_CHAT_UNSUPPORTED_RE.test(text);
}
function createTelegramDraftStream(params) {


sed -n '70780,71240p' /usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js


chatId,
		cfg,
		telegramCfg,
		topicConfig,
		groupConfig,
		effectiveGroupAllow,
		senderId,
		senderUsername,
		resolveGroupPolicy,
		enforcePolicy: useAccessGroups,
		useTopicAndGroupOverrides: false,
		enforceAllowlistAuthorization: requireAuth,
		allowEmptyAllowlistEntries: true,
		requireSenderForAllowlistAuthorization: true,
		checkChatAllowlist: useAccessGroups
	});
	if (!policyAccess.allowed) {
		if (policyAccess.reason === "group-policy-disabled") return await sendAuthMessage("Telegram group commands are disabled.");
		if (policyAccess.reason === "group-policy-allowlist-no-sender" || policyAccess.reason === "group-policy-allowlist-unauthorized") return await rejectNotAuthorized();
		if (policyAccess.reason === "group-chat-not-allowed") return await sendAuthMessage("This group is not allowed.");
	}
	const dmAllow = normalizeDmAllowFromWithStore$1({
		allowFrom: dmAllowFrom,
		storeAllowFrom: isGroup ? [] : storeAllowFrom,
		dmPolicy: effectiveDmPolicy
	});
	const senderAllowed = isSenderAllowed$1({
		allow: dmAllow,
		senderId,
		senderUsername
	});
	const commandAuthorized = resolveCommandAuthorizedFromAuthorizers({
		useAccessGroups,
		authorizers: [{
			configured: dmAllow.hasEntries,
			allowed: senderAllowed
		}],
		modeWhenAccessGroupsOff: "configured"
	});
	if (requireAuth && !commandAuthorized) return await rejectNotAuthorized();
	return {
		chatId,
		isGroup,
		isForum,
		resolvedThreadId,
		senderId,
		senderUsername,
		groupConfig,
		topicConfig,
		commandAuthorized
	};
}
const registerTelegramNativeCommands = ({ bot, cfg, runtime, accountId, telegramCfg, allowFrom, groupAllowFrom, replyToMode, textLimit, useAccessGroups, nativeEnabled, nativeSkillsEnabled, nativeDisabledExplicit, resolveGroupPolicy, resolveTelegramGroupConfig, shouldSkipUpdate, opts }) => {
	const boundRoute = nativeEnabled && nativeSkillsEnabled ? resolveAgentRoute({
		cfg,
		channel: "telegram",
		accountId
	}) : null;
	if (nativeEnabled && nativeSkillsEnabled && !boundRoute) runtime.log?.("nativeSkillsEnabled is true but no agent route is bound for this Telegram account; skill commands will not appear in the native menu.");
	const skillCommands = nativeEnabled && nativeSkillsEnabled && boundRoute ? listSkillCommandsForAgents({
		cfg,
		agentIds: [boundRoute.agentId]
	}) : [];
	const nativeCommands = nativeEnabled ? listNativeCommandSpecsForConfig(cfg, {
		skillCommands,
		provider: "telegram"
	}) : [];
	const reservedCommands = new Set(listNativeCommandSpecs().map((command) => normalizeTelegramCommandName(command.name)));
	for (const command of skillCommands) reservedCommands.add(command.name.toLowerCase());
	const customResolution = resolveTelegramCustomCommands({
		commands: telegramCfg.customCommands,
		reservedCommands
	});
	for (const issue of customResolution.issues) runtime.error?.(danger(issue.message));
	const customCommands = customResolution.commands;
	const pluginCatalog = buildPluginTelegramMenuCommands({
		specs: getPluginCommandSpecs(),
		existingCommands: new Set([...nativeCommands.map((command) => normalizeTelegramCommandName(command.name)), ...customCommands.map((command) => command.command)].map((command) => command.toLowerCase()))
	});
	for (const issue of pluginCatalog.issues) runtime.error?.(danger(issue));
	const { commandsToRegister, totalCommands, maxCommands, overflowCount } = buildCappedTelegramMenuCommands({ allCommands: [
		...nativeCommands.map((command) => {
			const normalized = normalizeTelegramCommandName(command.name);
			if (!TELEGRAM_COMMAND_NAME_PATTERN.test(normalized)) {
				runtime.error?.(danger(`Native command "${command.name}" is invalid for Telegram (resolved to "${normalized}"). Skipping.`));
				return null;
			}
			return {
				command: normalized,
				description: command.description
			};
		}).filter((cmd) => cmd !== null),
		...nativeEnabled ? pluginCatalog.commands : [],
		...customCommands
	] });
	if (overflowCount > 0) runtime.log?.(`Telegram limits bots to ${maxCommands} commands. ${totalCommands} configured; registering first ${maxCommands}. Use channels.telegram.commands.native: false to disable, or reduce plugin/skill/custom commands.`);
	syncTelegramMenuCommands({
		bot,
		runtime,
		commandsToRegister,
		accountId,
		botIdentity: opts.token
	});
	const resolveCommandRuntimeContext = (params) => {
		const { msg, isGroup, isForum, resolvedThreadId } = params;
		const chatId = msg.chat.id;
		const messageThreadId = msg.message_thread_id;
		const threadSpec = resolveTelegramThreadSpec({
			isGroup,
			isForum,
			messageThreadId
		});
		const parentPeer = buildTelegramParentPeer({
			isGroup,
			resolvedThreadId,
			chatId
		});
		const route = resolveAgentRoute({
			cfg,
			channel: "telegram",
			accountId,
			peer: {
				kind: isGroup ? "group" : "direct",
				id: isGroup ? buildTelegramGroupPeerId(chatId, resolvedThreadId) : String(chatId)
			},
			parentPeer
		});
		return {
			chatId,
			threadSpec,
			route,
			mediaLocalRoots: getAgentScopedMediaLocalRoots(cfg, route.agentId),
			tableMode: resolveMarkdownTableMode({
				cfg,
				channel: "telegram",
				accountId: route.accountId
			}),
			chunkMode: resolveChunkMode(cfg, "telegram", route.accountId)
		};
	};
	const buildCommandDeliveryBaseOptions = (params) => ({
		chatId: String(params.chatId),
		token: opts.token,
		runtime,
		bot,
		mediaLocalRoots: params.mediaLocalRoots,
		replyToMode,
		textLimit,
		thread: params.threadSpec,
		tableMode: params.tableMode,
		chunkMode: params.chunkMode,
		linkPreview: telegramCfg.linkPreview
	});
	if (commandsToRegister.length > 0 || pluginCatalog.commands.length > 0) if (typeof bot.command !== "function") logVerbose("telegram: bot.command unavailable; skipping native handlers");
	else {
		for (const command of nativeCommands) {
			const normalizedCommandName = normalizeTelegramCommandName(command.name);
			bot.command(normalizedCommandName, async (ctx) => {
				const msg = ctx.message;
				if (!msg) return;
				if (shouldSkipUpdate(ctx)) return;
				const auth = await resolveTelegramCommandAuth({
					msg,
					bot,
					cfg,
					accountId,
					telegramCfg,
					allowFrom,
					groupAllowFrom,
					useAccessGroups,
					resolveGroupPolicy,
					resolveTelegramGroupConfig,
					requireAuth: true
				});
				if (!auth) return;
				const { chatId, isGroup, isForum, resolvedThreadId, senderId, senderUsername, groupConfig, topicConfig, commandAuthorized } = auth;
				const { threadSpec, route, mediaLocalRoots, tableMode, chunkMode } = resolveCommandRuntimeContext({
					msg,
					isGroup,
					isForum,
					resolvedThreadId
				});
				const deliveryBaseOptions = buildCommandDeliveryBaseOptions({
					chatId,
					mediaLocalRoots,
					threadSpec,
					tableMode,
					chunkMode
				});
				const threadParams = buildTelegramThreadParams(threadSpec) ?? {};
				const commandDefinition = findCommandByNativeName(command.name, "telegram");
				const rawText = ctx.match?.trim() ?? "";
				const commandArgs = commandDefinition ? parseCommandArgs(commandDefinition, rawText) : rawText ? { raw: rawText } : void 0;
				const prompt = commandDefinition ? buildCommandTextFromArgs(commandDefinition, commandArgs) : rawText ? `/${command.name} ${rawText}` : `/${command.name}`;
				const menu = commandDefinition ? resolveCommandArgMenu({
					command: commandDefinition,
					args: commandArgs,
					cfg
				}) : null;
				if (menu && commandDefinition) {
					const title = menu.title ?? `Choose ${menu.arg.description || menu.arg.name} for /${commandDefinition.nativeName ?? commandDefinition.key}.`;
					const rows = [];
					for (let i = 0; i < menu.choices.length; i += 2) {
						const slice = menu.choices.slice(i, i + 2);
						rows.push(slice.map((choice) => {
							const args = { values: { [menu.arg.name]: choice.value } };
							return {
								text: choice.label,
								callback_data: buildCommandTextFromArgs(commandDefinition, args)
							};
						}));
					}
					const replyMarkup = buildInlineKeyboard(rows);
					await withTelegramApiErrorLogging({
						operation: "sendMessage",
						runtime,
						fn: () => bot.api.sendMessage(chatId, title, {
							...replyMarkup ? { reply_markup: replyMarkup } : {},
							...threadParams
						})
					});
					return;
				}
				const baseSessionKey = route.sessionKey;
				const dmThreadId = threadSpec.scope === "dm" ? threadSpec.id : void 0;
				const sessionKey = (dmThreadId != null ? resolveThreadSessionKeys({
					baseSessionKey,
					threadId: `${chatId}:${dmThreadId}`
				}) : null)?.sessionKey ?? baseSessionKey;
				const { skillFilter, groupSystemPrompt } = resolveTelegramGroupPromptSettings({
					groupConfig,
					topicConfig
				});
				const conversationLabel = isGroup ? msg.chat.title ? `${msg.chat.title} id:${chatId}` : `group:${chatId}` : buildSenderName(msg) ?? String(senderId || chatId);
				const ctxPayload = finalizeInboundContext({
					Body: prompt,
					BodyForAgent: prompt,
					RawBody: prompt,
					CommandBody: prompt,
					CommandArgs: commandArgs,
					From: isGroup ? buildTelegramGroupFrom(chatId, resolvedThreadId) : `telegram:${chatId}`,
					To: `slash:${senderId || chatId}`,
					ChatType: isGroup ? "group" : "direct",
					ConversationLabel: conversationLabel,
					GroupSubject: isGroup ? msg.chat.title ?? void 0 : void 0,
					GroupSystemPrompt: isGroup || !isGroup && groupConfig ? groupSystemPrompt : void 0,
					SenderName: buildSenderName(msg),
					SenderId: senderId || void 0,
					SenderUsername: senderUsername || void 0,
					Surface: "telegram",
					Provider: "telegram",
					MessageSid: String(msg.message_id),
					Timestamp: msg.date ? msg.date * 1e3 : void 0,
					WasMentioned: true,
					CommandAuthorized: commandAuthorized,
					CommandSource: "native",
					SessionKey: `telegram:slash:${senderId || chatId}`,
					AccountId: route.accountId,
					CommandTargetSessionKey: sessionKey,
					MessageThreadId: threadSpec.id,
					IsForum: isForum,
					OriginatingChannel: "telegram",
					OriginatingTo: `telegram:${chatId}`
				});
				await recordInboundSessionMetaSafe({
					cfg,
					agentId: route.agentId,
					sessionKey: ctxPayload.SessionKey ?? route.sessionKey,
					ctx: ctxPayload,
					onError: (err) => runtime.error?.(danger(`telegram slash: failed updating session meta: ${String(err)}`))
				});
				const disableBlockStreaming = typeof telegramCfg.blockStreaming === "boolean" ? !telegramCfg.blockStreaming : void 0;
				const deliveryState = {
					delivered: false,
					skippedNonSilent: 0
				};
				const { onModelSelected, ...prefixOptions } = createReplyPrefixOptions({
					cfg,
					agentId: route.agentId,
					channel: "telegram",
					accountId: route.accountId
				});
				await dispatchReplyWithBufferedBlockDispatcher({
					ctx: ctxPayload,
					cfg,
					dispatcherOptions: {
						...prefixOptions,
						deliver: async (payload, _info) => {
							if ((await deliverReplies({
								replies: [payload],
								...deliveryBaseOptions
							})).delivered) deliveryState.delivered = true;
						},
						onSkip: (_payload, info) => {
							if (info.reason !== "silent") deliveryState.skippedNonSilent += 1;
						},
						onError: (err, info) => {
							runtime.error?.(danger(`telegram slash ${info.kind} reply failed: ${String(err)}`));
						}
					},
					replyOptions: {
						skillFilter,
						disableBlockStreaming,
						onModelSelected
					}
				});
				if (!deliveryState.delivered && deliveryState.skippedNonSilent > 0) await deliverReplies({
					replies: [{ text: EMPTY_RESPONSE_FALLBACK }],
					...deliveryBaseOptions
				});
			});
		}
		for (const pluginCommand of pluginCatalog.commands) bot.command(pluginCommand.command, async (ctx) => {
			const msg = ctx.message;
			if (!msg) return;
			if (shouldSkipUpdate(ctx)) return;
			const chatId = msg.chat.id;
			const rawText = ctx.match?.trim() ?? "";
			const commandBody = `/${pluginCommand.command}${rawText ? ` ${rawText}` : ""}`;
			const match = matchPluginCommand(commandBody);
			if (!match) {
				await withTelegramApiErrorLogging({
					operation: "sendMessage",
					runtime,
					fn: () => bot.api.sendMessage(chatId, "Command not found.")
				});
				return;
			}
			const auth = await resolveTelegramCommandAuth({
				msg,
				bot,
				cfg,
				accountId,
				telegramCfg,
				allowFrom,
				groupAllowFrom,
				useAccessGroups,
				resolveGroupPolicy,
				resolveTelegramGroupConfig,
				requireAuth: match.command.requireAuth !== false
			});
			if (!auth) return;
			const { senderId, commandAuthorized, isGroup, isForum, resolvedThreadId } = auth;
			const { threadSpec, mediaLocalRoots, tableMode, chunkMode } = resolveCommandRuntimeContext({
				msg,
				isGroup,
				isForum,
				resolvedThreadId
			});
			const deliveryBaseOptions = buildCommandDeliveryBaseOptions({
				chatId,
				mediaLocalRoots,
				threadSpec,
				tableMode,
				chunkMode
			});
			const from = isGroup ? buildTelegramGroupFrom(chatId, threadSpec.id) : `telegram:${chatId}`;
			const to = `telegram:${chatId}`;
			await deliverReplies({
				replies: [await executePluginCommand({
					command: match.command,
					args: match.args,
					senderId,
					channel: "telegram",
					isAuthorizedSender: commandAuthorized,
					commandBody,
					config: cfg,
					from,
					to,
					accountId,
					messageThreadId: threadSpec.id
				})],
				...deliveryBaseOptions
			});
		});
	}
	else if (nativeDisabledExplicit) withTelegramApiErrorLogging({
		operation: "setMyCommands",
		runtime,
		fn: () => bot.api.setMyCommands([])
	}).catch(() => {});
};

//#endregion
//#region src/telegram/sendchataction-401-backoff.ts
const BACKOFF_POLICY = {
	initialMs: 1e3,
	maxMs: 3e5,
	factor: 2,
	jitter: .1
};
function is401Error(error) {
	if (!error) return false;
	const message = error instanceof Error ? error.message : JSON.stringify(error);
	return message.includes("401") || message.toLowerCase().includes("unauthorized");
}
/**
* Creates a GLOBAL (per-account) handler for sendChatAction that tracks 401 errors
* across all message contexts. This prevents the infinite loop that caused Telegram
* to delete bots (issue #27092).
*
* When a 401 occurs, exponential backoff is applied (1s → 2s → 4s → ... → 5min).
* After maxConsecutive401 failures (default 10), all sendChatAction calls are
* suspended until reset() is called.
*/
function createTelegramSendChatActionHandler({ sendChatActionFn, logger, maxConsecutive401 = 10 }) {
	let consecutive401Failures = 0;
	let suspended = false;
	const reset = () => {
		consecutive401Failures = 0;
		suspended = false;
	};
	const sendChatAction = async (chatId, action, threadParams) => {
		if (suspended) return;
		if (consecutive401Failures > 0) {
			const backoffMs = computeBackoff(BACKOFF_POLICY, consecutive401Failures);
			logger(`sendChatAction backoff: waiting ${backoffMs}ms before retry (failure ${consecutive401Failures}/${maxConsecutive401})`);
			await sleepWithAbort(backoffMs);
		}
		try {
			await sendChatActionFn(chatId, action, threadParams);
			if (consecutive401Failures > 0) {
				logger(`sendChatAction recovered after ${consecutive401Failures} consecutive 401 failures`);
				consecutive401Failures = 0;
			}
		} catch (error) {
			if (is401Error(error)) {
				consecutive401Failures++;
				if (consecutive401Failures >= maxConsecutive401) {
					suspended = true;
					logger(`CRITICAL: sendChatAction suspended after ${consecutive401Failures} consecutive 401 errors. Bot token is likely invalid. Telegram may DELETE the bot if requests continue. Replace the token and restart: openclaw channels restart telegram`);
				} else logger(`sendChatAction 401 error (${consecutive401Failures}/${maxConsecutive401}). Retrying with exponential backoff.`);
			}
			throw error;
		}
	};
	return {
		sendChatAction,
		isSuspended: () => suspended,
		reset
	};
}

//#endregion
//#region src/telegram/sequential-key.ts
function getTelegramSequentialKey(ctx) {
	const reaction = ctx.update?.message_reaction;
	if (reaction?.chat?.id) return `telegram:${reaction.chat.id}`;
	const msg = ctx.message ?? ctx.channelPost ?? ctx.editedChannelPost ?? ctx.update?.message ?? ctx.update?.edited_message ?? ctx.update?.channel_post ?? ctx.update?.edited_channel_post ?? ctx.update?.callback_query?.message;
	const chatId = msg?.chat?.id ?? ctx.chat?.id;
	const rawText = msg?.text ?? msg?.caption;
	const botUsername = ctx.me?.username;
	if (isAbortRequestText(rawText, botUsername ? { botUsername } : void 0)) {
		if (typeof chatId === "number") return `telegram:${chatId}:control`;
		return "telegram:control";
	}
	const isGroup = msg?.chat?.type === "group" || msg?.chat?.type === "supergroup";
	const messageThreadId = msg?.message_thread_id;
	const isForum = msg?.chat?.is_forum;
	const threadId = isGroup ? resolveTelegramForumThreadId({
		isForum,


grep -n "function shouldSkipUpdate\|shouldSkipUpdate =\|processed.*update\|update_id" /usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js | head -80


67021:const resolveTelegramUpdateId = (ctx) => ctx.update?.update_id ?? ctx.update_id;
71288:	const shouldSkipUpdate = (ctx) => {


sed -n '71240,71480p' /usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js


isForum,
		messageThreadId
	}) : messageThreadId;
	if (typeof chatId === "number") return threadId != null ? `telegram:${chatId}:topic:${threadId}` : `telegram:${chatId}`;
	return "telegram:unknown";
}

//#endregion
//#region src/telegram/bot.ts
function createTelegramBot(opts) {
	const runtime = opts.runtime ?? createNonExitingRuntime();
	const cfg = opts.config ?? loadConfig();
	const account = resolveTelegramAccount({
		cfg,
		accountId: opts.accountId
	});
	const telegramCfg = account.config;
	const fetchImpl = resolveTelegramFetch(opts.proxyFetch, { network: telegramCfg.network });
	const shouldProvideFetch = Boolean(fetchImpl);
	const fetchForClient = fetchImpl;
	const timeoutSeconds = typeof telegramCfg?.timeoutSeconds === "number" && Number.isFinite(telegramCfg.timeoutSeconds) ? Math.max(1, Math.floor(telegramCfg.timeoutSeconds)) : void 0;
	const client = shouldProvideFetch || timeoutSeconds ? {
		...shouldProvideFetch && fetchImpl ? { fetch: fetchForClient } : {},
		...timeoutSeconds ? { timeoutSeconds } : {}
	} : void 0;
	const bot = new Bot(opts.token, client ? { client } : void 0);
	bot.api.config.use(apiThrottler());
	bot.catch((err) => {
		runtime.error?.(danger(`telegram bot error: ${formatUncaughtError(err)}`));
	});
	const recentUpdates = createTelegramUpdateDedupe();
	const initialUpdateId = typeof opts.updateOffset?.lastUpdateId === "number" ? opts.updateOffset.lastUpdateId : null;
	const pendingUpdateIds = /* @__PURE__ */ new Set();
	let highestCompletedUpdateId = initialUpdateId;
	let highestPersistedUpdateId = initialUpdateId;
	const maybePersistSafeWatermark = () => {
		if (typeof opts.updateOffset?.onUpdateId !== "function") return;
		if (highestCompletedUpdateId === null) return;
		let safe = highestCompletedUpdateId;
		if (pendingUpdateIds.size > 0) {
			let minPending = null;
			for (const id of pendingUpdateIds) if (minPending === null || id < minPending) minPending = id;
			if (minPending !== null) safe = Math.min(safe, minPending - 1);
		}
		if (highestPersistedUpdateId !== null && safe <= highestPersistedUpdateId) return;
		highestPersistedUpdateId = safe;
		opts.updateOffset.onUpdateId(safe);
	};
	const shouldSkipUpdate = (ctx) => {
		const updateId = resolveTelegramUpdateId(ctx);
		const skipCutoff = highestPersistedUpdateId ?? initialUpdateId;
		if (typeof updateId === "number" && skipCutoff !== null && updateId <= skipCutoff) return true;
		const key = buildTelegramUpdateKey(ctx);
		const skipped = recentUpdates.check(key);
		if (skipped && key && shouldLogVerbose()) logVerbose(`telegram dedupe: skipped ${key}`);
		return skipped;
	};
	bot.use(async (ctx, next) => {
		const updateId = resolveTelegramUpdateId(ctx);
		if (typeof updateId === "number") pendingUpdateIds.add(updateId);
		try {
			await next();
		} finally {
			if (typeof updateId === "number") {
				pendingUpdateIds.delete(updateId);
				if (highestCompletedUpdateId === null || updateId > highestCompletedUpdateId) highestCompletedUpdateId = updateId;
				maybePersistSafeWatermark();
			}
		}
	});
	bot.use(sequentialize(getTelegramSequentialKey));
	const rawUpdateLogger = createSubsystemLogger("gateway/channels/telegram/raw-update");
	const MAX_RAW_UPDATE_CHARS = 8e3;
	const MAX_RAW_UPDATE_STRING = 500;
	const MAX_RAW_UPDATE_ARRAY = 20;
	const stringifyUpdate = (update) => {
		const seen = /* @__PURE__ */ new WeakSet();
		return JSON.stringify(update ?? null, (key, value) => {
			if (typeof value === "string" && value.length > MAX_RAW_UPDATE_STRING) return `${value.slice(0, MAX_RAW_UPDATE_STRING)}...`;
			if (Array.isArray(value) && value.length > MAX_RAW_UPDATE_ARRAY) return [...value.slice(0, MAX_RAW_UPDATE_ARRAY), `...(${value.length - MAX_RAW_UPDATE_ARRAY} more)`];
			if (value && typeof value === "object") {
				if (seen.has(value)) return "[Circular]";
				seen.add(value);
			}
			return value;
		});
	};
	bot.use(async (ctx, next) => {
		if (shouldLogVerbose()) try {
			const raw = stringifyUpdate(ctx.update);
			const preview = raw.length > MAX_RAW_UPDATE_CHARS ? `${raw.slice(0, MAX_RAW_UPDATE_CHARS)}...` : raw;
			rawUpdateLogger.debug(`telegram update: ${preview}`);
		} catch (err) {
			rawUpdateLogger.debug(`telegram update log failed: ${String(err)}`);
		}
		await next();
	});
	const historyLimit = Math.max(0, telegramCfg.historyLimit ?? cfg.messages?.groupChat?.historyLimit ?? DEFAULT_GROUP_HISTORY_LIMIT);
	const groupHistories = /* @__PURE__ */ new Map();
	const textLimit = resolveTextChunkLimit(cfg, "telegram", account.accountId);
	const dmPolicy = telegramCfg.dmPolicy ?? "pairing";
	const allowFrom = opts.allowFrom ?? telegramCfg.allowFrom;
	const groupAllowFrom = opts.groupAllowFrom ?? telegramCfg.groupAllowFrom ?? telegramCfg.allowFrom ?? allowFrom;
	const replyToMode = opts.replyToMode ?? telegramCfg.replyToMode ?? "off";
	const nativeEnabled = resolveNativeCommandsEnabled({
		providerId: "telegram",
		providerSetting: telegramCfg.commands?.native,
		globalSetting: cfg.commands?.native
	});
	const nativeSkillsEnabled = resolveNativeSkillsEnabled({
		providerId: "telegram",
		providerSetting: telegramCfg.commands?.nativeSkills,
		globalSetting: cfg.commands?.nativeSkills
	});
	const nativeDisabledExplicit = isNativeCommandsExplicitlyDisabled({
		providerSetting: telegramCfg.commands?.native,
		globalSetting: cfg.commands?.native
	});
	const useAccessGroups = cfg.commands?.useAccessGroups !== false;
	const ackReactionScope = cfg.messages?.ackReactionScope ?? "group-mentions";
	const mediaMaxBytes = (opts.mediaMaxMb ?? telegramCfg.mediaMaxMb ?? 5) * 1024 * 1024;
	const logger = getChildLogger({ module: "telegram-auto-reply" });
	const streamMode = resolveTelegramStreamMode(telegramCfg);
	const resolveGroupPolicy = (chatId) => resolveChannelGroupPolicy({
		cfg,
		channel: "telegram",
		accountId: account.accountId,
		groupId: String(chatId)
	});
	const resolveGroupActivation = (params) => {
		const agentId = params.agentId ?? resolveDefaultAgentId(cfg);
		const sessionKey = params.sessionKey ?? `agent:${agentId}:telegram:group:${buildTelegramGroupPeerId(params.chatId, params.messageThreadId)}`;
		const storePath = resolveStorePath(cfg.session?.store, { agentId });
		try {
			const entry = loadSessionStore(storePath)[sessionKey];
			if (entry?.groupActivation === "always") return false;
			if (entry?.groupActivation === "mention") return true;
		} catch (err) {
			logVerbose(`Failed to load session for activation check: ${String(err)}`);
		}
	};
	const resolveGroupRequireMention = (chatId) => resolveChannelGroupRequireMention({
		cfg,
		channel: "telegram",
		accountId: account.accountId,
		groupId: String(chatId),
		requireMentionOverride: opts.requireMention,
		overrideOrder: "after-config"
	});
	const resolveTelegramGroupConfig = (chatId, messageThreadId) => {
		const groups = telegramCfg.groups;
		const direct = telegramCfg.direct;
		const chatIdStr = String(chatId);
		if (!chatIdStr.startsWith("-")) {
			const directConfig = direct?.[chatIdStr] ?? direct?.["*"];
			if (directConfig) return {
				groupConfig: directConfig,
				topicConfig: messageThreadId != null ? directConfig.topics?.[String(messageThreadId)] : void 0
			};
			return {
				groupConfig: void 0,
				topicConfig: void 0
			};
		}
		if (!groups) return {
			groupConfig: void 0,
			topicConfig: void 0
		};
		const groupConfig = groups[chatIdStr] ?? groups["*"];
		return {
			groupConfig,
			topicConfig: messageThreadId != null ? groupConfig?.topics?.[String(messageThreadId)] : void 0
		};
	};
	const processMessage = createTelegramMessageProcessor({
		bot,
		cfg,
		account,
		telegramCfg,
		historyLimit,
		groupHistories,
		dmPolicy,
		allowFrom,
		groupAllowFrom,
		ackReactionScope,
		logger,
		resolveGroupActivation,
		resolveGroupRequireMention,
		resolveTelegramGroupConfig,
		sendChatActionHandler: createTelegramSendChatActionHandler({
			sendChatActionFn: (chatId, action, threadParams) => bot.api.sendChatAction(chatId, action, threadParams),
			logger: (message) => logVerbose(`telegram: ${message}`)
		}),
		runtime,
		replyToMode,
		streamMode,
		textLimit,
		opts
	});
	registerTelegramNativeCommands({
		bot,
		cfg,
		runtime,
		accountId: account.accountId,
		telegramCfg,
		allowFrom,
		groupAllowFrom,
		replyToMode,
		textLimit,
		useAccessGroups,
		nativeEnabled,
		nativeSkillsEnabled,
		nativeDisabledExplicit,
		resolveGroupPolicy,
		resolveTelegramGroupConfig,
		shouldSkipUpdate,
		opts
	});
	registerTelegramHandlers({
		cfg,
		accountId: account.accountId,
		bot,
		opts,
		runtime,
		mediaMaxBytes,
		telegramCfg,
		allowFrom,
		groupAllowFrom,
		resolveGroupPolicy,
		resolveTelegramGroupConfig,
		shouldSkipUpdate,
		processMessage,
		logger
	});
	return bot;
}

//#endregion
//#region src/telegram/update-offset-store.ts
const STORE_VERSION = 2;
function normalizeAccountId(accountId) {


grep -n "function createTelegramUpdateDedupe\|buildTelegramUpdateKey\|recentUpdates\.check\|DEDUPE" /usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js | head -120


67022:const buildTelegramUpdateKey = (ctx) => {
71292:		const key = buildTelegramUpdateKey(ctx);
71293:		const skipped = recentUpdates.check(key);


sed -n '66980,67120p' /usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js


chatId,
			ok,
			status,
			error: ok ? null : "bot not in group",
			matchKey: chatId,
			matchSource: "id"
		});
	} catch (err) {
		groups.push({
			chatId,
			ok: false,
			status: null,
			error: err instanceof Error ? err.message : String(err),
			matchKey: chatId,
			matchSource: "id"
		});
	}
	return {
		ok: groups.every((g) => g.ok),
		checkedGroups: groups.length,
		unresolvedGroups: 0,
		hasWildcardUnmentionedGroups: false,
		groups,
		elapsedMs: Date.now() - started
	};
}

//#endregion
//#region src/telegram/allowed-updates.ts
function resolveTelegramAllowedUpdates() {
	const updates = [...API_CONSTANTS.DEFAULT_UPDATE_TYPES];
	if (!updates.includes("message_reaction")) updates.push("message_reaction");
	if (!updates.includes("channel_post")) updates.push("channel_post");
	return updates;
}

//#endregion
//#region src/telegram/bot-updates.ts
const MEDIA_GROUP_TIMEOUT_MS = 500;
const RECENT_TELEGRAM_UPDATE_TTL_MS = 5 * 6e4;
const RECENT_TELEGRAM_UPDATE_MAX = 2e3;
const resolveTelegramUpdateId = (ctx) => ctx.update?.update_id ?? ctx.update_id;
const buildTelegramUpdateKey = (ctx) => {
	const updateId = resolveTelegramUpdateId(ctx);
	if (typeof updateId === "number") return `update:${updateId}`;
	const callbackId = ctx.callbackQuery?.id;
	if (callbackId) return `callback:${callbackId}`;
	const msg = ctx.message ?? ctx.channelPost ?? ctx.editedChannelPost ?? ctx.update?.message ?? ctx.update?.edited_message ?? ctx.update?.channel_post ?? ctx.update?.edited_channel_post ?? ctx.callbackQuery?.message;
	const chatId = msg?.chat?.id;
	const messageId = msg?.message_id;
	if (typeof chatId !== "undefined" && typeof messageId === "number") return `message:${chatId}:${messageId}`;
};
const createTelegramUpdateDedupe = () => createDedupeCache({
	ttlMs: RECENT_TELEGRAM_UPDATE_TTL_MS,
	maxSize: RECENT_TELEGRAM_UPDATE_MAX
});

//#endregion
//#region src/telegram/bot/delivery.send.ts
const PARSE_ERR_RE = /can't parse entities|parse entities|find end of the entity/i;
const EMPTY_TEXT_ERR_RE = /message text is empty/i;
const THREAD_NOT_FOUND_RE$1 = /message thread not found/i;
function isTelegramThreadNotFoundError(err) {
	if (err instanceof GrammyError) return THREAD_NOT_FOUND_RE$1.test(err.description);
	return THREAD_NOT_FOUND_RE$1.test(formatErrorMessage(err));
}
function hasMessageThreadIdParam(params) {
	if (!params) return false;
	return typeof params.message_thread_id === "number";
}
function removeMessageThreadIdParam(params) {
	if (!params) return {};
	const { message_thread_id: _ignored, ...rest } = params;
	return rest;
}
async function sendTelegramWithThreadFallback(params) {
	const allowThreadlessRetry = params.thread?.scope === "dm";
	const hasThreadId = hasMessageThreadIdParam(params.requestParams);
	const shouldSuppressFirstErrorLog = (err) => allowThreadlessRetry && hasThreadId && isTelegramThreadNotFoundError(err);
	const mergedShouldLog = params.shouldLog ? (err) => params.shouldLog(err) && !shouldSuppressFirstErrorLog(err) : (err) => !shouldSuppressFirstErrorLog(err);
	try {
		return await withTelegramApiErrorLogging({
			operation: params.operation,
			runtime: params.runtime,
			shouldLog: mergedShouldLog,
			fn: () => params.send(params.requestParams)
		});
	} catch (err) {
		if (!allowThreadlessRetry || !hasThreadId || !isTelegramThreadNotFoundError(err)) throw err;
		const retryParams = removeMessageThreadIdParam(params.requestParams);
		params.runtime.log?.(`telegram ${params.operation}: message thread not found; retrying without message_thread_id`);
		return await withTelegramApiErrorLogging({
			operation: `${params.operation} (threadless retry)`,
			runtime: params.runtime,
			fn: () => params.send(retryParams)
		});
	}
}
function buildTelegramSendParams(opts) {
	const threadParams = buildTelegramThreadParams(opts?.thread);
	const params = {};
	if (opts?.replyToMessageId) params.reply_to_message_id = opts.replyToMessageId;
	if (threadParams) params.message_thread_id = threadParams.message_thread_id;
	return params;
}
async function sendTelegramText(bot, chatId, text, runtime, opts) {
	const baseParams = buildTelegramSendParams({
		replyToMessageId: opts?.replyToMessageId,
		thread: opts?.thread
	});
	const linkPreviewOptions = opts?.linkPreview ?? true ? void 0 : { is_disabled: true };
	const htmlText = (opts?.textMode ?? "markdown") === "html" ? text : markdownToTelegramHtml(text);
	const fallbackText = opts?.plainText ?? text;
	const hasFallbackText = fallbackText.trim().length > 0;
	const sendPlainFallback = async () => {
		const res = await sendTelegramWithThreadFallback({
			operation: "sendMessage",
			runtime,
			thread: opts?.thread,
			requestParams: baseParams,
			send: (effectiveParams) => bot.api.sendMessage(chatId, fallbackText, {
				...linkPreviewOptions ? { link_preview_options: linkPreviewOptions } : {},
				...opts?.replyMarkup ? { reply_markup: opts.replyMarkup } : {},
				...effectiveParams
			})
		});
		runtime.log?.(`telegram sendMessage ok chat=${chatId} message=${res.message_id} (plain)`);
		return res.message_id;
	};
	if (!htmlText.trim()) {
		if (!hasFallbackText) throw new Error("telegram sendMessage failed: empty formatted text and empty plain fallback");
		return await sendPlainFallback();
	}
	try {
		const res = await sendTelegramWithThreadFallback({
			operation: "sendMessage",
			runtime,
			thread: opts?.thread,
			requestParams: baseParams,
			shouldLog: (err) => {
				const errText = formatErrorMessage(err);


python3 - <<'PY'
from pathlib import Path
p=Path('/usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js')
text=p.read_text()
start=text.find('const resolveTelegramUpdateId = (ctx) => ctx.update?.update_id ?? ctx.update_id;')
print(start)
print(text[start:start+1200])
PY


2400316
const resolveTelegramUpdateId = (ctx) => ctx.update?.update_id ?? ctx.update_id;
const buildTelegramUpdateKey = (ctx) => {
	const updateId = resolveTelegramUpdateId(ctx);
	if (typeof updateId === "number") return `update:${updateId}`;
	const callbackId = ctx.callbackQuery?.id;
	if (callbackId) return `callback:${callbackId}`;
	const msg = ctx.message ?? ctx.channelPost ?? ctx.editedChannelPost ?? ctx.update?.message ?? ctx.update?.edited_message ?? ctx.update?.channel_post ?? ctx.update?.edited_channel_post ?? ctx.callbackQuery?.message;
	const chatId = msg?.chat?.id;
	const messageId = msg?.message_id;
	if (typeof chatId !== "undefined" && typeof messageId === "number") return `message:${chatId}:${messageId}`;
};
const createTelegramUpdateDedupe = () => createDedupeCache({
	ttlMs: RECENT_TELEGRAM_UPDATE_TTL_MS,
	maxSize: RECENT_TELEGRAM_UPDATE_MAX
});

//#endregion
//#region src/telegram/bot/delivery.send.ts
const PARSE_ERR_RE = /can't parse entities|parse entities|find end of the entity/i;
const EMPTY_TEXT_ERR_RE = /message text is empty/i;
const THREAD_NOT_FOUND_RE$1 = /message thread not found/i;
function isTelegramThreadNotFoundError(err) {
	if (err instanceof GrammyError) ret


python3 - <<'PY'
from pathlib import Path
p=Path('/usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js')
text=p.read_text()
old='''\tconst recentUpdates = createTelegramUpdateDedupe();
\tconst initialUpdateId = typeof opts.updateOffset?.lastUpdateId === "number" ? opts.updateOffset.lastUpdateId : null;
\tconst pendingUpdateIds = /* @__PURE__ */ new Set();
\tlet highestCompletedUpdateId = initialUpdateId;
\tlet highestPersistedUpdateId = initialUpdateId;
'''
new='''\tconst recentUpdates = createTelegramUpdateDedupe();
\tconst latestSeenMessageIdByChat = /* @__PURE__ */ new Map();
\tconst initialUpdateId = typeof opts.updateOffset?.lastUpdateId === "number" ? opts.updateOffset.lastUpdateId : null;
\tconst pendingUpdateIds = /* @__PURE__ */ new Set();
\tlet highestCompletedUpdateId = initialUpdateId;
\tlet highestPersistedUpdateId = initialUpdateId;
'''
if old not in text:
    raise SystemExit('anchor1 not found')
text=text.replace(old,new,1)
old2='''\tconst shouldSkipUpdate = (ctx) => {
\t\tconst updateId = resolveTelegramUpdateId(ctx);
\t\tconst skipCutoff = highestPersistedUpdateId ?? initialUpdateId;
\t\tif (typeof updateId === "number" && skipCutoff !== null && updateId <= skipCutoff) return true;
\t\tconst key = buildTelegramUpdateKey(ctx);
\t\tthe skipped = recentUpdates.check(key);
\t\tif (skipped && key && shouldLogVerbose()) logVerbose(`telegram dedupe: skipped ${key}`);
\t\treturn skipped;
\t};
'''
if old2 not in text:
    # typo intentional likely 'const skipped' not 'the skipped'
    old2='''\tconst shouldSkipUpdate = (ctx) => {
\t\tconst updateId = resolveTelegramUpdateId(ctx);
\t\tconst skipCutoff = highestPersistedUpdateId ?? initialUpdateId;
\t\tif (typeof updateId === "number" && skipCutoff !== null && updateId <= skipCutoff) return true;
\t\tconst key = buildTelegramUpdateKey(ctx);
\t\tconst skipped = recentUpdates.check(key);
\t\tif (skipped && key && shouldLogVerbose()) logVerbose(`telegram dedupe: skipped ${key}`);
\t\treturn skipped;
\t};
'''
new2='''\tconst shouldSkipUpdate = (ctx) => {
\t\tconst updateId = resolveTelegramUpdateId(ctx);
\t\tconst skipCutoff = highestPersistedUpdateId ?? initialUpdateId;
\t\tif (typeof updateId === "number" && skipCutoff !== null && updateId <= skipCutoff) {
\t\t\truntime.log?.(`metric=dedupe_hit channel=telegram reason=offset_cutoff update_id=${updateId}`);
\t\t\treturn true;
\t\t}
\t\tconst msg = ctx.message ?? ctx.channelPost ?? ctx.editedChannelPost ?? ctx.update?.message ?? ctx.update?.edited_message ?? ctx.update?.channel_post ?? ctx.update?.edited_channel_post ?? ctx.callbackQuery?.message;
\t\tconst chatId = msg?.chat?.id;
\t\tconst messageId = msg?.message_id;
\t\tif (typeof chatId !== "undefined" && typeof messageId === "number") {
\t\t\tconst chatKey = String(chatId);
\t\t\tconst latestSeen = latestSeenMessageIdByChat.get(chatKey);
\t\t\tif (typeof latestSeen === "number" && messageId < latestSeen) {
\t\t\t\truntime.log?.(`metric=dedupe_hit channel=telegram reason=stale_backlog chat_id=${chatKey} message_id=${messageId} latest_seen_message_id=${latestSeen}`);
\t\t\t\tif (shouldLogVerbose()) logVerbose(`telegram dedupe: stale backlog dropped chat=${chatKey} message=${messageId} latest=${latestSeen}`);
\t\t\t\treturn true;
\t\t\t}
\t\t\tif (latestSeen == null || messageId > latestSeen) latestSeenMessageIdByChat.set(chatKey, messageId);
\t\t}
\t\tconst key = buildTelegramUpdateKey(ctx);
\t\tconst skipped = recentUpdates.check(key);
\t\tif (skipped && key) {
\t\t\truntime.log?.(`metric=dedupe_hit channel=telegram reason=update_cache key=${key}`);
\t\t\tif (shouldLogVerbose()) logVerbose(`telegram dedupe: skipped ${key}`);
\t\t}
\t\treturn skipped;
\t};
'''
if old2 not in text:
    raise SystemExit('anchor2 not found')
text=text.replace(old2,new2,1)
p.write_text(text)
print('patched')
PY


patched


sed -n '71270,71360p' /usr/lib/node_modules/openclaw/dist/subagent-registry-CkqrXKq4.js


const recentUpdates = createTelegramUpdateDedupe();
	const latestSeenMessageIdByChat = /* @__PURE__ */ new Map();
	const initialUpdateId = typeof opts.updateOffset?.lastUpdateId === "number" ? opts.updateOffset.lastUpdateId : null;
	const pendingUpdateIds = /* @__PURE__ */ new Set();
	let highestCompletedUpdateId = initialUpdateId;
	let highestPersistedUpdateId = initialUpdateId;
	const maybePersistSafeWatermark = () => {
		if (typeof opts.updateOffset?.onUpdateId !== "function") return;
		if (highestCompletedUpdateId === null) return;
		let safe = highestCompletedUpdateId;
		if (pendingUpdateIds.size > 0) {
			let minPending = null;
			for (const id of pendingUpdateIds) if (minPending === null || id < minPending) minPending = id;
			if (minPending !== null) safe = Math.min(safe, minPending - 1);
		}
		if (highestPersistedUpdateId !== null && safe <= highestPersistedUpdateId) return;
		highestPersistedUpdateId = safe;
		opts.updateOffset.onUpdateId(safe);
	};
	const shouldSkipUpdate = (ctx) => {
		const updateId = resolveTelegramUpdateId(ctx);
		const skipCutoff = highestPersistedUpdateId ?? initialUpdateId;
		if (typeof updateId === "number" && skipCutoff !== null && updateId <= skipCutoff) {
			runtime.log?.(`metric=dedupe_hit channel=telegram reason=offset_cutoff update_id=${updateId}`);
			return true;
		}
		const msg = ctx.message ?? ctx.channelPost ?? ctx.editedChannelPost ?? ctx.update?.message ?? ctx.update?.edited_message ?? ctx.update?.channel_post ?? ctx.update?.edited_channel_post ?? ctx.callbackQuery?.message;
		const chatId = msg?.chat?.id;
		const messageId = msg?.message_id;
		if (typeof chatId !== "undefined" && typeof messageId === "number") {
			const chatKey = String(chatId);
			const latestSeen = latestSeenMessageIdByChat.get(chatKey);
			if (typeof latestSeen === "number" && messageId < latestSeen) {
				runtime.log?.(`metric=dedupe_hit channel=telegram reason=stale_backlog chat_id=${chatKey} message_id=${messageId} latest_seen_message_id=${latestSeen}`);
				if (shouldLogVerbose()) logVerbose(`telegram dedupe: stale backlog dropped chat=${chatKey} message=${messageId} latest=${latestSeen}`);
				return true;
			}
			if (latestSeen == null || messageId > latestSeen) latestSeenMessageIdByChat.set(chatKey, messageId);
		}
		const key = buildTelegramUpdateKey(ctx);
		const skipped = recentUpdates.check(key);
		if (skipped && key) {
			runtime.log?.(`metric=dedupe_hit channel=telegram reason=update_cache key=${key}`);
			if (shouldLogVerbose()) logVerbose(`telegram dedupe: skipped ${key}`);
		}
		return skipped;
	};
	bot.use(async (ctx, next) => {
		const updateId = resolveTelegramUpdateId(ctx);
		if (typeof updateId === "number") pendingUpdateIds.add(updateId);
		try {
			await next();
		} finally {
			if (typeof updateId === "number") {
				pendingUpdateIds.delete(updateId);
				if (highestCompletedUpdateId === null || updateId > highestCompletedUpdateId) highestCompletedUpdateId = updateId;
				maybePersistSafeWatermark();
			}
		}
	});
	bot.use(sequentialize(getTelegramSequentialKey));
	const rawUpdateLogger = createSubsystemLogger("gateway/channels/telegram/raw-update");
	const MAX_RAW_UPDATE_CHARS = 8e3;
	const MAX_RAW_UPDATE_STRING = 500;
	const MAX_RAW_UPDATE_ARRAY = 20;
	const stringifyUpdate = (update) => {
		const seen = /* @__PURE__ */ new WeakSet();
		return JSON.stringify(update ?? null, (key, value) => {
			if (typeof value === "string" && value.length > MAX_RAW_UPDATE_STRING) return `${value.slice(0, MAX_RAW_UPDATE_STRING)}...`;
			if (Array.isArray(value) && value.length > MAX_RAW_UPDATE_ARRAY) return [...value.slice(0, MAX_RAW_UPDATE_ARRAY), `...(${value.length - MAX_RAW_UPDATE_ARRAY} more)`];
			if (value && typeof value === "object") {
				if (seen.has(value)) return "[Circular]";
				seen.add(value);
			}
			return value;
		});
	};
	bot.use(async (ctx, next) => {
		if (shouldLogVerbose()) try {
			const raw = stringifyUpdate(ctx.update);
			const preview = raw.length > MAX_RAW_UPDATE_CHARS ? `${raw.slice(0, MAX_RAW_UPDATE_CHARS)}...` : raw;
			rawUpdateLogger.debug(`telegram update: ${preview}`);
		} catch (err) {
			rawUpdateLogger.debug(`telegram update log failed: ${String(err)}`);
		}
		await next();
	});
	const historyLimit = Math.max(0, telegramCfg.historyLimit ?? cfg.messages?.groupChat?.historyLimit ?? DEFAULT_GROUP_HISTORY_LIMIT);
	const groupHistories = /* @__PURE__ */ new Map();
	const textLimit = resolveTextChunkLimit(cfg, "telegram", account.accountId);
	const dmPolicy = telegramCfg.dmPolicy ?? "pairing";


Command still running (session mild-cloud, pid 3744058). Use process (list/poll/log/write/kill/clear/remove) for follow-up.

> rateright-v2-scaffold@0.1.0 build
> next build

▲ Next.js 16.1.6 (Turbopack)
- Environments: .env.local

  Creating an optimized production build ...