mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-25 00:51:20 +00:00
fix(send_message): accept E.164 phone numbers for signal/sms/whatsapp (#12936)
Follow-up to #12704. The SignalAdapter can resolve +E164 numbers to UUIDs via listContacts, but _parse_target_ref() in the send_message tool rejected '+' as non-digit and fell through to channel-name resolution — which fails for contacts without a prior session entry. Adds an E.164 branch in _parse_target_ref for phone-based platforms (signal, sms, whatsapp) that preserves the leading '+' so downstream adapters keep the format they expect. Non-phone platforms are unaffected. Reported by @qdrop17 on Discord after pulling #12704.
This commit is contained in:
parent
8f4db7bbd5
commit
be472138f3
2 changed files with 53 additions and 0 deletions
|
|
@ -770,6 +770,46 @@ class TestParseTargetRefMatrix:
|
|||
assert is_explicit is False
|
||||
|
||||
|
||||
class TestParseTargetRefE164:
|
||||
"""_parse_target_ref accepts E.164 phone numbers for phone-based platforms."""
|
||||
|
||||
def test_signal_e164_preserves_plus_prefix(self):
|
||||
"""signal:+E164 is explicit and preserves the leading '+' for signal-cli."""
|
||||
chat_id, thread_id, is_explicit = _parse_target_ref("signal", "+41791234567")
|
||||
assert chat_id == "+41791234567"
|
||||
assert thread_id is None
|
||||
assert is_explicit is True
|
||||
|
||||
def test_sms_e164_is_explicit(self):
|
||||
chat_id, _, is_explicit = _parse_target_ref("sms", "+15551234567")
|
||||
assert chat_id == "+15551234567"
|
||||
assert is_explicit is True
|
||||
|
||||
def test_whatsapp_e164_is_explicit(self):
|
||||
chat_id, _, is_explicit = _parse_target_ref("whatsapp", "+15551234567")
|
||||
assert chat_id == "+15551234567"
|
||||
assert is_explicit is True
|
||||
|
||||
def test_signal_bare_digits_still_work(self):
|
||||
"""Bare digit strings continue to match the generic numeric branch."""
|
||||
chat_id, _, is_explicit = _parse_target_ref("signal", "15551234567")
|
||||
assert chat_id == "15551234567"
|
||||
assert is_explicit is True
|
||||
|
||||
def test_signal_invalid_e164_rejected(self):
|
||||
"""Too-short, too-long, and non-numeric E.164 strings are not explicit."""
|
||||
assert _parse_target_ref("signal", "+123")[2] is False
|
||||
assert _parse_target_ref("signal", "+1234567890123456")[2] is False
|
||||
assert _parse_target_ref("signal", "+12abc4567890")[2] is False
|
||||
assert _parse_target_ref("signal", "+")[2] is False
|
||||
|
||||
def test_e164_prefix_only_matches_phone_platforms(self):
|
||||
"""'+' prefix must NOT be treated as explicit for non-phone platforms."""
|
||||
assert _parse_target_ref("telegram", "+15551234567")[2] is False
|
||||
assert _parse_target_ref("discord", "+15551234567")[2] is False
|
||||
assert _parse_target_ref("matrix", "+15551234567")[2] is False
|
||||
|
||||
|
||||
class TestSendDiscordThreadId:
|
||||
"""_send_discord uses thread_id when provided."""
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,13 @@ _FEISHU_TARGET_RE = re.compile(r"^\s*((?:oc|ou|on|chat|open)_[-A-Za-z0-9]+)(?::(
|
|||
_WEIXIN_TARGET_RE = re.compile(r"^\s*((?:wxid|gh|v\d+|wm|wb)_[A-Za-z0-9_-]+|[A-Za-z0-9._-]+@chatroom|filehelper)\s*$")
|
||||
# Discord snowflake IDs are numeric, same regex pattern as Telegram topic targets.
|
||||
_NUMERIC_TOPIC_RE = _TELEGRAM_TOPIC_TARGET_RE
|
||||
# Platforms that address recipients by phone number and accept E.164 format
|
||||
# (with a leading '+'). Without this, "+15551234567" fails the isdigit() check
|
||||
# below and falls through to channel-name resolution, which has no way to
|
||||
# resolve a raw phone number. Keeping the '+' preserves the E.164 form that
|
||||
# downstream adapters (signal, etc.) expect.
|
||||
_PHONE_PLATFORMS = frozenset({"signal", "sms", "whatsapp"})
|
||||
_E164_TARGET_RE = re.compile(r"^\s*\+(\d{7,15})\s*$")
|
||||
_IMAGE_EXTS = {".jpg", ".jpeg", ".png", ".webp", ".gif"}
|
||||
_VIDEO_EXTS = {".mp4", ".mov", ".avi", ".mkv", ".3gp"}
|
||||
_AUDIO_EXTS = {".ogg", ".opus", ".mp3", ".wav", ".m4a"}
|
||||
|
|
@ -317,6 +324,12 @@ def _parse_target_ref(platform_name: str, target_ref: str):
|
|||
match = _WEIXIN_TARGET_RE.fullmatch(target_ref)
|
||||
if match:
|
||||
return match.group(1), None, True
|
||||
if platform_name in _PHONE_PLATFORMS:
|
||||
match = _E164_TARGET_RE.fullmatch(target_ref)
|
||||
if match:
|
||||
# Preserve the leading '+' — signal-cli and sms/whatsapp adapters
|
||||
# expect E.164 format for direct recipients.
|
||||
return target_ref.strip(), None, True
|
||||
if target_ref.lstrip("-").isdigit():
|
||||
return target_ref, None, True
|
||||
# Matrix room IDs (start with !) and user IDs (start with @) are explicit
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue