@elizaos/plugin-telegram 1.0.2 → 1.0.9

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.
package/dist/index.js CHANGED
@@ -23,27 +23,6 @@ import {
23
23
  } from "@elizaos/core";
24
24
  import { Telegraf } from "telegraf";
25
25
 
26
- // src/environment.ts
27
- import { z } from "zod";
28
- var telegramEnvSchema = z.object({
29
- TELEGRAM_BOT_TOKEN: z.string().min(1, "Telegram bot token is required")
30
- });
31
- async function validateTelegramConfig(runtime) {
32
- try {
33
- const config = {
34
- TELEGRAM_BOT_TOKEN: runtime.getSetting("TELEGRAM_BOT_TOKEN") || process.env.TELEGRAM_BOT_TOKEN
35
- };
36
- return telegramEnvSchema.parse(config);
37
- } catch (error) {
38
- if (error instanceof z.ZodError) {
39
- const errorMessages = error.errors.map((err) => `${err.path.join(".")}: ${err.message}`).join("\n");
40
- throw new Error(`Telegram configuration validation failed:
41
- ${errorMessages}`);
42
- }
43
- throw error;
44
- }
45
- }
46
-
47
26
  // src/messageManager.ts
48
27
  import {
49
28
  ChannelType,
@@ -87,46 +66,46 @@ function convertMarkdownToTelegram(markdown) {
87
66
  return placeholder;
88
67
  }
89
68
  let converted = markdown;
90
- converted = converted.replace(/```(\w+)?\n([\s\S]*?)```/g, (match, lang, code) => {
69
+ converted = converted.replace(/```(\w+)?\n([\s\S]*?)```/g, (_match, lang, code) => {
91
70
  const escapedCode = escapeCode(code);
92
71
  const formatted = "```" + (lang || "") + "\n" + escapedCode + "```";
93
72
  return storeReplacement(formatted);
94
73
  });
95
- converted = converted.replace(/`([^`]+)`/g, (match, code) => {
74
+ converted = converted.replace(/`([^`]+)`/g, (_match, code) => {
96
75
  const escapedCode = escapeCode(code);
97
76
  const formatted = "`" + escapedCode + "`";
98
77
  return storeReplacement(formatted);
99
78
  });
100
79
  converted = converted.replace(
101
80
  /$begin:math:display$([^$end:math:display$]+)]$begin:math:text$([^)]+)$end:math:text$/g,
102
- (match, text, url) => {
81
+ (_match, text, url) => {
103
82
  const formattedText = escapePlainText(text);
104
83
  const escapedURL = escapeUrl(url);
105
84
  const formatted = `[${formattedText}](${escapedURL})`;
106
85
  return storeReplacement(formatted);
107
86
  }
108
87
  );
109
- converted = converted.replace(/\*\*([^*]+)\*\*/g, (match, content) => {
88
+ converted = converted.replace(/\*\*([^*]+)\*\*/g, (_match, content) => {
110
89
  const formattedContent = escapePlainText(content);
111
90
  const formatted = `*${formattedContent}*`;
112
91
  return storeReplacement(formatted);
113
92
  });
114
- converted = converted.replace(/~~([^~]+)~~/g, (match, content) => {
93
+ converted = converted.replace(/~~([^~]+)~~/g, (_match, content) => {
115
94
  const formattedContent = escapePlainText(content);
116
95
  const formatted = `~${formattedContent}~`;
117
96
  return storeReplacement(formatted);
118
97
  });
119
- converted = converted.replace(/(?<!\*)\*([^*\n]+)\*(?!\*)/g, (match, content) => {
98
+ converted = converted.replace(/(?<!\*)\*([^*\n]+)\*(?!\*)/g, (_match, content) => {
120
99
  const formattedContent = escapePlainText(content);
121
100
  const formatted = `_${formattedContent}_`;
122
101
  return storeReplacement(formatted);
123
102
  });
124
- converted = converted.replace(/_([^_\n]+)_/g, (match, content) => {
103
+ converted = converted.replace(/_([^_\n]+)_/g, (_match, content) => {
125
104
  const formattedContent = escapePlainText(content);
126
105
  const formatted = `_${formattedContent}_`;
127
106
  return storeReplacement(formatted);
128
107
  });
129
- converted = converted.replace(/^(#{1,6})\s*(.*)$/gm, (match, hashes, headerContent) => {
108
+ converted = converted.replace(/^(#{1,6})\s*(.*)$/gm, (_match, _hashes, headerContent) => {
130
109
  const formatted = `*${escapePlainText(headerContent.trim())}*`;
131
110
  return storeReplacement(formatted);
132
111
  });
@@ -196,7 +175,7 @@ var MessageManager = class {
196
175
  async processImage(message) {
197
176
  try {
198
177
  let imageUrl = null;
199
- logger.info(`Telegram Message: ${message}`);
178
+ logger.info(`Telegram Message: ${JSON.stringify(message, null, 2)}`);
200
179
  if ("photo" in message && message.photo?.length > 0) {
201
180
  const photo = message.photo[message.photo.length - 1];
202
181
  const fileLink = await this.bot.telegram.getFileLink(photo.file_id);
@@ -370,10 +349,8 @@ ${description}]` };
370
349
  logger.error("handleMessage: ctx.chat is undefined");
371
350
  return;
372
351
  }
373
- const roomId = createUniqueUuid(
374
- this.runtime,
375
- threadId ? `${ctx.chat.id}-${threadId}` : ctx.chat.id.toString()
376
- );
352
+ const telegramRoomid = threadId ? `${ctx.chat.id}-${threadId}` : ctx.chat.id.toString();
353
+ const roomId = createUniqueUuid(this.runtime, telegramRoomid);
377
354
  const messageId = createUniqueUuid(this.runtime, message?.message_id?.toString());
378
355
  const imageInfo = await this.processImage(message);
379
356
  let messageText = "";
@@ -386,6 +363,19 @@ ${description}]` };
386
363
  if (!fullText) return;
387
364
  const chat = message.chat;
388
365
  const channelType = getChannelType(chat);
366
+ const sourceId = createUniqueUuid(this.runtime, "" + chat.id);
367
+ await this.runtime.ensureConnection({
368
+ entityId,
369
+ roomId,
370
+ userName: ctx.from.username,
371
+ name: ctx.from.first_name,
372
+ source: "telegram",
373
+ channelId: telegramRoomid,
374
+ serverId: void 0,
375
+ type: channelType,
376
+ worldId: createUniqueUuid(this.runtime, roomId),
377
+ worldName: telegramRoomid
378
+ });
389
379
  const memory = {
390
380
  id: messageId,
391
381
  entityId,
@@ -393,21 +383,45 @@ ${description}]` };
393
383
  roomId,
394
384
  content: {
395
385
  text: fullText,
386
+ // attachments?
396
387
  source: "telegram",
388
+ // url?
397
389
  channelType,
398
390
  inReplyTo: "reply_to_message" in message && message.reply_to_message ? createUniqueUuid(this.runtime, message.reply_to_message.message_id.toString()) : void 0
399
391
  },
392
+ metadata: {
393
+ entityName: ctx.from.first_name,
394
+ entityUserName: ctx.from.username,
395
+ fromBot: ctx.from.is_bot,
396
+ // include very technical/exact reference to this user for security reasons
397
+ // don't remove or change this, spartan needs this
398
+ fromId: chat.id,
399
+ sourceId,
400
+ // why message? all Memories contain content (which is basically a message)
401
+ // what are the other types? see MemoryType
402
+ type: "message"
403
+ // MemoryType.MESSAGE
404
+ // scope: `shared`, `private`, or `room`
405
+ },
400
406
  createdAt: message.date * 1e3
401
407
  };
402
408
  const callback = async (content, _files) => {
403
409
  try {
404
410
  if (!content.text) return [];
405
- const sentMessages = await this.sendMessageInChunks(ctx, content, message.message_id);
406
- if (!sentMessages) return [];
411
+ let sentMessages = false;
412
+ if (content?.channelType === "DM") {
413
+ sentMessages = [];
414
+ if (ctx.from) {
415
+ const res = await this.bot.telegram.sendMessage(ctx.from.id, content.text);
416
+ sentMessages.push(res);
417
+ }
418
+ } else {
419
+ sentMessages = await this.sendMessageInChunks(ctx, content, message.message_id);
420
+ }
421
+ if (!Array.isArray(sentMessages)) return [];
407
422
  const memories = [];
408
423
  for (let i = 0; i < sentMessages.length; i++) {
409
424
  const sentMessage = sentMessages[i];
410
- const _isLastMessage = i === sentMessages.length - 1;
411
425
  const responseMemory = {
412
426
  id: createUniqueUuid(this.runtime, sentMessage.message_id.toString()),
413
427
  entityId: this.runtime.agentId,
@@ -622,15 +636,27 @@ var TelegramService = class _TelegramService extends Service {
622
636
  constructor(runtime) {
623
637
  super(runtime);
624
638
  logger2.log("\u{1F4F1} Constructing new TelegramService...");
639
+ const botToken = runtime.getSetting("TELEGRAM_BOT_TOKEN");
640
+ if (!botToken || botToken.trim() === "") {
641
+ logger2.warn("Telegram Bot Token not provided - Telegram functionality will be unavailable");
642
+ this.bot = null;
643
+ this.messageManager = null;
644
+ return;
645
+ }
625
646
  this.options = {
626
647
  telegram: {
627
648
  apiRoot: runtime.getSetting("TELEGRAM_API_ROOT") || process.env.TELEGRAM_API_ROOT || "https://api.telegram.org"
628
649
  }
629
650
  };
630
- const botToken = runtime.getSetting("TELEGRAM_BOT_TOKEN");
631
- this.bot = new Telegraf(botToken, this.options);
632
- this.messageManager = new MessageManager(this.bot, this.runtime);
633
- logger2.log("\u2705 TelegramService constructor completed");
651
+ try {
652
+ this.bot = new Telegraf(botToken, this.options);
653
+ this.messageManager = new MessageManager(this.bot, this.runtime);
654
+ logger2.log("\u2705 TelegramService constructor completed");
655
+ } catch (error) {
656
+ logger2.error(`Error initializing Telegram bot: ${error instanceof Error ? error.message : String(error)}`);
657
+ this.bot = null;
658
+ this.messageManager = null;
659
+ }
634
660
  }
635
661
  /**
636
662
  * Starts the Telegram service for the given runtime.
@@ -639,13 +665,16 @@ var TelegramService = class _TelegramService extends Service {
639
665
  * @returns {Promise<TelegramService>} A promise that resolves with the initialized TelegramService.
640
666
  */
641
667
  static async start(runtime) {
642
- await validateTelegramConfig(runtime);
668
+ const service = new _TelegramService(runtime);
669
+ if (!service.bot) {
670
+ logger2.warn("Telegram service started without bot functionality - no bot token provided");
671
+ return service;
672
+ }
643
673
  const maxRetries = 5;
644
674
  let retryCount = 0;
645
675
  let lastError = null;
646
676
  while (retryCount < maxRetries) {
647
677
  try {
648
- const service = new _TelegramService(runtime);
649
678
  logger2.success(
650
679
  `\u2705 Telegram client successfully started for character ${runtime.character.name}`
651
680
  );
@@ -668,9 +697,10 @@ var TelegramService = class _TelegramService extends Service {
668
697
  }
669
698
  }
670
699
  }
671
- throw new Error(
672
- `Telegram initialization failed after ${maxRetries} attempts. Last error: ${lastError?.message}`
700
+ logger2.error(
701
+ `Telegram initialization failed after ${maxRetries} attempts. Last error: ${lastError?.message}. Service will continue without Telegram functionality.`
673
702
  );
703
+ return service;
674
704
  }
675
705
  /**
676
706
  * Stops the agent runtime.
@@ -688,21 +718,27 @@ var TelegramService = class _TelegramService extends Service {
688
718
  * @returns A Promise that resolves once the bot has stopped.
689
719
  */
690
720
  async stop() {
691
- this.bot.stop();
721
+ this.bot?.stop();
692
722
  }
693
723
  /**
694
724
  * Initializes the Telegram bot by launching it, getting bot info, and setting up message manager.
695
725
  * @returns {Promise<void>} A Promise that resolves when the initialization is complete.
696
726
  */
697
727
  async initializeBot() {
698
- this.bot.launch({
728
+ this.bot?.start((ctx) => {
729
+ this.runtime.emitEvent(["TELEGRAM_SLASH_START" /* SLASH_START */], {
730
+ // we don't need this
731
+ ctx
732
+ });
733
+ });
734
+ this.bot?.launch({
699
735
  dropPendingUpdates: true,
700
736
  allowedUpdates: ["message", "message_reaction"]
701
737
  });
702
738
  const botInfo = await this.bot.telegram.getMe();
703
739
  logger2.log(`Bot info: ${JSON.stringify(botInfo)}`);
704
- process.once("SIGINT", () => this.bot.stop("SIGINT"));
705
- process.once("SIGTERM", () => this.bot.stop("SIGTERM"));
740
+ process.once("SIGINT", () => this.bot?.stop("SIGINT"));
741
+ process.once("SIGTERM", () => this.bot?.stop("SIGTERM"));
706
742
  }
707
743
  /**
708
744
  * Sets up the middleware chain for preprocessing messages before they reach handlers.
@@ -720,8 +756,8 @@ var TelegramService = class _TelegramService extends Service {
720
756
  * @private
721
757
  */
722
758
  setupMiddlewares() {
723
- this.bot.use(this.authorizationMiddleware.bind(this));
724
- this.bot.use(this.chatAndEntityMiddleware.bind(this));
759
+ this.bot?.use(this.authorizationMiddleware.bind(this));
760
+ this.bot?.use(this.chatAndEntityMiddleware.bind(this));
725
761
  }
726
762
  /**
727
763
  * Authorization middleware - checks if chat is allowed to interact with the bot
@@ -788,14 +824,14 @@ var TelegramService = class _TelegramService extends Service {
788
824
  * @private
789
825
  */
790
826
  setupMessageHandlers() {
791
- this.bot.on("message", async (ctx) => {
827
+ this.bot?.on("message", async (ctx) => {
792
828
  try {
793
829
  await this.messageManager.handleMessage(ctx);
794
830
  } catch (error) {
795
831
  logger2.error("Error handling message:", error);
796
832
  }
797
833
  });
798
- this.bot.on("message_reaction", async (ctx) => {
834
+ this.bot?.on("message_reaction", async (ctx) => {
799
835
  try {
800
836
  await this.messageManager.handleReaction(ctx);
801
837
  } catch (error) {
@@ -1074,7 +1110,7 @@ var TelegramService = class _TelegramService extends Service {
1074
1110
  entities,
1075
1111
  source: "telegram",
1076
1112
  chat,
1077
- botUsername: this.bot.botInfo.username
1113
+ botUsername: this.bot?.botInfo?.username
1078
1114
  };
1079
1115
  if (chat.type !== "private") {
1080
1116
  await this.runtime.emitEvent("TELEGRAM_WORLD_JOINED" /* WORLD_JOINED */, telegramWorldPayload);
@@ -1107,12 +1143,13 @@ var TelegramService = class _TelegramService extends Service {
1107
1143
  entityBatch.map(async (entity) => {
1108
1144
  try {
1109
1145
  if (entity.id) {
1146
+ const telegramMetadata = entity.metadata?.telegram;
1110
1147
  await this.runtime.ensureConnection({
1111
1148
  entityId: entity.id,
1112
1149
  roomId,
1113
- userName: entity.metadata?.telegram?.username,
1114
- name: entity.metadata?.telegram?.name,
1115
- userId: entity.metadata?.telegram?.id,
1150
+ userName: telegramMetadata?.username,
1151
+ name: telegramMetadata?.name,
1152
+ userId: telegramMetadata?.id,
1116
1153
  source: "telegram",
1117
1154
  channelId,
1118
1155
  serverId,
@@ -1125,7 +1162,8 @@ var TelegramService = class _TelegramService extends Service {
1125
1162
  );
1126
1163
  }
1127
1164
  } catch (err) {
1128
- logger2.warn(`Failed to sync user ${entity.metadata?.telegram?.username}: ${err}`);
1165
+ const telegramMetadata = entity.metadata?.telegram;
1166
+ logger2.warn(`Failed to sync user ${telegramMetadata?.username}: ${err}`);
1129
1167
  }
1130
1168
  })
1131
1169
  );
@@ -1197,7 +1235,7 @@ var TelegramService = class _TelegramService extends Service {
1197
1235
  this.syncedEntityIds.add(userId);
1198
1236
  } else if (chat.type === "group" || chat.type === "supergroup") {
1199
1237
  try {
1200
- const admins = await this.bot.telegram.getChatAdministrators(chat.id);
1238
+ const admins = await this.bot?.telegram.getChatAdministrators(chat.id);
1201
1239
  if (admins && admins.length > 0) {
1202
1240
  for (const admin of admins) {
1203
1241
  const userId = createUniqueUuid2(this.runtime, admin.user.id.toString());
@@ -1284,15 +1322,21 @@ var TelegramService = class _TelegramService extends Service {
1284
1322
  }
1285
1323
  }
1286
1324
  static registerSendHandlers(runtime, serviceInstance) {
1287
- if (serviceInstance) {
1325
+ if (serviceInstance && serviceInstance.bot) {
1288
1326
  runtime.registerSendHandler(
1289
1327
  "telegram",
1290
1328
  serviceInstance.handleSendMessage.bind(serviceInstance)
1291
1329
  );
1292
1330
  logger2.info("[Telegram] Registered send handler.");
1331
+ } else {
1332
+ logger2.warn("[Telegram] Cannot register send handler - bot not initialized.");
1293
1333
  }
1294
1334
  }
1295
1335
  async handleSendMessage(runtime, target, content) {
1336
+ if (!this.bot || !this.messageManager) {
1337
+ logger2.error("[Telegram SendHandler] Bot not initialized - cannot send messages.");
1338
+ throw new Error("Telegram bot is not initialized. Please provide TELEGRAM_BOT_TOKEN.");
1339
+ }
1296
1340
  let chatId;
1297
1341
  if (target.channelId) {
1298
1342
  chatId = target.channelId;
@@ -1406,6 +1450,9 @@ var TelegramTestSuite = class {
1406
1450
  }
1407
1451
  async testCreatingTelegramBot(runtime) {
1408
1452
  this.telegramClient = runtime.getService("telegram");
1453
+ if (!this.telegramClient || !this.telegramClient.messageManager) {
1454
+ throw new Error("Telegram service or message manager not initialized - check TELEGRAM_BOT_TOKEN");
1455
+ }
1409
1456
  this.bot = this.telegramClient.messageManager.bot;
1410
1457
  this.messageManager = this.telegramClient.messageManager;
1411
1458
  logger3.debug("Telegram bot initialized successfully.");