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.
This commit is contained in:
Teknium 2026-04-17 19:03:37 -07:00 committed by Teknium
parent 85cdb04bd4
commit b449a0e049
5 changed files with 21 additions and 19 deletions

View file

@ -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

View file

@ -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",

View file

@ -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",
],
)

View file

@ -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,12 +84,8 @@ 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
# 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)

View file

@ -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,11 +58,8 @@ 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:
# 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)