From b449a0e0492aac9227bfaf62b932602419d2a400 Mon Sep 17 00:00:00 2001 From: Teknium Date: Fri, 17 Apr 2026 19:03:37 -0700 Subject: [PATCH] fix(feishu-comment): use get_hermes_home(); drop dead asyncio wrapper; AUTHOR_MAP Follow-up polish on top of the cherry-picked #11023 commit. - feishu_comment_rules.py: replace import-time "~/.hermes" expanduser fallback with get_hermes_home() from hermes_constants (canonical, profile-safe). - tools/feishu_doc_tool.py, tools/feishu_drive_tool.py: drop the asyncio.get_event_loop().run_until_complete(asyncio.to_thread(...)) dance. Tool handlers run synchronously in a worker thread with no running loop, so the RuntimeError branch was always the one that executed. Calls client.request directly now. Unused asyncio import removed. - tests/gateway/test_feishu.py: add register_p2_customized_event to the mock EventDispatcher builder so the existing adapter test matches the new handler registration for drive.notice.comment_add_v1. - scripts/release.py: map liujinkun@bytedance.com -> liujinkun2025 for contributor attribution on release notes. --- gateway/platforms/feishu_comment_rules.py | 13 +++++++++---- scripts/release.py | 1 + tests/gateway/test_feishu.py | 5 +++++ tools/feishu_doc_tool.py | 11 +++-------- tools/feishu_drive_tool.py | 10 +++------- 5 files changed, 21 insertions(+), 19 deletions(-) diff --git a/gateway/platforms/feishu_comment_rules.py b/gateway/platforms/feishu_comment_rules.py index 6ddd4776d..054ef9569 100644 --- a/gateway/platforms/feishu_comment_rules.py +++ b/gateway/platforms/feishu_comment_rules.py @@ -11,21 +11,26 @@ from __future__ import annotations import json import logging -import os import time from dataclasses import dataclass, field from pathlib import Path from typing import Any, Dict, Optional +from hermes_constants import get_hermes_home + logger = logging.getLogger(__name__) # --------------------------------------------------------------------------- # Paths # --------------------------------------------------------------------------- +# +# Uses the canonical ``get_hermes_home()`` helper (HERMES_HOME-aware and +# profile-safe). Resolved at import time; this module is lazy-imported by +# the Feishu comment event handler, which runs long after profile overrides +# have been applied, so freezing paths here is safe. -_HERMES_HOME = Path(os.environ.get("HERMES_HOME", os.path.expanduser("~/.hermes"))) -RULES_FILE = _HERMES_HOME / "feishu_comment_rules.json" -PAIRING_FILE = _HERMES_HOME / "feishu_comment_pairing.json" +RULES_FILE = get_hermes_home() / "feishu_comment_rules.json" +PAIRING_FILE = get_hermes_home() / "feishu_comment_pairing.json" # --------------------------------------------------------------------------- # Data models diff --git a/scripts/release.py b/scripts/release.py index 464620d97..8fd6dfc18 100755 --- a/scripts/release.py +++ b/scripts/release.py @@ -76,6 +76,7 @@ AUTHOR_MAP = { "Asunfly@users.noreply.github.com": "Asunfly", # contributors (manual mapping from git names) "ahmedsherif95@gmail.com": "asheriif", + "liujinkun@bytedance.com": "liujinkun2025", "dmayhem93@gmail.com": "dmahan93", "samherring99@gmail.com": "samherring99", "desaiaum08@gmail.com": "Aum08Desai", diff --git a/tests/gateway/test_feishu.py b/tests/gateway/test_feishu.py index c5a6d8a55..661e37ec1 100644 --- a/tests/gateway/test_feishu.py +++ b/tests/gateway/test_feishu.py @@ -601,6 +601,10 @@ class TestAdapterBehavior(unittest.TestCase): calls.append("message_recalled") return self + def register_p2_customized_event(self, event_key, _handler): + calls.append(f"customized:{event_key}") + return self + def build(self): calls.append("build") return "handler" @@ -628,6 +632,7 @@ class TestAdapterBehavior(unittest.TestCase): "bot_deleted", "p2p_chat_entered", "message_recalled", + "customized:drive.notice.comment_add_v1", "build", ], ) diff --git a/tools/feishu_doc_tool.py b/tools/feishu_doc_tool.py index 110501db7..f334b915e 100644 --- a/tools/feishu_doc_tool.py +++ b/tools/feishu_doc_tool.py @@ -4,7 +4,6 @@ Provides ``feishu_doc_read`` for reading document content as plain text. Uses the same lazy-import + BaseRequest pattern as feishu_comment.py. """ -import asyncio import json import logging import threading @@ -85,13 +84,9 @@ def _handle_feishu_doc_read(args: dict, **kwargs) -> str: .build() ) - try: - response = asyncio.get_event_loop().run_until_complete( - asyncio.to_thread(client.request, request) - ) - except RuntimeError: - # No running event loop -- call synchronously - response = client.request(request) + # Tool handlers run synchronously in a worker thread (no running event + # loop), so call the blocking lark client directly. + response = client.request(request) code = getattr(response, "code", None) if code != 0: diff --git a/tools/feishu_drive_tool.py b/tools/feishu_drive_tool.py index b62876b9c..5742acf05 100644 --- a/tools/feishu_drive_tool.py +++ b/tools/feishu_drive_tool.py @@ -5,7 +5,6 @@ Uses the same lazy-import + BaseRequest pattern as feishu_comment.py. The lark client is injected per-thread by the comment event handler. """ -import asyncio import json import logging import threading @@ -59,12 +58,9 @@ def _do_request(client, method, uri, paths=None, queries=None, body=None): request = builder.build() - try: - response = asyncio.get_event_loop().run_until_complete( - asyncio.to_thread(client.request, request) - ) - except RuntimeError: - response = client.request(request) + # Tool handlers run synchronously in a worker thread (no running event + # loop), so call the blocking lark client directly. + response = client.request(request) code = getattr(response, "code", None) msg = getattr(response, "msg", "")