#21193: fix(tts): send voice messages as Opus bubbles on Telegram
size: XS
Cluster:
Voice Message Enhancements
## Summary
- Problem: TTS voice messages on Telegram arrive as MP3 document attachments instead of native voice bubbles
- Why: resolveChannelId() returns null when plugin registry is unavailable during TTS tool execution, falling back to MP3 instead of Opus format
- Fix 1 (tts.ts): resolveChannelId() falls back to normalizeChatChannelId() for static channel resolution
- Fix 2 (telegram.ts): Pass audioAsVoice through to sendVoice instead of sendDocument
## Change Type
- [x] Bug fix
## Scope
- [x] Gateway / orchestration
- [x] Integrations
## User-visible Changes
TTS audio on Telegram now arrives as native voice bubbles (Opus) instead of MP3 file attachments
## Security Impact
No security impact. No new permissions, tokens, network calls, or execution surface changes.
## Evidence
Tested on live Telegram bot: before fix voice messages arrived as MP3 documents, after fix they arrive as Opus voice bubbles. Verified audio content via Deepgram transcription.
## Compatibility
Backward compatible. No config/env/migration changes needed.
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Fixed TTS voice messages on Telegram to display as native voice bubbles (Opus) instead of MP3 document attachments. The fix addresses two issues: `resolveChannelId()` in `tts.ts` now falls back to static channel resolution when the plugin registry is unavailable during TTS tool execution, and the `audioAsVoice` flag is properly passed through in `telegram.ts` to use `sendVoice` instead of `sendDocument`.
- Fixed channel ID resolution fallback in `tts.ts:489-496`
- Properly passed through `audioAsVoice` flag in `telegram.ts:73`
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge with minimal risk
- The changes are minimal, well-targeted, and properly handle edge cases. The fallback logic in `resolveChannelId` prevents null pointer issues when the plugin registry is unavailable, and the `asVoice` parameter is correctly passed through with proper type checking. The code maintains backward compatibility and includes appropriate comments explaining the rationale.
- No files require special attention
<sub>Last reviewed commit: f3a810d</sub>
<!-- greptile_other_comments_section -->
<sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#12700: fix(tts): deliver WhatsApp voice as opus bubble instead of MP3 (#12...
by lailoo · 2026-02-09
85.3%
#15394: telegram: treat mp3 as voice-compatible when asVoice=true
by SnugMorg · 2026-02-13
81.2%
#13389: feat(telegram): support native voice notes with automatic OGG/Opus ...
by leavingme · 2026-02-10
79.7%
#21110: fix(tts): deliver audio via structured mediaUrl instead of MEDIA: t...
by hydro13 · 2026-02-19
79.4%
#23572: feat(voice): enable voice note conversation loop for Telegram and W...
by davidrudduck · 2026-02-22
78.6%
#19439: fix(tts): pass audioAsVoice flag through tool result pipeline
by brandonwise · 2026-02-17
78.4%
#19522: feat(bluebubbles): send TTS as native iMessage voice memos
by mwmacmahon · 2026-02-17
78.1%
#14227: fix(matrix): pass asVoice to audioAsVoice for native voice messages
by tfm-neo-ai · 2026-02-11
78.1%
#19673: fix(telegram): avoid starting streaming replies with only 1-2 words
by emanuelst · 2026-02-18
75.9%
#7965: feat(tts): add Speechify as TTS provider
by chaerla · 2026-02-03
75.8%