mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-03 17:27:37 +08:00
Add two operator-facing toggles for inbound Feishu admission, enabling
bot-to-bot scenarios such as A2A orchestration and inter-bot
notifications:
FEISHU_ALLOW_BOTS=none|mentions|all (default: none)
Accept messages from other bots. `mentions` requires the peer
bot to @-mention Hermes; `all` admits every peer-bot message.
FEISHU_REQUIRE_MENTION=true|false (default: true)
Whether group messages must @-mention the bot. Override per-chat
via `group_rules.<chat_id>.require_mention` in config.yaml.
Defaults preserve prior behavior. Self-echo protection is always on:
when the bot's identity is unresolved (auto-detection failed and
FEISHU_BOT_OPEN_ID unset), peer-bot messages are rejected fail-closed
to avoid feedback loops.
Admitted peer bots bypass the human-user allowlist
(FEISHU_ALLOWED_USERS) to match existing Discord behavior; humans
still need an explicit allowlist entry. yaml feishu.allow_bots is
bridged to the env var so the adapter and gateway auth layer share
one source of truth.
Resolving peer-bot display names requires the
application:bot.basic_info:read scope; without it, peers still route
but appear as their open_id.
Test: tests/gateway/test_feishu_bot_admission.py covers the admission
pipeline, group-policy bot-bypass, hydration, and event-dispatch
plumbing as a parametrized matrix.
Change-Id: I363cccb578c2a5c8b8bf0f0a890c01c89909e256
66 lines
2.0 KiB
Python
66 lines
2.0 KiB
Python
"""Shared fixtures for Feishu adapter tests (admission, group policy, dispatch)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import threading
|
|
from types import SimpleNamespace
|
|
from typing import Any, Optional
|
|
|
|
|
|
def make_sender(sender_type: str = "user", open_id: str = "ou_human",
|
|
user_id: Optional[str] = None, union_id: Optional[str] = None) -> Any:
|
|
return SimpleNamespace(
|
|
sender_type=sender_type,
|
|
sender_id=SimpleNamespace(open_id=open_id, user_id=user_id, union_id=union_id),
|
|
)
|
|
|
|
|
|
def make_message(message_id: str = "om_xxx", chat_type: str = "p2p",
|
|
chat_id: str = "oc_1", mentions: Optional[list] = None) -> Any:
|
|
return SimpleNamespace(
|
|
message_id=message_id,
|
|
chat_type=chat_type,
|
|
chat_id=chat_id,
|
|
mentions=mentions,
|
|
content="",
|
|
message_type="text",
|
|
)
|
|
|
|
|
|
def make_adapter_skeleton(
|
|
*,
|
|
bot_open_id: str = "ou_me",
|
|
bot_user_id: str = "",
|
|
allow_bots: str = "none",
|
|
require_mention: bool = True,
|
|
group_policy: str = "allowlist",
|
|
) -> Any:
|
|
from gateway.platforms.feishu import FeishuAdapter
|
|
|
|
adapter = object.__new__(FeishuAdapter)
|
|
adapter._bot_open_id = bot_open_id
|
|
adapter._bot_user_id = bot_user_id
|
|
adapter._bot_name = ""
|
|
adapter._app_id = ""
|
|
adapter._admins = set()
|
|
adapter._group_rules = {}
|
|
adapter._group_policy = group_policy
|
|
adapter._default_group_policy = group_policy
|
|
adapter._allowed_group_users = frozenset()
|
|
adapter._allow_bots = allow_bots
|
|
adapter._require_mention = require_mention
|
|
return adapter
|
|
|
|
|
|
def install_dedup_state(adapter: Any, seen: Optional[dict] = None) -> None:
|
|
adapter._seen_message_ids = dict(seen) if seen else {}
|
|
adapter._seen_message_order = list((seen or {}).keys())
|
|
adapter._dedup_cache_size = 100
|
|
adapter._dedup_lock = threading.Lock()
|
|
adapter._dedup_state_path = None
|
|
adapter._persist_seen_message_ids = lambda: None
|
|
|
|
|
|
def stub_mention(adapter: Any, mentions_self: bool) -> None:
|
|
adapter._mentions_self = lambda _message: mentions_self
|