feat: Telegram Bot API integration

- New client: src/clients/telegram.ts
- Tools: telegram_get_me, telegram_send_message, telegram_send_photo, telegram_get_updates, telegram_get_chat
- REST endpoints: GET /api/telegram/me, POST /api/telegram/message, POST /api/telegram/photo, GET /api/telegram/updates, GET /api/telegram/chat
- Multi-account env var pattern: TELEGRAM_{ACCOUNT}_BOT_TOKEN
- Uses Telegram Bot API (https://api.telegram.org)

Total tools: 24 (email 6, obsidian 5, whatsapp 3, linkedin 4, telegram 5)
This commit is contained in:
Garfield
2026-05-05 16:54:07 -04:00
parent 73f83c0d86
commit 385f91de4d
5 changed files with 439 additions and 0 deletions

View File

@@ -4,6 +4,7 @@ import { sendEmail, createDraft } from './smtp.js';
import { searchNotes, getNote, appendToNote, updateNote, getSyncStatus } from './clients/obsidian.js';
import { sendMessage, sendTemplate, getMessageStatus, listTemplates } from './clients/whatsapp.js';
import { getProfile as getLinkedInProfile, createPost as createLinkedInPost, searchConnections, sendMessage as sendLinkedInMessage } from './clients/linkedin.js';
import { getMe as getTelegramMe, sendMessage as sendTelegramMessage, sendPhoto as sendTelegramPhoto, getUpdates as getTelegramUpdates, getChat as getTelegramChat } from './clients/telegram.js';
const ACCOUNT_PARAM = {
account: {
@@ -284,6 +285,74 @@ export const tools: Tool[] = [
required: ['recipient_id', 'message'],
},
},
// ── Telegram tools ─────────────────────────────────────────────
{
name: 'telegram_get_me',
description:
'Get information about the Telegram bot. Use to verify the bot is connected and get its username.',
inputSchema: {
type: 'object',
properties: {
account: { type: 'string', description: 'Which Telegram account to use (default: "default")' },
},
},
},
{
name: 'telegram_send_message',
description:
'Send a text message via Telegram bot. Use when the user asks to send a Telegram message, DM someone, or notify a group/channel.',
inputSchema: {
type: 'object',
required: ['chat_id', 'text'],
properties: {
chat_id: { type: 'string', description: 'Chat ID, username (@username), or channel ID' },
text: { type: 'string', description: 'Message text to send' },
parse_mode: { type: 'string', enum: ['HTML', 'Markdown', 'MarkdownV2'], description: 'Formatting mode for the message' },
account: { type: 'string', description: 'Which Telegram account to use (default: "default")' },
},
},
},
{
name: 'telegram_send_photo',
description:
'Send a photo via Telegram bot. Use when the user wants to share an image through Telegram.',
inputSchema: {
type: 'object',
required: ['chat_id', 'photo'],
properties: {
chat_id: { type: 'string', description: 'Chat ID, username (@username), or channel ID' },
photo: { type: 'string', description: 'Photo URL or file_id to send' },
caption: { type: 'string', description: 'Optional caption text' },
account: { type: 'string', description: 'Which Telegram account to use (default: "default")' },
},
},
},
{
name: 'telegram_get_updates',
description:
'Get recent incoming messages and updates for the Telegram bot. Use when the user asks to check messages or read Telegram DMs.',
inputSchema: {
type: 'object',
properties: {
limit: { type: 'number', description: 'Max number of updates to return (default: 10)' },
account: { type: 'string', description: 'Which Telegram account to use (default: "default")' },
},
},
},
{
name: 'telegram_get_chat',
description:
'Get information about a Telegram chat or channel. Use to verify a chat exists and get its details.',
inputSchema: {
type: 'object',
required: ['chat_id'],
properties: {
chat_id: { type: 'string', description: 'Chat ID, username (@username), or channel ID' },
account: { type: 'string', description: 'Which Telegram account to use (default: "default")' },
},
},
},
];
function acct(args: Record<string, unknown>): Account {
@@ -417,6 +486,45 @@ export async function handleToolCall(
});
break;
// ── Telegram ───────────────────────────────────────────────
case 'telegram_get_me':
result = await getTelegramMe({
account: args.account as string | undefined,
});
break;
case 'telegram_send_message':
result = await sendTelegramMessage({
chat_id: args.chat_id as string | number,
text: args.text as string,
parse_mode: (args.parse_mode as 'HTML' | 'Markdown' | 'MarkdownV2') ?? undefined,
account: args.account as string | undefined,
});
break;
case 'telegram_send_photo':
result = await sendTelegramPhoto({
chat_id: args.chat_id as string | number,
photo: args.photo as string,
caption: args.caption as string | undefined,
account: args.account as string | undefined,
});
break;
case 'telegram_get_updates':
result = await getTelegramUpdates({
limit: (args.limit as number) ?? 10,
account: args.account as string | undefined,
});
break;
case 'telegram_get_chat':
result = await getTelegramChat({
chat_id: args.chat_id as string | number,
account: args.account as string | undefined,
});
break;
// Legacy Yahoo-prefixed names — keep working for any cached Claude sessions
case 'yahoo_get_profile':
result = await getProfile('yahoo');