You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Adds an opt-in per-platform suppress_text_when_voice config flag that drops the redundant written text when a voice reply (auto-TTS speak or a MEDIA voice clip) is delivered with no other non-voice content. On platforms whose voice notes arrive as caption-less attachments (e.g. Signal), this avoids the user receiving audio and the same text twice. Default off preserves existing behavior. Also fixes a latent bug where an empty handler response could raise UnboundLocalError by reading the suppression flag before it was initialized.
Type of Change
✨ New feature (non-breaking change that adds functionality)
🐛 Bug fix (UnboundLocalError on empty responses)
Changes Made
gateway/config.py — added PlatformConfig.suppress_text_when_voice: bool = False (parsed from top-level or extra), serialized in to_dict.
gateway/platforms/base.py — extracted _should_suppress_text_on_voice() helper; wired it into _process_message_background; initialized _suppress_text = False at function top (fixes the UnboundLocalError); kept the ✅-not-❌ success handling for suppressed voice delivery.
AI code review — automated review for reference, author can ignore or act on any point.
feat(gateway): per-platform suppress_text_when_voice for voice replies
Suppression is decided before the voice delivery outcome is known._suppress_text is set at the point the text would be sent, but the later if _suppress_text: delivery_attempted = True; delivery_succeeded = True; processing_ok = True marks the turn successful unconditionally. If TTS generation fails or the voice send raises after suppression was decided, the user receives neither audio nor text while the processing hooks report success. Consider computing/clearing _suppress_text based on the actual voice send result (e.g. clear it when the voice delivery fails so the text fallback still goes out, and only mark success when voice actually landed).
Same assumption for non-voice media._should_suppress_text_on_voice treats presence of images/local_files as "non-voice content, keep text" — but if those deliveries fail, text is still suppressed under the same "assume delivery succeeded" pattern. Minor given the first point, but the helper itself is purely presence-based.
Minor: to_dict always emits suppress_text_when_voice (non-optional bool defaulting False), consistent with typing_indicator/gateway_restart_notification — fine. The else: _suppress_text = False reset inside the response block correctly re-initializes per turn; good.
Fixed. Text suppression now tracks actual voice delivery. _voice_delivered_ok is set only when auto-TTS play_tts or a media voice send_voice actually succeeds; _should_suppress_text_on_voice takes that delivered flag instead of file presence; a queued MEDIA voice clip defers the text and falls back to text if the send fails; the success mask requires _suppress_text and _voice_delivered_ok. Added integration tests for voice-send failure → text fallback, voice+text failure → FAILURE, voice delivered → text suppressed + SUCCESS, and the agent-tool voice-clip path. On the non-voice media point: images/local_files stay presence-based intentionally: when they're present the helper keeps the text, so the text is the fallback if that media fails (the inverse of the voice bug, so no silent-drop case there).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
area/configConfig system, migrations, profilescomp/gatewayGateway runner, session dispatch, deliveryP3Low — cosmetic, nice to havesweeper:risk-compatibilitySweeper risk: may break existing users, config, migrations, defaults, or upgradessweeper:risk-message-deliverySweeper risk: may drop, duplicate, misroute, or suppress messagestool/ttsText-to-speech and transcriptiontype/featureNew feature or request
3 participants
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
Adds an opt-in per-platform
suppress_text_when_voiceconfig flag that drops the redundant written text when a voice reply (auto-TTS speak or a MEDIA voice clip) is delivered with no other non-voice content. On platforms whose voice notes arrive as caption-less attachments (e.g. Signal), this avoids the user receiving audio and the same text twice. Default off preserves existing behavior. Also fixes a latent bug where an empty handler response could raiseUnboundLocalErrorby reading the suppression flag before it was initialized.Type of Change
Changes Made
gateway/config.py— addedPlatformConfig.suppress_text_when_voice: bool = False(parsed from top-level orextra), serialized into_dict.gateway/platforms/base.py— extracted_should_suppress_text_on_voice()helper; wired it into_process_message_background; initialized_suppress_text = Falseat function top (fixes the UnboundLocalError); kept the ✅-not-❌ success handling for suppressed voice delivery.cli-config.yaml.example— documented the key.tests/gateway/test_suppress_text_when_voice.py— config parsing + helper logic tests.How to Test
platforms.signal.suppress_text_when_voice: true.Checklist