Slack Stop button on the progress message (CHOO-2589) - #374
Conversation
An agent's Slack progress surface now carries a Stop button that interrupts the running turn, wired to the same `!interrupt` path the room command uses. The button appears on both the native streaming card (as a button-only message beside it) and the posted working message (agent_sessions: false path), and is cleaned up when the turn ends so a stale button never lingers. The adapter handles `block_actions` interactive payloads via Socket Mode (interactivity is already enabled in the manifest). A click after the turn has ended returns a soft "that turn already finished" rather than firing a command.
There was a problem hiding this comment.
🟡 Changes recommended
The Slack Stop button implementation currently breaks/degenerates in key flows (non-session-card turns and indicator repositioning), and the docs edits are under docs/official/ which is generated and will be overwritten.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR adds an interactive Stop control to Slack’s agent progress surfaces so operators can interrupt a running turn via a message button, and introduces a capability flag (supports_interactive_stop) to advertise that support at the adapter level.
Changes:
- Adds a Slack Block Kit Stop button to both the native streaming card path (via a minimal companion message) and the non-card “working” message path.
- Routes Slack Socket Mode
interactive/block_actionspayloads to the existing interrupt command flow. - Introduces
supports_interactive_stopcapability on the base collaboration adapter and exposes it via the collaboration lifecycle service.
File summaries
| File | Description |
|---|---|
| docs/official/resources/room-commands.md | Documents the Slack Stop button as an alternative to !interrupt. |
| docs/official/deploy/messaging-apps/slack.md | Updates Slack progress documentation to mention the Stop button. |
| core/tests/switch_core/bridges/collaboration/test_slack_agent_sessions.py | Adds/updates tests asserting Stop button blocks, interactive handling, and cleanup behavior. |
| core/switch_core/bridges/collaboration/slack/adapter.py | Implements Stop button blocks, block action routing, and streaming/non-streaming progress updates. |
| core/switch_core/bridges/collaboration/lifecycle_service.py | Adds a supports_interactive_stop(...) capability query. |
| core/switch_core/bridges/collaboration/adapter.py | Declares the base supports_interactive_stop capability (default False). |
Review details
- Files reviewed: 6/6 changed files
- Comments generated: 5
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Three bugs in the initial Stop button implementation: 1. _handle_block_action checked _session_owner for liveness, but that dict is only populated when agent_sessions is on. When off (the non-card path), the button always said "already finished". Now also checks _working_msg as a fallback liveness signal. 2. reposition_runtime_state used the base class's plain-text send_message, losing the Block Kit blocks. Override in SlackAdapter to repost with the correct blocks (section + actions for non-streaming, button-only for streaming). 3. The streaming early-return guard didn't compare thread_root_id, so a button posted for one thread was reused when the thread changed. Now checks thread_root_id matches before skipping. Tests cover all three: block action on the non-card path (live and idle), reposition preserving the button on both paths, and the existing race condition and repost-failure tests updated for the new override.
|
I think someone else will own this sort of stuff so dropping it |
Summary
block_actionsinteractive payloads via Socket Mode, routingswitch_interruptclicks to the existing!interruptcommand pathsupports_interactive_stopon the base adapter (False) and sets it True on Slack only, following the existing capability family patternBefore / Now
Before: interrupting a turn from Slack required typing
!interrupt @agentor/interrupt @agentin the channel.Now: the agent's progress message carries a red Stop button. Click it and the turn stops within a beat. Clicking after the turn ended gives a soft "that turn already finished" response. No Slack app manifest change needed.
Test plan
uv run pytest core/tests/switch_core/bridges/collaboration/ -q-- 994 passedruff format --check .andruff check .-- cleanmypy-- clean