Skip to content

Slack: "is thinking..." status indicator gets stuck when agent ends without sending a reply #32295

@luisolave11

Description

@luisolave11

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.

screenshot showing stuck indicator

Reproduction

  1. Send a message that triggers the agent in a Slack thread where the adapter calls send_typing() (DM or @mention).
  2. 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.).
  3. 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:

  1. _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.
  2. 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).

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium — degraded but workaround existscomp/gatewayGateway runner, session dispatch, deliveryplatform/slackSlack app adaptertype/bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions