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:
Teknium
2026-04-20 03:02:44 -07:00
committed by GitHub
parent 8f4db7bbd5
commit be472138f3
2 changed files with 53 additions and 0 deletions

View File

@@ -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