Skip to content

feat: surface the set_status argument to listeners if required event details are available#1465

Merged
WilliamBergamin merged 2 commits intomainfrom
widen-set_status-availablility
Mar 19, 2026
Merged

feat: surface the set_status argument to listeners if required event details are available#1465
WilliamBergamin merged 2 commits intomainfrom
widen-set_status-availablility

Conversation

@WilliamBergamin
Copy link
Contributor

Summary

These changes aim to widen the availability of set_status to mirror the patterns established by say_stream

set_status is available on app.event and app.message listeners, if Bolt fails to extract channel or thread_ts then set_status will be None

Testing

  1. clone this branch
  2. build the project with scripts/build_pypi_package.sh
  3. Import the package in a Bolt project
  4. Play around with set_status
Sample app.py
import os
import logging
from time import sleep

from slack_bolt import App, SayStream, SetStatus
from slack_bolt.adapter.socket_mode import SocketModeHandler

logging.basicConfig(level=logging.DEBUG)

app = App(token=os.environ.get("SLACK_BOT_TOKEN"))

@app.event("app_mention")
def handle_app_mention(say_stream: SayStream, set_status: SetStatus):
  set_status(
      status="Thinking...",
      loading_messages=[
          "Waking up from my mass-production nap...",
          "Putting on my thinking cap...",
          "Consulting the ancient Stack Overflow...",
          "Bribing the servers with virtual cookies...",
          "Loading witty response... please hold...",
      ],
  )
  stream = say_stream(buffer_size=100)

  stream.append(markdown_text="*Someone rang the bat signal!* :bat:\n\n")
  sleep(5)
  stream.append(markdown_text="Oh wait, it's just an @mention. Even better!\n\n")
  stream.append(markdown_text="> Fun fact: I was mass-produced in a mass-production factory, but I like to think I'm *one of a kind*.\n\n")
  sleep(1)
  stream.append(markdown_text="Anyway, here's my *totally professional* take:\n\n")
  stream.append(markdown_text="1. `say_stream` is basically magic — words appear like I'm *actually typing* :sparkles:\n")
  sleep(1)
  stream.append(markdown_text="2. Streaming means you don't have to stare at a blank screen wondering if I ghosted you\n")
  sleep(1)
  stream.append(markdown_text="3. Bolt for Python makes building Slack apps easier than microwaving leftovers\n\n")
  sleep(0.5)
  stream.append(markdown_text="_*mic drop*_ :microphone:")
  stream.stop()

@app.message("")
def handle_ask_bot(say_stream: SayStream, set_status: SetStatus):
  set_status(
      status="Thinking...",
      loading_messages=[
          "Waking up from my mass-production nap...",
          "Putting on my thinking cap...",
          "Consulting the ancient Stack Overflow...",
          "Bribing the servers with virtual cookies...",
          "Loading witty response... please hold...",
      ],
  )
  stream = say_stream(buffer_size=100)

  stream.append(markdown_text="*Psst...* you just DMed a bot. Bold move. I respect that. :sunglasses:\n\n")
  sleep(5)
  stream.append(markdown_text="Let me consult my *vast knowledge database*...\n\n")
  stream.append(markdown_text="```\n[ scanning... ]\n[ found: 1 brain cell ]\n[ deploying it now ]\n```\n\n")
  sleep(1)
  stream.append(markdown_text="Okay here's the deal:\n\n")
  sleep(1)
  stream.append(markdown_text=":rocket: *Streaming responses* means you get to watch me think in real time — terrifying, I know\n")
  sleep(1)
  stream.append(markdown_text=":hammer_and_wrench: *Bolt for Python* is the secret sauce behind my dazzling personality\n")
  sleep(1)
  stream.append(markdown_text=":zap: *Socket Mode* keeps our conversation nice and private — no nosy webhooks here\n\n")
  sleep(0.5)
  stream.append(markdown_text="That's all I've got. Don't forget to tip your bot! :robot_face:")
  stream.stop()

if __name__ == "__main__":
  SocketModeHandler(app, os.environ.get("SLACK_APP_TOKEN")).start()
manifest.json
{
    "_metadata": {
        "major_version": 1,
        "minor_version": 1
    },
    "display_information": {
        "name": "set_status_experiment"
    },
    "features": {
        "app_home": {
            "home_tab_enabled": false,
            "messages_tab_enabled": true,
            "messages_tab_read_only_enabled": false
        },
        "bot_user": {
            "display_name": "set_status_experiment",
            "always_online": false
        }
    },
    "oauth_config": {
        "scopes": {
            "bot": [
                "app_mentions:read",
                "chat:write",
                "im:read",
                "im:write",
                "channels:history",
                "im:history"
            ]
        }
    },
    "settings": {
        "event_subscriptions": {
            "bot_events": [
                "app_mention",
                "message.im"
            ]
        },
        "interactivity": {
            "is_enabled": true
        },
        "org_deploy_enabled": true,
        "socket_mode_enabled": true,
        "token_rotation_enabled": false
    }
}

Category

  • slack_bolt.App and/or its core components
  • slack_bolt.async_app.AsyncApp and/or its core components
  • Adapters in slack_bolt.adapter
  • Document pages under /docs
  • Others

Requirements

Please read the Contributing guidelines and Code of Conduct before creating this issue or pull request. By submitting, you are agreeing to those rules.

  • I've read and understood the Contributing Guidelines and have done my best effort to follow them.
  • I've read and agree to the Code of Conduct.
  • I've run ./scripts/install_all_and_run_tests.sh after making the changes.

@codecov
Copy link

codecov bot commented Mar 19, 2026

Codecov Report

❌ Patch coverage is 75.00000% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.43%. Comparing base (7aa415f) to head (1658ec5).
⚠️ Report is 1 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...lack_bolt/context/assistant/assistant_utilities.py 50.00% 1 Missing ⚠️
...olt/context/assistant/async_assistant_utilities.py 50.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1465      +/-   ##
==========================================
- Coverage   91.47%   91.43%   -0.05%     
==========================================
  Files         232      232              
  Lines        7334     7340       +6     
==========================================
+ Hits         6709     6711       +2     
- Misses        625      629       +4     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Member

@zimeg zimeg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@WilliamBergamin LGTM! These are nice patterns being followed 🐣

Comment on lines 53 to 62
@property
def set_status(self) -> SetStatus:
warnings.warn(
"AssistantUtilities.set_status is deprecated. "
"Use the set_status argument directly in your listener function "
"or access it via context.set_status instead.",
DeprecationWarning,
stacklevel=2,
)
return SetStatus(self.client, self.channel_id, self.thread_ts)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📣 question: This deprecation is visible to callers of set_status using the assistant class? I think this has solid recommendations but want to make sure I'm not misunderstanding the scope of change!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope from what I understand this deprecation would only be visible for users that try to do something like

assistant_utils = AssistantUtilities()

assistant_utils.set_status

I'm actually considering removing def set_status(self) entirely since I think this class was intended for internal use 🤔

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@WilliamBergamin Ahha this catches confusion I had in not finding these messages! Let's save removal for upcoming breaking change since I understand type definitions might be imported from a particular path?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's save removal for upcoming breaking change since I understand type definitions might be imported from a particular path?

Yess I agree it will be safer to do this in a major

@zimeg zimeg changed the title feat: widen the availability of set_status feat: surface the set_status argument to listeners if required event details are available Mar 19, 2026
@WilliamBergamin WilliamBergamin merged commit ba7df02 into main Mar 19, 2026
16 checks passed
@WilliamBergamin WilliamBergamin deleted the widen-set_status-availablility branch March 19, 2026 20:01
@WilliamBergamin
Copy link
Contributor Author

@lukegalbraithrussell now set_status will be available on app.event and app.message listeners unless the channel or thread_ts can't be sourced from the payload 📖

This is the same behavior say_stream follows, I'm not sure how to document this 🤔

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants