Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Make telegram client #63

Merged
merged 10 commits into from
Jan 31, 2025
5 changes: 5 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,8 @@ DRY_RUN=1
# Discord Bot Token (https://discord.com/developers/applications)
# Required Gateway Intents: Server Members, Message Content, Presence
DISCORD_TOKEN=

# gramJS needs to be supplied all of these values (regardless of whether you're running a user client or bot)
TELEGRAM_TOKEN=
TELEGRAM_API_ID=
TELEGRAM_API_HASH=
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Add documentation links for obtaining Telegram credentials

The verification confirms there is no existing documentation for setting up Telegram credentials. Please add setup instructions to the project documentation, including:

🔗 Analysis chain

Add documentation links for obtaining Telegram credentials.

While the comment indicates these values are required, it would be helpful to add specific instructions or links for obtaining these credentials:

Please ensure these credentials are properly documented in the project's setup guide or README.md.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if setup instructions exist in README
rg -i "telegram.*credentials|telegram.*setup" README.md

Length of output: 107


Script:

#!/bin/bash
# Find all markdown files and documentation directories
fd -t f -e md
fd -t d "^docs$|^documentation$|^wiki$" -d 2

Length of output: 618


Script:

#!/bin/bash
# Search for Telegram-related content in documentation
rg -i "telegram|gramjs" -A 3 -B 3 "*.md"

Length of output: 87


Script:

#!/bin/bash
# Search for Telegram-related content in all found markdown files
rg -i "telegram|gramjs" -A 3 -B 3 "readme.md" "docs/README.md" "docs/docs/pages/api-reference/**/*.md"

Length of output: 178

178 changes: 178 additions & 0 deletions examples/example-telegram.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
import { Orchestrator } from "../packages/core/src/core/orchestrator";
import { HandlerRole } from "../packages/core/src/core/types";
import { TelegramClient } from "../packages/core/src/core/io/telegram";
import { RoomManager } from "../packages/core/src/core/room-manager";
import { ChromaVectorDB } from "../packages/core/src/core/vector-db";
import { MessageProcessor } from "../packages/core/src/core/processors/message-processor";
import { LLMClient } from "../packages/core/src/core/llm-client";
import { env } from "../packages/core/src/core/env";
import { LogLevel } from "../packages/core/src/core/types";
import chalk from "chalk";
import { defaultCharacter } from "../packages/core/src/core/character";
import { z } from "zod";
import readline from "readline";
import { MongoDb } from "../packages/core/src/core/mongo-db";


async function main() {
const loglevel = LogLevel.DEBUG;

// Initialize core dependencies
const vectorDb = new ChromaVectorDB("telegram_agent", {
chromaUrl: "http://localhost:8000",
logLevel: loglevel,
});
Comment on lines +29 to +32
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Move database URL to environment variables.

Hardcoding the ChromaDB URL reduces configurability and portability. Consider moving it to environment variables.

 const vectorDb = new ChromaVectorDB("telegram_agent", {
-    chromaUrl: "http://localhost:8000",
+    chromaUrl: env.CHROMA_DB_URL,
     logLevel: loglevel,
 });

Committable suggestion skipped: line range outside the PR's diff.


await vectorDb.purge(); // Clear previous session data

const roomManager = new RoomManager(vectorDb);

const llmClient = new LLMClient({
// model: "openrouter:deepseek/deepseek-r1", // Using a supported model
model: "openrouter:deepseek/deepseek-r1-distill-llama-70b",
temperature: 0.3,
});

// Initialize processor with default character personality
const processor = new MessageProcessor(
llmClient,
defaultCharacter,
loglevel
);
const scheduledTaskDb = new MongoDb(
"mongodb://localhost:27017",
"myApp",
"scheduled_tasks"
);
Comment on lines +50 to +54
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Configure MongoDB connection via environment variables.

Similar to ChromaDB, the MongoDB connection details should be configurable through environment variables.

 const scheduledTaskDb = new MongoDb(
-    "mongodb://localhost:27017",
-    "myApp",
-    "scheduled_tasks"
+    env.MONGODB_URL,
+    env.MONGODB_DB_NAME,
+    env.MONGODB_COLLECTION
 );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const scheduledTaskDb = new MongoDb(
"mongodb://localhost:27017",
"myApp",
"scheduled_tasks"
);
const scheduledTaskDb = new MongoDb(
env.MONGODB_URL,
env.MONGODB_DB_NAME,
env.MONGODB_COLLECTION
);


await scheduledTaskDb.connect();
console.log(chalk.green("✅ Scheduled task database connected"));

await scheduledTaskDb.deleteAll();

// Initialize core system
const core = new Orchestrator(
roomManager,
vectorDb,
[processor],
scheduledTaskDb,
{
level: loglevel,
enableColors: true,
enableTimestamp: true,
}
);

// Set up Telegram bot client with credentials
const telegram = new TelegramClient(
{
bot_token: env.TELEGRAM_TOKEN,
api_id: parseInt(env.TELEGRAM_API_ID as string),
api_hash: env.TELEGRAM_API_HASH,
is_bot: true,
},
loglevel,
);
Copy link
Contributor

@coderabbitai coderabbitai bot Jan 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add input validation for API credentials.

The parseInt conversion of TELEGRAM_API_ID lacks error handling. Consider adding validation to ensure the value is a valid number.

+const apiId = parseInt(env.TELEGRAM_API_ID as string);
+if (isNaN(apiId)) {
+    throw new Error('TELEGRAM_API_ID must be a valid number');
+}
 const telegram = new TelegramClient(
     {
         bot_token: env.TELEGRAM_TOKEN,
-        api_id: parseInt(env.TELEGRAM_API_ID as string),
+        api_id: apiId,
         api_hash: env.TELEGRAM_API_HASH,
         is_bot: true,
     },
     loglevel,
 );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const telegram = new TelegramClient(
{
bot_token: env.TELEGRAM_TOKEN,
api_id: parseInt(env.TELEGRAM_API_ID as string),
api_hash: env.TELEGRAM_API_HASH,
is_bot: true,
},
loglevel,
);
const apiId = parseInt(env.TELEGRAM_API_ID as string);
if (isNaN(apiId)) {
throw new Error('TELEGRAM_API_ID must be a valid number');
}
const telegram = new TelegramClient(
{
bot_token: env.TELEGRAM_TOKEN,
api_id: apiId,
api_hash: env.TELEGRAM_API_HASH,
is_bot: true,
},
loglevel,
);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!




// Set up Telegram user client with credentials
// const telegram = new TelegramClient(
// {
// bot_token: env.TELEGRAM_TOKEN,
// api_id: parseInt(env.TELEGRAM_API_ID as string),
// api_hash: env.TELEGRAM_API_HASH,
// is_bot: false,
// },
// loglevel,
// );



// Register input handler for getting Telegram messages from channel, chat, etc
core.registerIOHandler({
name: "telegram_channel_scraper",
role: HandlerRole.INPUT,
handler: async (data: unknown) => {
const messageData = data as {
chatId: number;
limit?: number;
offset?: number;
};
return telegram.createChannelScraper().handler(messageData);
},
schema: z
.object({
chatId: z
.number()
.describe("The chat ID to retrieve messages from"),
limit: z
.number()
.optional()
.describe("The limit for the number of messages to fetch"),
offset: z
.number()
.optional()
.describe("The offset for the messages to fetch"),
})
.describe(
"This is for getting messages from a chat"
),
});


// Register output handler for sending Telegram messages from bot or user
core.registerIOHandler({
name: "telegram_send_message",
role: HandlerRole.OUTPUT,
handler: async (data: unknown) => {
const messageData = data as {
content: string;
chatId: number;
};
return telegram.createSendMessageOutput().handler(messageData);
},
schema: z
.object({
content: z.string(),
chatId: z
.number()
.optional()
.describe("The chat ID for the message"),
})
.describe(
"This is for sending a message."
),
});

// Set up readline interface
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});

// Start the prompt loop
console.log(chalk.cyan("🤖 Bot is now running and monitoring Telegram..."));
console.log(chalk.cyan("You can type messages in the console."));
console.log(chalk.cyan('Type "exit" to quit'));

// Handle graceful shutdown
process.on("SIGINT", async () => {
console.log(chalk.yellow("\n\nShutting down..."));

// Clean up resources
telegram.logout();
core.removeIOHandler("telegram_channel_scraper");
core.removeIOHandler("telegram_send_message");
rl.close();

console.log(chalk.green("✅ Shutdown complete"));
process.exit(0);
});
}

// Run the example
main().catch((error) => {
console.error(chalk.red("Fatal error:"), error);
process.exit(1);
});
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"twitter": "bun run examples/example-twitter.ts",
"server": "bun run examples/example-server.ts",
"discord": "bun run examples/example-discord.ts",
"telegram": "bun run examples/example-telegram.ts",
"api": "bun run examples/example-api.ts",
"ui": "pnpm --dir clients/example-ui run dev",
"test": "bun run packages/core",
Expand All @@ -21,12 +22,13 @@
"ajv": "^8.17.1",
"chalk": "^5.4.1",
"cors": "^2.8.5",
"express": "^4.21.2",
"discord.js": "^14.17.3",
"express": "^4.21.2",
"lerna": "^8.1.9",
"mongodb": "^6.12.0",
"prettier": "^3.4.2",
"readline": "^1.3.0",
"telegram": "^2.26.16",
"ws": "^8.18.0",
"zod": "^3.24.1"
},
Expand Down
3 changes: 3 additions & 0 deletions packages/core/src/core/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ const envSchema = z.object({
OPENROUTER_API_KEY: z.string(),
GRAPHQL_URL: z.string(),
DISCORD_TOKEN: z.string(),
TELEGRAM_TOKEN: z.string(),
TELEGRAM_API_ID: z.string(),
TELEGRAM_API_HASH: z.string(),
WEBSOCKET_URL: z.string().default("ws://localhost:8080"),
DRY_RUN: z
.preprocess((val) => val === "1" || val === "true", z.boolean())
Expand Down
Loading
Loading