Skip to content

Commit 750ed4b

Browse files
Merge branch 'main' into remove-agent-experiment
2 parents 64f955b + ba7df02 commit 750ed4b

File tree

10 files changed

+414
-18
lines changed

10 files changed

+414
-18
lines changed

slack_bolt/context/assistant/assistant_utilities.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import warnings
12
from typing import Optional
23

34
from slack_sdk.web import WebClient
@@ -51,6 +52,13 @@ def is_valid(self) -> bool:
5152

5253
@property
5354
def set_status(self) -> SetStatus:
55+
warnings.warn(
56+
"AssistantUtilities.set_status is deprecated. "
57+
"Use the set_status argument directly in your listener function "
58+
"or access it via context.set_status instead.",
59+
DeprecationWarning,
60+
stacklevel=2,
61+
)
5462
return SetStatus(self.client, self.channel_id, self.thread_ts)
5563

5664
@property

slack_bolt/context/assistant/async_assistant_utilities.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import warnings
12
from typing import Optional
23

34
from slack_sdk.web.async_client import AsyncWebClient
@@ -54,6 +55,13 @@ def is_valid(self) -> bool:
5455

5556
@property
5657
def set_status(self) -> AsyncSetStatus:
58+
warnings.warn(
59+
"AsyncAssistantUtilities.set_status is deprecated. "
60+
"Use the set_status argument directly in your listener function "
61+
"or access it via context.set_status instead.",
62+
DeprecationWarning,
63+
stacklevel=2,
64+
)
5765
return AsyncSetStatus(self.client, self.channel_id, self.thread_ts)
5866

5967
@property

slack_bolt/middleware/attaching_agent_kwargs/async_attaching_agent_kwargs.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from slack_bolt.context.assistant.async_assistant_utilities import AsyncAssistantUtilities
44
from slack_bolt.context.assistant.thread_context_store.async_store import AsyncAssistantThreadContextStore
55
from slack_bolt.context.say_stream.async_say_stream import AsyncSayStream
6+
from slack_bolt.context.set_status.async_set_status import AsyncSetStatus
67
from slack_bolt.middleware.async_middleware import AsyncMiddleware
78
from slack_bolt.request.async_request import AsyncBoltRequest
89
from slack_bolt.request.payload_utils import is_assistant_event, to_event
@@ -32,7 +33,6 @@ async def async_process(
3233
thread_context_store=self.thread_context_store,
3334
)
3435
req.context["say"] = assistant.say
35-
req.context["set_status"] = assistant.set_status
3636
req.context["set_title"] = assistant.set_title
3737
req.context["set_suggested_prompts"] = assistant.set_suggested_prompts
3838
req.context["get_thread_context"] = assistant.get_thread_context
@@ -41,6 +41,11 @@ async def async_process(
4141
# TODO: in the future we might want to introduce a "proper" extract_ts utility
4242
thread_ts = req.context.thread_ts or event.get("ts")
4343
if req.context.channel_id and thread_ts:
44+
req.context["set_status"] = AsyncSetStatus(
45+
client=req.context.client,
46+
channel_id=req.context.channel_id,
47+
thread_ts=thread_ts,
48+
)
4449
req.context["say_stream"] = AsyncSayStream(
4550
client=req.context.client,
4651
channel=req.context.channel_id,

slack_bolt/middleware/attaching_agent_kwargs/attaching_agent_kwargs.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from slack_bolt.context.assistant.assistant_utilities import AssistantUtilities
44
from slack_bolt.context.assistant.thread_context_store.store import AssistantThreadContextStore
55
from slack_bolt.context.say_stream.say_stream import SayStream
6+
from slack_bolt.context.set_status.set_status import SetStatus
67
from slack_bolt.middleware import Middleware
78
from slack_bolt.request.payload_utils import is_assistant_event, to_event
89
from slack_bolt.request.request import BoltRequest
@@ -26,7 +27,6 @@ def process(self, *, req: BoltRequest, resp: BoltResponse, next: Callable[[], Bo
2627
thread_context_store=self.thread_context_store,
2728
)
2829
req.context["say"] = assistant.say
29-
req.context["set_status"] = assistant.set_status
3030
req.context["set_title"] = assistant.set_title
3131
req.context["set_suggested_prompts"] = assistant.set_suggested_prompts
3232
req.context["get_thread_context"] = assistant.get_thread_context
@@ -35,6 +35,11 @@ def process(self, *, req: BoltRequest, resp: BoltResponse, next: Callable[[], Bo
3535
# TODO: in the future we might want to introduce a "proper" extract_ts utility
3636
thread_ts = req.context.thread_ts or event.get("ts")
3737
if req.context.channel_id and thread_ts:
38+
req.context["set_status"] = SetStatus(
39+
client=req.context.client,
40+
channel_id=req.context.channel_id,
41+
thread_ts=thread_ts,
42+
)
3843
req.context["say_stream"] = SayStream(
3944
client=req.context.client,
4045
channel=req.context.channel_id,

tests/scenario_tests/test_events_assistant_without_middleware.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ def handle_message_event(
180180
):
181181
assert context.thread_ts == "1726133698.626339"
182182
assert say.thread_ts == None
183-
assert set_status is None
183+
assert set_status is not None
184184
assert set_title is None
185185
assert set_suggested_prompts is None
186186
assert get_thread_context is None
@@ -208,7 +208,7 @@ def handle_message_event(
208208
):
209209
assert context.thread_ts == "1726133698.626339"
210210
assert say.thread_ts == None
211-
assert set_status is None
211+
assert set_status is not None
212212
assert set_title is None
213213
assert set_suggested_prompts is None
214214
assert get_thread_context is None
@@ -236,7 +236,7 @@ def handle_message_event(
236236
):
237237
assert context.thread_ts == "1726133698.626339"
238238
assert say.thread_ts == None
239-
assert set_status is None
239+
assert set_status is not None
240240
assert set_title is None
241241
assert set_suggested_prompts is None
242242
assert get_thread_context is None
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
import json
2+
from threading import Event
3+
from urllib.parse import quote
4+
5+
from slack_sdk.web import WebClient
6+
7+
from slack_bolt import App, BoltContext, BoltRequest
8+
from slack_bolt.context.set_status.set_status import SetStatus
9+
from slack_bolt.middleware.assistant import Assistant
10+
from tests.mock_web_api_server import (
11+
assert_auth_test_count,
12+
assert_received_request_count,
13+
cleanup_mock_web_api_server,
14+
setup_mock_web_api_server,
15+
)
16+
from tests.scenario_tests.test_app import app_mention_event_body
17+
from tests.scenario_tests.test_events_assistant import thread_started_event_body
18+
from tests.scenario_tests.test_events_assistant import user_message_event_body as threaded_user_message_event_body
19+
from tests.scenario_tests.test_message_bot import bot_message_event_payload, user_message_event_payload
20+
from tests.scenario_tests.test_view_submission import body as view_submission_body
21+
from tests.utils import remove_os_env_temporarily, restore_os_env
22+
23+
24+
class TestEventsSetStatus:
25+
valid_token = "xoxb-valid"
26+
mock_api_server_base_url = "http://localhost:8888"
27+
web_client = WebClient(
28+
token=valid_token,
29+
base_url=mock_api_server_base_url,
30+
)
31+
32+
def setup_method(self):
33+
self.old_os_env = remove_os_env_temporarily()
34+
setup_mock_web_api_server(self)
35+
36+
def teardown_method(self):
37+
cleanup_mock_web_api_server(self)
38+
restore_os_env(self.old_os_env)
39+
40+
def test_set_status_injected_for_app_mention(self):
41+
app = App(client=self.web_client)
42+
43+
@app.event("app_mention")
44+
def handle_mention(set_status: SetStatus, context: BoltContext):
45+
assert set_status is not None
46+
assert isinstance(set_status, SetStatus)
47+
assert set_status == context.set_status
48+
assert set_status.channel_id == "C111"
49+
assert set_status.thread_ts == "1595926230.009600"
50+
set_status(status="Thinking...")
51+
52+
request = BoltRequest(body=app_mention_event_body, mode="socket_mode")
53+
response = app.dispatch(request)
54+
assert response.status == 200
55+
assert_auth_test_count(self, 1)
56+
assert_received_request_count(self, path="/assistant.threads.setStatus", min_count=1)
57+
58+
def test_set_status_injected_for_threaded_message(self):
59+
app = App(client=self.web_client)
60+
61+
@app.event("message")
62+
def handle_message(set_status: SetStatus, context: BoltContext):
63+
assert set_status is not None
64+
assert isinstance(set_status, SetStatus)
65+
assert set_status == context.set_status
66+
assert set_status.channel_id == "D111"
67+
assert set_status.thread_ts == "1726133698.626339"
68+
set_status(status="Thinking...")
69+
70+
request = BoltRequest(body=threaded_user_message_event_body, mode="socket_mode")
71+
response = app.dispatch(request)
72+
assert response.status == 200
73+
assert_auth_test_count(self, 1)
74+
assert_received_request_count(self, path="/assistant.threads.setStatus", min_count=1)
75+
76+
def test_set_status_in_user_message(self):
77+
app = App(client=self.web_client)
78+
79+
@app.message("")
80+
def handle_user_message(set_status: SetStatus, context: BoltContext):
81+
assert set_status is not None
82+
assert isinstance(set_status, SetStatus)
83+
assert set_status == context.set_status
84+
assert set_status.channel_id == "C111"
85+
assert set_status.thread_ts == "1610261659.001400"
86+
set_status(status="Thinking...")
87+
88+
request = BoltRequest(body=user_message_event_payload, mode="socket_mode")
89+
response = app.dispatch(request)
90+
assert response.status == 200
91+
assert_auth_test_count(self, 1)
92+
assert_received_request_count(self, path="/assistant.threads.setStatus", min_count=1)
93+
94+
def test_set_status_in_bot_message(self):
95+
app = App(client=self.web_client)
96+
97+
@app.message("")
98+
def handle_bot_message(set_status: SetStatus, context: BoltContext):
99+
assert set_status is not None
100+
assert isinstance(set_status, SetStatus)
101+
assert set_status == context.set_status
102+
assert set_status.channel_id == "C111"
103+
assert set_status.thread_ts == "1610261539.000900"
104+
set_status(status="Thinking...")
105+
106+
request = BoltRequest(body=bot_message_event_payload, mode="socket_mode")
107+
response = app.dispatch(request)
108+
assert response.status == 200
109+
assert_auth_test_count(self, 1)
110+
assert_received_request_count(self, path="/assistant.threads.setStatus", min_count=1)
111+
112+
def test_set_status_in_assistant_thread_started(self):
113+
app = App(client=self.web_client)
114+
assistant = Assistant()
115+
116+
@assistant.thread_started
117+
def start_thread(set_status: SetStatus, context: BoltContext):
118+
assert set_status is not None
119+
assert isinstance(set_status, SetStatus)
120+
assert set_status == context.set_status
121+
assert set_status.channel_id == "D111"
122+
assert set_status.thread_ts == "1726133698.626339"
123+
set_status(status="Thinking...")
124+
125+
app.assistant(assistant)
126+
127+
request = BoltRequest(body=thread_started_event_body, mode="socket_mode")
128+
response = app.dispatch(request)
129+
assert response.status == 200
130+
assert_auth_test_count(self, 1)
131+
assert_received_request_count(self, path="/assistant.threads.setStatus", min_count=1)
132+
133+
def test_set_status_in_assistant_user_message(self):
134+
app = App(client=self.web_client)
135+
assistant = Assistant()
136+
137+
@assistant.user_message
138+
def handle_user_message(set_status: SetStatus, context: BoltContext):
139+
assert set_status is not None
140+
assert isinstance(set_status, SetStatus)
141+
assert set_status == context.set_status
142+
assert set_status.channel_id == "D111"
143+
assert set_status.thread_ts == "1726133698.626339"
144+
set_status(status="Thinking...")
145+
146+
app.assistant(assistant)
147+
148+
request = BoltRequest(body=threaded_user_message_event_body, mode="socket_mode")
149+
response = app.dispatch(request)
150+
assert response.status == 200
151+
assert_auth_test_count(self, 1)
152+
assert_received_request_count(self, path="/assistant.threads.setStatus", min_count=1)
153+
154+
def test_set_status_is_none_for_view_submission(self):
155+
app = App(client=self.web_client, request_verification_enabled=False)
156+
listener_called = Event()
157+
158+
@app.view("view-id")
159+
def handle_view(ack, set_status, context: BoltContext):
160+
ack()
161+
assert set_status is None
162+
assert context.set_status is None
163+
listener_called.set()
164+
165+
request = BoltRequest(
166+
body=f"payload={quote(json.dumps(view_submission_body))}",
167+
)
168+
response = app.dispatch(request)
169+
assert response.status == 200
170+
assert_auth_test_count(self, 1)
171+
assert listener_called.is_set()

tests/scenario_tests_async/test_events_assistant_without_middleware.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ async def handle_message_event(
197197
):
198198
assert context.thread_ts == "1726133698.626339"
199199
assert say.thread_ts == None
200-
assert set_status is None
200+
assert set_status is not None
201201
assert set_title is None
202202
assert set_suggested_prompts is None
203203
assert get_thread_context is None
@@ -226,7 +226,7 @@ async def handle_message_event(
226226
):
227227
assert context.thread_ts == "1726133698.626339"
228228
assert say.thread_ts == None
229-
assert set_status is None
229+
assert set_status is not None
230230
assert set_title is None
231231
assert set_suggested_prompts is None
232232
assert get_thread_context is None
@@ -255,7 +255,7 @@ async def handle_message_event(
255255
):
256256
assert context.thread_ts == "1726133698.626339"
257257
assert say.thread_ts == None
258-
assert set_status is None
258+
assert set_status is not None
259259
assert set_title is None
260260
assert set_suggested_prompts is None
261261
assert get_thread_context is None

0 commit comments

Comments
 (0)