Skip to content

fix(mattermost): honor metadata.thread_id for thread replies#12096

Open
YangManBOBO wants to merge 1 commit into
NousResearch:mainfrom
YangManBOBO:fix/issue-12063-mattermost-thread-metadata
Open

fix(mattermost): honor metadata.thread_id for thread replies#12096
YangManBOBO wants to merge 1 commit into
NousResearch:mainfrom
YangManBOBO:fix/issue-12063-mattermost-thread-metadata

Conversation

@YangManBOBO

Copy link
Copy Markdown

Summary

  • MattermostAdapter.send now maps gateway metadata.thread_id to API root_id when reply_mode is thread, matching gateway/delivery.py behavior
  • Explicit reply_to still takes precedence over metadata.thread_id

Test plan

  • Ran tests/gateway/test_mattermost.py::TestMattermostSend (new tests for metadata thread and reply_to precedence)

Closes #12063.

网关投递路径通过 metadata 传递 thread_id;在 reply_mode 为 thread 时将其映射为 Mattermost posts 的 root_id,并保留 reply_to 优先于 metadata。
@briandevans

Copy link
Copy Markdown
Contributor

Hi @YangManBOBO — dropping by from #12076 (Teknium closed mine as a duplicate of this one). Your fix shape matches what I landed on, and I'm happy to defer to your version. Two edge-case observations from my tests that might be worth adding to yours if you have cycles:

  1. Non-mapping metadata values. If a caller passes metadata=[] or metadata="whatever" (theoretically out-of-contract but happens when callers stringify a payload), metadata.get("thread_id") would raise AttributeError. My fix handled it with an isinstance(metadata, dict) guard before the .get(). Small defensive pin:

    if not root_post_id and isinstance(metadata, dict):
        tid = metadata.get("thread_id")
        ...

    Test: test_send_invalid_metadata_type_ignored — asserts metadata={"bad"} (set) or metadata="str" doesn't crash.

  2. Multi-chunk consistency. Long messages chunk into multiple posts via truncate_message(...). All chunks should carry the same root_id so the whole reply lands in-thread as one conversation, not with chunk 1 threaded and chunks 2+ at channel root. Your diff already handles this correctly (since root_post_id is computed once outside the chunk loop), but a test pinning that invariant guards against future refactors breaking it:

    # force chunking by posting > MAX_POST_LENGTH
    await adapter.send(chat_id, "x" * (MAX_POST_LENGTH + 100), metadata={"thread_id": "rid"})
    # assert every captured post payload has root_id == "rid"

Feel free to cherry-pick / ignore — whatever you think is useful. Cheers!

@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/gateway Gateway runner, session dispatch, delivery labels Apr 24, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Related to #6617 and #12299 — competing Mattermost threading fixes. All address #12063.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery P2 Medium — degraded but workaround exists type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Mattermost adapter ignores metadata.thread_id, so gateway thread replies post to channel root

3 participants