From 6e5987127e42bf9b7e9a7bb9f42a9889ac984122 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sun, 25 Jan 2026 18:47:54 -0600 Subject: [PATCH] =?UTF-8?q?fix(signal):=20replace=20=EF=BF=BC=20with=20@uu?= =?UTF-8?q?id/@phone=20from=20mentions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Related #1926 Signal mentions were appearing as  (object replacement character) instead of readable identifiers. This caused Clawdbot to misinterpret messages and respond inappropriately. Now parses dataMessage.mentions array and replaces the placeholder character with @{uuid} or @{phone} from the mention metadata. --- src/signal/monitor/event-handler.ts | 18 +++++++++++++++++- src/signal/monitor/event-handler.types.ts | 9 +++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/signal/monitor/event-handler.ts b/src/signal/monitor/event-handler.ts index 72195ff78..8cf290c68 100644 --- a/src/signal/monitor/event-handler.ts +++ b/src/signal/monitor/event-handler.ts @@ -313,7 +313,23 @@ export function createSignalEventHandler(deps: SignalEventHandlerDeps) { : deps.isSignalReactionMessage(dataMessage?.reaction) ? dataMessage?.reaction : null; - const messageText = (dataMessage?.message ?? "").trim(); + + // Replace  (object replacement character) with @uuid or @phone from mentions + let messageText = (dataMessage?.message ?? "").trim(); + if (messageText && dataMessage?.mentions?.length) { + const mentions = dataMessage.mentions + .filter((m) => (m.uuid || m.number) && m.start != null && m.length != null) + .sort((a, b) => (b.start ?? 0) - (a.start ?? 0)); // Reverse order to avoid index shifting + + for (const mention of mentions) { + const start = mention.start!; + const length = mention.length!; + const identifier = mention.uuid || mention.number || ""; + const replacement = `@${identifier}`; + messageText = messageText.slice(0, start) + replacement + messageText.slice(start + length); + } + } + const quoteText = dataMessage?.quote?.text?.trim() ?? ""; const hasBodyContent = Boolean(messageText || quoteText) || Boolean(!reaction && dataMessage?.attachments?.length); diff --git a/src/signal/monitor/event-handler.types.ts b/src/signal/monitor/event-handler.types.ts index 153bdf501..d68cb5093 100644 --- a/src/signal/monitor/event-handler.types.ts +++ b/src/signal/monitor/event-handler.types.ts @@ -16,10 +16,19 @@ export type SignalEnvelope = { reactionMessage?: SignalReactionMessage | null; }; +export type SignalMention = { + name?: string | null; + number?: string | null; + uuid?: string | null; + start?: number | null; + length?: number | null; +}; + export type SignalDataMessage = { timestamp?: number; message?: string | null; attachments?: Array; + mentions?: Array | null; groupInfo?: { groupId?: string | null; groupName?: string | null;