From 5d90386baab5cc6355d7e73e30571466c9223a6d Mon Sep 17 00:00:00 2001 From: Siddharth Balyan <52913345+alt-glitch@users.noreply.github.com> Date: Wed, 13 May 2026 19:28:50 +0530 Subject: [PATCH] fix(gateway): add lazy_deps.ensure() to slack, matrix, dingtalk, feishu adapters (#25014) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only Discord and Telegram had lazy-install hooks in their check_*_requirements() functions. The remaining four platforms that were moved to lazy_deps (Slack, Matrix, DingTalk, Feishu) would just return False immediately if their packages weren't pre-installed — no attempt to install them at runtime. This means even with the .venv permissions fix (#24841), these four platforms would still fail to load in Docker (or any fresh install) unless the user manually ran pip install. Add the same lazy_deps.ensure() pattern to all four, matching the existing Discord/Telegram implementation. --- gateway/platforms/dingtalk.py | 28 ++++++++++++++++++++++++++-- gateway/platforms/feishu.py | 21 +++++++++++++++++++-- gateway/platforms/matrix.py | 19 ++++++++++++++----- gateway/platforms/slack.py | 26 ++++++++++++++++++++++++-- tools/lazy_deps.py | 1 + 5 files changed, 84 insertions(+), 11 deletions(-) diff --git a/gateway/platforms/dingtalk.py b/gateway/platforms/dingtalk.py index 579c382c704..06b30db7b04 100644 --- a/gateway/platforms/dingtalk.py +++ b/gateway/platforms/dingtalk.py @@ -111,9 +111,33 @@ DINGTALK_TYPE_MAPPING = { def check_dingtalk_requirements() -> bool: - """Check if DingTalk dependencies are available and configured.""" + """Check if DingTalk dependencies are available and configured. + + Lazy-installs dingtalk-stream via ``tools.lazy_deps.ensure("platform.dingtalk")`` + on first call if not present. + """ + global DINGTALK_STREAM_AVAILABLE, dingtalk_stream, ChatbotMessage, CallbackMessage, AckMessage + global HTTPX_AVAILABLE, httpx if not DINGTALK_STREAM_AVAILABLE or not HTTPX_AVAILABLE: - return False + try: + from tools.lazy_deps import ensure as _lazy_ensure + _lazy_ensure("platform.dingtalk", prompt=False) + except Exception: + return False + try: + import dingtalk_stream as _ds + from dingtalk_stream import ChatbotMessage as _CM + from dingtalk_stream.frames import CallbackMessage as _CBM, AckMessage as _AM + import httpx as _httpx + except ImportError: + return False + dingtalk_stream = _ds + ChatbotMessage = _CM + CallbackMessage = _CBM + AckMessage = _AM + httpx = _httpx + DINGTALK_STREAM_AVAILABLE = True + HTTPX_AVAILABLE = True if not os.getenv("DINGTALK_CLIENT_ID") or not os.getenv("DINGTALK_CLIENT_SECRET"): return False return True diff --git a/gateway/platforms/feishu.py b/gateway/platforms/feishu.py index ae3f7075104..e7be062e84c 100644 --- a/gateway/platforms/feishu.py +++ b/gateway/platforms/feishu.py @@ -1343,8 +1343,25 @@ def _run_official_feishu_ws_client(ws_client: Any, adapter: Any) -> None: def check_feishu_requirements() -> bool: - """Check if Feishu/Lark dependencies are available.""" - return FEISHU_AVAILABLE + """Check if Feishu/Lark dependencies are available. + + Lazy-installs lark-oapi via ``tools.lazy_deps.ensure("platform.feishu")`` + on first call if not present. + """ + global FEISHU_AVAILABLE + if FEISHU_AVAILABLE: + return True + try: + from tools.lazy_deps import ensure as _lazy_ensure + _lazy_ensure("platform.feishu", prompt=False) + except Exception: + return False + try: + import lark_oapi # noqa: F401 + except ImportError: + return False + FEISHU_AVAILABLE = True + return True class FeishuAdapter(BasePlatformAdapter): diff --git a/gateway/platforms/matrix.py b/gateway/platforms/matrix.py index 0133dc2dac7..12075e67837 100644 --- a/gateway/platforms/matrix.py +++ b/gateway/platforms/matrix.py @@ -224,7 +224,11 @@ def _check_e2ee_deps() -> bool: def check_matrix_requirements() -> bool: - """Return True if the Matrix adapter can be used.""" + """Return True if the Matrix adapter can be used. + + Lazy-installs mautrix via ``tools.lazy_deps.ensure("platform.matrix")`` + on first call if not present. + """ token = os.getenv("MATRIX_ACCESS_TOKEN", "") password = os.getenv("MATRIX_PASSWORD", "") homeserver = os.getenv("MATRIX_HOMESERVER", "") @@ -238,10 +242,15 @@ def check_matrix_requirements() -> bool: try: import mautrix # noqa: F401 except ImportError: - logger.warning( - "Matrix: mautrix not installed. Run: pip install 'mautrix[encryption]'" - ) - return False + try: + from tools.lazy_deps import ensure as _lazy_ensure + _lazy_ensure("platform.matrix", prompt=False) + import mautrix # noqa: F401, F811 + except Exception: + logger.warning( + "Matrix: mautrix not installed. Run: pip install 'mautrix[encryption]'" + ) + return False # If encryption is requested, verify E2EE deps are available at startup # rather than silently degrading to plaintext-only at connect time. diff --git a/gateway/platforms/slack.py b/gateway/platforms/slack.py index 7fbefd446ca..432b01d80bf 100644 --- a/gateway/platforms/slack.py +++ b/gateway/platforms/slack.py @@ -73,8 +73,30 @@ class _ThreadContextCache: def check_slack_requirements() -> bool: - """Check if Slack dependencies are available.""" - return SLACK_AVAILABLE + """Check if Slack dependencies are available. + + Lazy-installs slack-bolt/slack-sdk via ``tools.lazy_deps.ensure("platform.slack")`` + on first call if not present. + """ + global SLACK_AVAILABLE, AsyncApp, AsyncSocketModeHandler, AsyncWebClient + if SLACK_AVAILABLE: + return True + try: + from tools.lazy_deps import ensure as _lazy_ensure + _lazy_ensure("platform.slack", prompt=False) + except Exception: + return False + try: + from slack_bolt.async_app import AsyncApp as _App + from slack_bolt.adapter.socket_mode.async_handler import AsyncSocketModeHandler as _Handler + from slack_sdk.web.async_client import AsyncWebClient as _Client + except ImportError: + return False + AsyncApp = _App + AsyncSocketModeHandler = _Handler + AsyncWebClient = _Client + SLACK_AVAILABLE = True + return True def _extract_text_from_slack_blocks(blocks: list) -> str: diff --git a/tools/lazy_deps.py b/tools/lazy_deps.py index d086d117307..6e298c23320 100644 --- a/tools/lazy_deps.py +++ b/tools/lazy_deps.py @@ -120,6 +120,7 @@ LAZY_DEPS: dict[str, tuple[str, ...]] = { "platform.slack": ( "slack-bolt==1.27.0", "slack-sdk==3.40.1", + "aiohttp==3.13.3", ), "platform.matrix": ( "mautrix[encryption]==0.21.0",