Skip to content

fix(telegram): pass explicit duration to send_voice/send_audio for long clips - #36009

Closed
liuhao1024 wants to merge 1 commit into
NousResearch:mainfrom
liuhao1024:fix/telegram-voice-audio-duration
Closed

fix(telegram): pass explicit duration to send_voice/send_audio for long clips#36009
liuhao1024 wants to merge 1 commit into
NousResearch:mainfrom
liuhao1024:fix/telegram-voice-audio-duration

Conversation

@liuhao1024

Copy link
Copy Markdown
Contributor

What does this PR do?

Passes an explicit duration kwarg to Telegram's sendVoice and sendAudio API calls so that voice/audio clips longer than ~4 min 50 s display the correct duration instead of 0:00.

Related Issue

Fixes #36005

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)

Changes Made

  • gateway/platforms/telegram.py: Add _probe_audio_duration() helper that probes audio file duration via mutagen (if installed) with a file-size fallback, and pass the result as duration to both send_voice and send_audio Bot API calls.
  • tests/gateway/test_telegram_voice_duration.py: Add regression tests — unit tests for _probe_audio_duration (missing file, OGG/MP3 file-size fallback, minimum duration) and integration tests verifying send_voice passes duration for both voice (OGG) and audio (MP3) paths.

How to Test

  1. Configure the Telegram gateway with TTS enabled.
  2. Trigger a voice reply whose audio is longer than ~4:50 (e.g. a long text_to_speech answer).
  3. Open the resulting voice/audio bubble in any Telegram client — it should show the real duration (e.g. 4:53) with a working progress bar instead of 0:00.
  4. Run pytest tests/gateway/test_telegram_voice_duration.py -v — all 6 tests should pass.

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: macOS

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — or N/A
  • I've updated cli-config.yaml.example if I added/changed config keys — or N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — or N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — or N/A
  • I've updated tool descriptions/schemas if I changed tool behavior — or N/A

Code Intelligence

  • Analyzed: gateway/platforms/telegram.py:send_voice (caller chain: GatewayRunner._send_voice_reply → TelegramAdapter.send_voice → _bot.send_voice / _bot.send_audio)
  • Blast radius: LOW — single adapter method, no shared state changes
  • Related patterns: Discord adapter already probes duration via mutagen (plugins/platforms/discord/adapter.py:1880-1886); this PR follows the same pattern for Telegram

…ng clips

Telegram only auto-derives duration from container metadata for short
recordings.  For clips longer than ~4 min 50 s it delivers the message
with duration 0 unless the sender passes an explicit `duration` kwarg
to sendVoice / sendAudio.

Add `_probe_audio_duration()` helper that tries mutagen (if installed)
for accurate metadata, then falls back to a file-size estimate so the
duration is always populated.  The helper is called once per send_voice
invocation and the result is passed to both the .ogg/.opus voice path
and the .mp3/.m4a audio path.

Fixes NousResearch#36005
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/gateway Gateway runner, session dispatch, delivery platform/telegram Telegram bot adapter tool/tts Text-to-speech and transcription labels May 31, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Competing with #36020 — both fix #36005. #36020 has a more thorough probe chain (wave→mutagen→ffprobe) with off-thread execution.

@liuhao1024

Copy link
Copy Markdown
Contributor Author

@alt-glitch Thanks for the triage. Looking at #36020, I agree it has a more comprehensive probe chain (wave→mutagen→ffprobe). My PR only uses mutagen with a file-size fallback. Given that #36020 covers more cases and has a better design, I'll defer to that approach. Feel free to close this PR as superseded.

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for isolating the two native Telegram send paths. The underlying issue remains present on current main: plugins/platforms/telegram/adapter.py:5860-5869 and :5886-5895 do not pass duration.

Problems

  • The PR targets gateway/platforms/telegram.py, but commit 5600105478ffde29d7566b45421b100eaa29c4ef migrated the live adapter to plugins/platforms/telegram/adapter.py. This is not a clean cherry-pick.
  • The fallback added at gateway/platforms/telegram.py:355 in this PR derives duration from fixed guessed bitrates. That can provide an incorrect Telegram duration for variable- or differently-encoded files; the new tests validate only the estimate on synthetic byte files.

Suggested changes

  • Port the behavior into plugins/platforms/telegram/adapter.py, retaining its current chat-ID normalization and retry/DM-topic wrapper.
  • Send duration only when it is derived from actual readable media metadata; otherwise preserve prior behavior by omitting it. Add assertions for both current plugin send paths alongside tests/gateway/test_telegram_documents.py:577.

Automated hermes-sweeper review.

size_bytes = os.path.getsize(audio_path)
ext = os.path.splitext(audio_path)[1].lower()
# OGG/Opus voice ≈ 16 kbps; MP3/M4A ≈ 128 kbps
bytes_per_sec = 2000 if ext in {".ogg", ".opus"} else 16000

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is a guessed bitrate rather than a duration probe: OGG/Opus and MP3/M4A can use different or variable bitrates, so this may make Telegram display an incorrect duration. Prefer omitting duration when metadata cannot be read rather than sending an estimate.

@teknium1 teknium1 added sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 13, 2026
@teknium1

Copy link
Copy Markdown
Contributor

Closing as superseded: the same issue (#36005) was fixed via #65535, a salvage of #36020 by @szafranski, which was chosen for its deeper probe chain (stdlib wave → mutagen → ffprobe, run off-thread) and coverage of the standalone send_message path including the thread-retry. Your PR correctly identified the fix site — thanks for the contribution, and sorry we could only take one of the two.

@teknium1 teknium1 closed this Jul 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery P2 Medium — degraded but workaround exists platform/telegram Telegram bot adapter sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages tool/tts Text-to-speech and transcription type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Telegram voice/audio longer than ~4:50 shows 0:00 (duration not set on send)

3 participants