Skip to content

fix(tools): forward thread_ts to chat.postMessage so 3-segment Slack targets thread - #32496

Closed
bejewel-sangwon wants to merge 1 commit into
NousResearch:mainfrom
bejewel-sangwon:fix/slack-thread-ts-drop
Closed

fix(tools): forward thread_ts to chat.postMessage so 3-segment Slack targets thread#32496
bejewel-sangwon wants to merge 1 commit into
NousResearch:mainfrom
bejewel-sangwon:fix/slack-thread-ts-drop

Conversation

@bejewel-sangwon

Copy link
Copy Markdown

What does this PR do?

send_message(target="slack:<channel>:<thread_ts>") was silently posting to the channel root instead of threading under the given parent. The 3-segment Slack target syntax existed and was parsed, but the thread_ts was dropped on the way to chat.postMessage.

Two consecutive layers were responsible:

  1. In _send_to_platform (tools/send_message_tool.py), the Slack branch did not forward thread_id to _send_slack. Every other platform branch (Telegram, Discord, Matrix, Feishu, Signal, Yuanbao) does.
  2. _send_slack itself did not include thread_ts on the chat.postMessage payload at all.

Net effect: any caller passing slack:<channel>:<thread_ts> got the parsing-side validation to pass but the message still landed at the channel root. This surfaced as multi-bot conversation chains "splitting" across multiple threads in environments that rely on send_message to keep replies inside the originating thread.

Related Issue

N/A — discovered while debugging cross-bot Slack threading in a self-hosted gateway deployment.

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)

Changes Made

  • tools/send_message_tool.py:
    • _send_to_platform Slack branch now forwards thread_id to _send_slack.
    • _send_slack gains a thread_id parameter and, when set, includes thread_ts on the chat.postMessage payload.
  • tests/tools/test_send_message_tool.py:
    • New: test_slack_thread_id_forwarded_to_send_slack
    • New: test_slack_send_slack_includes_thread_ts_in_payload
    • New: test_slack_send_slack_omits_thread_ts_when_no_thread_id
    • Updated: test_slack_messages_are_formatted_before_send to assert the new thread_id=None keyword argument.

How to Test

scripts/run_tests.sh tests/tools/test_send_message_tool.py

All 124 tests pass locally (4.8s on macOS 15.x).

Manual repro of the original bug (pre-fix):

# Before: posts to channel root regardless of the :thread_ts suffix
send_message(action="send",
             target="slack:C0B4N9Z121E:1779330010.215119",
             message="reply inside the thread")
# After: actually threads under 1779330010.215119

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix (no unrelated commits)
  • I've run scripts/run_tests.sh tests/tools/test_send_message_tool.py and all 124 tests pass
  • I've added tests for my changes (3 new + 1 updated)
  • I've tested on my platform: macOS 15.x

Documentation & Housekeeping

  • I've updated relevant documentation (docstrings) — _send_slack docstring now documents the new parameter
  • I've updated cli-config.yaml.example if I added/changed config keys — N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — N/A
  • I've considered cross-platform impact — N/A (network call only, no OS-specific code)
  • I've updated tool descriptions/schemas if I changed tool behavior — N/A (no schema change, behavior now matches the existing SEND_MESSAGE_SCHEMA description that already documents 3-segment targets)

…targets thread

send_message(target='slack:<channel>:<thread_ts>') was silently
degrading to a channel-root post because _send_to_platform did not
forward thread_id to _send_slack, and _send_slack did not include
thread_ts on the chat.postMessage payload.

Every other platform branch (Telegram, Discord, Matrix, Feishu,
Signal, Yuanbao) already forwards thread_id. Slack was the only
exception.

Behavior change:
- Slack 3-segment targets now thread correctly under the given parent.
- 2-segment targets (slack:<channel>) keep existing channel-root
  behavior — payload omits thread_ts when thread_id is None.

Tests:
- test_slack_thread_id_forwarded_to_send_slack: verifies
  _send_to_platform passes thread_id keyword to _send_slack.
- test_slack_send_slack_includes_thread_ts_in_payload: verifies
  thread_ts lands on the chat.postMessage payload when set.
- test_slack_send_slack_omits_thread_ts_when_no_thread_id: verifies
  the channel-root path stays clean when no thread_id is provided.
- test_slack_messages_are_formatted_before_send: updated to assert
  the new thread_id=None keyword argument.

All 124 tests in tests/tools/test_send_message_tool.py pass.
@bejewel-sangwon

Copy link
Copy Markdown
Author

Closing as duplicate of #23764 (same author, same fix, opened 2026-05-11). I missed it during my pre-submit search — apologies for the noise. Will move my test additions (3 new unit tests for thread_ts payload) as a review comment on #23764 if helpful.

@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/gateway Gateway runner, session dispatch, delivery platform/slack Slack app adapter tool/web Web search and extraction labels May 26, 2026
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 platform/slack Slack app adapter tool/web Web search and extraction type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants