@elizaos/plugin-telegram 1.0.4 → 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.
@@ -0,0 +1,10 @@
1
+ export declare const MESSAGE_CONSTANTS: {
2
+ readonly MAX_MESSAGES: 50;
3
+ readonly RECENT_MESSAGE_COUNT: 5;
4
+ readonly CHAT_HISTORY_COUNT: 10;
5
+ readonly DEFAULT_SIMILARITY_THRESHOLD: 0.6;
6
+ readonly DEFAULT_SIMILARITY_THRESHOLD_FOLLOW_UPS: 0.4;
7
+ readonly INTEREST_DECAY_TIME: number;
8
+ readonly PARTIAL_INTEREST_DECAY: number;
9
+ };
10
+ export declare const TELEGRAM_SERVICE_NAME = "telegram";
@@ -0,0 +1,21 @@
1
+ import type { IAgentRuntime } from '@elizaos/core';
2
+ import { z } from 'zod';
3
+ export declare const telegramEnvSchema: z.ZodObject<{
4
+ TELEGRAM_BOT_TOKEN: z.ZodString;
5
+ }, "strip", z.ZodTypeAny, {
6
+ TELEGRAM_BOT_TOKEN: string;
7
+ }, {
8
+ TELEGRAM_BOT_TOKEN: string;
9
+ }>;
10
+ /**
11
+ * Represents the type definition for configuring a Telegram bot based on the inferred schema.
12
+ */
13
+ export type TelegramConfig = z.infer<typeof telegramEnvSchema>;
14
+ /**
15
+ * Validates the Telegram configuration by retrieving the Telegram bot token from the runtime settings or environment variables.
16
+ * Returns null if validation fails instead of throwing an error.
17
+ *
18
+ * @param {IAgentRuntime} runtime - The agent runtime used to get the setting.
19
+ * @returns {Promise<TelegramConfig | null>} A promise that resolves with the validated Telegram configuration or null if invalid.
20
+ */
21
+ export declare function validateTelegramConfig(runtime: IAgentRuntime): Promise<TelegramConfig | null>;
package/dist/index.d.ts CHANGED
@@ -1,328 +1,6 @@
1
- import { Content, IAgentRuntime, Service, TargetInfo, Plugin } from '@elizaos/core';
2
- import { Message, Update } from '@telegraf/types';
3
- import { Telegraf, Context, NarrowedContext } from 'telegraf';
4
-
5
- /**
6
- * Extention of the core Content type just for Telegram
7
- */
8
- interface TelegramContent extends Content {
9
- /** Array of buttons */
10
- buttons?: Button[];
11
- }
12
- /**
13
- * Represents a flexible button configuration
14
- */
15
- type Button = {
16
- /** The type of button */
17
- kind: 'login' | 'url';
18
- /** The text to display on the button */
19
- text: string;
20
- /** The URL or endpoint the button should link to */
21
- url: string;
22
- };
23
-
24
- /**
25
- * Enum representing different types of media.
26
- * @enum { string }
27
- * @readonly
28
- */
29
- declare enum MediaType {
30
- PHOTO = "photo",
31
- VIDEO = "video",
32
- DOCUMENT = "document",
33
- AUDIO = "audio",
34
- ANIMATION = "animation"
35
- }
36
- /**
37
- * Class representing a message manager.
38
- * @class
39
- */
40
- declare class MessageManager {
41
- bot: Telegraf<Context>;
42
- protected runtime: IAgentRuntime;
43
- /**
44
- * Constructor for creating a new instance of a BotAgent.
45
- *
46
- * @param {Telegraf<Context>} bot - The Telegraf instance used for interacting with the bot platform.
47
- * @param {IAgentRuntime} runtime - The runtime environment for the agent.
48
- */
49
- constructor(bot: Telegraf<Context>, runtime: IAgentRuntime);
50
- /**
51
- * Process an image from a Telegram message to extract the image URL and description.
52
- *
53
- * @param {Message} message - The Telegram message object containing the image.
54
- * @returns {Promise<{ description: string } | null>} The description of the processed image or null if no image found.
55
- */
56
- processImage(message: Message): Promise<{
57
- description: string;
58
- } | null>;
59
- /**
60
- * Sends a message in chunks, handling attachments and splitting the message if necessary
61
- *
62
- * @param {Context} ctx - The context object representing the current state of the bot
63
- * @param {TelegramContent} content - The content of the message to be sent
64
- * @param {number} [replyToMessageId] - The ID of the message to reply to, if any
65
- * @returns {Promise<Message.TextMessage[]>} - An array of TextMessage objects representing the messages sent
66
- */
67
- sendMessageInChunks(ctx: Context, content: TelegramContent, replyToMessageId?: number): Promise<Message.TextMessage[]>;
68
- /**
69
- * Sends media to a chat using the Telegram API.
70
- *
71
- * @param {Context} ctx - The context object containing information about the current chat.
72
- * @param {string} mediaPath - The path to the media to be sent, either a URL or a local file path.
73
- * @param {MediaType} type - The type of media being sent (PHOTO, VIDEO, DOCUMENT, AUDIO, or ANIMATION).
74
- * @param {string} [caption] - Optional caption for the media being sent.
75
- *
76
- * @returns {Promise<void>} A Promise that resolves when the media is successfully sent.
77
- */
78
- sendMedia(ctx: Context, mediaPath: string, type: MediaType, caption?: string): Promise<void>;
79
- /**
80
- * Splits a given text into an array of strings based on the maximum message length.
81
- *
82
- * @param {string} text - The text to split into chunks.
83
- * @returns {string[]} An array of strings with each element representing a chunk of the original text.
84
- */
85
- private splitMessage;
86
- /**
87
- * Handle incoming messages from Telegram and process them accordingly.
88
- * @param {Context} ctx - The context object containing information about the message.
89
- * @returns {Promise<void>}
90
- */
91
- handleMessage(ctx: Context): Promise<void>;
92
- /**
93
- * Handles the reaction event triggered by a user reacting to a message.
94
- * @param {NarrowedContext<Context<Update>, Update.MessageReactionUpdate>} ctx The context of the message reaction update
95
- * @returns {Promise<void>} A Promise that resolves when the reaction handling is complete
96
- */
97
- handleReaction(ctx: NarrowedContext<Context<Update>, Update.MessageReactionUpdate>): Promise<void>;
98
- /**
99
- * Sends a message to a Telegram chat and emits appropriate events
100
- * @param {number | string} chatId - The Telegram chat ID to send the message to
101
- * @param {Content} content - The content to send
102
- * @param {number} [replyToMessageId] - Optional message ID to reply to
103
- * @returns {Promise<Message.TextMessage[]>} The sent messages
104
- */
105
- sendMessage(chatId: number | string, content: Content, replyToMessageId?: number): Promise<Message.TextMessage[]>;
106
- }
107
-
108
- /**
109
- * Class representing a Telegram service that allows the agent to send and receive messages on Telegram.
110
- * This service handles all Telegram-specific functionality including:
111
- * - Initializing and managing the Telegram bot
112
- * - Setting up middleware for preprocessing messages
113
- * - Handling message and reaction events
114
- * - Synchronizing Telegram chats, users, and entities with the agent runtime
115
- * - Managing forum topics as separate rooms
116
- *
117
- * @extends Service
118
- */
119
- declare class TelegramService extends Service {
120
- static serviceType: string;
121
- capabilityDescription: string;
122
- private bot;
123
- messageManager: MessageManager;
124
- private options;
125
- private knownChats;
126
- private syncedEntityIds;
127
- /**
128
- * Constructor for TelegramService class.
129
- * @param {IAgentRuntime} runtime - The runtime object for the agent.
130
- */
131
- constructor(runtime: IAgentRuntime);
132
- /**
133
- * Starts the Telegram service for the given runtime.
134
- *
135
- * @param {IAgentRuntime} runtime - The agent runtime to start the Telegram service for.
136
- * @returns {Promise<TelegramService>} A promise that resolves with the initialized TelegramService.
137
- */
138
- static start(runtime: IAgentRuntime): Promise<TelegramService>;
139
- /**
140
- * Stops the agent runtime.
141
- * @param {IAgentRuntime} runtime - The agent runtime to stop
142
- */
143
- static stop(runtime: IAgentRuntime): Promise<void>;
144
- /**
145
- * Asynchronously stops the bot.
146
- *
147
- * @returns A Promise that resolves once the bot has stopped.
148
- */
149
- stop(): Promise<void>;
150
- /**
151
- * Initializes the Telegram bot by launching it, getting bot info, and setting up message manager.
152
- * @returns {Promise<void>} A Promise that resolves when the initialization is complete.
153
- */
154
- private initializeBot;
155
- /**
156
- * Sets up the middleware chain for preprocessing messages before they reach handlers.
157
- * This critical method establishes a sequential processing pipeline that:
158
- *
159
- * 1. Authorization - Verifies if a chat is allowed to interact with the bot based on configured settings
160
- * 2. Chat Discovery - Ensures chat entities and worlds exist in the runtime, creating them if needed
161
- * 3. Forum Topics - Handles Telegram forum topics as separate rooms for better conversation management
162
- * 4. Entity Synchronization - Ensures message senders are properly synchronized as entities
163
- *
164
- * The middleware chain runs in sequence for each message, with each step potentially
165
- * enriching the context or stopping processing if conditions aren't met.
166
- * This preprocessing is essential for maintaining consistent state before message handlers execute.
167
- *
168
- * @private
169
- */
170
- private setupMiddlewares;
171
- /**
172
- * Authorization middleware - checks if chat is allowed to interact with the bot
173
- * based on the TELEGRAM_ALLOWED_CHATS configuration.
174
- *
175
- * @param {Context} ctx - The context of the incoming update
176
- * @param {Function} next - The function to call to proceed to the next middleware
177
- * @returns {Promise<void>}
178
- * @private
179
- */
180
- private authorizationMiddleware;
181
- /**
182
- * Chat and entity management middleware - handles new chats, forum topics, and entity synchronization.
183
- * This middleware implements decision logic to determine which operations are needed based on
184
- * the chat type and whether we've seen this chat before.
185
- *
186
- * @param {Context} ctx - The context of the incoming update
187
- * @param {Function} next - The function to call to proceed to the next middleware
188
- * @returns {Promise<void>}
189
- * @private
190
- */
191
- private chatAndEntityMiddleware;
192
- /**
193
- * Process an existing chat based on chat type and message properties.
194
- * Different chat types require different processing steps.
195
- *
196
- * @param {Context} ctx - The context of the incoming update
197
- * @returns {Promise<void>}
198
- * @private
199
- */
200
- private processExistingChat;
201
- /**
202
- * Sets up message and reaction handlers for the bot.
203
- * Configures event handlers to process incoming messages and reactions.
204
- *
205
- * @private
206
- */
207
- private setupMessageHandlers;
208
- /**
209
- * Checks if a group is authorized, based on the TELEGRAM_ALLOWED_CHATS setting.
210
- * @param {Context} ctx - The context of the incoming update.
211
- * @returns {Promise<boolean>} A Promise that resolves with a boolean indicating if the group is authorized.
212
- */
213
- private isGroupAuthorized;
214
- /**
215
- * Synchronizes an entity from a message context with the runtime system.
216
- * This method handles three cases:
217
- * 1. Message sender - most common case
218
- * 2. New chat member - when a user joins the chat
219
- * 3. Left chat member - when a user leaves the chat
220
- *
221
- * @param {Context} ctx - The context of the incoming update
222
- * @returns {Promise<void>}
223
- * @private
224
- */
225
- private syncEntity;
226
- /**
227
- * Synchronizes the message sender entity with the runtime system.
228
- * This is the most common entity sync case.
229
- *
230
- * @param {Context} ctx - The context of the incoming update
231
- * @param {UUID} worldId - The ID of the world
232
- * @param {UUID} roomId - The ID of the room
233
- * @param {string} chatId - The ID of the chat
234
- * @returns {Promise<void>}
235
- * @private
236
- */
237
- private syncMessageSender;
238
- /**
239
- * Synchronizes a new chat member entity with the runtime system.
240
- * Triggered when a user joins the chat.
241
- *
242
- * @param {Context} ctx - The context of the incoming update
243
- * @param {UUID} worldId - The ID of the world
244
- * @param {UUID} roomId - The ID of the room
245
- * @param {string} chatId - The ID of the chat
246
- * @returns {Promise<void>}
247
- * @private
248
- */
249
- private syncNewChatMember;
250
- /**
251
- * Updates entity status when a user leaves the chat.
252
- *
253
- * @param {Context} ctx - The context of the incoming update
254
- * @returns {Promise<void>}
255
- * @private
256
- */
257
- private syncLeftChatMember;
258
- /**
259
- * Handles forum topics by creating appropriate rooms in the runtime system.
260
- * This enables proper conversation management for Telegram's forum feature.
261
- *
262
- * @param {Context} ctx - The context of the incoming update
263
- * @returns {Promise<void>}
264
- * @private
265
- */
266
- private handleForumTopic;
267
- /**
268
- * Builds entity for message sender
269
- */
270
- private buildMsgSenderEntity;
271
- /**
272
- * Handles new chat discovery and emits WORLD_JOINED event.
273
- * This is a critical function that ensures new chats are properly
274
- * registered in the runtime system and appropriate events are emitted.
275
- *
276
- * @param {Context} ctx - The context of the incoming update
277
- * @returns {Promise<void>}
278
- * @private
279
- */
280
- private handleNewChat;
281
- /**
282
- * Processes entities in batches to prevent overwhelming the system.
283
- *
284
- * @param {Entity[]} entities - The entities to process
285
- * @param {UUID} roomId - The ID of the room to connect entities to
286
- * @param {string} channelId - The channel ID
287
- * @param {string} serverId - The server ID
288
- * @param {ChannelType} roomType - The type of the room
289
- * @param {UUID} worldId - The ID of the world
290
- * @returns {Promise<void>}
291
- * @private
292
- */
293
- private batchProcessEntities;
294
- /**
295
- * Gets chat title and channel type based on Telegram chat type.
296
- * Maps Telegram-specific chat types to standardized system types.
297
- *
298
- * @param {any} chat - The Telegram chat object
299
- * @returns {Object} Object containing chatTitle and channelType
300
- * @private
301
- */
302
- private getChatTypeInfo;
303
- /**
304
- * Builds standardized entity representations from Telegram chat data.
305
- * Transforms Telegram-specific user data into system-standard Entity objects.
306
- *
307
- * @param {any} chat - The Telegram chat object
308
- * @returns {Promise<Entity[]>} Array of standardized Entity objects
309
- * @private
310
- */
311
- private buildStandardizedEntities;
312
- /**
313
- * Extracts and builds the room object for a forum topic from a message context.
314
- * This refactored method can be used both in middleware and when handling new chats.
315
- *
316
- * @param {Context} ctx - The context of the incoming update
317
- * @param {UUID} worldId - The ID of the world the topic belongs to
318
- * @returns {Promise<Room | null>} A Promise that resolves with the room or null if not a topic
319
- * @private
320
- */
321
- private buildForumTopicRoom;
322
- static registerSendHandlers(runtime: IAgentRuntime, serviceInstance: TelegramService): void;
323
- handleSendMessage(runtime: IAgentRuntime, target: TargetInfo, content: Content): Promise<void>;
324
- }
325
-
1
+ import type { Plugin } from '@elizaos/core';
2
+ import { TelegramService } from './service';
3
+ import { MessageManager } from './messageManager';
326
4
  declare const telegramPlugin: Plugin;
327
-
328
- export { MessageManager, TelegramService, telegramPlugin as default };
5
+ export { TelegramService, MessageManager };
6
+ export default telegramPlugin;
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
  });
@@ -384,6 +363,7 @@ ${description}]` };
384
363
  if (!fullText) return;
385
364
  const chat = message.chat;
386
365
  const channelType = getChannelType(chat);
366
+ const sourceId = createUniqueUuid(this.runtime, "" + chat.id);
387
367
  await this.runtime.ensureConnection({
388
368
  entityId,
389
369
  roomId,
@@ -405,6 +385,7 @@ ${description}]` };
405
385
  text: fullText,
406
386
  // attachments?
407
387
  source: "telegram",
388
+ // url?
408
389
  channelType,
409
390
  inReplyTo: "reply_to_message" in message && message.reply_to_message ? createUniqueUuid(this.runtime, message.reply_to_message.message_id.toString()) : void 0
410
391
  },
@@ -415,9 +396,12 @@ ${description}]` };
415
396
  // include very technical/exact reference to this user for security reasons
416
397
  // don't remove or change this, spartan needs this
417
398
  fromId: chat.id,
399
+ sourceId,
418
400
  // why message? all Memories contain content (which is basically a message)
419
- // what are the other types?
401
+ // what are the other types? see MemoryType
420
402
  type: "message"
403
+ // MemoryType.MESSAGE
404
+ // scope: `shared`, `private`, or `room`
421
405
  },
422
406
  createdAt: message.date * 1e3
423
407
  };
@@ -425,7 +409,7 @@ ${description}]` };
425
409
  try {
426
410
  if (!content.text) return [];
427
411
  let sentMessages = false;
428
- if (content?.target === "DM") {
412
+ if (content?.channelType === "DM") {
429
413
  sentMessages = [];
430
414
  if (ctx.from) {
431
415
  const res = await this.bot.telegram.sendMessage(ctx.from.id, content.text);
@@ -438,7 +422,6 @@ ${description}]` };
438
422
  const memories = [];
439
423
  for (let i = 0; i < sentMessages.length; i++) {
440
424
  const sentMessage = sentMessages[i];
441
- const _isLastMessage = i === sentMessages.length - 1;
442
425
  const responseMemory = {
443
426
  id: createUniqueUuid(this.runtime, sentMessage.message_id.toString()),
444
427
  entityId: this.runtime.agentId,
@@ -653,15 +636,27 @@ var TelegramService = class _TelegramService extends Service {
653
636
  constructor(runtime) {
654
637
  super(runtime);
655
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
+ }
656
646
  this.options = {
657
647
  telegram: {
658
648
  apiRoot: runtime.getSetting("TELEGRAM_API_ROOT") || process.env.TELEGRAM_API_ROOT || "https://api.telegram.org"
659
649
  }
660
650
  };
661
- const botToken = runtime.getSetting("TELEGRAM_BOT_TOKEN");
662
- this.bot = new Telegraf(botToken, this.options);
663
- this.messageManager = new MessageManager(this.bot, this.runtime);
664
- 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
+ }
665
660
  }
666
661
  /**
667
662
  * Starts the Telegram service for the given runtime.
@@ -670,13 +665,16 @@ var TelegramService = class _TelegramService extends Service {
670
665
  * @returns {Promise<TelegramService>} A promise that resolves with the initialized TelegramService.
671
666
  */
672
667
  static async start(runtime) {
673
- 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
+ }
674
673
  const maxRetries = 5;
675
674
  let retryCount = 0;
676
675
  let lastError = null;
677
676
  while (retryCount < maxRetries) {
678
677
  try {
679
- const service = new _TelegramService(runtime);
680
678
  logger2.success(
681
679
  `\u2705 Telegram client successfully started for character ${runtime.character.name}`
682
680
  );
@@ -699,9 +697,10 @@ var TelegramService = class _TelegramService extends Service {
699
697
  }
700
698
  }
701
699
  }
702
- throw new Error(
703
- `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.`
704
702
  );
703
+ return service;
705
704
  }
706
705
  /**
707
706
  * Stops the agent runtime.
@@ -719,21 +718,27 @@ var TelegramService = class _TelegramService extends Service {
719
718
  * @returns A Promise that resolves once the bot has stopped.
720
719
  */
721
720
  async stop() {
722
- this.bot.stop();
721
+ this.bot?.stop();
723
722
  }
724
723
  /**
725
724
  * Initializes the Telegram bot by launching it, getting bot info, and setting up message manager.
726
725
  * @returns {Promise<void>} A Promise that resolves when the initialization is complete.
727
726
  */
728
727
  async initializeBot() {
729
- 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({
730
735
  dropPendingUpdates: true,
731
736
  allowedUpdates: ["message", "message_reaction"]
732
737
  });
733
738
  const botInfo = await this.bot.telegram.getMe();
734
739
  logger2.log(`Bot info: ${JSON.stringify(botInfo)}`);
735
- process.once("SIGINT", () => this.bot.stop("SIGINT"));
736
- process.once("SIGTERM", () => this.bot.stop("SIGTERM"));
740
+ process.once("SIGINT", () => this.bot?.stop("SIGINT"));
741
+ process.once("SIGTERM", () => this.bot?.stop("SIGTERM"));
737
742
  }
738
743
  /**
739
744
  * Sets up the middleware chain for preprocessing messages before they reach handlers.
@@ -751,8 +756,8 @@ var TelegramService = class _TelegramService extends Service {
751
756
  * @private
752
757
  */
753
758
  setupMiddlewares() {
754
- this.bot.use(this.authorizationMiddleware.bind(this));
755
- this.bot.use(this.chatAndEntityMiddleware.bind(this));
759
+ this.bot?.use(this.authorizationMiddleware.bind(this));
760
+ this.bot?.use(this.chatAndEntityMiddleware.bind(this));
756
761
  }
757
762
  /**
758
763
  * Authorization middleware - checks if chat is allowed to interact with the bot
@@ -819,14 +824,14 @@ var TelegramService = class _TelegramService extends Service {
819
824
  * @private
820
825
  */
821
826
  setupMessageHandlers() {
822
- this.bot.on("message", async (ctx) => {
827
+ this.bot?.on("message", async (ctx) => {
823
828
  try {
824
829
  await this.messageManager.handleMessage(ctx);
825
830
  } catch (error) {
826
831
  logger2.error("Error handling message:", error);
827
832
  }
828
833
  });
829
- this.bot.on("message_reaction", async (ctx) => {
834
+ this.bot?.on("message_reaction", async (ctx) => {
830
835
  try {
831
836
  await this.messageManager.handleReaction(ctx);
832
837
  } catch (error) {
@@ -1105,7 +1110,7 @@ var TelegramService = class _TelegramService extends Service {
1105
1110
  entities,
1106
1111
  source: "telegram",
1107
1112
  chat,
1108
- botUsername: this.bot.botInfo.username
1113
+ botUsername: this.bot?.botInfo?.username
1109
1114
  };
1110
1115
  if (chat.type !== "private") {
1111
1116
  await this.runtime.emitEvent("TELEGRAM_WORLD_JOINED" /* WORLD_JOINED */, telegramWorldPayload);
@@ -1230,7 +1235,7 @@ var TelegramService = class _TelegramService extends Service {
1230
1235
  this.syncedEntityIds.add(userId);
1231
1236
  } else if (chat.type === "group" || chat.type === "supergroup") {
1232
1237
  try {
1233
- const admins = await this.bot.telegram.getChatAdministrators(chat.id);
1238
+ const admins = await this.bot?.telegram.getChatAdministrators(chat.id);
1234
1239
  if (admins && admins.length > 0) {
1235
1240
  for (const admin of admins) {
1236
1241
  const userId = createUniqueUuid2(this.runtime, admin.user.id.toString());
@@ -1317,15 +1322,21 @@ var TelegramService = class _TelegramService extends Service {
1317
1322
  }
1318
1323
  }
1319
1324
  static registerSendHandlers(runtime, serviceInstance) {
1320
- if (serviceInstance) {
1325
+ if (serviceInstance && serviceInstance.bot) {
1321
1326
  runtime.registerSendHandler(
1322
1327
  "telegram",
1323
1328
  serviceInstance.handleSendMessage.bind(serviceInstance)
1324
1329
  );
1325
1330
  logger2.info("[Telegram] Registered send handler.");
1331
+ } else {
1332
+ logger2.warn("[Telegram] Cannot register send handler - bot not initialized.");
1326
1333
  }
1327
1334
  }
1328
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
+ }
1329
1340
  let chatId;
1330
1341
  if (target.channelId) {
1331
1342
  chatId = target.channelId;
@@ -1439,6 +1450,9 @@ var TelegramTestSuite = class {
1439
1450
  }
1440
1451
  async testCreatingTelegramBot(runtime) {
1441
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
+ }
1442
1456
  this.bot = this.telegramClient.messageManager.bot;
1443
1457
  this.messageManager = this.telegramClient.messageManager;
1444
1458
  logger3.debug("Telegram bot initialized successfully.");