Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 25 additions & 4 deletions gateway/platforms/signal.py
Original file line number Diff line number Diff line change
Expand Up @@ -922,12 +922,33 @@ async def send_voice(
reply_to: Optional[str] = None,
**kwargs,
) -> SendResult:
"""Send an audio file as a Signal attachment.
"""Send an audio file as a Signal voice note.

Signal does not distinguish voice messages from file attachments at
the API level, so this routes through the same RPC send path.
Uses the voiceNote flag so Signal renders it as an inline voice
message rather than a plain file attachment.
"""
return await self._send_attachment(chat_id, audio_path, "Audio", caption)
await self._stop_typing_indicator(chat_id)
try:
file_size = Path(audio_path).stat().st_size
except FileNotFoundError:
return SendResult(success=False, error=f"Audio file not found: {audio_path}")
if file_size > SIGNAL_MAX_ATTACHMENT_SIZE:
return SendResult(success=False, error=f"Audio too large ({file_size} bytes)")
params: Dict[str, Any] = {
"account": self.account,
"message": caption or "",
"attachments": [audio_path],
"voiceNote": True,
}
if chat_id.startswith("group:"):
params["groupId"] = chat_id[6:]
else:
params["recipient"] = [await self._resolve_recipient(chat_id)]
result = await self._rpc("send", params)
if result is not None:
self._track_sent_timestamp(result)
return SendResult(success=True)
return SendResult(success=False, error="RPC send voice failed")

async def send_video(
self,
Expand Down
2 changes: 1 addition & 1 deletion tools/tts_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -957,7 +957,7 @@ def text_to_speech_tool(
# and needs ffmpeg for conversion.
from gateway.session_context import get_session_env
platform = get_session_env("HERMES_SESSION_PLATFORM", "").lower()
want_opus = (platform == "telegram")
want_opus = platform in ("telegram", "signal")

# Determine output path
if output_path:
Expand Down
2 changes: 1 addition & 1 deletion website/docs/user-guide/messaging/signal.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ The adapter supports sending and receiving media in both directions.
The agent can send media files via `MEDIA:` tags in responses. The following delivery methods are supported:

- **Images** — `send_image_file` sends PNG, JPEG, GIF, WebP as native Signal attachments
- **Voice** — `send_voice` sends audio files (OGG, MP3, WAV, M4A, AAC) as attachments
- **Voice** — `send_voice` sends audio files (OGG, MP3, WAV, M4A, AAC) as inline voice notes
- **Video** — `send_video` sends MP4 video files
- **Documents** — `send_document` sends any file type (PDF, ZIP, etc.)

Expand Down