Summary
Slack's is thinking... status indicator (set via assistant.threads.setStatus) can get stuck on a thread when no agent is actually running. The bot appears to be "thinking" indefinitely until the next reply lands in that thread.

Reproduction
- Send a message that triggers the agent in a Slack thread where the adapter calls
send_typing() (DM or @mention).
- Interrupt / kill / crash the agent before it sends its final reply (gateway restart mid-turn,
/stop while pending, exception in the agent loop after send_typing but before the final send, etc.).
- The Slack thread now shows
Hermes is thinking... forever — even though _running_agents is empty.
Sending /stop returns gateway.stop.no_active but does not clear the status indicator, because _handle_stop_command only clears typing on the "agent was running" branch.
Root cause
gateway/platforms/slack.py:
send_typing() (line ~902) calls assistant.threads.setStatus(status="is thinking...") and records chat_id → thread_ts in self._active_status_threads.
stop_typing() (line ~931) clears the status, but is only invoked from:
- the
send() success path (line ~810), and
- the
send() finalize branch (line ~890).
If the agent never reaches a successful send() for that thread (interrupt, crash, gateway restart, exception in tool call → no final reply), the status stays set server-side on Slack. The Slack API persists assistant statuses on the thread until explicitly cleared or until the bot posts in the thread, so a gateway restart does not fix it — only a subsequent successful reply does.
Additionally, _handle_stop_command (gateway/run.py:9516) does not call adapter.stop_typing() when _running_agents has no entry for the session — so /stop cannot rescue a stuck indicator either.
Proposed fix
Belt-and-suspenders, in two places:
_handle_stop_command: always call adapter.stop_typing(chat_id) before returning, regardless of whether an agent was active. Cheap no-op for platforms without server-persisted status.
- Slack adapter teardown / agent-exit cleanup: also clear status in the gateway's "agent finished without sending" code path (the same place
_running_agents is cleared on exception / interrupt). The Slack adapter already tracks _active_status_threads — pop and clear it whenever the agent's run ends without a send(), not only on successful reply.
Optionally: a watchdog that auto-clears entries in _active_status_threads older than N seconds with no corresponding running agent.
Affected versions
Reproduces on main (May 2026). Affects Slack DMs and @mention threads where assistant:write scope is granted.
Workaround
Send any message to the bot in that thread — the next successful send() clears the status. Restarting the gateway does NOT clear it (status is server-side on Slack).
Reported via dogfooding (Hermes ↔ Slack).
Summary
Slack's
is thinking...status indicator (set viaassistant.threads.setStatus) can get stuck on a thread when no agent is actually running. The bot appears to be "thinking" indefinitely until the next reply lands in that thread.Reproduction
send_typing()(DM or @mention)./stopwhile pending, exception in the agent loop aftersend_typingbut before the finalsend, etc.).Hermes is thinking...forever — even though_running_agentsis empty.Sending
/stopreturnsgateway.stop.no_activebut does not clear the status indicator, because_handle_stop_commandonly clears typing on the "agent was running" branch.Root cause
gateway/platforms/slack.py:send_typing()(line ~902) callsassistant.threads.setStatus(status="is thinking...")and recordschat_id → thread_tsinself._active_status_threads.stop_typing()(line ~931) clears the status, but is only invoked from:send()success path (line ~810), andsend()finalize branch (line ~890).If the agent never reaches a successful
send()for that thread (interrupt, crash, gateway restart, exception in tool call → no final reply), the status stays set server-side on Slack. The Slack API persists assistant statuses on the thread until explicitly cleared or until the bot posts in the thread, so a gateway restart does not fix it — only a subsequent successful reply does.Additionally,
_handle_stop_command(gateway/run.py:9516) does not calladapter.stop_typing()when_running_agentshas no entry for the session — so/stopcannot rescue a stuck indicator either.Proposed fix
Belt-and-suspenders, in two places:
_handle_stop_command: always calladapter.stop_typing(chat_id)before returning, regardless of whether an agent was active. Cheap no-op for platforms without server-persisted status._running_agentsis cleared on exception / interrupt). The Slack adapter already tracks_active_status_threads— pop and clear it whenever the agent's run ends without asend(), not only on successful reply.Optionally: a watchdog that auto-clears entries in
_active_status_threadsolder than N seconds with no corresponding running agent.Affected versions
Reproduces on
main(May 2026). Affects Slack DMs and @mention threads whereassistant:writescope is granted.Workaround
Send any message to the bot in that thread — the next successful
send()clears the status. Restarting the gateway does NOT clear it (status is server-side on Slack).Reported via dogfooding (Hermes ↔ Slack).