You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Native Slack streaming silently drops the reply for top-level DMs. The agent runs, produces text, and nothing reaches the user. Channel @-mentions and threaded DM replies are unaffected.
Root cause
_handle_message_event (src/chat_sdk/adapters/slack/adapter.py) encodes a top-level DM thread id with an empty thread_ts — intentional, so open_dm subscriptions match incoming DMs.
Thread._handle_stream (src/chat_sdk/thread.py) calls adapter.stream() with no try/except. Its _fallback_stream post+edit path is reached only when the adapter has nostream method at all — not when stream() raises.
Net effect: after PR #89 a DM streaming reply fails clean instead of failing confusingly, but it is still never delivered.
Proposed fix
For an empty thread_ts, SlackAdapter.stream() should accumulate the stream and post_message once instead of raising. DMs degrade to a single non-streamed message; channels keep native streaming. This can replace the raise introduced in draft PR #89:
post_message already normalizes thread_ts or None, so an empty DM thread_ts posts as a normal message (Slack accepts that for chat.postMessage; only chat.startStream requires one).
Note
Production-tested: chinchill-api currently runs exactly this as a MultiTenantSlackAdapter subclass override. Folding it into the SDK lets that override be deleted.
Summary
Native Slack streaming silently drops the reply for top-level DMs. The agent runs, produces text, and nothing reaches the user. Channel @-mentions and threaded DM replies are unaffected.
Root cause
_handle_message_event(src/chat_sdk/adapters/slack/adapter.py) encodes a top-level DM thread id with an emptythread_ts— intentional, soopen_dmsubscriptions match incoming DMs.SlackAdapter.stream()raiseValidationErrorfor an emptythread_tsinstead of passing it tochat.startStream, which rejects it.Thread._handle_stream(src/chat_sdk/thread.py) callsadapter.stream()with notry/except. Its_fallback_streampost+edit path is reached only when the adapter has nostreammethod at all — not whenstream()raises.Net effect: after PR #89 a DM streaming reply fails clean instead of failing confusingly, but it is still never delivered.
Proposed fix
For an empty
thread_ts,SlackAdapter.stream()should accumulate the stream andpost_messageonce instead of raising. DMs degrade to a single non-streamed message; channels keep native streaming. This can replace theraiseintroduced in draft PR #89:post_messagealready normalizesthread_ts or None, so an empty DMthread_tsposts as a normal message (Slack accepts that forchat.postMessage; onlychat.startStreamrequires one).Note
Production-tested: chinchill-api currently runs exactly this as a
MultiTenantSlackAdaptersubclass override. Folding it into the SDK lets that override be deleted.