Skip to content

Commit f10f94d

Browse files
committed
refactor: remove agent from context, construct in kwargs injection instead
1 parent c2a590d commit f10f94d

7 files changed

Lines changed: 20 additions & 126 deletions

File tree

slack_bolt/context/async_context.py

Lines changed: 1 addition & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import TYPE_CHECKING, Optional
1+
from typing import Optional
22

33
from slack_sdk.web.async_client import AsyncWebClient
44

@@ -15,9 +15,6 @@
1515
from slack_bolt.context.set_title.async_set_title import AsyncSetTitle
1616
from slack_bolt.util.utils import create_copy
1717

18-
if TYPE_CHECKING:
19-
from slack_bolt.agent.async_agent import AsyncBoltAgent
20-
2118

2219
class AsyncBoltContext(BaseContext):
2320
"""Context object associated with a request from Slack."""
@@ -190,36 +187,6 @@ async def handle_button_clicks(context):
190187
self["fail"] = AsyncFail(client=self.client, function_execution_id=self.function_execution_id)
191188
return self["fail"]
192189

193-
@property
194-
def agent(self) -> "AsyncBoltAgent":
195-
"""`agent` listener argument for building AI-powered Slack agents.
196-
197-
Experimental:
198-
This API is experimental and may change in future releases.
199-
200-
@app.event("app_mention")
201-
async def handle_mention(agent):
202-
stream = await agent.chat_stream()
203-
await stream.append(markdown_text="Hello!")
204-
await stream.stop()
205-
206-
Returns:
207-
`AsyncBoltAgent` instance
208-
"""
209-
if "agent" not in self:
210-
# Deferred import: AsyncBoltAgent is only imported at runtime when accessed,
211-
# avoiding unnecessary loading when the agent property is never used.
212-
from slack_bolt.agent.async_agent import AsyncBoltAgent
213-
214-
self["agent"] = AsyncBoltAgent(
215-
client=self.client,
216-
channel_id=self.channel_id,
217-
thread_ts=self.thread_ts,
218-
team_id=self.team_id,
219-
user_id=self.user_id,
220-
)
221-
return self["agent"]
222-
223190
@property
224191
def set_title(self) -> Optional[AsyncSetTitle]:
225192
return self.get("set_title")

slack_bolt/context/base_context.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ class BaseContext(dict):
3838
"set_status",
3939
"set_title",
4040
"set_suggested_prompts",
41-
"agent",
4241
]
4342
# Note that these items are not copyable, so when you add new items to this list,
4443
# you must modify ThreadListenerRunner/AsyncioListenerRunner's _build_lazy_request method to pass the values.

slack_bolt/context/context.py

Lines changed: 1 addition & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import TYPE_CHECKING, Optional
1+
from typing import Optional
22

33
from slack_sdk import WebClient
44

@@ -15,9 +15,6 @@
1515
from slack_bolt.context.set_title import SetTitle
1616
from slack_bolt.util.utils import create_copy
1717

18-
if TYPE_CHECKING:
19-
from slack_bolt.agent.agent import BoltAgent
20-
2118

2219
class BoltContext(BaseContext):
2320
"""Context object associated with a request from Slack."""
@@ -191,36 +188,6 @@ def handle_button_clicks(context):
191188
self["fail"] = Fail(client=self.client, function_execution_id=self.function_execution_id)
192189
return self["fail"]
193190

194-
@property
195-
def agent(self) -> "BoltAgent":
196-
"""`agent` listener argument for building AI-powered Slack agents.
197-
198-
Experimental:
199-
This API is experimental and may change in future releases.
200-
201-
@app.event("app_mention")
202-
def handle_mention(agent):
203-
stream = agent.chat_stream()
204-
stream.append(markdown_text="Hello!")
205-
stream.stop()
206-
207-
Returns:
208-
`BoltAgent` instance
209-
"""
210-
if "agent" not in self:
211-
# Deferred import: BoltAgent is only imported at runtime when accessed,
212-
# avoiding unnecessary loading when the agent property is never used.
213-
from slack_bolt.agent.agent import BoltAgent
214-
215-
self["agent"] = BoltAgent(
216-
client=self.client,
217-
channel_id=self.channel_id,
218-
thread_ts=self.thread_ts,
219-
team_id=self.team_id,
220-
user_id=self.user_id,
221-
)
222-
return self["agent"]
223-
224191
@property
225192
def set_title(self) -> Optional[SetTitle]:
226193
return self.get("set_title")

slack_bolt/kwargs_injection/async_utils.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,15 @@ def build_async_required_kwargs(
8787

8888
# Defer agent creation to avoid constructing AsyncBoltAgent on every request
8989
if "agent" in required_arg_names or "args" in required_arg_names:
90-
all_available_args["agent"] = request.context.agent
90+
from slack_bolt.agent.async_agent import AsyncBoltAgent
91+
92+
all_available_args["agent"] = AsyncBoltAgent(
93+
client=request.context.client,
94+
channel_id=request.context.channel_id,
95+
thread_ts=request.context.thread_ts,
96+
team_id=request.context.team_id,
97+
user_id=request.context.user_id,
98+
)
9199
if "agent" in required_arg_names:
92100
warnings.warn(
93101
"The agent listener argument is experimental and may change in future versions.",

slack_bolt/kwargs_injection/utils.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,15 @@ def build_required_kwargs(
8686

8787
# Defer agent creation to avoid constructing BoltAgent on every request
8888
if "agent" in required_arg_names or "args" in required_arg_names:
89-
all_available_args["agent"] = request.context.agent
89+
from slack_bolt.agent.agent import BoltAgent
90+
91+
all_available_args["agent"] = BoltAgent(
92+
client=request.context.client,
93+
channel_id=request.context.channel_id,
94+
thread_ts=request.context.thread_ts,
95+
team_id=request.context.team_id,
96+
user_id=request.context.user_id,
97+
)
9098
if "agent" in required_arg_names:
9199
warnings.warn(
92100
"The agent listener argument is experimental and may change in future versions.",

tests/scenario_tests/test_events_agent.py

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -80,33 +80,6 @@ def handle_action(ack, agent: BoltAgent):
8080
assert response.status == 200
8181
assert_target_called()
8282

83-
def test_agent_accessible_via_context(self):
84-
app = App(client=self.web_client)
85-
86-
state = {"called": False}
87-
88-
def assert_target_called():
89-
count = 0
90-
while state["called"] is False and count < 20:
91-
sleep(0.1)
92-
count += 1
93-
assert state["called"] is True
94-
state["called"] = False
95-
96-
@app.event("app_mention")
97-
def handle_mention(context: BoltContext):
98-
agent = context.agent
99-
assert agent is not None
100-
assert isinstance(agent, BoltAgentDirect)
101-
# Verify the same instance is returned on subsequent access
102-
assert context.agent is agent
103-
state["called"] = True
104-
105-
request = BoltRequest(body=app_mention_event_body, mode="socket_mode")
106-
response = app.dispatch(request)
107-
assert response.status == 200
108-
assert_target_called()
109-
11083
def test_agent_kwarg_emits_experimental_warning(self):
11184
app = App(client=self.web_client)
11285

tests/scenario_tests_async/test_events_agent.py

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -86,34 +86,6 @@ async def handle_action(ack, agent: AsyncBoltAgent):
8686
assert response.status == 200
8787
await assert_target_called()
8888

89-
@pytest.mark.asyncio
90-
async def test_agent_accessible_via_context(self):
91-
app = AsyncApp(client=self.web_client)
92-
93-
state = {"called": False}
94-
95-
async def assert_target_called():
96-
count = 0
97-
while state["called"] is False and count < 20:
98-
await asyncio.sleep(0.1)
99-
count += 1
100-
assert state["called"] is True
101-
state["called"] = False
102-
103-
@app.event("app_mention")
104-
async def handle_mention(context: AsyncBoltContext):
105-
agent = context.agent
106-
assert agent is not None
107-
assert isinstance(agent, AsyncBoltAgent)
108-
# Verify the same instance is returned on subsequent access
109-
assert context.agent is agent
110-
state["called"] = True
111-
112-
request = AsyncBoltRequest(body=app_mention_event_body, mode="socket_mode")
113-
response = await app.async_dispatch(request)
114-
assert response.status == 200
115-
await assert_target_called()
116-
11789
@pytest.mark.asyncio
11890
async def test_agent_kwarg_emits_experimental_warning(self):
11991
app = AsyncApp(client=self.web_client)

0 commit comments

Comments
 (0)