This commit is contained in:
Adam Rummer 2026-04-24 23:44:38 +01:00 committed by GitHub
commit a5830218db
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 64 additions and 2 deletions

View file

@ -18,6 +18,7 @@ Environment variables:
MATRIX_REQUIRE_MENTION Require @mention in rooms (default: true)
MATRIX_FREE_RESPONSE_ROOMS Comma-separated room IDs exempt from mention requirement
MATRIX_AUTO_THREAD Auto-create threads for room messages (default: true)
MATRIX_DM_AUTO_THREAD Auto-create threads for DM messages (default: false)
MATRIX_RECOVERY_KEY Recovery key for cross-signing verification after device key rotation
MATRIX_DM_MENTION_THREADS Create a thread when bot is @mentioned in a DM (default: false)
"""
@ -260,6 +261,9 @@ class MatrixAdapter(BasePlatformAdapter):
"1",
"yes",
)
self._dm_auto_thread: bool = os.getenv(
"MATRIX_DM_AUTO_THREAD", "false"
).lower() in ("true", "1", "yes")
self._dm_mention_threads: bool = os.getenv(
"MATRIX_DM_MENTION_THREADS", "false"
).lower() in ("true", "1", "yes")
@ -1278,7 +1282,7 @@ class MatrixAdapter(BasePlatformAdapter):
body = self._strip_mention(body)
# Auto-thread.
if not is_dm and not thread_id and self._auto_thread:
if not thread_id and ((not is_dm and self._auto_thread) or (is_dm and self._dm_auto_thread)):
thread_id = event_id
self._threads.mark(thread_id)

View file

@ -56,7 +56,7 @@ _EXTRA_ENV_KEYS = frozenset({
"WHATSAPP_MODE", "WHATSAPP_ENABLED",
"MATTERMOST_HOME_CHANNEL", "MATTERMOST_REPLY_MODE",
"MATRIX_PASSWORD", "MATRIX_ENCRYPTION", "MATRIX_DEVICE_ID", "MATRIX_HOME_ROOM",
"MATRIX_REQUIRE_MENTION", "MATRIX_FREE_RESPONSE_ROOMS", "MATRIX_AUTO_THREAD",
"MATRIX_REQUIRE_MENTION", "MATRIX_FREE_RESPONSE_ROOMS", "MATRIX_AUTO_THREAD", "MATRIX_DM_AUTO_THREAD",
"MATRIX_RECOVERY_KEY",
})
import yaml
@ -1699,6 +1699,14 @@ OPTIONAL_ENV_VARS = {
"category": "messaging",
"advanced": True,
},
"MATRIX_DM_AUTO_THREAD": {
"description": "Auto-create threads for DM messages in Matrix (default: false)",
"prompt": "Auto-create threads in DMs (true/false)",
"url": None,
"password": False,
"category": "messaging",
"advanced": True,
},
"MATRIX_DEVICE_ID": {
"description": "Stable Matrix device ID for E2EE persistence across restarts (e.g. HERMES_BOT)",
"prompt": "Matrix device ID (stable across restarts)",

View file

@ -1952,3 +1952,53 @@ class TestMatrixPresence:
self.adapter._client = None
result = await self.adapter.set_presence("online")
assert result is False
# ---------------------------------------------------------------------------
# DM auto-thread
# ---------------------------------------------------------------------------
class TestMatrixDmAutoThread:
def setup_method(self):
self.adapter = _make_adapter()
self.adapter._is_dm_room = AsyncMock(return_value=True)
self.adapter._get_display_name = AsyncMock(return_value="Alice")
self.adapter._background_read_receipt = MagicMock()
# Disable require_mention so DMs pass gating
self.adapter._require_mention = False
@pytest.mark.asyncio
async def test_dm_auto_thread_enabled_creates_thread(self):
"""When dm_auto_thread is True, DM messages get auto-threaded."""
self.adapter._dm_auto_thread = True
ctx = await self.adapter._resolve_message_context(
room_id="!dm:ex",
sender="@alice:ex",
event_id="$ev1",
body="hello",
source_content={"body": "hello"},
relates_to={},
)
assert ctx is not None
_body, _is_dm, _chat_type, thread_id, _display, _source = ctx
assert thread_id == "$ev1"
@pytest.mark.asyncio
async def test_dm_auto_thread_disabled_no_thread(self):
"""When dm_auto_thread is False (default), DMs have no auto-thread."""
self.adapter._dm_auto_thread = False
ctx = await self.adapter._resolve_message_context(
room_id="!dm:ex",
sender="@alice:ex",
event_id="$ev2",
body="hello",
source_content={"body": "hello"},
relates_to={},
)
assert ctx is not None
_body, _is_dm, _chat_type, thread_id, _display, _source = ctx
assert thread_id is None