@geminixiang/mama 0.2.0-beta.0 → 0.2.0-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (273) hide show
  1. package/README.md +171 -334
  2. package/dist/adapter.d.ts +36 -10
  3. package/dist/adapter.d.ts.map +1 -1
  4. package/dist/adapter.js.map +1 -1
  5. package/dist/adapters/discord/bot.d.ts +10 -5
  6. package/dist/adapters/discord/bot.d.ts.map +1 -1
  7. package/dist/adapters/discord/bot.js +349 -114
  8. package/dist/adapters/discord/bot.js.map +1 -1
  9. package/dist/adapters/discord/context.d.ts +1 -1
  10. package/dist/adapters/discord/context.d.ts.map +1 -1
  11. package/dist/adapters/discord/context.js +102 -31
  12. package/dist/adapters/discord/context.js.map +1 -1
  13. package/dist/adapters/shared.d.ts +71 -0
  14. package/dist/adapters/shared.d.ts.map +1 -0
  15. package/dist/adapters/shared.js +168 -0
  16. package/dist/adapters/shared.js.map +1 -0
  17. package/dist/adapters/slack/bot.d.ts +29 -22
  18. package/dist/adapters/slack/bot.d.ts.map +1 -1
  19. package/dist/adapters/slack/bot.js +620 -186
  20. package/dist/adapters/slack/bot.js.map +1 -1
  21. package/dist/adapters/slack/branch-manager.d.ts +22 -0
  22. package/dist/adapters/slack/branch-manager.d.ts.map +1 -0
  23. package/dist/adapters/slack/branch-manager.js +97 -0
  24. package/dist/adapters/slack/branch-manager.js.map +1 -0
  25. package/dist/adapters/slack/context.d.ts +1 -1
  26. package/dist/adapters/slack/context.d.ts.map +1 -1
  27. package/dist/adapters/slack/context.js +136 -71
  28. package/dist/adapters/slack/context.js.map +1 -1
  29. package/dist/adapters/slack/session.d.ts +3 -0
  30. package/dist/adapters/slack/session.d.ts.map +1 -0
  31. package/dist/adapters/slack/session.js +16 -0
  32. package/dist/adapters/slack/session.js.map +1 -0
  33. package/dist/adapters/slack/tools/attach.d.ts +1 -1
  34. package/dist/adapters/slack/tools/attach.d.ts.map +1 -1
  35. package/dist/adapters/slack/tools/attach.js.map +1 -1
  36. package/dist/adapters/telegram/bot.d.ts +2 -0
  37. package/dist/adapters/telegram/bot.d.ts.map +1 -1
  38. package/dist/adapters/telegram/bot.js +190 -123
  39. package/dist/adapters/telegram/bot.js.map +1 -1
  40. package/dist/adapters/telegram/context.d.ts.map +1 -1
  41. package/dist/adapters/telegram/context.js +57 -59
  42. package/dist/adapters/telegram/context.js.map +1 -1
  43. package/dist/adapters/telegram/html.d.ts +3 -0
  44. package/dist/adapters/telegram/html.d.ts.map +1 -0
  45. package/dist/adapters/telegram/html.js +98 -0
  46. package/dist/adapters/telegram/html.js.map +1 -0
  47. package/dist/agent.d.ts +9 -10
  48. package/dist/agent.d.ts.map +1 -1
  49. package/dist/agent.js +645 -555
  50. package/dist/agent.js.map +1 -1
  51. package/dist/commands/auto-reply.d.ts +16 -0
  52. package/dist/commands/auto-reply.d.ts.map +1 -0
  53. package/dist/commands/auto-reply.js +69 -0
  54. package/dist/commands/auto-reply.js.map +1 -0
  55. package/dist/commands/index.d.ts +5 -0
  56. package/dist/commands/index.d.ts.map +1 -0
  57. package/dist/commands/index.js +19 -0
  58. package/dist/commands/index.js.map +1 -0
  59. package/dist/commands/login.d.ts +5 -0
  60. package/dist/commands/login.d.ts.map +1 -0
  61. package/dist/commands/login.js +76 -0
  62. package/dist/commands/login.js.map +1 -0
  63. package/dist/commands/model.d.ts +14 -0
  64. package/dist/commands/model.d.ts.map +1 -0
  65. package/dist/commands/model.js +112 -0
  66. package/dist/commands/model.js.map +1 -0
  67. package/dist/commands/new.d.ts +9 -0
  68. package/dist/commands/new.d.ts.map +1 -0
  69. package/dist/commands/new.js +28 -0
  70. package/dist/commands/new.js.map +1 -0
  71. package/dist/commands/registry.d.ts +7 -0
  72. package/dist/commands/registry.d.ts.map +1 -0
  73. package/dist/commands/registry.js +14 -0
  74. package/dist/commands/registry.js.map +1 -0
  75. package/dist/commands/sandbox.d.ts +10 -0
  76. package/dist/commands/sandbox.d.ts.map +1 -0
  77. package/dist/commands/sandbox.js +88 -0
  78. package/dist/commands/sandbox.js.map +1 -0
  79. package/dist/commands/session-view.d.ts +5 -0
  80. package/dist/commands/session-view.d.ts.map +1 -0
  81. package/dist/commands/session-view.js +62 -0
  82. package/dist/commands/session-view.js.map +1 -0
  83. package/dist/commands/types.d.ts +41 -0
  84. package/dist/commands/types.d.ts.map +1 -0
  85. package/dist/commands/types.js +2 -0
  86. package/dist/commands/types.js.map +1 -0
  87. package/dist/commands/utils.d.ts +8 -0
  88. package/dist/commands/utils.d.ts.map +1 -0
  89. package/dist/commands/utils.js +14 -0
  90. package/dist/commands/utils.js.map +1 -0
  91. package/dist/config.d.ts +53 -7
  92. package/dist/config.d.ts.map +1 -1
  93. package/dist/config.js +320 -55
  94. package/dist/config.js.map +1 -1
  95. package/dist/context.d.ts +10 -42
  96. package/dist/context.d.ts.map +1 -1
  97. package/dist/context.js +15 -128
  98. package/dist/context.js.map +1 -1
  99. package/dist/events.d.ts +16 -5
  100. package/dist/events.d.ts.map +1 -1
  101. package/dist/events.js +127 -58
  102. package/dist/events.js.map +1 -1
  103. package/dist/execution-resolver.d.ts +24 -0
  104. package/dist/execution-resolver.d.ts.map +1 -0
  105. package/dist/execution-resolver.js +115 -0
  106. package/dist/execution-resolver.js.map +1 -0
  107. package/dist/file-guards.d.ts +6 -0
  108. package/dist/file-guards.d.ts.map +1 -0
  109. package/dist/file-guards.js +48 -0
  110. package/dist/file-guards.js.map +1 -0
  111. package/dist/fs-atomic.d.ts +10 -0
  112. package/dist/fs-atomic.d.ts.map +1 -0
  113. package/dist/fs-atomic.js +45 -0
  114. package/dist/fs-atomic.js.map +1 -0
  115. package/dist/index.d.ts +7 -0
  116. package/dist/index.d.ts.map +1 -0
  117. package/dist/index.js +4 -0
  118. package/dist/index.js.map +1 -0
  119. package/dist/instrument.d.ts.map +1 -1
  120. package/dist/instrument.js +3 -3
  121. package/dist/instrument.js.map +1 -1
  122. package/dist/log.d.ts +3 -7
  123. package/dist/log.d.ts.map +1 -1
  124. package/dist/log.js +20 -45
  125. package/dist/log.js.map +1 -1
  126. package/dist/login/index.d.ts +41 -0
  127. package/dist/login/index.d.ts.map +1 -0
  128. package/dist/login/index.js +202 -0
  129. package/dist/login/index.js.map +1 -0
  130. package/dist/login/portal.d.ts +19 -0
  131. package/dist/login/portal.d.ts.map +1 -0
  132. package/dist/login/portal.js +1453 -0
  133. package/dist/login/portal.js.map +1 -0
  134. package/dist/login/session.d.ts +33 -0
  135. package/dist/login/session.d.ts.map +1 -0
  136. package/dist/login/session.js +68 -0
  137. package/dist/login/session.js.map +1 -0
  138. package/dist/main.d.ts.map +1 -1
  139. package/dist/main.js +229 -264
  140. package/dist/main.js.map +1 -1
  141. package/dist/provisioner.d.ts +79 -0
  142. package/dist/provisioner.d.ts.map +1 -0
  143. package/dist/provisioner.js +437 -0
  144. package/dist/provisioner.js.map +1 -0
  145. package/dist/runtime/conversation-orchestrator.d.ts +42 -0
  146. package/dist/runtime/conversation-orchestrator.d.ts.map +1 -0
  147. package/dist/runtime/conversation-orchestrator.js +150 -0
  148. package/dist/runtime/conversation-orchestrator.js.map +1 -0
  149. package/dist/runtime/index.d.ts +2 -0
  150. package/dist/runtime/index.d.ts.map +1 -0
  151. package/dist/runtime/index.js +2 -0
  152. package/dist/runtime/index.js.map +1 -0
  153. package/dist/runtime/session-runtime.d.ts +27 -0
  154. package/dist/runtime/session-runtime.d.ts.map +1 -0
  155. package/dist/runtime/session-runtime.js +211 -0
  156. package/dist/runtime/session-runtime.js.map +1 -0
  157. package/dist/sandbox/cloudflare.d.ts +15 -0
  158. package/dist/sandbox/cloudflare.d.ts.map +1 -0
  159. package/dist/sandbox/cloudflare.js +137 -0
  160. package/dist/sandbox/cloudflare.js.map +1 -0
  161. package/dist/sandbox/container.d.ts +16 -0
  162. package/dist/sandbox/container.d.ts.map +1 -0
  163. package/dist/sandbox/container.js +126 -0
  164. package/dist/sandbox/container.js.map +1 -0
  165. package/dist/sandbox/errors.d.ts +6 -0
  166. package/dist/sandbox/errors.d.ts.map +1 -0
  167. package/dist/sandbox/errors.js +11 -0
  168. package/dist/sandbox/errors.js.map +1 -0
  169. package/dist/sandbox/firecracker.d.ts +17 -0
  170. package/dist/sandbox/firecracker.d.ts.map +1 -0
  171. package/dist/sandbox/firecracker.js +212 -0
  172. package/dist/sandbox/firecracker.js.map +1 -0
  173. package/dist/sandbox/host.d.ts +11 -0
  174. package/dist/sandbox/host.d.ts.map +1 -0
  175. package/dist/sandbox/host.js +89 -0
  176. package/dist/sandbox/host.js.map +1 -0
  177. package/dist/sandbox/image.d.ts +5 -0
  178. package/dist/sandbox/image.d.ts.map +1 -0
  179. package/dist/sandbox/image.js +30 -0
  180. package/dist/sandbox/image.js.map +1 -0
  181. package/dist/sandbox/index.d.ts +22 -0
  182. package/dist/sandbox/index.d.ts.map +1 -0
  183. package/dist/sandbox/index.js +54 -0
  184. package/dist/sandbox/index.js.map +1 -0
  185. package/dist/sandbox/path-context.d.ts +4 -0
  186. package/dist/sandbox/path-context.d.ts.map +1 -0
  187. package/dist/sandbox/path-context.js +20 -0
  188. package/dist/sandbox/path-context.js.map +1 -0
  189. package/dist/sandbox/types.d.ts +67 -0
  190. package/dist/sandbox/types.d.ts.map +1 -0
  191. package/dist/sandbox/types.js +2 -0
  192. package/dist/sandbox/types.js.map +1 -0
  193. package/dist/sandbox/utils.d.ts +4 -0
  194. package/dist/sandbox/utils.d.ts.map +1 -0
  195. package/dist/sandbox/utils.js +51 -0
  196. package/dist/sandbox/utils.js.map +1 -0
  197. package/dist/sandbox.d.ts +1 -39
  198. package/dist/sandbox.d.ts.map +1 -1
  199. package/dist/sandbox.js +1 -286
  200. package/dist/sandbox.js.map +1 -1
  201. package/dist/sentry.d.ts +2 -2
  202. package/dist/sentry.d.ts.map +1 -1
  203. package/dist/sentry.js +6 -4
  204. package/dist/sentry.js.map +1 -1
  205. package/dist/session-policy.d.ts +13 -0
  206. package/dist/session-policy.d.ts.map +1 -0
  207. package/dist/session-policy.js +23 -0
  208. package/dist/session-policy.js.map +1 -0
  209. package/dist/session-store.d.ts +35 -8
  210. package/dist/session-store.d.ts.map +1 -1
  211. package/dist/session-store.js +182 -23
  212. package/dist/session-store.js.map +1 -1
  213. package/dist/session-view/command.d.ts +5 -0
  214. package/dist/session-view/command.d.ts.map +1 -0
  215. package/dist/session-view/command.js +11 -0
  216. package/dist/session-view/command.js.map +1 -0
  217. package/dist/session-view/portal.d.ts +16 -0
  218. package/dist/session-view/portal.d.ts.map +1 -0
  219. package/dist/session-view/portal.js +1742 -0
  220. package/dist/session-view/portal.js.map +1 -0
  221. package/dist/session-view/service.d.ts +34 -0
  222. package/dist/session-view/service.d.ts.map +1 -0
  223. package/dist/session-view/service.js +427 -0
  224. package/dist/session-view/service.js.map +1 -0
  225. package/dist/session-view/store.d.ts +18 -0
  226. package/dist/session-view/store.d.ts.map +1 -0
  227. package/dist/session-view/store.js +39 -0
  228. package/dist/session-view/store.js.map +1 -0
  229. package/dist/store.d.ts +4 -7
  230. package/dist/store.d.ts.map +1 -1
  231. package/dist/store.js +26 -52
  232. package/dist/store.js.map +1 -1
  233. package/dist/tool-diagnostics.d.ts +2 -0
  234. package/dist/tool-diagnostics.d.ts.map +1 -0
  235. package/dist/tool-diagnostics.js +7 -0
  236. package/dist/tool-diagnostics.js.map +1 -0
  237. package/dist/tools/bash.d.ts +1 -1
  238. package/dist/tools/bash.d.ts.map +1 -1
  239. package/dist/tools/bash.js.map +1 -1
  240. package/dist/tools/edit.d.ts +1 -1
  241. package/dist/tools/edit.d.ts.map +1 -1
  242. package/dist/tools/edit.js.map +1 -1
  243. package/dist/tools/event.d.ts +62 -0
  244. package/dist/tools/event.d.ts.map +1 -0
  245. package/dist/tools/event.js +138 -0
  246. package/dist/tools/event.js.map +1 -0
  247. package/dist/tools/index.d.ts +8 -2
  248. package/dist/tools/index.d.ts.map +1 -1
  249. package/dist/tools/index.js +5 -1
  250. package/dist/tools/index.js.map +1 -1
  251. package/dist/tools/read.d.ts +1 -1
  252. package/dist/tools/read.d.ts.map +1 -1
  253. package/dist/tools/read.js.map +1 -1
  254. package/dist/tools/write.d.ts +1 -1
  255. package/dist/tools/write.d.ts.map +1 -1
  256. package/dist/tools/write.js.map +1 -1
  257. package/dist/trigger.d.ts +31 -0
  258. package/dist/trigger.d.ts.map +1 -0
  259. package/dist/trigger.js +98 -0
  260. package/dist/trigger.js.map +1 -0
  261. package/dist/ui-copy.d.ts +12 -0
  262. package/dist/ui-copy.d.ts.map +1 -0
  263. package/dist/ui-copy.js +36 -0
  264. package/dist/ui-copy.js.map +1 -0
  265. package/dist/vault-routing.d.ts +4 -0
  266. package/dist/vault-routing.d.ts.map +1 -0
  267. package/dist/vault-routing.js +16 -0
  268. package/dist/vault-routing.js.map +1 -0
  269. package/dist/vault.d.ts +72 -0
  270. package/dist/vault.d.ts.map +1 -0
  271. package/dist/vault.js +264 -0
  272. package/dist/vault.js.map +1 -0
  273. package/package.json +16 -13
@@ -1 +1 @@
1
- {"version":3,"file":"bot.js","sourceRoot":"","sources":["../../../src/adapters/telegram/bot.ts"],"names":[],"mappings":"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","sourcesContent":["import { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { basename, join } from \"path\";\nimport { Bot as GrammyBot, InputFile } from \"grammy\";\nimport type { Bot, BotEvent, BotHandler, PlatformInfo } from \"../../adapter.js\";\nimport * as log from \"../../log.js\";\nimport { createTelegramAdapters } from \"./context.js\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface TelegramEvent extends BotEvent {\n type: \"message\" | \"command\";\n userName?: string;\n}\n\ninterface MessageContext {\n msg: any;\n text: string;\n chatId: string;\n chatType: string;\n userId: string;\n userName: string;\n msgId: string;\n threadTs: string | undefined;\n sessionKey: string;\n}\n\n// ============================================================================\n// Per-channel queue for sequential processing\n// ============================================================================\n\ntype QueuedWork = () => Promise<void>;\n\nclass ChannelQueue {\n private queue: QueuedWork[] = [];\n private processing = false;\n\n enqueue(work: QueuedWork): void {\n this.queue.push(work);\n this.processNext();\n }\n\n size(): number {\n return this.queue.length;\n }\n\n private async processNext(): Promise<void> {\n if (this.processing || this.queue.length === 0) return;\n this.processing = true;\n const work = this.queue.shift()!;\n try {\n await work();\n } catch (err) {\n log.logWarning(\"Telegram queue error\", err instanceof Error ? err.message : String(err));\n }\n this.processing = false;\n this.processNext();\n }\n}\n\n// ============================================================================\n// TelegramBot\n// ============================================================================\n\nexport class TelegramBot implements Bot {\n private client: GrammyBot;\n private handler: BotHandler;\n private botToken: string;\n private workingDir: string;\n private botUserId: string | null = null;\n private botUsername: string | null = null;\n private queues = new Map<string, ChannelQueue>();\n private startupTime: number = 0;\n\n constructor(handler: BotHandler, config: { token: string; workingDir: string }) {\n this.handler = handler;\n this.botToken = config.token;\n this.workingDir = config.workingDir;\n this.client = new GrammyBot(config.token);\n this.client.catch((err) => {\n log.logWarning(\"Telegram error\", err instanceof Error ? err.message : String(err));\n });\n }\n\n // ==========================================================================\n // Public API (implements Bot)\n // ==========================================================================\n\n async start(): Promise<void> {\n const me = await this.client.api.getMe();\n this.botUserId = String(me.id);\n this.botUsername = me.username ?? null;\n this.startupTime = Date.now();\n\n await this.client.api.setMyCommands([\n { command: \"start\", description: \"Welcome message\" },\n { command: \"help\", description: \"Show available commands\" },\n { command: \"stop\", description: \"Stop ongoing conversation\" },\n { command: \"new\", description: \"Reset conversation history and start fresh\" },\n ]);\n\n this.setupEventHandlers();\n\n // Start polling in background (bot.start() runs indefinitely)\n this.client.start().catch((err) => {\n log.logWarning(\"Telegram polling error\", err instanceof Error ? err.message : String(err));\n });\n\n log.logConnected();\n log.logInfo(`Telegram bot started as @${this.botUsername ?? this.botUserId}`);\n }\n\n async postMessage(channel: string, text: string): Promise<string> {\n const result = await this.postMessageRaw(parseInt(channel), text);\n return String(result);\n }\n\n async updateMessage(channel: string, ts: string, text: string): Promise<void> {\n try {\n await this.client.api.editMessageText(parseInt(channel), parseInt(ts), text, {\n parse_mode: \"HTML\",\n });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n if (!msg.includes(\"message is not modified\")) {\n throw err;\n }\n }\n }\n\n enqueueEvent(event: BotEvent): boolean {\n const queue = this.getQueue(event.channel);\n if (queue.size() >= 5) {\n log.logWarning(\n `Event queue full for ${event.channel}, discarding: ${event.text.substring(0, 50)}`,\n );\n return false;\n }\n log.logInfo(`Enqueueing event for ${event.channel}: ${event.text.substring(0, 50)}`);\n queue.enqueue(() => {\n const adapters = createTelegramAdapters(event as TelegramEvent, this, true);\n return this.handler.handleEvent(event, this, adapters, true);\n });\n return true;\n }\n\n getPlatformInfo(): PlatformInfo {\n return {\n name: \"telegram\",\n formattingGuide:\n '## Telegram Formatting (HTML mode)\\nBold: <b>text</b>, Italic: <i>text</i>, Code: <code>code</code>, Pre: <pre>code</pre>\\nLinks: <a href=\"url\">text</a>',\n channels: [],\n users: [],\n };\n }\n\n // ==========================================================================\n // Internal helpers (used by context.ts)\n // ==========================================================================\n\n async postMessageRaw(chatId: number, text: string): Promise<number> {\n const result = await this.client.api.sendMessage(chatId, text, { parse_mode: \"HTML\" });\n return result.message_id;\n }\n\n async postPlainMessage(chatId: number, text: string): Promise<void> {\n await this.client.api.sendMessage(chatId, text);\n }\n\n async postReply(chatId: number, replyToMessageId: number, text: string): Promise<number> {\n const result = await this.client.api.sendMessage(chatId, text, {\n parse_mode: \"HTML\",\n reply_parameters: { message_id: replyToMessageId },\n });\n return result.message_id;\n }\n\n async deleteMessageRaw(chatId: number, messageId: number): Promise<void> {\n await this.client.api.deleteMessage(chatId, messageId);\n }\n\n async sendTyping(chatId: number): Promise<void> {\n await this.client.api.sendChatAction(chatId, \"typing\");\n }\n\n async uploadFile(channel: string, filePath: string, title?: string): Promise<void> {\n const fileName = title ?? basename(filePath);\n const fileContent = readFileSync(filePath);\n await this.client.api.sendDocument(parseInt(channel), new InputFile(fileContent, fileName));\n }\n\n logToFile(channel: string, entry: object): void {\n const dir = join(this.workingDir, channel);\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n appendFileSync(join(dir, \"log.jsonl\"), `${JSON.stringify(entry)}\\n`);\n }\n\n logBotResponse(channel: string, text: string, ts: string): void {\n this.logToFile(channel, {\n date: new Date().toISOString(),\n ts,\n user: \"bot\",\n text,\n attachments: [],\n isBot: true,\n });\n }\n\n /**\n * Process attachments from a Telegram message\n * Downloads files before returning metadata so the agent can read them immediately\n * Returns format compatible with ChatMessage: { name: string, localPath: string }[]\n */\n async processAttachments(\n chatId: string,\n message: any,\n ): Promise<{ name: string; localPath: string }[]> {\n const downloads: Array<Promise<{ name: string; localPath: string } | null>> = [];\n\n // Handle photos (take the largest size for best quality)\n if (message.photo && message.photo.length > 0) {\n const photos = message.photo;\n const photo = photos[photos.length - 1]; // Largest photo\n const fileId = photo.file_id;\n\n downloads.push(this.processTelegramFile(chatId, fileId, `photo_${message.message_id}.jpg`));\n }\n\n // Handle documents\n if (message.document) {\n const doc = message.document;\n const fileId = doc.file_id;\n const fileName = doc.file_name ?? `document_${message.message_id}`;\n\n downloads.push(this.processTelegramFile(chatId, fileId, fileName));\n }\n\n const attachments = await Promise.all(downloads);\n return attachments.filter(\n (attachment): attachment is { name: string; localPath: string } => attachment !== null,\n );\n }\n\n /**\n * Download a file from Telegram and return attachment metadata\n */\n private async processTelegramFile(\n chatId: string,\n fileId: string,\n originalName: string,\n ): Promise<{ name: string; localPath: string } | null> {\n try {\n // Get file info from Telegram\n const file = await this.client.api.getFile(fileId);\n if (!file.file_path) {\n log.logWarning(\"Telegram file has no path\", fileId);\n return null;\n }\n\n // Generate local filename\n const ts = Date.now();\n const sanitizedName = originalName.replace(/[^a-zA-Z0-9._-]/g, \"_\");\n const filename = `${ts}_${sanitizedName}`;\n const localPath = `${chatId}/attachments/${filename}`;\n const fullDir = join(this.workingDir, chatId, \"attachments\");\n\n if (!existsSync(fullDir)) mkdirSync(fullDir, { recursive: true });\n\n // Construct download URL\n const downloadUrl = `https://api.telegram.org/file/bot${this.botToken}/${file.file_path}`;\n\n // Download the file\n const response = await fetch(downloadUrl);\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n const buffer = await response.arrayBuffer();\n writeFileSync(join(fullDir, filename), Buffer.from(buffer));\n\n return {\n name: originalName,\n localPath: localPath,\n };\n } catch (err) {\n log.logWarning(`Failed to process Telegram file`, `${originalName}: ${err}`);\n return null;\n }\n }\n\n // ==========================================================================\n // Private - Event Handlers\n // ==========================================================================\n\n private getQueue(channelId: string): ChannelQueue {\n let queue = this.queues.get(channelId);\n if (!queue) {\n queue = new ChannelQueue();\n this.queues.set(channelId, queue);\n }\n return queue;\n }\n\n private extractMessageContext(msg: any): MessageContext | null {\n if (!msg) return null;\n if (msg.date * 1000 < this.startupTime) return null;\n if (msg.from?.is_bot) return null;\n\n const text = msg.text ?? msg.caption ?? \"\";\n if (!text && !msg.document && !msg.photo) return null;\n\n const chatId = String(msg.chat.id);\n const chatType = msg.chat.type;\n const userId = String(msg.from?.id ?? \"unknown\");\n const userName = msg.from?.username ?? msg.from?.first_name ?? userId;\n const msgId = String(msg.message_id);\n const replyToId = msg.reply_to_message?.message_id;\n const threadTs = replyToId ? String(replyToId) : undefined;\n\n // Private chats: single session per chat (no per-message splitting)\n // Groups: per-thread sessions (use reply chain or unique message id)\n const sessionKey = chatType === \"private\" ? chatId : `${chatId}:${threadTs ?? msgId}`;\n\n return { msg, text, chatId, chatType, userId, userName, msgId, threadTs, sessionKey };\n }\n\n private isAddressedToBot(text: string, chatType: string): boolean {\n if (chatType === \"private\") return true;\n if (!this.botUsername) return false;\n return text.toLowerCase().includes(`@${this.botUsername.toLowerCase()}`);\n }\n\n private cleanText(text: string): string {\n if (!this.botUsername) return text.trim();\n return text.replace(new RegExp(`@${this.botUsername}`, \"gi\"), \"\").trim();\n }\n\n private setupEventHandlers(): void {\n // --- Slash commands (registered before catch-all so grammY intercepts them) ---\n\n this.client.command(\"start\", async (ctx) => {\n const mc = this.extractMessageContext(ctx.message);\n if (!mc) return;\n await this.postMessageRaw(\n parseInt(mc.chatId),\n [\n \"<b>Welcome!</b>\",\n \"\",\n \"I'm an AI coding agent. Send me a message or use these commands:\",\n \"\",\n \"/new — Reset conversation history and start fresh\",\n \"/stop — Stop the current conversation\",\n \"/help — Show available commands\",\n ].join(\"\\n\"),\n );\n });\n\n this.client.command(\"help\", async (ctx) => {\n const mc = this.extractMessageContext(ctx.message);\n if (!mc) return;\n await this.postMessageRaw(\n parseInt(mc.chatId),\n [\n \"<b>Available commands:</b>\",\n \"\",\n \"/start — Welcome message\",\n \"/help — Show this help\",\n \"/stop — Stop ongoing conversation\",\n \"/new — Reset conversation history and start fresh\",\n \"\",\n \"You can also send a regular message to chat with the agent.\",\n ].join(\"\\n\"),\n );\n });\n\n this.client.command(\"stop\", async (ctx) => {\n const mc = this.extractMessageContext(ctx.message);\n if (!mc) return;\n if (this.handler.isRunning(mc.sessionKey)) {\n await this.handler.handleStop(mc.sessionKey, mc.chatId, this);\n } else {\n await this.postMessage(mc.chatId, \"Nothing running.\");\n }\n });\n\n this.client.command(\"new\", async (ctx) => {\n const mc = this.extractMessageContext(ctx.message);\n if (!mc) return;\n await this.handler.handleNew(mc.sessionKey, mc.chatId, this);\n });\n\n // --- Catch-all for regular (non-command) messages ---\n\n this.client.on(\"message\", async (ctx) => {\n const mc = this.extractMessageContext(ctx.message);\n if (!mc) return;\n\n // In groups, only respond when addressed to bot\n if (!this.isAddressedToBot(mc.text, mc.chatType)) return;\n\n const cleanedText = this.cleanText(mc.text);\n\n // Process attachments\n const processedAttachments = await this.processAttachments(mc.chatId, mc.msg);\n\n const event: TelegramEvent = {\n type: \"message\",\n channel: mc.chatId,\n ts: mc.msgId,\n thread_ts: mc.threadTs,\n sessionKey: mc.sessionKey,\n user: mc.userId,\n userName: mc.userName,\n text: cleanedText,\n attachments: processedAttachments,\n };\n\n // Log the message\n this.logToFile(mc.chatId, {\n date: new Date(mc.msg.date * 1000).toISOString(),\n ts: mc.msgId,\n user: mc.userId,\n userName: mc.userName,\n text: cleanedText,\n attachments: processedAttachments,\n isBot: false,\n });\n\n // Handle bare \"stop\" text (backward compat)\n if (cleanedText.toLowerCase() === \"stop\") {\n if (this.handler.isRunning(mc.sessionKey)) {\n await this.handler.handleStop(mc.sessionKey, mc.chatId, this);\n } else {\n await this.postMessage(mc.chatId, \"Nothing running.\");\n }\n return;\n }\n\n if (this.handler.isRunning(mc.sessionKey)) {\n await this.postMessage(mc.chatId, \"Already working. Say <code>/stop</code> to cancel.\");\n } else {\n this.getQueue(mc.sessionKey).enqueue(() => {\n const adapters = createTelegramAdapters(event, this, false);\n return this.handler.handleEvent(event, this, adapters, false);\n });\n }\n });\n }\n}\n"]}
1
+ {"version":3,"file":"bot.js","sourceRoot":"","sources":["../../../src/adapters/telegram/bot.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { basename, join } from \"path\";\nimport { Bot as GrammyBot, InputFile } from \"grammy\";\nimport type { Bot, BotEvent, BotHandler, PlatformInfo } from \"../../adapter.js\";\nimport * as log from \"../../log.js\";\nimport { resolveChatSessionKey } from \"../../session-policy.js\";\nimport { evaluateAutoReplyPolicy } from \"../../trigger.js\";\nimport { formatAlreadyWorking, formatNothingRunning } from \"../../ui-copy.js\";\nimport {\n appendBotResponseLog,\n appendChannelLog,\n ChannelQueue,\n resolveOnlyScopedStopTarget,\n resolveStopTarget,\n withRetry,\n} from \"../shared.js\";\nimport { createTelegramAdapters } from \"./context.js\";\nimport { escapeTelegramHtml } from \"./html.js\";\n\n// grammY surfaces Telegram errors as `GrammyError` with `error_code` mirroring\n// the Bot API. 429 is the rate-limit status; the response also includes\n// `parameters.retry_after` but exponential backoff is good enough here.\nfunction telegramIsRateLimited(err: Error): boolean {\n return (err as { error_code?: number }).error_code === 429;\n}\n\nconst telegramRetry = <T>(fn: () => Promise<T>): Promise<T> =>\n withRetry(fn, { isRateLimited: telegramIsRateLimited });\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface TelegramEvent extends BotEvent {\n type: \"message\" | \"command\";\n userName?: string;\n}\n\ninterface MessageContext {\n msg: any;\n text: string;\n chatId: string;\n chatType: string;\n conversationKind: \"direct\" | \"shared\";\n userId: string;\n userName: string;\n msgId: string;\n threadTs: string | undefined;\n sessionKey: string;\n}\n\n// ============================================================================\n// TelegramBot\n// ============================================================================\n\nfunction isTelegramHtmlParseError(message: string): boolean {\n return message.includes(\"can't parse entities\");\n}\n\nexport class TelegramBot implements Bot {\n private client: GrammyBot;\n private handler: BotHandler;\n private botToken: string;\n private workingDir: string;\n private botUserId: string | null = null;\n private botUsername: string | null = null;\n private queues = new Map<string, ChannelQueue>();\n private startupTime: number = 0;\n\n constructor(handler: BotHandler, config: { token: string; workingDir: string }) {\n this.handler = handler;\n this.botToken = config.token;\n this.workingDir = config.workingDir;\n this.client = new GrammyBot(config.token);\n this.client.catch((err) => {\n log.logWarning(\"Telegram error\", err instanceof Error ? err.message : String(err));\n });\n }\n\n // ==========================================================================\n // Public API (implements Bot)\n // ==========================================================================\n\n async start(): Promise<void> {\n const me = await this.client.api.getMe();\n this.botUserId = String(me.id);\n this.botUsername = me.username ?? null;\n this.startupTime = Date.now();\n\n await this.client.api.setMyCommands([\n { command: \"login\", description: \"Store credentials in your private vault\" },\n { command: \"session\", description: \"Open the current session in the web viewer\" },\n { command: \"model\", description: \"Switch this conversation's LLM model\" },\n { command: \"sandbox\", description: \"Show or boost sandbox limits\" },\n { command: \"stop\", description: \"Stop ongoing conversation\" },\n { command: \"new\", description: \"Reset conversation history and start fresh\" },\n ]);\n\n this.setupEventHandlers();\n\n // Start polling in background (bot.start() runs indefinitely)\n this.client.start().catch((err) => {\n log.logWarning(\"Telegram polling error\", err instanceof Error ? err.message : String(err));\n });\n\n log.logConnected(\"Telegram\");\n log.logInfo(`Telegram bot started as @${this.botUsername ?? this.botUserId}`);\n }\n\n async postMessage(channel: string, text: string): Promise<string> {\n const result = await this.postMessageRaw(parseInt(channel), text);\n return String(result);\n }\n\n async updateMessage(channel: string, ts: string, text: string): Promise<void> {\n return telegramRetry(async () => {\n try {\n await this.client.api.editMessageText(parseInt(channel), parseInt(ts), text, {\n parse_mode: \"HTML\",\n });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n if (msg.includes(\"message is not modified\")) {\n return;\n }\n if (!isTelegramHtmlParseError(msg)) {\n throw err;\n }\n await this.client.api.editMessageText(\n parseInt(channel),\n parseInt(ts),\n escapeTelegramHtml(text),\n {\n parse_mode: \"HTML\",\n },\n );\n }\n });\n }\n\n enqueueEvent(event: BotEvent): boolean {\n const conversationId = event.conversationId;\n const queue = this.getQueue(conversationId);\n if (queue.size() >= 5) {\n log.logWarning(\n `Event queue full for ${conversationId}, discarding: ${event.text.substring(0, 50)}`,\n );\n return false;\n }\n log.logInfo(`Enqueueing event for ${conversationId}: ${event.text.substring(0, 50)}`);\n queue.enqueue(() => {\n const adapters = createTelegramAdapters(event as TelegramEvent, this, true);\n return this.handler.handleEvent(event, this, adapters, true);\n });\n return true;\n }\n\n getPlatformInfo(): PlatformInfo {\n return {\n name: \"telegram\",\n formattingGuide:\n '## Telegram Formatting (HTML mode)\\nBold: <b>text</b>, Italic: <i>text</i>, Code: <code>code</code>, Pre: <pre>code</pre>\\nLinks: <a href=\"url\">text</a>',\n channels: [],\n users: [],\n };\n }\n\n // ==========================================================================\n // Internal helpers (used by context.ts)\n // ==========================================================================\n\n async postMessageRaw(chatId: number, text: string): Promise<number> {\n return telegramRetry(async () => {\n try {\n const result = await this.client.api.sendMessage(chatId, text, { parse_mode: \"HTML\" });\n return result.message_id;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n if (!isTelegramHtmlParseError(msg)) {\n throw err;\n }\n const result = await this.client.api.sendMessage(chatId, escapeTelegramHtml(text), {\n parse_mode: \"HTML\",\n });\n return result.message_id;\n }\n });\n }\n\n async postPlainMessage(chatId: number, text: string): Promise<void> {\n return telegramRetry(async () => {\n await this.client.api.sendMessage(chatId, text);\n });\n }\n\n async postReply(chatId: number, replyToMessageId: number, text: string): Promise<number> {\n return telegramRetry(async () => {\n try {\n const result = await this.client.api.sendMessage(chatId, text, {\n parse_mode: \"HTML\",\n reply_parameters: { message_id: replyToMessageId },\n });\n return result.message_id;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n if (!isTelegramHtmlParseError(msg)) {\n throw err;\n }\n const result = await this.client.api.sendMessage(chatId, escapeTelegramHtml(text), {\n parse_mode: \"HTML\",\n reply_parameters: { message_id: replyToMessageId },\n });\n return result.message_id;\n }\n });\n }\n\n async deleteMessageRaw(chatId: number, messageId: number): Promise<void> {\n await this.client.api.deleteMessage(chatId, messageId);\n }\n\n async sendTyping(chatId: number): Promise<void> {\n await this.client.api.sendChatAction(chatId, \"typing\");\n }\n\n async uploadFile(channel: string, filePath: string, title?: string): Promise<void> {\n return telegramRetry(async () => {\n const fileName = title ?? basename(filePath);\n const fileContent = readFileSync(filePath);\n await this.client.api.sendDocument(parseInt(channel), new InputFile(fileContent, fileName));\n });\n }\n\n logToFile(channel: string, entry: object): void {\n appendChannelLog(this.workingDir, channel, entry);\n }\n\n logBotResponse(channel: string, text: string, ts: string): void {\n appendBotResponseLog(this.workingDir, channel, text, ts);\n }\n\n /**\n * Process attachments from a Telegram message\n * Downloads files before returning metadata so the agent can read them immediately\n * Returns format compatible with ChatMessage: { name: string, localPath: string }[]\n */\n async processAttachments(\n chatId: string,\n message: any,\n ): Promise<{ name: string; localPath: string }[]> {\n const downloads: Array<Promise<{ name: string; localPath: string } | null>> = [];\n\n // Handle photos (take the largest size for best quality)\n if (message.photo && message.photo.length > 0) {\n const photos = message.photo;\n const photo = photos[photos.length - 1]; // Largest photo\n const fileId = photo.file_id;\n\n downloads.push(this.processTelegramFile(chatId, fileId, `photo_${message.message_id}.jpg`));\n }\n\n // Handle documents\n if (message.document) {\n const doc = message.document;\n const fileId = doc.file_id;\n const fileName = doc.file_name ?? `document_${message.message_id}`;\n\n downloads.push(this.processTelegramFile(chatId, fileId, fileName));\n }\n\n const attachments = await Promise.all(downloads);\n return attachments.filter(\n (attachment): attachment is { name: string; localPath: string } => attachment !== null,\n );\n }\n\n /**\n * Download a file from Telegram and return attachment metadata\n */\n private async processTelegramFile(\n chatId: string,\n fileId: string,\n originalName: string,\n ): Promise<{ name: string; localPath: string } | null> {\n try {\n // Get file info from Telegram\n const file = await this.client.api.getFile(fileId);\n if (!file.file_path) {\n log.logWarning(\"Telegram file has no path\", fileId);\n return null;\n }\n\n // Generate local filename\n const ts = Date.now();\n const sanitizedName = originalName.replace(/[^a-zA-Z0-9._-]/g, \"_\");\n const filename = `${ts}_${sanitizedName}`;\n const localPath = `${chatId}/attachments/${filename}`;\n const fullDir = join(this.workingDir, chatId, \"attachments\");\n\n if (!existsSync(fullDir)) mkdirSync(fullDir, { recursive: true });\n\n // Construct download URL\n const downloadUrl = `https://api.telegram.org/file/bot${this.botToken}/${file.file_path}`;\n\n // Download the file\n const response = await fetch(downloadUrl);\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n const buffer = await response.arrayBuffer();\n writeFileSync(join(fullDir, filename), Buffer.from(buffer));\n\n return {\n name: originalName,\n localPath: localPath,\n };\n } catch (err) {\n log.logWarning(`Failed to process Telegram file`, `${originalName}: ${err}`);\n return null;\n }\n }\n\n // ==========================================================================\n // Private - Event Handlers\n // ==========================================================================\n\n private getQueue(channelId: string): ChannelQueue {\n let queue = this.queues.get(channelId);\n if (!queue) {\n queue = new ChannelQueue(\"Telegram\");\n this.queues.set(channelId, queue);\n }\n return queue;\n }\n\n private extractMessageContext(msg: any): MessageContext | null {\n if (!msg) return null;\n if (msg.date * 1000 < this.startupTime) return null;\n if (msg.from?.is_bot) return null;\n\n const text = msg.text ?? msg.caption ?? \"\";\n if (!text && !msg.document && !msg.photo) return null;\n\n const chatId = String(msg.chat.id);\n const chatType = msg.chat.type;\n const userId = String(msg.from?.id ?? \"unknown\");\n const userName = msg.from?.username ?? msg.from?.first_name ?? userId;\n const msgId = String(msg.message_id);\n const replyToId = msg.reply_to_message?.message_id;\n const threadTs = replyToId ? String(replyToId) : undefined;\n const conversationKind = chatType === \"private\" ? \"direct\" : \"shared\";\n\n const sessionKey = resolveChatSessionKey({\n conversationId: chatId,\n conversationKind,\n messageId: msgId,\n threadTs,\n });\n\n return {\n msg,\n text,\n chatId,\n chatType,\n conversationKind,\n userId,\n userName,\n msgId,\n threadTs,\n sessionKey,\n };\n }\n\n private isAddressedToBot(text: string, chatType: string): boolean {\n if (chatType === \"private\") return true;\n if (!this.botUsername) return false;\n return text.toLowerCase().includes(`@${this.botUsername.toLowerCase()}`);\n }\n\n private cleanText(text: string): string {\n if (!this.botUsername) return text.trim();\n return text.replace(new RegExp(`@${this.botUsername}`, \"gi\"), \"\").trim();\n }\n\n private isStopText(text: string): boolean {\n return /^\\/?stop(?:@\\w+)?$/i.test(text.trim());\n }\n\n private resolveStopTarget(mc: MessageContext): string | null {\n const directTarget = resolveStopTarget({\n handler: this.handler,\n conversationId: mc.chatId,\n sessionKey: mc.sessionKey,\n });\n if (directTarget) return directTarget;\n return resolveOnlyScopedStopTarget(this.handler, mc.chatId);\n }\n\n private setupEventHandlers(): void {\n // --- Slash commands (registered before catch-all so grammY intercepts them) ---\n\n this.client.command(\"stop\", async (ctx) => {\n const mc = this.extractMessageContext(ctx.message);\n if (!mc) return;\n const stopTarget = this.resolveStopTarget(mc);\n if (stopTarget) {\n await this.handler.handleStop(stopTarget, mc.chatId, this);\n } else {\n await this.postMessage(mc.chatId, formatNothingRunning(\"telegram\"));\n }\n });\n\n this.client.command(\"new\", async (ctx) => {\n const mc = this.extractMessageContext(ctx.message);\n if (!mc) return;\n await this.handler.handleNewCommand(mc.sessionKey, mc.chatId, this);\n });\n\n this.client.command(\"sandbox\", async (ctx) => {\n const mc = this.extractMessageContext(ctx.message);\n if (!mc) return;\n const cleanedText = this.cleanText(mc.text).replace(/^\\/sandbox(?:@\\w+)?/i, \"/pi-sandbox\");\n const event: TelegramEvent = {\n type: \"command\",\n conversationId: mc.chatId,\n conversationKind: mc.conversationKind,\n ts: mc.msgId,\n thread_ts: mc.threadTs,\n sessionKey: mc.sessionKey,\n user: mc.userId,\n userName: mc.userName,\n text: cleanedText,\n attachments: [],\n };\n this.logToFile(mc.chatId, {\n date: new Date(mc.msg.date * 1000).toISOString(),\n ts: mc.msgId,\n ...(mc.conversationKind === \"shared\" && mc.threadTs ? { threadTs: mc.threadTs } : {}),\n user: mc.userId,\n userName: mc.userName,\n text: cleanedText,\n attachments: [],\n isBot: false,\n });\n const adapters = createTelegramAdapters(event, this, false);\n await this.handler.handleEvent(event, this, adapters, false);\n });\n\n // --- Catch-all for regular (non-command) messages ---\n\n this.client.on(\"message\", async (ctx) => {\n const mc = this.extractMessageContext(ctx.message);\n if (!mc) return;\n\n const cleanedText = this.cleanText(mc.text);\n const addressedToBot = this.isAddressedToBot(mc.text, mc.chatType);\n\n if (this.isStopText(cleanedText)) {\n this.logToFile(mc.chatId, {\n date: new Date(mc.msg.date * 1000).toISOString(),\n ts: mc.msgId,\n user: mc.userId,\n userName: mc.userName,\n text: cleanedText,\n attachments: [],\n isBot: false,\n });\n\n const stopTarget = this.resolveStopTarget(mc);\n if (stopTarget) {\n await this.handler.handleStop(stopTarget, mc.chatId, this);\n } else if (addressedToBot || mc.chatType === \"private\") {\n await this.postMessage(mc.chatId, formatNothingRunning(\"telegram\"));\n }\n return;\n }\n\n const isAutoReplyCandidate = mc.chatType !== \"private\" && !addressedToBot;\n\n const eventBase: TelegramEvent = {\n type: \"message\",\n conversationId: mc.chatId,\n conversationKind: mc.conversationKind,\n ts: mc.msgId,\n thread_ts: mc.threadTs,\n sessionKey: mc.sessionKey,\n user: mc.userId,\n userName: mc.userName,\n text: cleanedText,\n };\n\n const triggerResult = isAutoReplyCandidate\n ? await evaluateAutoReplyPolicy({ event: eventBase, workingDir: this.workingDir })\n : ({ trigger: true, reason: \"addressed\" } as const);\n\n const logEntryBase = {\n date: new Date(mc.msg.date * 1000).toISOString(),\n ts: mc.msgId,\n ...(mc.conversationKind === \"shared\" && mc.threadTs ? { threadTs: mc.threadTs } : {}),\n user: mc.userId,\n userName: mc.userName,\n text: cleanedText,\n isBot: false,\n };\n\n if (!triggerResult.trigger) {\n this.logToFile(mc.chatId, { ...logEntryBase, attachments: [] });\n return;\n }\n\n const processedAttachments = await this.processAttachments(mc.chatId, mc.msg);\n const event: TelegramEvent = { ...eventBase, attachments: processedAttachments };\n\n this.logToFile(mc.chatId, { ...logEntryBase, attachments: processedAttachments });\n\n if (this.handler.isRunning(mc.sessionKey)) {\n await this.postMessage(mc.chatId, formatAlreadyWorking(\"telegram\", \"/stop\"));\n } else {\n this.getQueue(mc.sessionKey).enqueue(() => {\n const adapters = createTelegramAdapters(event, this, false);\n return this.handler.handleEvent(event, this, adapters, false);\n });\n }\n });\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../src/adapters/telegram/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEvF,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE3D,eAAO,MAAM,yBAAyB,qTAIuD,CAAC;AAwD9F,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,aAAa,EACpB,GAAG,EAAE,WAAW,EAChB,QAAQ,CAAC,EAAE,OAAO,GACjB;IACD,OAAO,EAAE,WAAW,CAAC;IACrB,WAAW,EAAE,mBAAmB,CAAC;IACjC,QAAQ,EAAE,YAAY,CAAC;CACxB,CA2HA","sourcesContent":["import type { ChatMessage, ChatResponseContext, PlatformInfo } from \"../../adapter.js\";\nimport * as log from \"../../log.js\";\nimport type { TelegramBot, TelegramEvent } from \"./bot.js\";\n\nexport const TELEGRAM_FORMATTING_GUIDE = `## Telegram Formatting (HTML mode)\nBold: <b>text</b>, Italic: <i>text</i>, Code: <code>code</code>, Pre: <pre>code</pre>\nLinks: <a href=\"url\">text</a>\nDo NOT use Markdown asterisks or backtick syntax.\nDo NOT use <table> tags — they are unsupported. Use <pre> with ASCII art for tables instead.`;\n\nfunction htmlTableToText(tableHtml: string): string {\n const rows: string[][] = [];\n for (const rowMatch of tableHtml.matchAll(/<tr[^>]*>([\\s\\S]*?)<\\/tr>/gi)) {\n const cells: string[] = [];\n for (const cellMatch of rowMatch[1].matchAll(/<t[dh][^>]*>([\\s\\S]*?)<\\/t[dh]>/gi)) {\n cells.push(cellMatch[1].replace(/<[^>]+>/g, \"\").trim());\n }\n if (cells.length > 0) rows.push(cells);\n }\n\n if (rows.length === 0) return \"\";\n\n const numCols = Math.max(...rows.map((r) => r.length));\n const colWidths: number[] = Array(numCols).fill(0);\n for (const row of rows) {\n for (let i = 0; i < row.length; i++) {\n colWidths[i] = Math.max(colWidths[i], (row[i] ?? \"\").length);\n }\n }\n\n const sep = \"+\" + colWidths.map((w) => \"-\".repeat(w + 2)).join(\"+\") + \"+\";\n const lines: string[] = [sep];\n for (let i = 0; i < rows.length; i++) {\n const cells = colWidths.map((w, j) => ` ${(rows[i][j] ?? \"\").padEnd(w)} `);\n lines.push(\"|\" + cells.join(\"|\") + \"|\");\n if (i === 0) lines.push(sep);\n }\n lines.push(sep);\n return lines.join(\"\\n\");\n}\n\nfunction sanitizeTelegramHtml(text: string): string {\n if (!text.includes(\"<table\")) return text;\n return text.replace(/<table[\\s\\S]*?<\\/table>/gi, (tableHtml) => {\n const ascii = htmlTableToText(tableHtml);\n return ascii ? `<pre>${ascii}</pre>` : \"\";\n });\n}\n\nasync function notifyError(\n bot: TelegramBot,\n chatId: number,\n label: string,\n err: unknown,\n): Promise<void> {\n const errMsg = err instanceof Error ? err.message : String(err);\n log.logWarning(`Telegram ${label} error`, errMsg);\n try {\n await bot.postPlainMessage(chatId, `⚠️ 發送失敗:${errMsg}`);\n } catch {\n // ignore secondary failure\n }\n}\n\nexport function createTelegramAdapters(\n event: TelegramEvent,\n bot: TelegramBot,\n _isEvent?: boolean,\n): {\n message: ChatMessage;\n responseCtx: ChatResponseContext;\n platform: PlatformInfo;\n} {\n let messageId: number | null = null;\n let accumulatedText = \"\";\n let updatePromise = Promise.resolve();\n let typingInterval: ReturnType<typeof setInterval> | null = null;\n\n function stopTyping() {\n if (typingInterval !== null) {\n clearInterval(typingInterval);\n typingInterval = null;\n }\n }\n\n const chatId = parseInt(event.channel);\n const replyToId = event.thread_ts ? parseInt(event.thread_ts) : null;\n\n const message: ChatMessage = {\n id: event.ts,\n sessionKey: event.sessionKey ?? `${event.channel}:${event.thread_ts ?? event.ts}`,\n userId: event.user,\n userName: event.userName,\n text: event.text,\n attachments: event.attachments,\n threadTs: event.thread_ts,\n };\n\n const platform: PlatformInfo = {\n name: \"telegram\",\n formattingGuide: TELEGRAM_FORMATTING_GUIDE,\n channels: [],\n users: [],\n };\n\n // Telegram message length limit is 4096 chars; use 3800 for safety\n const MAX_LENGTH = 3800;\n const truncationNote = \"\\n\\n<i>(message truncated, ask me to elaborate on specific parts)</i>\";\n\n function truncate(text: string, limit: number, note: string): string {\n if (text.length > limit) {\n return text.substring(0, limit - note.length) + note;\n }\n return text;\n }\n\n async function sendOrUpdate(displayText: string): Promise<void> {\n if (messageId !== null) {\n await bot.updateMessage(event.channel, String(messageId), displayText);\n } else if (replyToId !== null) {\n messageId = await bot.postReply(chatId, replyToId, displayText);\n } else {\n messageId = await bot.postMessageRaw(chatId, displayText);\n }\n }\n\n const responseCtx: ChatResponseContext = {\n respond: async (text: string) => {\n updatePromise = updatePromise.then(async () => {\n try {\n const sanitized = sanitizeTelegramHtml(text);\n accumulatedText = accumulatedText ? `${accumulatedText}\\n${sanitized}` : sanitized;\n const displayText = truncate(accumulatedText, MAX_LENGTH, truncationNote);\n await sendOrUpdate(displayText);\n if (messageId !== null) {\n bot.logBotResponse(event.channel, text, String(messageId));\n }\n } catch (err) {\n await notifyError(bot, chatId, \"respond\", err);\n }\n });\n await updatePromise;\n },\n\n replaceResponse: async (text: string) => {\n updatePromise = updatePromise.then(async () => {\n try {\n accumulatedText = truncate(sanitizeTelegramHtml(text), MAX_LENGTH, truncationNote);\n await sendOrUpdate(accumulatedText);\n } catch (err) {\n await notifyError(bot, chatId, \"replaceResponse\", err);\n }\n });\n await updatePromise;\n },\n\n // Telegram has no threads discard thread-only messages (e.g. usage summary)\n respondInThread: async (_text: string) => {},\n\n setTyping: async (isTyping: boolean) => {\n if (isTyping && typingInterval === null) {\n // Send immediately and repeat every 4s (Telegram clears indicator after ~5s)\n bot.sendTyping(chatId).catch(() => {});\n typingInterval = setInterval(() => {\n bot.sendTyping(chatId).catch(() => {});\n }, 4000);\n } else if (!isTyping) {\n stopTyping();\n }\n },\n\n setWorking: async (working: boolean) => {\n if (!working) stopTyping();\n },\n\n uploadFile: async (filePath: string, title?: string) => {\n await bot.uploadFile(event.channel, filePath, title);\n },\n\n deleteResponse: async () => {\n updatePromise = updatePromise.then(async () => {\n if (messageId !== null) {\n try {\n await bot.deleteMessageRaw(chatId, messageId);\n } catch {\n // Ignore errors\n }\n messageId = null;\n }\n });\n await updatePromise;\n },\n };\n\n return { message, responseCtx, platform };\n}\n"]}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../src/adapters/telegram/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,mBAAmB,EAEnB,YAAY,EACb,MAAM,kBAAkB,CAAC;AAI1B,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE3D,eAAO,MAAM,yBAAyB,qTAIuD,CAAC;AA6B9F,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,aAAa,EACpB,GAAG,EAAE,WAAW,EAChB,QAAQ,CAAC,EAAE,OAAO,GACjB;IACD,OAAO,EAAE,WAAW,CAAC;IACrB,WAAW,EAAE,mBAAmB,CAAC;IACjC,QAAQ,EAAE,YAAY,CAAC;CACxB,CAiKA","sourcesContent":["import type {\n ChatMessage,\n ChatResponseContext,\n ChatToolResult,\n PlatformInfo,\n} from \"../../adapter.js\";\nimport * as log from \"../../log.js\";\nimport { formatToolArgs, splitText } from \"../shared.js\";\nimport { sanitizeTelegramHtml } from \"./html.js\";\nimport type { TelegramBot, TelegramEvent } from \"./bot.js\";\n\nexport const TELEGRAM_FORMATTING_GUIDE = `## Telegram Formatting (HTML mode)\nBold: <b>text</b>, Italic: <i>text</i>, Code: <code>code</code>, Pre: <pre>code</pre>\nLinks: <a href=\"url\">text</a>\nDo NOT use Markdown asterisks or backtick syntax.\nDo NOT use <table> tags — they are unsupported. Use <pre> with ASCII art for tables instead.`;\n\n// Telegram message length limit is 4096 chars; 3800 leaves headroom for HTML escapes.\nconst MAX_LENGTH = 3800;\n\nconst formatTelegramContinuation = (partNum: number): string => `(continued ${partNum})`;\n\nasync function notifyError(\n bot: TelegramBot,\n chatId: number,\n label: string,\n err: unknown,\n): Promise<void> {\n const errMsg = err instanceof Error ? err.message : String(err);\n log.logWarning(`Telegram ${label} error`, errMsg);\n try {\n await bot.postPlainMessage(chatId, `⚠️ 發送失敗:${errMsg}`);\n } catch {\n // ignore secondary failure\n }\n}\n\nfunction formatToolResult(result: ChatToolResult): string {\n const argsFormatted = formatToolArgs(result.args);\n const duration = (result.durationMs / 1000).toFixed(1);\n const title = `${result.isError ? \"Error\" : \"Done\"} ${result.toolName}${result.label ? `: ${result.label}` : \"\"} (${duration}s)`;\n return [title, argsFormatted, result.result].filter(Boolean).join(\"\\n\\n\");\n}\n\nexport function createTelegramAdapters(\n event: TelegramEvent,\n bot: TelegramBot,\n _isEvent?: boolean,\n): {\n message: ChatMessage;\n responseCtx: ChatResponseContext;\n platform: PlatformInfo;\n} {\n let messageId: number | null = null;\n let accumulatedText = \"\";\n let updatePromise = Promise.resolve();\n let typingInterval: ReturnType<typeof setInterval> | null = null;\n let typingFailureWarned = false;\n\n function stopTyping() {\n if (typingInterval !== null) {\n clearInterval(typingInterval);\n typingInterval = null;\n }\n }\n\n const conversationId = event.conversationId;\n const chatId = parseInt(conversationId);\n const replyToId = event.thread_ts ? parseInt(event.thread_ts) : null;\n\n const message: ChatMessage = {\n id: event.ts,\n sessionKey: event.sessionKey ?? `${conversationId}:${event.thread_ts ?? event.ts}`,\n conversationKind: event.conversationKind,\n userId: event.user,\n userName: event.userName,\n text: event.text,\n attachments: event.attachments,\n threadTs: event.thread_ts,\n };\n\n const platform: PlatformInfo = {\n name: \"telegram\",\n formattingGuide: TELEGRAM_FORMATTING_GUIDE,\n channels: [],\n users: [],\n };\n\n async function sendContinuation(text: string): Promise<void> {\n await bot.postMessageRaw(chatId, text);\n }\n\n async function sendOrUpdate(displayText: string): Promise<void> {\n if (messageId !== null) {\n await bot.updateMessage(conversationId, String(messageId), displayText);\n } else if (replyToId !== null) {\n messageId = await bot.postReply(chatId, replyToId, displayText);\n } else {\n messageId = await bot.postMessageRaw(chatId, displayText);\n }\n }\n\n const responseCtx: ChatResponseContext = {\n respond: async (text: string) => {\n updatePromise = updatePromise.then(async () => {\n try {\n const sanitized = sanitizeTelegramHtml(text);\n accumulatedText = accumulatedText ? `${accumulatedText}\\n${sanitized}` : sanitized;\n const [firstPart, ...extraParts] = splitText(\n accumulatedText,\n MAX_LENGTH,\n formatTelegramContinuation,\n );\n await sendOrUpdate(firstPart);\n for (const part of extraParts) {\n await sendContinuation(part);\n }\n if (messageId !== null) {\n bot.logBotResponse(conversationId, text, String(messageId));\n }\n } catch (err) {\n await notifyError(bot, chatId, \"respond\", err);\n }\n });\n await updatePromise;\n },\n\n replaceResponse: async (text: string) => {\n updatePromise = updatePromise.then(async () => {\n try {\n accumulatedText = sanitizeTelegramHtml(text);\n const [firstPart, ...extraParts] = splitText(\n accumulatedText,\n MAX_LENGTH,\n formatTelegramContinuation,\n );\n await sendOrUpdate(firstPart);\n for (const part of extraParts) {\n await sendContinuation(part);\n }\n } catch (err) {\n await notifyError(bot, chatId, \"replaceResponse\", err);\n }\n });\n await updatePromise;\n },\n\n respondDiagnostic: async (text: string, options?: { style?: \"muted\" | \"error\" }) => {\n updatePromise = updatePromise.then(async () => {\n try {\n const prefix = options?.style === \"error\" ? \"Error: \" : \"\";\n for (const part of splitText(\n sanitizeTelegramHtml(`${prefix}${text}`),\n MAX_LENGTH,\n formatTelegramContinuation,\n )) {\n await sendContinuation(part);\n }\n } catch (err) {\n await notifyError(bot, chatId, \"respondDiagnostic\", err);\n }\n });\n await updatePromise;\n },\n\n respondToolResult: async (result: ChatToolResult) => {\n await responseCtx.respondDiagnostic(formatToolResult(result));\n },\n\n setTyping: async (isTyping: boolean) => {\n const onTypingError = (err: unknown): void => {\n if (typingFailureWarned) return;\n typingFailureWarned = true;\n log.logWarning(\n \"Telegram sendTyping failed (further occurrences suppressed for this session)\",\n err instanceof Error ? err.message : String(err),\n );\n };\n if (isTyping && typingInterval === null) {\n // Send immediately and repeat every 4s (Telegram clears indicator after ~5s)\n bot.sendTyping(chatId).catch(onTypingError);\n typingInterval = setInterval(() => {\n bot.sendTyping(chatId).catch(onTypingError);\n }, 4000);\n } else if (!isTyping) {\n stopTyping();\n }\n },\n\n setWorking: async (working: boolean) => {\n if (!working) stopTyping();\n },\n\n uploadFile: async (filePath: string, title?: string) => {\n await bot.uploadFile(conversationId, filePath, title);\n },\n\n deleteResponse: async () => {\n updatePromise = updatePromise.then(async () => {\n if (messageId !== null) {\n try {\n await bot.deleteMessageRaw(chatId, messageId);\n } catch {\n // Ignore errors\n }\n messageId = null;\n }\n });\n await updatePromise;\n },\n };\n\n return { message, responseCtx, platform };\n}\n"]}
@@ -1,47 +1,14 @@
1
1
  import * as log from "../../log.js";
2
+ import { formatToolArgs, splitText } from "../shared.js";
3
+ import { sanitizeTelegramHtml } from "./html.js";
2
4
  export const TELEGRAM_FORMATTING_GUIDE = `## Telegram Formatting (HTML mode)
3
5
  Bold: <b>text</b>, Italic: <i>text</i>, Code: <code>code</code>, Pre: <pre>code</pre>
4
6
  Links: <a href="url">text</a>
5
7
  Do NOT use Markdown asterisks or backtick syntax.
6
8
  Do NOT use <table> tags — they are unsupported. Use <pre> with ASCII art for tables instead.`;
7
- function htmlTableToText(tableHtml) {
8
- const rows = [];
9
- for (const rowMatch of tableHtml.matchAll(/<tr[^>]*>([\s\S]*?)<\/tr>/gi)) {
10
- const cells = [];
11
- for (const cellMatch of rowMatch[1].matchAll(/<t[dh][^>]*>([\s\S]*?)<\/t[dh]>/gi)) {
12
- cells.push(cellMatch[1].replace(/<[^>]+>/g, "").trim());
13
- }
14
- if (cells.length > 0)
15
- rows.push(cells);
16
- }
17
- if (rows.length === 0)
18
- return "";
19
- const numCols = Math.max(...rows.map((r) => r.length));
20
- const colWidths = Array(numCols).fill(0);
21
- for (const row of rows) {
22
- for (let i = 0; i < row.length; i++) {
23
- colWidths[i] = Math.max(colWidths[i], (row[i] ?? "").length);
24
- }
25
- }
26
- const sep = "+" + colWidths.map((w) => "-".repeat(w + 2)).join("+") + "+";
27
- const lines = [sep];
28
- for (let i = 0; i < rows.length; i++) {
29
- const cells = colWidths.map((w, j) => ` ${(rows[i][j] ?? "").padEnd(w)} `);
30
- lines.push("|" + cells.join("|") + "|");
31
- if (i === 0)
32
- lines.push(sep);
33
- }
34
- lines.push(sep);
35
- return lines.join("\n");
36
- }
37
- function sanitizeTelegramHtml(text) {
38
- if (!text.includes("<table"))
39
- return text;
40
- return text.replace(/<table[\s\S]*?<\/table>/gi, (tableHtml) => {
41
- const ascii = htmlTableToText(tableHtml);
42
- return ascii ? `<pre>${ascii}</pre>` : "";
43
- });
44
- }
9
+ // Telegram message length limit is 4096 chars; 3800 leaves headroom for HTML escapes.
10
+ const MAX_LENGTH = 3800;
11
+ const formatTelegramContinuation = (partNum) => `(continued ${partNum})`;
45
12
  async function notifyError(bot, chatId, label, err) {
46
13
  const errMsg = err instanceof Error ? err.message : String(err);
47
14
  log.logWarning(`Telegram ${label} error`, errMsg);
@@ -52,22 +19,31 @@ async function notifyError(bot, chatId, label, err) {
52
19
  // ignore secondary failure
53
20
  }
54
21
  }
22
+ function formatToolResult(result) {
23
+ const argsFormatted = formatToolArgs(result.args);
24
+ const duration = (result.durationMs / 1000).toFixed(1);
25
+ const title = `${result.isError ? "Error" : "Done"} ${result.toolName}${result.label ? `: ${result.label}` : ""} (${duration}s)`;
26
+ return [title, argsFormatted, result.result].filter(Boolean).join("\n\n");
27
+ }
55
28
  export function createTelegramAdapters(event, bot, _isEvent) {
56
29
  let messageId = null;
57
30
  let accumulatedText = "";
58
31
  let updatePromise = Promise.resolve();
59
32
  let typingInterval = null;
33
+ let typingFailureWarned = false;
60
34
  function stopTyping() {
61
35
  if (typingInterval !== null) {
62
36
  clearInterval(typingInterval);
63
37
  typingInterval = null;
64
38
  }
65
39
  }
66
- const chatId = parseInt(event.channel);
40
+ const conversationId = event.conversationId;
41
+ const chatId = parseInt(conversationId);
67
42
  const replyToId = event.thread_ts ? parseInt(event.thread_ts) : null;
68
43
  const message = {
69
44
  id: event.ts,
70
- sessionKey: event.sessionKey ?? `${event.channel}:${event.thread_ts ?? event.ts}`,
45
+ sessionKey: event.sessionKey ?? `${conversationId}:${event.thread_ts ?? event.ts}`,
46
+ conversationKind: event.conversationKind,
71
47
  userId: event.user,
72
48
  userName: event.userName,
73
49
  text: event.text,
@@ -80,18 +56,12 @@ export function createTelegramAdapters(event, bot, _isEvent) {
80
56
  channels: [],
81
57
  users: [],
82
58
  };
83
- // Telegram message length limit is 4096 chars; use 3800 for safety
84
- const MAX_LENGTH = 3800;
85
- const truncationNote = "\n\n<i>(message truncated, ask me to elaborate on specific parts)</i>";
86
- function truncate(text, limit, note) {
87
- if (text.length > limit) {
88
- return text.substring(0, limit - note.length) + note;
89
- }
90
- return text;
59
+ async function sendContinuation(text) {
60
+ await bot.postMessageRaw(chatId, text);
91
61
  }
92
62
  async function sendOrUpdate(displayText) {
93
63
  if (messageId !== null) {
94
- await bot.updateMessage(event.channel, String(messageId), displayText);
64
+ await bot.updateMessage(conversationId, String(messageId), displayText);
95
65
  }
96
66
  else if (replyToId !== null) {
97
67
  messageId = await bot.postReply(chatId, replyToId, displayText);
@@ -106,10 +76,13 @@ export function createTelegramAdapters(event, bot, _isEvent) {
106
76
  try {
107
77
  const sanitized = sanitizeTelegramHtml(text);
108
78
  accumulatedText = accumulatedText ? `${accumulatedText}\n${sanitized}` : sanitized;
109
- const displayText = truncate(accumulatedText, MAX_LENGTH, truncationNote);
110
- await sendOrUpdate(displayText);
79
+ const [firstPart, ...extraParts] = splitText(accumulatedText, MAX_LENGTH, formatTelegramContinuation);
80
+ await sendOrUpdate(firstPart);
81
+ for (const part of extraParts) {
82
+ await sendContinuation(part);
83
+ }
111
84
  if (messageId !== null) {
112
- bot.logBotResponse(event.channel, text, String(messageId));
85
+ bot.logBotResponse(conversationId, text, String(messageId));
113
86
  }
114
87
  }
115
88
  catch (err) {
@@ -121,8 +94,12 @@ export function createTelegramAdapters(event, bot, _isEvent) {
121
94
  replaceResponse: async (text) => {
122
95
  updatePromise = updatePromise.then(async () => {
123
96
  try {
124
- accumulatedText = truncate(sanitizeTelegramHtml(text), MAX_LENGTH, truncationNote);
125
- await sendOrUpdate(accumulatedText);
97
+ accumulatedText = sanitizeTelegramHtml(text);
98
+ const [firstPart, ...extraParts] = splitText(accumulatedText, MAX_LENGTH, formatTelegramContinuation);
99
+ await sendOrUpdate(firstPart);
100
+ for (const part of extraParts) {
101
+ await sendContinuation(part);
102
+ }
126
103
  }
127
104
  catch (err) {
128
105
  await notifyError(bot, chatId, "replaceResponse", err);
@@ -130,14 +107,35 @@ export function createTelegramAdapters(event, bot, _isEvent) {
130
107
  });
131
108
  await updatePromise;
132
109
  },
133
- // Telegram has no threads — discard thread-only messages (e.g. usage summary)
134
- respondInThread: async (_text) => { },
110
+ respondDiagnostic: async (text, options) => {
111
+ updatePromise = updatePromise.then(async () => {
112
+ try {
113
+ const prefix = options?.style === "error" ? "Error: " : "";
114
+ for (const part of splitText(sanitizeTelegramHtml(`${prefix}${text}`), MAX_LENGTH, formatTelegramContinuation)) {
115
+ await sendContinuation(part);
116
+ }
117
+ }
118
+ catch (err) {
119
+ await notifyError(bot, chatId, "respondDiagnostic", err);
120
+ }
121
+ });
122
+ await updatePromise;
123
+ },
124
+ respondToolResult: async (result) => {
125
+ await responseCtx.respondDiagnostic(formatToolResult(result));
126
+ },
135
127
  setTyping: async (isTyping) => {
128
+ const onTypingError = (err) => {
129
+ if (typingFailureWarned)
130
+ return;
131
+ typingFailureWarned = true;
132
+ log.logWarning("Telegram sendTyping failed (further occurrences suppressed for this session)", err instanceof Error ? err.message : String(err));
133
+ };
136
134
  if (isTyping && typingInterval === null) {
137
135
  // Send immediately and repeat every 4s (Telegram clears indicator after ~5s)
138
- bot.sendTyping(chatId).catch(() => { });
136
+ bot.sendTyping(chatId).catch(onTypingError);
139
137
  typingInterval = setInterval(() => {
140
- bot.sendTyping(chatId).catch(() => { });
138
+ bot.sendTyping(chatId).catch(onTypingError);
141
139
  }, 4000);
142
140
  }
143
141
  else if (!isTyping) {
@@ -149,7 +147,7 @@ export function createTelegramAdapters(event, bot, _isEvent) {
149
147
  stopTyping();
150
148
  },
151
149
  uploadFile: async (filePath, title) => {
152
- await bot.uploadFile(event.channel, filePath, title);
150
+ await bot.uploadFile(conversationId, filePath, title);
153
151
  },
154
152
  deleteResponse: async () => {
155
153
  updatePromise = updatePromise.then(async () => {
@@ -1 +1 @@
1
- {"version":3,"file":"context.js","sourceRoot":"","sources":["../../../src/adapters/telegram/context.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ChatMessage, ChatResponseContext, PlatformInfo } from \"../../adapter.js\";\nimport * as log from \"../../log.js\";\nimport type { TelegramBot, TelegramEvent } from \"./bot.js\";\n\nexport const TELEGRAM_FORMATTING_GUIDE = `## Telegram Formatting (HTML mode)\nBold: <b>text</b>, Italic: <i>text</i>, Code: <code>code</code>, Pre: <pre>code</pre>\nLinks: <a href=\"url\">text</a>\nDo NOT use Markdown asterisks or backtick syntax.\nDo NOT use <table> tags — they are unsupported. Use <pre> with ASCII art for tables instead.`;\n\nfunction htmlTableToText(tableHtml: string): string {\n const rows: string[][] = [];\n for (const rowMatch of tableHtml.matchAll(/<tr[^>]*>([\\s\\S]*?)<\\/tr>/gi)) {\n const cells: string[] = [];\n for (const cellMatch of rowMatch[1].matchAll(/<t[dh][^>]*>([\\s\\S]*?)<\\/t[dh]>/gi)) {\n cells.push(cellMatch[1].replace(/<[^>]+>/g, \"\").trim());\n }\n if (cells.length > 0) rows.push(cells);\n }\n\n if (rows.length === 0) return \"\";\n\n const numCols = Math.max(...rows.map((r) => r.length));\n const colWidths: number[] = Array(numCols).fill(0);\n for (const row of rows) {\n for (let i = 0; i < row.length; i++) {\n colWidths[i] = Math.max(colWidths[i], (row[i] ?? \"\").length);\n }\n }\n\n const sep = \"+\" + colWidths.map((w) => \"-\".repeat(w + 2)).join(\"+\") + \"+\";\n const lines: string[] = [sep];\n for (let i = 0; i < rows.length; i++) {\n const cells = colWidths.map((w, j) => ` ${(rows[i][j] ?? \"\").padEnd(w)} `);\n lines.push(\"|\" + cells.join(\"|\") + \"|\");\n if (i === 0) lines.push(sep);\n }\n lines.push(sep);\n return lines.join(\"\\n\");\n}\n\nfunction sanitizeTelegramHtml(text: string): string {\n if (!text.includes(\"<table\")) return text;\n return text.replace(/<table[\\s\\S]*?<\\/table>/gi, (tableHtml) => {\n const ascii = htmlTableToText(tableHtml);\n return ascii ? `<pre>${ascii}</pre>` : \"\";\n });\n}\n\nasync function notifyError(\n bot: TelegramBot,\n chatId: number,\n label: string,\n err: unknown,\n): Promise<void> {\n const errMsg = err instanceof Error ? err.message : String(err);\n log.logWarning(`Telegram ${label} error`, errMsg);\n try {\n await bot.postPlainMessage(chatId, `⚠️ 發送失敗:${errMsg}`);\n } catch {\n // ignore secondary failure\n }\n}\n\nexport function createTelegramAdapters(\n event: TelegramEvent,\n bot: TelegramBot,\n _isEvent?: boolean,\n): {\n message: ChatMessage;\n responseCtx: ChatResponseContext;\n platform: PlatformInfo;\n} {\n let messageId: number | null = null;\n let accumulatedText = \"\";\n let updatePromise = Promise.resolve();\n let typingInterval: ReturnType<typeof setInterval> | null = null;\n\n function stopTyping() {\n if (typingInterval !== null) {\n clearInterval(typingInterval);\n typingInterval = null;\n }\n }\n\n const chatId = parseInt(event.channel);\n const replyToId = event.thread_ts ? parseInt(event.thread_ts) : null;\n\n const message: ChatMessage = {\n id: event.ts,\n sessionKey: event.sessionKey ?? `${event.channel}:${event.thread_ts ?? event.ts}`,\n userId: event.user,\n userName: event.userName,\n text: event.text,\n attachments: event.attachments,\n threadTs: event.thread_ts,\n };\n\n const platform: PlatformInfo = {\n name: \"telegram\",\n formattingGuide: TELEGRAM_FORMATTING_GUIDE,\n channels: [],\n users: [],\n };\n\n // Telegram message length limit is 4096 chars; use 3800 for safety\n const MAX_LENGTH = 3800;\n const truncationNote = \"\\n\\n<i>(message truncated, ask me to elaborate on specific parts)</i>\";\n\n function truncate(text: string, limit: number, note: string): string {\n if (text.length > limit) {\n return text.substring(0, limit - note.length) + note;\n }\n return text;\n }\n\n async function sendOrUpdate(displayText: string): Promise<void> {\n if (messageId !== null) {\n await bot.updateMessage(event.channel, String(messageId), displayText);\n } else if (replyToId !== null) {\n messageId = await bot.postReply(chatId, replyToId, displayText);\n } else {\n messageId = await bot.postMessageRaw(chatId, displayText);\n }\n }\n\n const responseCtx: ChatResponseContext = {\n respond: async (text: string) => {\n updatePromise = updatePromise.then(async () => {\n try {\n const sanitized = sanitizeTelegramHtml(text);\n accumulatedText = accumulatedText ? `${accumulatedText}\\n${sanitized}` : sanitized;\n const displayText = truncate(accumulatedText, MAX_LENGTH, truncationNote);\n await sendOrUpdate(displayText);\n if (messageId !== null) {\n bot.logBotResponse(event.channel, text, String(messageId));\n }\n } catch (err) {\n await notifyError(bot, chatId, \"respond\", err);\n }\n });\n await updatePromise;\n },\n\n replaceResponse: async (text: string) => {\n updatePromise = updatePromise.then(async () => {\n try {\n accumulatedText = truncate(sanitizeTelegramHtml(text), MAX_LENGTH, truncationNote);\n await sendOrUpdate(accumulatedText);\n } catch (err) {\n await notifyError(bot, chatId, \"replaceResponse\", err);\n }\n });\n await updatePromise;\n },\n\n // Telegram has no threads — discard thread-only messages (e.g. usage summary)\n respondInThread: async (_text: string) => {},\n\n setTyping: async (isTyping: boolean) => {\n if (isTyping && typingInterval === null) {\n // Send immediately and repeat every 4s (Telegram clears indicator after ~5s)\n bot.sendTyping(chatId).catch(() => {});\n typingInterval = setInterval(() => {\n bot.sendTyping(chatId).catch(() => {});\n }, 4000);\n } else if (!isTyping) {\n stopTyping();\n }\n },\n\n setWorking: async (working: boolean) => {\n if (!working) stopTyping();\n },\n\n uploadFile: async (filePath: string, title?: string) => {\n await bot.uploadFile(event.channel, filePath, title);\n },\n\n deleteResponse: async () => {\n updatePromise = updatePromise.then(async () => {\n if (messageId !== null) {\n try {\n await bot.deleteMessageRaw(chatId, messageId);\n } catch {\n // Ignore errors\n }\n messageId = null;\n }\n });\n await updatePromise;\n },\n };\n\n return { message, responseCtx, platform };\n}\n"]}
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../../src/adapters/telegram/context.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ChatMessage,\n ChatResponseContext,\n ChatToolResult,\n PlatformInfo,\n} from \"../../adapter.js\";\nimport * as log from \"../../log.js\";\nimport { formatToolArgs, splitText } from \"../shared.js\";\nimport { sanitizeTelegramHtml } from \"./html.js\";\nimport type { TelegramBot, TelegramEvent } from \"./bot.js\";\n\nexport const TELEGRAM_FORMATTING_GUIDE = `## Telegram Formatting (HTML mode)\nBold: <b>text</b>, Italic: <i>text</i>, Code: <code>code</code>, Pre: <pre>code</pre>\nLinks: <a href=\"url\">text</a>\nDo NOT use Markdown asterisks or backtick syntax.\nDo NOT use <table> tags — they are unsupported. Use <pre> with ASCII art for tables instead.`;\n\n// Telegram message length limit is 4096 chars; 3800 leaves headroom for HTML escapes.\nconst MAX_LENGTH = 3800;\n\nconst formatTelegramContinuation = (partNum: number): string => `(continued ${partNum})`;\n\nasync function notifyError(\n bot: TelegramBot,\n chatId: number,\n label: string,\n err: unknown,\n): Promise<void> {\n const errMsg = err instanceof Error ? err.message : String(err);\n log.logWarning(`Telegram ${label} error`, errMsg);\n try {\n await bot.postPlainMessage(chatId, `⚠️ 發送失敗:${errMsg}`);\n } catch {\n // ignore secondary failure\n }\n}\n\nfunction formatToolResult(result: ChatToolResult): string {\n const argsFormatted = formatToolArgs(result.args);\n const duration = (result.durationMs / 1000).toFixed(1);\n const title = `${result.isError ? \"Error\" : \"Done\"} ${result.toolName}${result.label ? `: ${result.label}` : \"\"} (${duration}s)`;\n return [title, argsFormatted, result.result].filter(Boolean).join(\"\\n\\n\");\n}\n\nexport function createTelegramAdapters(\n event: TelegramEvent,\n bot: TelegramBot,\n _isEvent?: boolean,\n): {\n message: ChatMessage;\n responseCtx: ChatResponseContext;\n platform: PlatformInfo;\n} {\n let messageId: number | null = null;\n let accumulatedText = \"\";\n let updatePromise = Promise.resolve();\n let typingInterval: ReturnType<typeof setInterval> | null = null;\n let typingFailureWarned = false;\n\n function stopTyping() {\n if (typingInterval !== null) {\n clearInterval(typingInterval);\n typingInterval = null;\n }\n }\n\n const conversationId = event.conversationId;\n const chatId = parseInt(conversationId);\n const replyToId = event.thread_ts ? parseInt(event.thread_ts) : null;\n\n const message: ChatMessage = {\n id: event.ts,\n sessionKey: event.sessionKey ?? `${conversationId}:${event.thread_ts ?? event.ts}`,\n conversationKind: event.conversationKind,\n userId: event.user,\n userName: event.userName,\n text: event.text,\n attachments: event.attachments,\n threadTs: event.thread_ts,\n };\n\n const platform: PlatformInfo = {\n name: \"telegram\",\n formattingGuide: TELEGRAM_FORMATTING_GUIDE,\n channels: [],\n users: [],\n };\n\n async function sendContinuation(text: string): Promise<void> {\n await bot.postMessageRaw(chatId, text);\n }\n\n async function sendOrUpdate(displayText: string): Promise<void> {\n if (messageId !== null) {\n await bot.updateMessage(conversationId, String(messageId), displayText);\n } else if (replyToId !== null) {\n messageId = await bot.postReply(chatId, replyToId, displayText);\n } else {\n messageId = await bot.postMessageRaw(chatId, displayText);\n }\n }\n\n const responseCtx: ChatResponseContext = {\n respond: async (text: string) => {\n updatePromise = updatePromise.then(async () => {\n try {\n const sanitized = sanitizeTelegramHtml(text);\n accumulatedText = accumulatedText ? `${accumulatedText}\\n${sanitized}` : sanitized;\n const [firstPart, ...extraParts] = splitText(\n accumulatedText,\n MAX_LENGTH,\n formatTelegramContinuation,\n );\n await sendOrUpdate(firstPart);\n for (const part of extraParts) {\n await sendContinuation(part);\n }\n if (messageId !== null) {\n bot.logBotResponse(conversationId, text, String(messageId));\n }\n } catch (err) {\n await notifyError(bot, chatId, \"respond\", err);\n }\n });\n await updatePromise;\n },\n\n replaceResponse: async (text: string) => {\n updatePromise = updatePromise.then(async () => {\n try {\n accumulatedText = sanitizeTelegramHtml(text);\n const [firstPart, ...extraParts] = splitText(\n accumulatedText,\n MAX_LENGTH,\n formatTelegramContinuation,\n );\n await sendOrUpdate(firstPart);\n for (const part of extraParts) {\n await sendContinuation(part);\n }\n } catch (err) {\n await notifyError(bot, chatId, \"replaceResponse\", err);\n }\n });\n await updatePromise;\n },\n\n respondDiagnostic: async (text: string, options?: { style?: \"muted\" | \"error\" }) => {\n updatePromise = updatePromise.then(async () => {\n try {\n const prefix = options?.style === \"error\" ? \"Error: \" : \"\";\n for (const part of splitText(\n sanitizeTelegramHtml(`${prefix}${text}`),\n MAX_LENGTH,\n formatTelegramContinuation,\n )) {\n await sendContinuation(part);\n }\n } catch (err) {\n await notifyError(bot, chatId, \"respondDiagnostic\", err);\n }\n });\n await updatePromise;\n },\n\n respondToolResult: async (result: ChatToolResult) => {\n await responseCtx.respondDiagnostic(formatToolResult(result));\n },\n\n setTyping: async (isTyping: boolean) => {\n const onTypingError = (err: unknown): void => {\n if (typingFailureWarned) return;\n typingFailureWarned = true;\n log.logWarning(\n \"Telegram sendTyping failed (further occurrences suppressed for this session)\",\n err instanceof Error ? err.message : String(err),\n );\n };\n if (isTyping && typingInterval === null) {\n // Send immediately and repeat every 4s (Telegram clears indicator after ~5s)\n bot.sendTyping(chatId).catch(onTypingError);\n typingInterval = setInterval(() => {\n bot.sendTyping(chatId).catch(onTypingError);\n }, 4000);\n } else if (!isTyping) {\n stopTyping();\n }\n },\n\n setWorking: async (working: boolean) => {\n if (!working) stopTyping();\n },\n\n uploadFile: async (filePath: string, title?: string) => {\n await bot.uploadFile(conversationId, filePath, title);\n },\n\n deleteResponse: async () => {\n updatePromise = updatePromise.then(async () => {\n if (messageId !== null) {\n try {\n await bot.deleteMessageRaw(chatId, messageId);\n } catch {\n // Ignore errors\n }\n messageId = null;\n }\n });\n await updatePromise;\n },\n };\n\n return { message, responseCtx, platform };\n}\n"]}
@@ -0,0 +1,3 @@
1
+ export declare function escapeTelegramHtml(text: string): string;
2
+ export declare function sanitizeTelegramHtml(text: string): string;
3
+ //# sourceMappingURL=html.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../../src/adapters/telegram/html.ts"],"names":[],"mappings":"AA+CA,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKvD;AAkCD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAgBzD","sourcesContent":["function htmlTableToText(tableHtml: string): string {\n const rows: string[][] = [];\n for (const rowMatch of tableHtml.matchAll(/<tr[^>]*>([\\s\\S]*?)<\\/tr>/gi)) {\n const cells: string[] = [];\n for (const cellMatch of rowMatch[1].matchAll(/<t[dh][^>]*>([\\s\\S]*?)<\\/t[dh]>/gi)) {\n cells.push(cellMatch[1].replace(/<[^>]+>/g, \"\").trim());\n }\n if (cells.length > 0) rows.push(cells);\n }\n\n if (rows.length === 0) return \"\";\n\n const numCols = Math.max(...rows.map((r) => r.length));\n const colWidths: number[] = Array(numCols).fill(0);\n for (const row of rows) {\n for (let i = 0; i < row.length; i++) {\n colWidths[i] = Math.max(colWidths[i], (row[i] ?? \"\").length);\n }\n }\n\n const sep = \"+\" + colWidths.map((w) => \"-\".repeat(w + 2)).join(\"+\") + \"+\";\n const lines: string[] = [sep];\n for (let i = 0; i < rows.length; i++) {\n const cells = colWidths.map((w, j) => ` ${(rows[i][j] ?? \"\").padEnd(w)} `);\n lines.push(\"|\" + cells.join(\"|\") + \"|\");\n if (i === 0) lines.push(sep);\n }\n lines.push(sep);\n return lines.join(\"\\n\");\n}\n\nconst SIMPLE_TAG_ALIASES: Record<string, string> = {\n b: \"b\",\n strong: \"b\",\n i: \"i\",\n em: \"i\",\n u: \"u\",\n ins: \"u\",\n s: \"s\",\n strike: \"s\",\n del: \"s\",\n code: \"code\",\n pre: \"pre\",\n blockquote: \"blockquote\",\n \"tg-spoiler\": \"tg-spoiler\",\n};\n\nexport function escapeTelegramHtml(text: string): string {\n return text\n .replace(/&(?!(?:amp|lt|gt|quot|apos|#39|#\\d+|#x[\\da-f]+);)/gi, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\");\n}\n\nfunction escapeTelegramAttribute(text: string): string {\n return escapeTelegramHtml(text).replace(/\"/g, \"&quot;\");\n}\n\nfunction sanitizeTelegramTag(tag: string): string {\n const trimmed = tag.trim();\n\n if (/^<br\\s*\\/?>$/i.test(trimmed)) return \"\\n\";\n if (/^<(p|div)\\s*>$/i.test(trimmed)) return \"\";\n if (/^<\\/(p|div)\\s*>$/i.test(trimmed)) return \"\\n\";\n\n const match = trimmed.match(/^<\\s*(\\/?)\\s*([a-z0-9-]+)([^>]*)>$/i);\n if (!match) return escapeTelegramHtml(tag);\n\n const [, closing, rawName, rawAttrs] = match;\n const name = rawName.toLowerCase();\n const aliasedName = SIMPLE_TAG_ALIASES[name];\n\n if (aliasedName) {\n return `<${closing}${aliasedName}>`;\n }\n\n if (name === \"a\") {\n if (closing) return \"</a>\";\n const hrefMatch = rawAttrs.match(/\\bhref\\s*=\\s*([\"'])(.*?)\\1/i);\n if (!hrefMatch) return escapeTelegramHtml(tag);\n return `<a href=\"${escapeTelegramAttribute(hrefMatch[2])}\">`;\n }\n\n return escapeTelegramHtml(tag);\n}\n\nexport function sanitizeTelegramHtml(text: string): string {\n const withAsciiTables = text.replace(/<table[\\s\\S]*?<\\/table>/gi, (tableHtml) => {\n const ascii = htmlTableToText(tableHtml);\n return ascii ? `<pre>${ascii}</pre>` : \"\";\n });\n\n return withAsciiTables\n .split(/(<[^>]+>)/g)\n .filter(Boolean)\n .map((segment) => {\n if (segment.startsWith(\"<\") && segment.endsWith(\">\")) {\n return sanitizeTelegramTag(segment);\n }\n return escapeTelegramHtml(segment);\n })\n .join(\"\");\n}\n"]}
@@ -0,0 +1,98 @@
1
+ function htmlTableToText(tableHtml) {
2
+ const rows = [];
3
+ for (const rowMatch of tableHtml.matchAll(/<tr[^>]*>([\s\S]*?)<\/tr>/gi)) {
4
+ const cells = [];
5
+ for (const cellMatch of rowMatch[1].matchAll(/<t[dh][^>]*>([\s\S]*?)<\/t[dh]>/gi)) {
6
+ cells.push(cellMatch[1].replace(/<[^>]+>/g, "").trim());
7
+ }
8
+ if (cells.length > 0)
9
+ rows.push(cells);
10
+ }
11
+ if (rows.length === 0)
12
+ return "";
13
+ const numCols = Math.max(...rows.map((r) => r.length));
14
+ const colWidths = Array(numCols).fill(0);
15
+ for (const row of rows) {
16
+ for (let i = 0; i < row.length; i++) {
17
+ colWidths[i] = Math.max(colWidths[i], (row[i] ?? "").length);
18
+ }
19
+ }
20
+ const sep = "+" + colWidths.map((w) => "-".repeat(w + 2)).join("+") + "+";
21
+ const lines = [sep];
22
+ for (let i = 0; i < rows.length; i++) {
23
+ const cells = colWidths.map((w, j) => ` ${(rows[i][j] ?? "").padEnd(w)} `);
24
+ lines.push("|" + cells.join("|") + "|");
25
+ if (i === 0)
26
+ lines.push(sep);
27
+ }
28
+ lines.push(sep);
29
+ return lines.join("\n");
30
+ }
31
+ const SIMPLE_TAG_ALIASES = {
32
+ b: "b",
33
+ strong: "b",
34
+ i: "i",
35
+ em: "i",
36
+ u: "u",
37
+ ins: "u",
38
+ s: "s",
39
+ strike: "s",
40
+ del: "s",
41
+ code: "code",
42
+ pre: "pre",
43
+ blockquote: "blockquote",
44
+ "tg-spoiler": "tg-spoiler",
45
+ };
46
+ export function escapeTelegramHtml(text) {
47
+ return text
48
+ .replace(/&(?!(?:amp|lt|gt|quot|apos|#39|#\d+|#x[\da-f]+);)/gi, "&amp;")
49
+ .replace(/</g, "&lt;")
50
+ .replace(/>/g, "&gt;");
51
+ }
52
+ function escapeTelegramAttribute(text) {
53
+ return escapeTelegramHtml(text).replace(/"/g, "&quot;");
54
+ }
55
+ function sanitizeTelegramTag(tag) {
56
+ const trimmed = tag.trim();
57
+ if (/^<br\s*\/?>$/i.test(trimmed))
58
+ return "\n";
59
+ if (/^<(p|div)\s*>$/i.test(trimmed))
60
+ return "";
61
+ if (/^<\/(p|div)\s*>$/i.test(trimmed))
62
+ return "\n";
63
+ const match = trimmed.match(/^<\s*(\/?)\s*([a-z0-9-]+)([^>]*)>$/i);
64
+ if (!match)
65
+ return escapeTelegramHtml(tag);
66
+ const [, closing, rawName, rawAttrs] = match;
67
+ const name = rawName.toLowerCase();
68
+ const aliasedName = SIMPLE_TAG_ALIASES[name];
69
+ if (aliasedName) {
70
+ return `<${closing}${aliasedName}>`;
71
+ }
72
+ if (name === "a") {
73
+ if (closing)
74
+ return "</a>";
75
+ const hrefMatch = rawAttrs.match(/\bhref\s*=\s*(["'])(.*?)\1/i);
76
+ if (!hrefMatch)
77
+ return escapeTelegramHtml(tag);
78
+ return `<a href="${escapeTelegramAttribute(hrefMatch[2])}">`;
79
+ }
80
+ return escapeTelegramHtml(tag);
81
+ }
82
+ export function sanitizeTelegramHtml(text) {
83
+ const withAsciiTables = text.replace(/<table[\s\S]*?<\/table>/gi, (tableHtml) => {
84
+ const ascii = htmlTableToText(tableHtml);
85
+ return ascii ? `<pre>${ascii}</pre>` : "";
86
+ });
87
+ return withAsciiTables
88
+ .split(/(<[^>]+>)/g)
89
+ .filter(Boolean)
90
+ .map((segment) => {
91
+ if (segment.startsWith("<") && segment.endsWith(">")) {
92
+ return sanitizeTelegramTag(segment);
93
+ }
94
+ return escapeTelegramHtml(segment);
95
+ })
96
+ .join("");
97
+ }
98
+ //# sourceMappingURL=html.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html.js","sourceRoot":"","sources":["../../../src/adapters/telegram/html.ts"],"names":[],"mappings":"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","sourcesContent":["function htmlTableToText(tableHtml: string): string {\n const rows: string[][] = [];\n for (const rowMatch of tableHtml.matchAll(/<tr[^>]*>([\\s\\S]*?)<\\/tr>/gi)) {\n const cells: string[] = [];\n for (const cellMatch of rowMatch[1].matchAll(/<t[dh][^>]*>([\\s\\S]*?)<\\/t[dh]>/gi)) {\n cells.push(cellMatch[1].replace(/<[^>]+>/g, \"\").trim());\n }\n if (cells.length > 0) rows.push(cells);\n }\n\n if (rows.length === 0) return \"\";\n\n const numCols = Math.max(...rows.map((r) => r.length));\n const colWidths: number[] = Array(numCols).fill(0);\n for (const row of rows) {\n for (let i = 0; i < row.length; i++) {\n colWidths[i] = Math.max(colWidths[i], (row[i] ?? \"\").length);\n }\n }\n\n const sep = \"+\" + colWidths.map((w) => \"-\".repeat(w + 2)).join(\"+\") + \"+\";\n const lines: string[] = [sep];\n for (let i = 0; i < rows.length; i++) {\n const cells = colWidths.map((w, j) => ` ${(rows[i][j] ?? \"\").padEnd(w)} `);\n lines.push(\"|\" + cells.join(\"|\") + \"|\");\n if (i === 0) lines.push(sep);\n }\n lines.push(sep);\n return lines.join(\"\\n\");\n}\n\nconst SIMPLE_TAG_ALIASES: Record<string, string> = {\n b: \"b\",\n strong: \"b\",\n i: \"i\",\n em: \"i\",\n u: \"u\",\n ins: \"u\",\n s: \"s\",\n strike: \"s\",\n del: \"s\",\n code: \"code\",\n pre: \"pre\",\n blockquote: \"blockquote\",\n \"tg-spoiler\": \"tg-spoiler\",\n};\n\nexport function escapeTelegramHtml(text: string): string {\n return text\n .replace(/&(?!(?:amp|lt|gt|quot|apos|#39|#\\d+|#x[\\da-f]+);)/gi, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\");\n}\n\nfunction escapeTelegramAttribute(text: string): string {\n return escapeTelegramHtml(text).replace(/\"/g, \"&quot;\");\n}\n\nfunction sanitizeTelegramTag(tag: string): string {\n const trimmed = tag.trim();\n\n if (/^<br\\s*\\/?>$/i.test(trimmed)) return \"\\n\";\n if (/^<(p|div)\\s*>$/i.test(trimmed)) return \"\";\n if (/^<\\/(p|div)\\s*>$/i.test(trimmed)) return \"\\n\";\n\n const match = trimmed.match(/^<\\s*(\\/?)\\s*([a-z0-9-]+)([^>]*)>$/i);\n if (!match) return escapeTelegramHtml(tag);\n\n const [, closing, rawName, rawAttrs] = match;\n const name = rawName.toLowerCase();\n const aliasedName = SIMPLE_TAG_ALIASES[name];\n\n if (aliasedName) {\n return `<${closing}${aliasedName}>`;\n }\n\n if (name === \"a\") {\n if (closing) return \"</a>\";\n const hrefMatch = rawAttrs.match(/\\bhref\\s*=\\s*([\"'])(.*?)\\1/i);\n if (!hrefMatch) return escapeTelegramHtml(tag);\n return `<a href=\"${escapeTelegramAttribute(hrefMatch[2])}\">`;\n }\n\n return escapeTelegramHtml(tag);\n}\n\nexport function sanitizeTelegramHtml(text: string): string {\n const withAsciiTables = text.replace(/<table[\\s\\S]*?<\\/table>/gi, (tableHtml) => {\n const ascii = htmlTableToText(tableHtml);\n return ascii ? `<pre>${ascii}</pre>` : \"\";\n });\n\n return withAsciiTables\n .split(/(<[^>]+>)/g)\n .filter(Boolean)\n .map((segment) => {\n if (segment.startsWith(\"<\") && segment.endsWith(\">\")) {\n return sanitizeTelegramTag(segment);\n }\n return escapeTelegramHtml(segment);\n })\n .join(\"\");\n}\n"]}