feat(channels): Signal messenger support via signal-cli daemon - #268
feat(channels): Signal messenger support via signal-cli daemon#268ibhagwan wants to merge 1 commit into
Conversation
Implements Signal platform adapter using signal-cli daemon HTTP/JSON-RPC interface. Features: - Continuous SSE streaming with exponential backoff reconnection (2s→60s) - Typing indicators sent every 8 seconds while processing messages - Attachment upload/download with 100MB size validation - DM pairing integration (reuses existing pairing system) - Group message filtering (disabled by default for security) - Allowlist checking for E.164 numbers and UUIDs - Phone number redaction in all debug logs (+1555****4567) - Health check monitor for stale SSE connections - Enhanced session context: shows E164 + UUID for DMs, name + ID for groups Signal support in send_message tool: - Added 'signal' platform to platform_map - Added attachments array parameter for sending files - Added _send_signal() function using JSON-RPC - Updated tool schema with Signal examples Authorization fixes: - Added SIGNAL_ALLOWED_USERS and SIGNAL_GROUP_ALLOWED_USERS support - Fixed group allowlist checking in run.py _is_user_authorized() - Signal users in group allowlist now correctly authorized Phone redaction: - Added _SIGNAL_PHONE_RE regex pattern for E164 numbers - Added redact function matching signal.py _redact_phone() logic - Applied to RedactingFormatter for all gateway logs Session context improvements: - Added user_id_alt field for Signal UUIDs and chat_id_alt for group IDs - Updated description property to show E164 + UUID for DMs (e.g., 'DM with John Smith (+15551234567/uuid:abc...)') - Updated description to show group name + ID (e.g., 'group: Supreme Leader (ID: abc123)') - Updated build_source() in base adapter to accept new optional fields Configuration (environment variables): - SIGNAL_HTTP_URL, SIGNAL_ACCOUNT (required) - SIGNAL_ALLOWED_USERS, SIGNAL_GROUP_ALLOWED_USERS - SIGNAL_DM_POLICY (pairing|allowlist|open) - SIGNAL_GROUP_POLICY (disabled|allowlist|open) - SIGNAL_DEBUG for verbose logging Files: - gateway/platforms/signal.py: NEW - Complete adapter (934 lines) - gateway/run.py: SignalAdapter factory, group allowlist, SIGNAL_DEBUG - gateway/config.py: Platform.SIGNAL enum, env overrides - gateway/session.py: Added user_id_alt and chat_id_alt fields, enhanced description - gateway/platforms/base.py: Added user_id_alt and chat_id_alt params to build_source - tools/send_message_tool.py: Signal platform + attachments support - agent/redact.py: Signal phone number redaction - hermes_cli/config.py, setup.py: Signal config metadata - tests/gateway/test_signal.py: NEW - Unit tests - tests/agent/test_redact.py: Added Signal redaction tests
|
Thanks for this substantial contribution, @ibhagwan! This is a really well-built adapter — solid architecture, good security defaults (pairing for DMs, groups disabled), SSE reconnection with exponential backoff, and clean integration with the existing platform patterns. Great work. We're going to hold off on merging for now since we want to be able to test a new platform adapter end-to-end before landing it, but we've done a thorough review and want to share our findings so you can address them in the meantime: Bugs1. Timestamp read from wrong dict (Medium) timestamp = envelope.get("timestamp", 0)Should be 2. Inconsistent HTTP library in send_message_tool.py (Medium) 3. Account phone number logged without redaction (Low-Medium)
Most other log lines correctly use 4. "id": f"send_{int(__import__('time').time() * 1000)}",Should just 5. Wildcard allowlist check (Low) if self.allowed_users == ["*"]:This only matches if the list is exactly 6. Async tests require pytest-asyncio (Low) What we verified (for when we revisit)Full diff reviewed — all 17 files, 1856 additions checked. Delegated deep-dive analysis that:
What looked great
Next steps
|
Complete Signal adapter using signal-cli daemon HTTP API. Based on PR #268 by ibhagwan, rebuilt on current main with bug fixes. Architecture: - SSE streaming for inbound messages with exponential backoff (2s→60s) - JSON-RPC 2.0 for outbound (send, typing, attachments, contacts) - Health monitor detects stale SSE connections (120s threshold) - Phone number redaction in all logs and global redact.py Features: - DM and group message support with separate access policies - DM policies: pairing (default), allowlist, open - Group policies: disabled (default), allowlist, open - Attachment download with magic-byte type detection - Typing indicators (8s refresh interval) - 100MB attachment size limit, 8000 char message limit - E.164 phone + UUID allowlist support Integration: - Platform.SIGNAL enum in gateway/config.py - Signal in _is_user_authorized() allowlist maps (gateway/run.py) - Adapter factory in _create_adapter() (gateway/run.py) - user_id_alt/chat_id_alt fields in SessionSource for UUIDs - send_message tool support via httpx JSON-RPC (not aiohttp) - Interactive setup wizard in 'hermes gateway setup' - Connectivity testing during setup (pings /api/v1/check) - signal-cli detection and install guidance Bug fixes from PR #268: - Timestamp reads from envelope_data (not outer wrapper) - Uses httpx consistently (not aiohttp in send_message tool) - SIGNAL_DEBUG scoped to signal logger (not root) - extract_images regex NOT modified (preserves group numbering) - pairing.py NOT modified (no cross-platform side effects) - No dual authorization (adapter defers to run.py for user auth) - Wildcard uses set membership ('*' in set, not list equality) - .zip default for PK magic bytes (not .docx) No new Python dependencies — uses httpx (already core). External requirement: signal-cli daemon (user-installed). Tests: 30 new tests covering config, init, helpers, session source, phone redaction, authorization, and send_message integration. Co-authored-by: ibhagwan <ibhagwan@users.noreply.github.com>
|
Thanks for the excellent work @ibhagwan! Your Signal adapter implementation was the foundation for what we merged in commit 24f549a. We rebuilt it on current main (the branch had diverged significantly in 4 shared files) and fixed the bugs identified during review:
Your architecture design — SSE streaming + JSON-RPC + health monitoring — was solid and we kept it intact. You're credited as co-author in the commit. Closing this PR since the work is merged. Thank you! 🎉 |
|
Tysm, that's fantastic news @teknium1! |
Complete Signal adapter using signal-cli daemon HTTP API. Based on PR NousResearch#268 by ibhagwan, rebuilt on current main with bug fixes. Architecture: - SSE streaming for inbound messages with exponential backoff (2s→60s) - JSON-RPC 2.0 for outbound (send, typing, attachments, contacts) - Health monitor detects stale SSE connections (120s threshold) - Phone number redaction in all logs and global redact.py Features: - DM and group message support with separate access policies - DM policies: pairing (default), allowlist, open - Group policies: disabled (default), allowlist, open - Attachment download with magic-byte type detection - Typing indicators (8s refresh interval) - 100MB attachment size limit, 8000 char message limit - E.164 phone + UUID allowlist support Integration: - Platform.SIGNAL enum in gateway/config.py - Signal in _is_user_authorized() allowlist maps (gateway/run.py) - Adapter factory in _create_adapter() (gateway/run.py) - user_id_alt/chat_id_alt fields in SessionSource for UUIDs - send_message tool support via httpx JSON-RPC (not aiohttp) - Interactive setup wizard in 'hermes gateway setup' - Connectivity testing during setup (pings /api/v1/check) - signal-cli detection and install guidance Bug fixes from PR NousResearch#268: - Timestamp reads from envelope_data (not outer wrapper) - Uses httpx consistently (not aiohttp in send_message tool) - SIGNAL_DEBUG scoped to signal logger (not root) - extract_images regex NOT modified (preserves group numbering) - pairing.py NOT modified (no cross-platform side effects) - No dual authorization (adapter defers to run.py for user auth) - Wildcard uses set membership ('*' in set, not list equality) - .zip default for PK magic bytes (not .docx) No new Python dependencies — uses httpx (already core). External requirement: signal-cli daemon (user-installed). Tests: 30 new tests covering config, init, helpers, session source, phone redaction, authorization, and send_message integration. Co-authored-by: ibhagwan <ibhagwan@users.noreply.github.com>
Complete Signal adapter using signal-cli daemon HTTP API. Based on PR NousResearch#268 by ibhagwan, rebuilt on current main with bug fixes. Architecture: - SSE streaming for inbound messages with exponential backoff (2s→60s) - JSON-RPC 2.0 for outbound (send, typing, attachments, contacts) - Health monitor detects stale SSE connections (120s threshold) - Phone number redaction in all logs and global redact.py Features: - DM and group message support with separate access policies - DM policies: pairing (default), allowlist, open - Group policies: disabled (default), allowlist, open - Attachment download with magic-byte type detection - Typing indicators (8s refresh interval) - 100MB attachment size limit, 8000 char message limit - E.164 phone + UUID allowlist support Integration: - Platform.SIGNAL enum in gateway/config.py - Signal in _is_user_authorized() allowlist maps (gateway/run.py) - Adapter factory in _create_adapter() (gateway/run.py) - user_id_alt/chat_id_alt fields in SessionSource for UUIDs - send_message tool support via httpx JSON-RPC (not aiohttp) - Interactive setup wizard in 'hermes gateway setup' - Connectivity testing during setup (pings /api/v1/check) - signal-cli detection and install guidance Bug fixes from PR NousResearch#268: - Timestamp reads from envelope_data (not outer wrapper) - Uses httpx consistently (not aiohttp in send_message tool) - SIGNAL_DEBUG scoped to signal logger (not root) - extract_images regex NOT modified (preserves group numbering) - pairing.py NOT modified (no cross-platform side effects) - No dual authorization (adapter defers to run.py for user auth) - Wildcard uses set membership ('*' in set, not list equality) - .zip default for PK magic bytes (not .docx) No new Python dependencies — uses httpx (already core). External requirement: signal-cli daemon (user-installed). Tests: 30 new tests covering config, init, helpers, session source, phone redaction, authorization, and send_message integration. Co-authored-by: ibhagwan <ibhagwan@users.noreply.github.com>
Complete Signal adapter using signal-cli daemon HTTP API. Based on PR NousResearch#268 by ibhagwan, rebuilt on current main with bug fixes. Architecture: - SSE streaming for inbound messages with exponential backoff (2s→60s) - JSON-RPC 2.0 for outbound (send, typing, attachments, contacts) - Health monitor detects stale SSE connections (120s threshold) - Phone number redaction in all logs and global redact.py Features: - DM and group message support with separate access policies - DM policies: pairing (default), allowlist, open - Group policies: disabled (default), allowlist, open - Attachment download with magic-byte type detection - Typing indicators (8s refresh interval) - 100MB attachment size limit, 8000 char message limit - E.164 phone + UUID allowlist support Integration: - Platform.SIGNAL enum in gateway/config.py - Signal in _is_user_authorized() allowlist maps (gateway/run.py) - Adapter factory in _create_adapter() (gateway/run.py) - user_id_alt/chat_id_alt fields in SessionSource for UUIDs - send_message tool support via httpx JSON-RPC (not aiohttp) - Interactive setup wizard in 'hermes gateway setup' - Connectivity testing during setup (pings /api/v1/check) - signal-cli detection and install guidance Bug fixes from PR NousResearch#268: - Timestamp reads from envelope_data (not outer wrapper) - Uses httpx consistently (not aiohttp in send_message tool) - SIGNAL_DEBUG scoped to signal logger (not root) - extract_images regex NOT modified (preserves group numbering) - pairing.py NOT modified (no cross-platform side effects) - No dual authorization (adapter defers to run.py for user auth) - Wildcard uses set membership ('*' in set, not list equality) - .zip default for PK magic bytes (not .docx) No new Python dependencies — uses httpx (already core). External requirement: signal-cli daemon (user-installed). Tests: 30 new tests covering config, init, helpers, session source, phone redaction, authorization, and send_message integration. Co-authored-by: ibhagwan <ibhagwan@users.noreply.github.com>
…37) Adds the `artifact.session.spawn` built-in intent handler. Instead of executing anything inline, it creates a session through the standard session runtime and returns the live `session_id` in the invoke result, so the client can click through into real-time introspection of the run. This is the gateway half of the intent-as-session flow the native client (hermes-native NousResearch#268) is already wired to consume: on a `succeeded` result carrying `session_id`, the success row becomes a link into that session. Security invariants preserved: - The initial task is composed server-side from the binding's author-declared `session_prompt` template plus the entity resolved out of the pinned content. The raw client `entity_ref` is a lookup key only, never spliced into the instruction (§0.2). An unresolved ref fails closed rather than spawning a session at an attacker-controlled string. - Confirmation still runs in the invocation engine before the handler, so a destructive binding creates the session only after the user confirms. - The lone dependency on the server module (in-process `_methods` dispatch) is isolated in `_spawn_session` so it's stubbable in tests and doesn't leak the server surface into the intent engine. 5 new tests (session id flows back, task seeded from stored entity not raw ref, unresolved-entity fail-closed, artifact-scoped spawn, destructive confirm gate). Docs updated with the new built-in and result shape. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Implements Signal platform adapter using signal-cli daemon HTTP/JSON-RPC interface.
Features:
Signal support in send_message tool:
Authorization fixes:
Phone redaction:
Session context improvements:
Configuration (environment variables):
Files: