From d73a6f5ac27be85abae70b52af13c845a31b4e73 Mon Sep 17 00:00:00 2001
From: szafranski
Date: Mon, 13 Jul 2026 23:32:04 +0200
Subject: [PATCH] fix(telegram): include duration in standalone sends
---
tests/gateway/test_telegram_voice_duration.py | 35 +++++++++++++++++++
tools/send_message_tool.py | 8 +++++
2 files changed, 43 insertions(+)
diff --git a/tests/gateway/test_telegram_voice_duration.py b/tests/gateway/test_telegram_voice_duration.py
index 307407298f25..226d6f63e294 100644
--- a/tests/gateway/test_telegram_voice_duration.py
+++ b/tests/gateway/test_telegram_voice_duration.py
@@ -46,6 +46,7 @@ from plugins.platforms.telegram.adapter import ( # noqa: E402
_coerce_duration_seconds,
_probe_voice_duration_seconds,
)
+from tools.send_message_tool import _send_telegram # noqa: E402
def _write_wav(path, *, rate, frames):
@@ -186,3 +187,37 @@ async def test_voice_send_omits_unknown_duration(monkeypatch, tmp_path):
await adapter.send_voice("123", str(audio))
assert adapter._bot.send_voice.await_args.kwargs["duration"] is None
+
+
+@pytest.mark.asyncio
+@pytest.mark.parametrize(
+ ("filename", "is_voice", "sender_name"),
+ [("reply.ogg", True, "send_voice"), ("song.mp3", False, "send_audio")],
+)
+async def test_standalone_send_includes_duration_on_thread_retry(
+ monkeypatch, tmp_path, filename, is_voice, sender_name
+):
+ audio = tmp_path / filename
+ audio.write_bytes(b"audio")
+ bot = MagicMock()
+ bot.send_message = AsyncMock()
+ bot.send_photo = AsyncMock()
+ bot.send_video = AsyncMock()
+ bot.send_voice = AsyncMock()
+ bot.send_audio = AsyncMock()
+ bot.send_document = AsyncMock()
+ sender = getattr(bot, sender_name)
+ sender.side_effect = [
+ Exception("Bad Request: message thread not found"),
+ MagicMock(message_id=3),
+ ]
+ monkeypatch.setattr(sys.modules["telegram"], "Bot", lambda **_kwargs: bot)
+ monkeypatch.setattr(telegram_mod, "_probe_voice_duration_seconds", lambda _path: 314)
+
+ result = await _send_telegram(
+ "token", "-1001234567890", "", media_files=[(str(audio), is_voice)], thread_id="17585"
+ )
+
+ assert result.get("success") is True, result
+ assert sender.await_count == 2
+ assert all(call.kwargs["duration"] == 314 for call in sender.await_args_list)
diff --git a/tools/send_message_tool.py b/tools/send_message_tool.py
index c143ea8064f1..24e8386ce215 100644
--- a/tools/send_message_tool.py
+++ b/tools/send_message_tool.py
@@ -1314,6 +1314,14 @@ async def _send_telegram(token, chat_id, message, media_files=None, thread_id=No
if _tg_caption is not None and not (ext in _VOICE_EXTS and is_voice):
media_kwargs["caption"] = _tg_caption
media_kwargs["parse_mode"] = send_parse_mode
+ if (ext in _VOICE_EXTS and is_voice) or ext in _TELEGRAM_SEND_AUDIO_EXTS:
+ try:
+ from plugins.platforms.telegram.adapter import _probe_voice_duration_seconds
+ duration = await asyncio.to_thread(_probe_voice_duration_seconds, media_path)
+ if duration is not None:
+ media_kwargs["duration"] = duration
+ except Exception:
+ pass
try:
if ext in _IMAGE_EXTS and not force_document:
last_msg = await bot.send_photo(