fix(gateway): honor auto TTS for text replies - #51196
Conversation
tonydwb
left a comment
There was a problem hiding this comment.
Code Review Summary
Verdict: Approved
Overview
Fixes _should_send_voice_reply to honor the adapter._should_auto_tts_for_chat() hook so that text replies trigger TTS when voice.auto_tts is enabled at the adapter level.
Analysis
- Targeted bug fix with clear behavioral description
- Adds adapter-level
auto_ttscheck alongside the existing_voice_modecheck - Explicit
offoverride still respected - Debug logging added for skipped replies
- 3 new unit tests covering the key scenarios
✅ Looks Good
- Clean, minimal change
- Good test coverage
- Debug logging won't impact production (uses
logger.debug)
Reviewed by Hermes Agent
tonydwb
left a comment
There was a problem hiding this comment.
Code Review Summary
Verdict: Approved
Fixes the gateway auto-TTS logic to properly honor auto_tts: true for text replies (not just voice/speech replies). Previously, text-mode replies with auto_tts: true would skip the TTS generation.
Changes
gateway/run.py: +20/-1tests/gateway/test_auto_voice_reply_format.py: +35/-3
Quality
- Small, targeted fix (2 files)
- Good test coverage added
- No security concerns
Reviewed by Hermes Agent
teknium1
left a comment
There was a problem hiding this comment.
Thanks for identifying the missing final-text-reply path; current main still lacks adapter/default auto-TTS in gateway/run.py:13108-13113.
Problems
gateway/run.py:10949also enables TTS for an explicit/voice onchat. That command recordsvoice_onlyand adds the chat to the adapter enabled set (gateway/slash_commands.py:2469-2474), while_should_auto_tts_for_chat()returns true for enabled chats (gateway/platforms/base.py:2677-2687). A text input would therefore receive audio, contrary to the existingvoice_onlycontract intests/gateway/test_voice_command.py:352-354.- The new
voice_onlytest attests/gateway/test_auto_voice_reply_format.py:95-103has no adapter configured, so it does not exercise that state.
Suggested changes
- Apply the adapter-default branch only when
voice_mode is None, retaining the existing explicitalland voice-inputvoice_onlycases. - Add a text-input regression test with
voice_onlyand an adapter predicate returning true.
Automated hermes-sweeper review.
| # explicitly turned off. The base adapter's own auto-TTS path only | ||
| # covers voice-input replies, so final text replies need the runner | ||
| # path here. | ||
| or (voice_mode != "off" and adapter_auto_tts) |
There was a problem hiding this comment.
_should_auto_tts_for_chat() is also true for a chat explicitly enabled by /voice on, whose persisted mode is voice_only. This branch would then send TTS for text input, violating the existing voice_only contract. Restrict the adapter-default branch to voice_mode is None and add a regression test with a true adapter predicate.
Salvaged from PR #51196 (@55nx954gn6-debug). _should_send_voice_reply only consulted the runner's _voice_mode dict (/voice on|voice_only|all), so the global voice.auto_tts config default — which is synced into each adapter's _auto_tts_default on gateway connect — was invisible to the runner path. Net effect: with streaming enabled and only global auto-TTS configured (no per-chat /voice opt-in), the streamed reply consumed the text, the base adapter's auto-TTS got text_content=None, and no voice reply was ever sent (#51867/#23983 remainder). The runner now also asks the adapter's _should_auto_tts_for_chat(chat_id) (which encodes per-chat /voice on|off overrides over the global default); an explicit /voice off chat mode remains a hard override. Refs #51867 #23983 #51282 #13126
Salvaged from PR #51196 (@55nx954gn6-debug). _should_send_voice_reply only consulted the runner's _voice_mode dict (/voice on|voice_only|all), so the global voice.auto_tts config default — which is synced into each adapter's _auto_tts_default on gateway connect — was invisible to the runner path. Net effect: with streaming enabled and only global auto-TTS configured (no per-chat /voice opt-in), the streamed reply consumed the text, the base adapter's auto-TTS got text_content=None, and no voice reply was ever sent (#51867/#23983 remainder). The runner now also asks the adapter's _should_auto_tts_for_chat(chat_id) (which encodes per-chat /voice on|off overrides over the global default); an explicit /voice off chat mode remains a hard override. Refs #51867 #23983 #51282 #13126
|
Merged into main via consolidated salvage PR #73508 (merge Your contribution is credited to you in git history. Thank you! Closing this PR as merged-via-salvage. |
Salvaged from PR NousResearch#51196 (@55nx954gn6-debug). _should_send_voice_reply only consulted the runner's _voice_mode dict (/voice on|voice_only|all), so the global voice.auto_tts config default — which is synced into each adapter's _auto_tts_default on gateway connect — was invisible to the runner path. Net effect: with streaming enabled and only global auto-TTS configured (no per-chat /voice opt-in), the streamed reply consumed the text, the base adapter's auto-TTS got text_content=None, and no voice reply was ever sent (NousResearch#51867/NousResearch#23983 remainder). The runner now also asks the adapter's _should_auto_tts_for_chat(chat_id) (which encodes per-chat /voice on|off overrides over the global default); an explicit /voice off chat mode remains a hard override. Refs NousResearch#51867 NousResearch#23983 NousResearch#51282 NousResearch#13126
Summary
Validation