From 116796b2a4d31b1dbef384bb28bb016d02916222 Mon Sep 17 00:00:00 2001 From: feyclaw Date: Mon, 13 Apr 2026 04:39:40 +0300 Subject: [PATCH] feat(channels): add voice message support in TelegramAdapter (#3150) Add handler for message:voice in Telegram channel adapter. Voice messages are downloaded via Telegram Bot API and passed as audio attachments in the Envelope, matching the existing pattern for document handling. This enables users to send voice messages through Telegram which can then be processed by the model or transcription skills. Co-authored-by: Teafey --- .../channels/telegram/src/TelegramAdapter.ts | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/packages/channels/telegram/src/TelegramAdapter.ts b/packages/channels/telegram/src/TelegramAdapter.ts index 5a6b58f8d..c984885a3 100644 --- a/packages/channels/telegram/src/TelegramAdapter.ts +++ b/packages/channels/telegram/src/TelegramAdapter.ts @@ -155,6 +155,59 @@ export class TelegramChannel extends ChannelBase { }); }); + // Voice messages + this.bot.on('message:voice', async (ctx) => { + const msg = ctx.message; + const voice = msg.voice; + const fileName = `voice_${Date.now()}.ogg`; + + const envelope = this.buildEnvelope( + msg, + msg.caption || '(voice message)', + msg.caption_entities, + ); + + try { + const file = await ctx.api.getFile(voice.file_id); + const fileUrl = this.getFileUrl(file.file_path!); + const resp = await fetch(fileUrl); + if (!resp.ok) throw new Error(`HTTP ${resp.status}`); + const buf = Buffer.from(await resp.arrayBuffer()); + + // Save to temp dir so the agent can read it via read-file tool + const dir = join(tmpdir(), 'channel-files', randomUUID()); + mkdirSync(dir, { recursive: true }); + const filePath = join(dir, fileName); + writeFileSync(filePath, buf); + + envelope.text = msg.caption || ''; + envelope.attachments = [ + { + type: 'audio', + filePath, + mimeType: voice.mime_type || 'audio/ogg', + fileName, + }, + ]; + } catch (err) { + process.stderr.write( + `[Telegram:${this.name}] Failed to download voice message: ${err instanceof Error ? err.message : err}\n`, + ); + envelope.text = + (msg.caption || '') + + `\n\n(User sent a voice message but download failed)`; + } + + this.handleInbound(envelope).catch((err) => { + process.stderr.write( + `[Telegram:${this.name}] Error handling message: ${err}\n`, + ); + ctx + .reply('Sorry, something went wrong processing your message.') + .catch(() => {}); + }); + }); + this.bot.start({ drop_pending_updates: true }).catch((err) => { process.stderr.write( `[Telegram:${this.name}] Bot launch error: ${err}\n`,