import { Telegraf, Context } from "telegraf";
import { message } from "telegraf/filters";
import {
AgentRuntime,
createMessageMemory,
stringToUuid,
type UUID,
} from "@elizaos/core";
import { openaiPlugin } from "@elizaos/plugin-openai";
import { plugin as sqlPlugin } from "@elizaos/plugin-sql";
import { v4 as uuidv4 } from "uuid";
// Character definition
const character = {
name: "Eliza",
username: "eliza_bot",
bio: "A helpful AI assistant for Telegram.",
system: `You are Eliza, a friendly AI assistant on Telegram.
Behavior:
- Be helpful, friendly, and concise
- Keep responses under 4000 characters (Telegram limit)
- Use Telegram markdown formatting (bold, italic, code)
- Acknowledge whether you're in a private chat or group
- Be conversational and engaging
When responding:
- For simple questions, give brief answers
- For complex topics, offer to elaborate
- Use emoji occasionally to be friendly 😊
- In groups, be aware of the conversation context`,
};
console.log("🚀 Initializing Eliza Telegram Bot...");
// Initialize elizaOS runtime
const runtime = new AgentRuntime({
character,
plugins: [sqlPlugin, openaiPlugin],
});
await runtime.initialize();
console.log("✅ Runtime initialized");
// Initialize Telegram bot
const bot = new Telegraf(process.env.TELEGRAM_BOT_TOKEN!);
// Start command
bot.command("start", async (ctx) => {
const welcomeMessage = `Welcome! 👋\n\nI'm ${character.name}, your AI assistant. I'm here to help answer questions, have conversations, and assist with various tasks.\n\n**Commands:**\n/help - Show available commands\n/chat - Start a conversation\n/clear - Clear conversation history\n\nJust send me a message to get started!`;
await ctx.reply(welcomeMessage, { parse_mode: "Markdown" });
});
// Help command
bot.command("help", async (ctx) => {
const helpMessage = `**How to use ${character.name}:**\n\n• Simply send me any message and I'll respond\n• I can answer questions, have conversations, and help with tasks\n• In groups, mention me or reply to my messages\n\n**Commands:**\n/start - Welcome message\n/help - This help message\n/chat - Start a conversation\n/clear - Clear your conversation history\n\n**Tips:**\n• I remember our conversation context\n• You can ask follow-up questions\n• I work in both private chats and groups`;
await ctx.reply(helpMessage, { parse_mode: "Markdown" });
});
// Clear command
bot.command("clear", async (ctx) => {
// In a real implementation, clear the user's conversation history
await ctx.reply("Conversation history cleared! 🧹\n\nLet's start fresh.");
});
// Chat command
bot.command("chat", async (ctx) => {
await ctx.reply(
"Ready to chat! Just send me a message. 💬"
);
});
// Handle all text messages
bot.on(message("text"), async (ctx) => {
try {
// Ignore commands (already handled above)
if (ctx.message.text.startsWith("/")) return;
// Show typing indicator
await ctx.sendChatAction("typing");
// Get user and chat info
const userId = ctx.from.id.toString();
const chatId = ctx.chat.id.toString();
const isGroup = ctx.chat.type === "group" || ctx.chat.type === "supergroup";
const userMessage = ctx.message.text;
// In groups, only respond to mentions or replies
if (isGroup) {
const botUsername = ctx.botInfo.username;
const isMentioned = userMessage.includes(`@${botUsername}`);
const isReply = ctx.message.reply_to_message?.from?.id === ctx.botInfo.id;
if (!isMentioned && !isReply) {
return; // Ignore message in group
}
}
// Build context
const context = isGroup
? `Group chat: ${ctx.chat.title || "Unknown"}\nUser: ${ctx.from.first_name || "Unknown"}`
: `Private chat with: ${ctx.from.first_name || "Unknown"}`;
const fullMessage = `${context}\n\nUser message: ${userMessage}`;
// Create message for elizaOS
const messageMemory = createMessageMemory({
id: uuidv4() as UUID,
entityId: stringToUuid(userId),
roomId: stringToUuid(chatId),
content: { text: fullMessage },
});
// Get response from elizaOS
let response = "";
await runtime.messageService!.handleMessage(
runtime,
messageMemory,
async (content) => {
if (content?.text) {
response += content.text;
}
return [];
}
);
// Telegram message length limit is 4096
if (response.length > 4000) {
// Split into chunks
const chunks = splitMessage(response, 4000);
for (const chunk of chunks) {
await ctx.reply(chunk, { parse_mode: "Markdown" });
}
} else {
await ctx.reply(response, { parse_mode: "Markdown" });
}
} catch (error) {
console.error("Error handling message:", error);
await ctx.reply(
"Sorry, I encountered an error processing your message. Please try again. 😕"
);
}
});
// Split long messages
function splitMessage(text: string, maxLength: number): string[] {
if (text.length <= maxLength) return [text];
const chunks: string[] = [];
let currentChunk = "";
const paragraphs = text.split("\n");
for (const paragraph of paragraphs) {
if (currentChunk.length + paragraph.length + 1 > maxLength) {
if (currentChunk) chunks.push(currentChunk.trim());
currentChunk = paragraph;
} else {
currentChunk += (currentChunk ? "\n" : "") + paragraph;
}
}
if (currentChunk) chunks.push(currentChunk.trim());
return chunks;
}
// Handle inline queries (for inline mode)
bot.on("inline_query", async (ctx) => {
const query = ctx.inlineQuery.query;
if (!query) {
return ctx.answerInlineQuery([]);
}
// Get quick response
const messageMemory = createMessageMemory({
id: uuidv4() as UUID,
entityId: stringToUuid(ctx.from.id.toString()),
roomId: stringToUuid("inline"),
content: { text: query },
});
let response = "";
await runtime.messageService!.handleMessage(
runtime,
messageMemory,
async (content) => {
if (content?.text) {
response += content.text;
}
return [];
}
);
// Return inline result
await ctx.answerInlineQuery([
{
type: "article",
id: "1",
title: "Eliza's Response",
description: response.slice(0, 100) + "...",
input_message_content: {
message_text: response,
parse_mode: "Markdown",
},
},
]);
});
// Error handling
bot.catch((err, ctx) => {
console.error("Bot error:", err);
ctx.reply("An error occurred. Please try again later.");
});
// Graceful shutdown
process.once("SIGINT", () => {
console.log("\n🚦 Shutting down...");
bot.stop("SIGINT");
runtime.stop();
});
process.once("SIGTERM", () => {
console.log("\n🚦 Shutting down...");
bot.stop("SIGTERM");
runtime.stop();
});
// Launch bot
console.log("✅ Starting bot...");
bot.launch();
console.log("🤖 Bot is running!\n");