Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Use listener registry for assistant ordering
  • Loading branch information
Cr1stal committed May 31, 2026
commit 32e48e0445789fac3808edf391dc86ca4f0bc21b
8 changes: 3 additions & 5 deletions slack_bolt/app/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
CallableAuthorize,
)

from slack_bolt.app.listener_registry import ListenerRegistry
from slack_bolt.context.assistant.thread_context_store.store import AssistantThreadContextStore

from slack_bolt.error import BoltError, BoltUnhandledRequestError
Expand Down Expand Up @@ -348,8 +349,7 @@ def message_hello(message, say):
# --------------------------------------

self._middleware_list: List[Middleware] = []
self._listeners: List[Listener] = []
self._assistant_listener_insertion_index = 0
self._listeners: ListenerRegistry[Listener] = ListenerRegistry()

if listener_executor is None:
listener_executor = ThreadPoolExecutor(max_workers=5)
Expand Down Expand Up @@ -706,9 +706,7 @@ def _register_assistant_listeners(self, assistant: Assistant) -> None:
self._assistant_thread_context_store = assistant.thread_context_store

def register_listener(listener: Listener) -> None:
# Keep Assistant listeners before catch-all listeners while preserving Assistant registration order.
self._listeners.insert(self._assistant_listener_insertion_index, listener)
self._assistant_listener_insertion_index += 1
self._listeners.append_assistant(listener)

assistant._register_app_listeners(register_listener)

Expand Down
8 changes: 3 additions & 5 deletions slack_bolt/app/async_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from aiohttp import web

from slack_bolt.app.async_server import AsyncSlackAppServer
from slack_bolt.app.listener_registry import ListenerRegistry
from slack_bolt.context.assistant.thread_context_store.async_store import (
AsyncAssistantThreadContextStore,
)
Expand Down Expand Up @@ -360,8 +361,7 @@ async def message_hello(message, say): # async function
# --------------------------------------

self._async_middleware_list: List[AsyncMiddleware] = []
self._async_listeners: List[AsyncListener] = []
self._assistant_listener_insertion_index = 0
self._async_listeners: ListenerRegistry[AsyncListener] = ListenerRegistry()

self._assistant_thread_context_store = assistant_thread_context_store
self._attaching_conversation_kwargs_enabled = attaching_conversation_kwargs_enabled
Expand Down Expand Up @@ -733,9 +733,7 @@ def _register_assistant_listeners(self, assistant: AsyncAssistant) -> None:
self._assistant_thread_context_store = assistant.thread_context_store

def register_listener(listener: AsyncListener) -> None:
# Keep Assistant listeners before catch-all listeners while preserving Assistant registration order.
self._async_listeners.insert(self._assistant_listener_insertion_index, listener)
self._assistant_listener_insertion_index += 1
self._async_listeners.append_assistant(listener)

assistant._register_app_listeners(register_listener)

Expand Down
33 changes: 33 additions & 0 deletions slack_bolt/app/listener_registry.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from typing import Generic, Iterator, List, TypeVar, Union, overload

ListenerT = TypeVar("ListenerT")


class ListenerRegistry(Generic[ListenerT]):
def __init__(self) -> None:
self._assistant_listeners: List[ListenerT] = []
self._listeners: List[ListenerT] = []

def append(self, listener: ListenerT) -> None:
self._listeners.append(listener)

def append_assistant(self, listener: ListenerT) -> None:
self._assistant_listeners.append(listener)

def __iter__(self) -> Iterator[ListenerT]:
yield from self._assistant_listeners
yield from self._listeners

def __len__(self) -> int:
return len(self._assistant_listeners) + len(self._listeners)

@overload
def __getitem__(self, index: int) -> ListenerT:
pass

@overload
def __getitem__(self, index: slice) -> List[ListenerT]:
pass

def __getitem__(self, index: Union[int, slice]) -> Union[ListenerT, List[ListenerT]]:
return list(self)[index]