Repository navigation
Conversation
added 16 commits
March 31, 2026 11:55
…tting The _markdown_to_html() method attempted to import the 'markdown' library which was never listed as a dependency, causing it to always fall through to a minimal regex fallback that only handled bold, italic, and inline code. This meant code blocks, headers, links, lists, blockquotes, and horizontal rules all rendered as raw markdown text in Matrix clients. Changes: - Add Markdown>=3.6 to the [matrix] optional dependency in pyproject.toml - Add sane_lists extension for better list handling - Rewrite the regex fallback to comprehensively handle all common markdown - Protected regions pattern prevents code content from being transformed - Import html.escape for proper HTML entity handling in code blocks
…t, presence, emote/notice Tier 1 Matrix enhancement — adds major missing features: Reactions: - Send reactions via m.reaction events (m.annotation rel_type) - Processing lifecycle: 👀 on start, ✅/❌ on complete (like Discord) - Receive reaction events (ReactionEvent + UnknownEvent fallback) - Configurable via MATRIX_REACTIONS env var (default: true) Read receipts: - Auto-send m.read + m.fully_read on incoming text and media messages - send_read_receipt() method using room_read_markers() API Message redaction: - redact_message() via room_redact() — agent can delete mistakes Room history: - fetch_room_history() via room_messages() — context loading on rejoin Room management: - create_room() with name, topic, invite list, DM flag, preset - invite_user() via room_invite() Presence: - set_presence() for online/offline/unavailable status Message types: - send_emote() for /me style actions (m.emote) - send_notice() for bot-appropriate non-alerting messages (m.notice) - Both support markdown-to-HTML conversion
…erter Security hardening for _markdown_to_html_fallback(): - HTML-escape all non-code text BEFORE applying markdown transforms. Previously, raw HTML in input (e.g. <script>, <img onerror=...>) would pass through unescaped into the formatted_body. Now all text outside of protected regions (code blocks, inline code, links) is escaped via html.escape() before any transformation occurs. - Add _sanitize_link_url() to reject dangerous URI schemes (javascript:, data:, vbscript:) and escape double-quotes in URLs to prevent href attribute breakout. - Extract and protect markdown links [text](url) BEFORE the global HTML-escape step, building <a> tags with escaped text and sanitized URLs. - Blockquote detection now handles both '>' and '>' (the escaped form) since blockquote markers are HTML-escaped in Phase 1b. - Harden the Python-Markdown library path: deregister the html_block preprocessor so raw HTML in source is escaped rather than passed through. Additional fixes: - Validate set_presence() state against allowed values (online/offline/ unavailable) before sending to homeserver. - Wrap fire-and-forget read receipt calls in _background_read_receipt() with try/except to prevent silently lost exceptions. - Escape code language class attribute in fenced blocks to prevent injection via crafted language identifiers. Verified against 12 XSS/injection vectors and 9 functional regression tests — all pass.
Tests cover: - HTML injection prevention (12 XSS vectors: script tags, img onerror, javascript:/data:/vbscript: URIs, attribute breakout, link text injection) - Extended formatting (code blocks, headers, lists, blockquotes, HR, strikethrough, links, complex mixed documents) - Link URL sanitization (scheme blocking, quote escaping) - Reactions (send, processing lifecycle, disabled state) - Read receipts (send, no-client guard) - Message redaction (redact, no-client guard) - Room management (create, invite, no-client guard) - Presence (valid state, invalid state rejected, no-client guard) - Message types (emote, notice, empty text guard) All 109 tests pass (63 existing + 46 new).
The base class calls stop_typing() when processing completes but it was a no-op. Now properly sends room_typing(typing_state=False) to clear the typing indicator in Matrix rooms.
…CEIPTS Supports three modes: - 'immediate' (default): send read receipt on message arrival - 'after_processing': send after agent finishes processing - 'disabled': never send read receipts Documented in module docstring.
The reaction handler for older matrix-nio versions was missing the dedup check that _on_reaction already had, potentially processing the same reaction event multiple times.
New tools/matrix_tools.py with six tools following the homeassistant_tool.py pattern: - matrix_send_reaction: react with emoji to messages - matrix_redact_message: delete/redact messages - matrix_create_room: create new rooms with options - matrix_invite_user: invite users to rooms - matrix_fetch_history: fetch room message history - matrix_set_presence: set bot online status All tools include input validation, proper error handling, and JSON return format. Uses _run_async bridge pattern for sync→async.
Register the adapter instance on connect() and clear it on disconnect() so the LLM-callable matrix tools have access to the running adapter.
Add standalone 'matrix' toolset and include matrix tools in 'hermes-matrix' platform toolset for full Matrix bot deployments.
Ensures matrix tools are imported and registered when the tool system initializes.
Informs the LLM about available Matrix-specific tools and HTML formatting support when running on the Matrix platform.
…ssues - Replace _run_async ThreadPoolExecutor pattern with run_coroutine_threadsafe() on the adapter's own event loop, fixing potential nio client state corruption from cross-loop access - Store event loop reference as adapter._loop in connect() - Add _ensure_adapter() null-check helper called by every handler - Restrict create_room preset to private_chat/public_chat only (trusted_private_chat grants elevated power levels to all members) - Add length limits: emoji (32), reason (500), name (255), topic (1000), status_msg (255) to prevent resource abuse via prompt injection - Silently cap over-length fields rather than rejecting
Collaborator
|
Thanks for the Matrix feature work. The underlying Matrix operations are already present on main, but the LLM-callable layer still needs a current-architecture implementation. Problems
Suggested changes
Automated hermes-sweeper review. |
Author
|
Closing as superseded. This PR targets the pre-mautrix layout ( Replacement in-flight: #61218 ( Not merged upstream; no code from this branch should be landed as-is. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Tier 1.5: Matrix LLM-Callable Tools & Enhanced Event Handling
Builds on the Tier 1 foundation from #4338 to add LLM-callable Matrix tools and improve event handling reliability.
What changed and why
New: 6 LLM-callable Matrix tools (
tools/matrix_tools.py, 467 lines):matrix_send_reaction— Send emoji reactions to messagesmatrix_redact_message— Delete/redact messages with optional reasonmatrix_create_room— Create Matrix rooms with presets and invitesmatrix_invite_user— Invite users to roomsmatrix_fetch_history— Retrieve room message history (paginated, up to 200)matrix_set_presence— Set online/offline/unavailable statusAll tools include comprehensive input validation (prefix checks, length bounds, enum validation) and security hardening (threading lock on adapter reference, coroutine leak prevention, public room creation gating).
New: Configurable read receipt timing (
MATRIX_READ_RECEIPTSenv var):immediate(default) — send read receipt on message receiveafter_processing— send after agent finishes processingdisabled— never send read receiptsNew:
stop_typingoverride — properly clears typing indicator viaroom_typing(typing_state=False)New: Event deduplication in
_on_unknown_event— prevents duplicate processing of reaction events from older nio versionsNew: Matrix platform hint in prompt builder — describes available Matrix tools and HTML formatting support
Architecture
tools/homeassistant_tool.py)set_matrix_adapter()/_ensure_adapter()with threading lock_run_async) handles sync→async tool calls with 30s timeout and coroutine cleanuptoolsets.pyasmatrixtoolset, included inhermes-matrixcompositemodel_tools.pymodule loaderSecurity
Two security audit passes performed:
!prefix, event_id$prefix, user_id@prefix, emoji length cap)future.cancel()on timeout prevents coroutine leaksMATRIX_ALLOW_PUBLIC_ROOMSenv var (default: disabled)How to test
Files changed (6 files, +779/-3)
tools/matrix_tools.pygateway/platforms/matrix.pytoolsets.pymodel_tools.pyagent/prompt_builder.pytests/gateway/test_matrix.pyChecklist
pytest tests/ -qpasses (118/118)