← Back to PRs

#15956: feat(signal): enhanced inbound message handling

by heyhudson open 2026-02-14 03:22 View on GitHub →
docs channel: signal gateway size: XL trusted-contributor
## Summary Signal inbound events currently drop or flatten important metadata (multi-attachment details, quotes, edits, stickers, polls, contacts, link previews, and text styles). That makes downstream hooks/templates/agents lose context, and it can also cause command or mention logic to misfire. This PR upgrades Signal inbound normalization so that richer Signal payloads are preserved in `MsgContext` while keeping existing single-attachment behavior backward-compatible. This matters because users can send far more than plain text in Signal, and missing metadata causes: - quoted replies to lose who or what is being replied to, - only one attachment to be represented even when multiple exist, - stickers/polls/contacts to lose semantics, - styled text to interfere with control-command and mention detection, - and debounce merging to accidentally blend per-message metadata that should stay atomic. ## What Changed ### Enriched Signal inbound context - `src/signal/monitor/event-handler.ts`: Captures full media arrays (`MediaPaths`, `MediaTypes`, `MediaCaptions`, `MediaDimensions`) and keeps first-item aliases (`MediaPath`, `MediaType`, `MediaCaption`, `MediaDimension`) for compatibility. - `src/signal/monitor/event-handler.ts`: Handles sticker attachments as media and emits sticker metadata into `UntrustedContext`. - `src/signal/monitor/event-handler.ts`: Maps quote metadata to `ReplyToId`, `ReplyToBody`, `ReplyToSender`, and `ReplyToIsQuote`. - `src/signal/monitor/event-handler.ts`: Maps edit metadata to `EditTargetTimestamp`. - `src/signal/monitor/event-handler.ts`: Adds link-preview/contact/poll context into `UntrustedContext`. - `src/signal/monitor/event-handler.ts`: Uses `Promise.allSettled` for attachment fetches so one failed download does not discard other successful attachments. ### Safer mention and command behavior with styled text - `src/signal/monitor/event-handler.ts`: Introduces text-style rendering (`applySignalTextStyles`) and keeps plain text separately for command/mention checks. - `src/signal/monitor/event-handler.ts`: Mention and control-command matching now run on plain text, avoiding false negatives/positives from markdown markers. - `src/signal/monitor/mentions.ts`: `renderSignalMentions` now returns expanded text plus offset-shift metadata so style ranges remain aligned after mention replacement. ### Debounce behavior for richer events - `src/signal/monitor/event-handler.ts`: Debounce merging remains for plain text, but avoids carrying per-message reply/edit/media fields across merged entries. - `src/signal/monitor/event-handler.ts`: Merges `UntrustedContext` across debounced entries so Signal metadata (for example poll votes and link previews) is not lost. ### Type, config, and docs updates - `src/signal/monitor/event-handler.types.ts` and `src/auto-reply/templating.ts`: Extends wire/context types for richer inbound metadata. - `src/config/types.signal.ts`, `src/config/zod-schema.providers-core.ts`, and `src/signal/monitor.ts`: Adds account-level toggles `injectLinkPreviews` (default `true`) and `preserveTextStyles` (default `true`). - `docs/channels/signal.md` and `docs/gateway/configuration-reference.md`: Documents new inbound feature behavior and config switches. ### Media note formatting improvements - `src/auto-reply/media-note.ts`: Adds dimension/caption output in inbound media note formatting. - `src/auto-reply/media-note.test.ts`: Adds coverage for dimension and caption rendering. ## Design Notes - Backward compatibility over purity: keep singular media fields alongside new plural fields so existing templates/hooks continue to work. - Rich metadata goes into `UntrustedContext`: preserves Signal-specific context without polluting primary user text. - Defaults are opt-out: link previews and text-style preservation default to enabled for better fidelity, but are configurable per account. - Fault tolerance over fail-fast for media downloads: partial success is better than dropping all attachments. ## Testing Ran targeted tests for touched behavior: - `pnpm test -- src/auto-reply/media-note.test.ts src/signal/monitor/event-handler.inbound-contract.test.ts src/signal/monitor/event-handler.mention-gating.test.ts` (Result: `3` files passed, `64` tests passed) - `pnpm vitest run --config vitest.e2e.config.ts src/signal/monitor.event-handler.sender-prefix.e2e.test.ts` (Result: `1` file passed, `1` test passed) ## AI Disclosure - [x] AI-assisted - [x] Fully tested ## Related Issues - #10637 - #10638 - #13106 - #16545 - #18552 --- Closes #21958

Most Similar PRs