/** * Extract cross-message context from a raw Telegram message: whether it was * forwarded (and from whom), what it replies to in the same chat, a quoted * excerpt, or a reply to a message in another chat. The bot receives all of * this on the normal message object — in private chats (mode 1) and business * chats (mode 2) alike — so this pure extractor is shared by both modes and the * rendering lives in `core/turns.ts` (`buildContextLines`). */ import type { Chat, ExternalReplyInfo, Message, MessageOrigin, User, } from "@grammyjs/types"; import type { MessageContext } from "../core/turns"; import { extractProfileFromUser } from "./profile"; /** A human name for a chat: title (group/channel), first name (private), or @username. */ function chatDisplayName(chat: Chat): string { const named = chat as { title?: string; first_name?: string; username?: string; }; if (named.title) return `«${named.title}»`; if (named.first_name) return named.first_name; if (named.username) return `@${named.username}`; return `chat ${chat.id}`; } /** Describe where a forwarded/origin message originally came from. */ export function describeMessageOrigin(origin: MessageOrigin): string { switch (origin.type) { case "user": return extractProfileFromUser(origin.sender_user).displayName; case "hidden_user": return `${origin.sender_user_name} (hidden)`; case "chat": { const name = chatDisplayName(origin.sender_chat); return origin.author_signature ? `${name} (${origin.author_signature})` : name; } case "channel": { const name = `channel ${chatDisplayName(origin.chat)}`; return origin.author_signature ? `${name} (${origin.author_signature})` : name; } } } /** The visible text a (reply) message carries — body or caption. */ function replyText(message: Message): string { const media = message as { text?: string; caption?: string; photo?: unknown; document?: { file_name?: string }; video?: unknown; voice?: unknown; audio?: unknown; sticker?: { emoji?: string }; }; if (media.text) return media.text; if (media.caption) return media.caption; if (media.photo) return ""; if (media.video) return "