mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-25 00:51:20 +00:00
refactor(gateway): simplify Feishu websocket config helpers
Consolidate coercion functions, extract loop readiness check, and deduplicate test mock setup to improve maintainability without changing behavior. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
157d6184e3
commit
18727ca9aa
2 changed files with 30 additions and 44 deletions
|
|
@ -362,28 +362,22 @@ def _strip_markdown_to_plain_text(text: str) -> str:
|
|||
return plain.strip()
|
||||
|
||||
|
||||
def _coerce_non_negative_int(value: Any, default: int) -> int:
|
||||
def _coerce_int(value: Any, default: Optional[int] = None, min_value: int = 0) -> Optional[int]:
|
||||
"""Coerce value to int with optional default and minimum constraint."""
|
||||
try:
|
||||
parsed = int(value)
|
||||
except (TypeError, ValueError):
|
||||
return default
|
||||
return parsed if parsed >= 0 else default
|
||||
return parsed if parsed >= min_value else default
|
||||
|
||||
|
||||
def _coerce_positive_int(value: Any, default: int) -> int:
|
||||
try:
|
||||
parsed = int(value)
|
||||
except (TypeError, ValueError):
|
||||
return default
|
||||
return parsed if parsed >= 1 else default
|
||||
def _coerce_required_int(value: Any, default: int, min_value: int = 0) -> int:
|
||||
parsed = _coerce_int(value, default=default, min_value=min_value)
|
||||
return default if parsed is None else parsed
|
||||
|
||||
|
||||
def _coerce_optional_positive_int(value: Any) -> Optional[int]:
|
||||
try:
|
||||
parsed = int(value)
|
||||
except (TypeError, ValueError):
|
||||
return None
|
||||
return parsed if parsed >= 1 else None
|
||||
def _is_loop_ready(loop: Optional[asyncio.AbstractEventLoop]) -> bool:
|
||||
return loop is not None and not bool(getattr(loop, "is_closed", lambda: False)())
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
@ -970,12 +964,13 @@ def _run_official_feishu_ws_client(ws_client: Any, adapter: Any) -> None:
|
|||
return await original_connect(*args, **kwargs)
|
||||
|
||||
def _configure_with_overrides(conf: Any) -> Any:
|
||||
assert original_configure is not None
|
||||
result = original_configure(conf)
|
||||
_apply_runtime_ws_overrides()
|
||||
return result
|
||||
|
||||
ws_client_module.websockets.connect = _connect_with_overrides
|
||||
if callable(original_configure):
|
||||
if original_configure is not None:
|
||||
setattr(ws_client, "_configure", _configure_with_overrides)
|
||||
_apply_runtime_ws_overrides()
|
||||
try:
|
||||
|
|
@ -984,7 +979,7 @@ def _run_official_feishu_ws_client(ws_client: Any, adapter: Any) -> None:
|
|||
pass
|
||||
finally:
|
||||
ws_client_module.websockets.connect = original_connect
|
||||
if callable(original_configure):
|
||||
if original_configure is not None:
|
||||
setattr(ws_client, "_configure", original_configure)
|
||||
pending = [t for t in asyncio.all_tasks(loop) if not t.done()]
|
||||
for task in pending:
|
||||
|
|
@ -1100,10 +1095,10 @@ class FeishuAdapter(BasePlatformAdapter):
|
|||
str(extra.get("webhook_path") or os.getenv("FEISHU_WEBHOOK_PATH", _DEFAULT_WEBHOOK_PATH)).strip()
|
||||
or _DEFAULT_WEBHOOK_PATH
|
||||
),
|
||||
ws_reconnect_nonce=_coerce_non_negative_int(extra.get("ws_reconnect_nonce"), 30),
|
||||
ws_reconnect_interval=_coerce_positive_int(extra.get("ws_reconnect_interval"), 120),
|
||||
ws_ping_interval=_coerce_optional_positive_int(extra.get("ws_ping_interval")),
|
||||
ws_ping_timeout=_coerce_optional_positive_int(extra.get("ws_ping_timeout")),
|
||||
ws_reconnect_nonce=_coerce_required_int(extra.get("ws_reconnect_nonce"), default=30, min_value=0),
|
||||
ws_reconnect_interval=_coerce_required_int(extra.get("ws_reconnect_interval"), default=120, min_value=1),
|
||||
ws_ping_interval=_coerce_int(extra.get("ws_ping_interval"), default=None, min_value=1),
|
||||
ws_ping_timeout=_coerce_int(extra.get("ws_ping_timeout"), default=None, min_value=1),
|
||||
)
|
||||
|
||||
def _apply_settings(self, settings: FeishuAdapterSettings) -> None:
|
||||
|
|
|
|||
|
|
@ -17,6 +17,18 @@ except ImportError:
|
|||
_HAS_LARK_OAPI = False
|
||||
|
||||
|
||||
def _mock_event_dispatcher_builder(mock_handler_class):
|
||||
mock_builder = Mock()
|
||||
mock_builder.register_p2_im_message_message_read_v1 = Mock(return_value=mock_builder)
|
||||
mock_builder.register_p2_im_message_receive_v1 = Mock(return_value=mock_builder)
|
||||
mock_builder.register_p2_im_message_reaction_created_v1 = Mock(return_value=mock_builder)
|
||||
mock_builder.register_p2_im_message_reaction_deleted_v1 = Mock(return_value=mock_builder)
|
||||
mock_builder.register_p2_card_action_trigger = Mock(return_value=mock_builder)
|
||||
mock_builder.build = Mock(return_value=object())
|
||||
mock_handler_class.builder = Mock(return_value=mock_builder)
|
||||
return mock_builder
|
||||
|
||||
|
||||
class TestPlatformEnum(unittest.TestCase):
|
||||
def test_feishu_in_platform_enum(self):
|
||||
from gateway.config import Platform
|
||||
|
|
@ -269,14 +281,7 @@ class TestFeishuAdapterMessaging(unittest.TestCase):
|
|||
patch.object(adapter, "_build_lark_client", return_value=SimpleNamespace()),
|
||||
patch("gateway.platforms.feishu.web", web_module),
|
||||
):
|
||||
mock_builder = Mock()
|
||||
mock_builder.register_p2_im_message_message_read_v1 = Mock(return_value=mock_builder)
|
||||
mock_builder.register_p2_im_message_receive_v1 = Mock(return_value=mock_builder)
|
||||
mock_builder.register_p2_im_message_reaction_created_v1 = Mock(return_value=mock_builder)
|
||||
mock_builder.register_p2_im_message_reaction_deleted_v1 = Mock(return_value=mock_builder)
|
||||
mock_builder.register_p2_card_action_trigger = Mock(return_value=mock_builder)
|
||||
mock_builder.build = Mock(return_value=object())
|
||||
mock_handler_class.builder = Mock(return_value=mock_builder)
|
||||
_mock_event_dispatcher_builder(mock_handler_class)
|
||||
connected = asyncio.run(adapter.connect())
|
||||
|
||||
self.assertTrue(connected)
|
||||
|
|
@ -306,14 +311,7 @@ class TestFeishuAdapterMessaging(unittest.TestCase):
|
|||
patch.object(adapter, "_hydrate_bot_identity", new=AsyncMock()),
|
||||
patch.object(adapter, "_build_lark_client", return_value=SimpleNamespace()),
|
||||
):
|
||||
mock_builder = Mock()
|
||||
mock_builder.register_p2_im_message_message_read_v1 = Mock(return_value=mock_builder)
|
||||
mock_builder.register_p2_im_message_receive_v1 = Mock(return_value=mock_builder)
|
||||
mock_builder.register_p2_im_message_reaction_created_v1 = Mock(return_value=mock_builder)
|
||||
mock_builder.register_p2_im_message_reaction_deleted_v1 = Mock(return_value=mock_builder)
|
||||
mock_builder.register_p2_card_action_trigger = Mock(return_value=mock_builder)
|
||||
mock_builder.build = Mock(return_value=object())
|
||||
mock_handler_class.builder = Mock(return_value=mock_builder)
|
||||
_mock_event_dispatcher_builder(mock_handler_class)
|
||||
|
||||
loop = asyncio.new_event_loop()
|
||||
future = loop.create_future()
|
||||
|
|
@ -391,14 +389,7 @@ class TestFeishuAdapterMessaging(unittest.TestCase):
|
|||
patch("gateway.platforms.feishu.asyncio.sleep", side_effect=lambda delay: sleeps.append(delay)),
|
||||
patch.object(adapter, "_build_lark_client", return_value=SimpleNamespace()),
|
||||
):
|
||||
mock_builder = Mock()
|
||||
mock_builder.register_p2_im_message_message_read_v1 = Mock(return_value=mock_builder)
|
||||
mock_builder.register_p2_im_message_receive_v1 = Mock(return_value=mock_builder)
|
||||
mock_builder.register_p2_im_message_reaction_created_v1 = Mock(return_value=mock_builder)
|
||||
mock_builder.register_p2_im_message_reaction_deleted_v1 = Mock(return_value=mock_builder)
|
||||
mock_builder.register_p2_card_action_trigger = Mock(return_value=mock_builder)
|
||||
mock_builder.build = Mock(return_value=object())
|
||||
mock_handler_class.builder = Mock(return_value=mock_builder)
|
||||
_mock_event_dispatcher_builder(mock_handler_class)
|
||||
|
||||
loop = asyncio.new_event_loop()
|
||||
future = loop.create_future()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue