mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-02 02:01:47 +00:00
feat(gateway): centralize audio routing + FLAC support + Telegram doc fallback (#17833)
Extracted from PR #17211 (@versun) so it can land independently of the local_command TTS provider redesign. - Add should_send_media_as_audio(platform, ext, is_voice) in gateway/platforms/base.py; single source of truth for audio routing. - Add .flac to recognized audio extensions (MEDIA regex, weixin audio set, send_message audio set). - Telegram send_voice() now falls back to send_document for formats Telegram's Bot API can't play natively (.wav, .flac, ...) instead of raising; MP3/M4A still go to sendAudio, Opus/OGG still go to sendVoice. - Route _send_telegram() in send_message_tool through a narrower _TELEGRAM_SEND_AUDIO_EXTS = {.mp3, .m4a} set. - cron.scheduler._send_media_via_adapter now delegates the audio decision to should_send_media_as_audio so it matches the gateway. - Update the cron live-adapter ogg test to flag [[audio_as_voice]] so it still routes to sendVoice under the new Telegram-specific policy. - Tests: unit coverage for should_send_media_as_audio across platforms, end-to-end MEDIA routing via _process_message_background and GatewayRunner._deliver_media_from_response, TelegramAdapter.send_voice fallback for FLAC/WAV. Co-authored-by: Versun <me+github7604@versun.org>
This commit is contained in:
parent
26787ce638
commit
aa7bf329bc
10 changed files with 417 additions and 19 deletions
|
|
@ -453,6 +453,87 @@ class TestMediaGroups:
|
|||
adapter.handle_message.assert_not_awaited()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# TestSendVoice — outbound audio delivery
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class TestSendVoice:
|
||||
"""Tests for TelegramAdapter.send_voice() routing across audio formats."""
|
||||
|
||||
@pytest.fixture()
|
||||
def connected_adapter(self, adapter):
|
||||
"""Adapter with a mock bot attached."""
|
||||
bot = AsyncMock()
|
||||
adapter._bot = bot
|
||||
return adapter
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_flac_falls_back_to_document(self, connected_adapter, tmp_path):
|
||||
"""Telegram sendAudio does not accept FLAC — must fall back to sendDocument."""
|
||||
audio_file = tmp_path / "clip.flac"
|
||||
audio_file.write_bytes(b"fLaC" + b"\x00" * 32)
|
||||
|
||||
mock_msg = MagicMock()
|
||||
mock_msg.message_id = 101
|
||||
connected_adapter._bot.send_voice = AsyncMock()
|
||||
connected_adapter._bot.send_audio = AsyncMock()
|
||||
connected_adapter._bot.send_document = AsyncMock(return_value=mock_msg)
|
||||
|
||||
result = await connected_adapter.send_voice(
|
||||
chat_id="12345",
|
||||
audio_path=str(audio_file),
|
||||
caption="Audio",
|
||||
)
|
||||
|
||||
assert result.success is True
|
||||
assert result.message_id == "101"
|
||||
connected_adapter._bot.send_document.assert_awaited_once()
|
||||
connected_adapter._bot.send_audio.assert_not_awaited()
|
||||
connected_adapter._bot.send_voice.assert_not_awaited()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_wav_falls_back_to_document(self, connected_adapter, tmp_path):
|
||||
"""Telegram sendAudio does not accept WAV — must fall back to sendDocument."""
|
||||
audio_file = tmp_path / "clip.wav"
|
||||
audio_file.write_bytes(b"RIFF" + b"\x00" * 32)
|
||||
|
||||
mock_msg = MagicMock()
|
||||
mock_msg.message_id = 102
|
||||
connected_adapter._bot.send_voice = AsyncMock()
|
||||
connected_adapter._bot.send_audio = AsyncMock()
|
||||
connected_adapter._bot.send_document = AsyncMock(return_value=mock_msg)
|
||||
|
||||
result = await connected_adapter.send_voice(
|
||||
chat_id="12345",
|
||||
audio_path=str(audio_file),
|
||||
)
|
||||
|
||||
assert result.success is True
|
||||
connected_adapter._bot.send_document.assert_awaited_once()
|
||||
connected_adapter._bot.send_audio.assert_not_awaited()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_mp3_routes_to_send_audio(self, connected_adapter, tmp_path):
|
||||
"""MP3 is Telegram-sendAudio-compatible."""
|
||||
audio_file = tmp_path / "clip.mp3"
|
||||
audio_file.write_bytes(b"ID3" + b"\x00" * 32)
|
||||
|
||||
mock_msg = MagicMock()
|
||||
mock_msg.message_id = 103
|
||||
connected_adapter._bot.send_voice = AsyncMock()
|
||||
connected_adapter._bot.send_audio = AsyncMock(return_value=mock_msg)
|
||||
connected_adapter._bot.send_document = AsyncMock()
|
||||
|
||||
result = await connected_adapter.send_voice(
|
||||
chat_id="12345",
|
||||
audio_path=str(audio_file),
|
||||
)
|
||||
|
||||
assert result.success is True
|
||||
connected_adapter._bot.send_audio.assert_awaited_once()
|
||||
connected_adapter._bot.send_document.assert_not_awaited()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# TestSendDocument — outbound file attachment delivery
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue