fix(mattermost): preserve threaded delivery targets - #45654
Conversation
Parse Mattermost channel/root-post targets, honor metadata thread IDs as root_id in the adapter, and avoid cross-event-loop live adapter sends from send_message. Add regression coverage for Mattermost target parsing, cron explicit targets, and metadata thread delivery.
|
Related: #35343 also addresses the Mattermost aiohttp cross-loop failure. This PR intentionally covers that symptom only as part of a broader threaded-delivery fix: Mattermost target parsing for |
tonydwb
left a comment
There was a problem hiding this comment.
Code Review Summary
Verdict: Approved
Correctness
- Mattermost adapter now reads
thread_idorroot_idfrom metadata as fallback whenreply_tois not set, preserving threaded delivery context. - Adds
User-Agent: HermesAgent-Mattermost/1.0header for better server-side identification. - Properly resolves root ID for CRT (threading) in all delivery paths.
Testing
- Tests in
test_mattermost.pyandtest_send_message_target_parse.pycover threaded delivery.
No Issues Found
- No secrets, no debug artifacts.
Reviewed by Hermes Agent
teknium1
left a comment
There was a problem hiding this comment.
Thanks for the focused Mattermost delivery coverage. The explicit target parsing remains needed on current main: tools/send_message_tool.py:531-616 has no Mattermost branch, while cron/scheduler.py:1128-1159 relies on that parser for explicit delivery thread IDs.
Problems
tests/tools/test_send_message_target_parse.pychanges the E.164 regression input to+155****4567; that is not E.164-shaped, so the test no longer covers the parser boundary it names.- The new
mattermost:<channel_id>:<root_post_id>syntax is not documented inSEND_MESSAGE_SCHEMA(tools/send_message_tool.py:217).
Suggested changes
- Restore a valid fictitious E.164-shaped test value.
- Update the target schema description/example for Mattermost threaded delivery.
- Salvage only the still-needed parser/cron work onto current main. The adapter metadata-thread behavior is already implemented more broadly by merged commit
5a0e0d35b(#46885), so those overlapping hunks should not be reapplied unchanged.
This is an automated hermes-sweeper review.
| def test_e164_target_still_requires_phone_platform() -> None: | ||
| assert _parse_target_ref("matrix", "+15551234567")[2] is False | ||
| assert _parse_target_ref("matrix", "+155****4567")[2] is False | ||
|
|
There was a problem hiding this comment.
Please keep this a valid fictitious E.164-shaped number (for example +15555550123). +155****4567 cannot match _E164_TARGET_RE, so this no longer verifies that E.164 targets are rejected on non-phone platforms.
What does this PR do?
Fixes several Mattermost outbound delivery paths that can lose thread context or fail when a live gateway adapter is present:
send_message(target="mattermost:<channel_id>:<root_post_id>")now parses Mattermost threaded targets instead of treating<channel_id>:<root_post_id>as one chat id.metadata.thread_id/metadata.root_idas the effective Mattermostroot_idwhenreply_tois absent.send_messageavoids directly awaiting the live Mattermost adapter from a potentially different event loop, which can trigger aiohttp'sTimeout context manager should be used inside a taskerror.Related Issue
No issue yet. This PR documents and fixes the reproduced bug directly.
Type of Change
Changes Made
tools/send_message_tool.py<channel_id>[:<root_post_id>]explicit target parsing.send_messagethrough standalone delivery instead of the live adapter cross-loop path.plugins/platforms/mattermost/adapter.pymetadata.thread_id/metadata.root_idas the effective threaded reply root whenreply_tois absent.User-Agentheader for REST and file-upload calls.tests/tools/test_send_message_target_parse.pytests/cron/test_scheduler.pymattermost:<channel_id>:<root_post_id>cron delivery target parsing.tests/gateway/test_mattermost.pymetadata.thread_id-> Mattermostroot_idbehavior.How to Test
Regression tests run locally:
Result:
I also verified the fix against a live Mattermost gateway after restarting the Hermes gateway process:
send_message(target="mattermost:<channel_id>:<root_post_id>")succeeded and the Mattermost API showedroot_id=<root_post_id>.mattermost:<channel_id>:<root_post_id>succeeded and preservedroot_id.deliver=originback to a Mattermost DM thread succeeded and preservedroot_id.Checklist
Code
fix(scope):,feat(scope):, etc.)pytest tests/ -qand all tests passDocumentation and Housekeeping
docs/, docstrings) — or N/Acli-config.yaml.exampleif I added/changed config keys — or N/ACONTRIBUTING.mdorAGENTS.mdif I changed architecture or workflows — or N/AScreenshots / Logs
Targeted regression test output: