Thêm bộ điều hợp nền tảng
Hướng dẫn này bao gồm việc thêm nền tảng nhắn tin mới vào cổng Hermes. Bộ điều hợp nền tảng kết nối Hermes với dịch vụ nhắn tin bên ngoài (Telegram, Discord, WeCom, v.v.) để người dùng có thể tương tác với đại lý thông qua dịch vụ đó.
Việc thêm bộ điều hợp nền tảng sẽ chạm vào hơn 20 tệp trên mã, cấu hình và tài liệu. Sử dụng hướng dẫn này làm danh sách kiểm tra — bản thân tệp bộ điều hợp thường chỉ chiếm 40% công việc.
Tổng quan về kiến trúc
User ↔ Messaging Platform ↔ Platform Adapter ↔ Gateway Runner ↔ AIAgent
Mọi bộ điều hợp đều mở rộng BasePlatformAdapter từ gateway/platforms/base.py và thực hiện:
connect()— Thiết lập kết nối (WebSocket, thăm dò ý kiến dài, máy chủ HTTP, v.v.)disconnect()— Tắt máy sạch sẽsend()— Gửi tin nhắn văn bản tới cuộc trò chuyệnsend_typing()— Hiển thị chỉ báo gõ (tùy chọn)get_chat_info()— Trả về siêu dữ liệu trò chuyện
Các tin nhắn gửi đến được bộ chuyển đổi nhận và chuyển tiếp qua self.handle_message(event), lớp cơ sở sẽ định tuyến đến trình chạy cổng.
Danh sách kiểm tra từng bước
1. Nền tảng Enum
Thêm nền tảng của bạn vào enum Platform trong gateway/config.py:
class Platform(str, Enum):
# ... existing platforms ...
NEWPLAT = "newplat"
2. Tệp điều hợp
Tạo gateway/platforms/newplat.py:
from gateway.config import Platform, PlatformConfig
from gateway.platforms.base import (
BasePlatformAdapter, MessageEvent, MessageType, SendResult,
)
def check_newplat_requirements() -> bool:
"""Return True if dependencies are available."""
return SOME_SDK_AVAILABLE
class NewPlatAdapter(BasePlatformAdapter):
def __init__(self, config: PlatformConfig):
super().__init__(config, Platform.NEWPLAT)
# Read config from config.extra dict
extra = config.extra or {}
self._API_key = extra.get("API_key") or os.getenv("NEWPLAT_API_KEY", "")
async def connect(self) -> bool:
# Set up connection, start polling/webhook
self._mark_connected()
return True
async def disconnect(self) -> None:
self._running = False
self._mark_disconnected()
async def send(self, chat_id, content, reply_to=None, metadata=None):
# Send message via platform API
return SendResult(success=True, message_id="...")
async def get_chat_info(self, chat_id):
return {"name": chat_id, "type": "dm"}
Đối với tin nhắn gửi đến, hãy tạo MessageEvent và gọi self.handle_message(event):
source = self.build_source(
chat_id=chat_id,
chat_name=name,
chat_type="dm", # or "group"
user_id=user_id,
user_name=user_name,
)
event = MessageEvent(
text=content,
message_type=MessageType.TEXT,
source=source,
message_id=msg_id,
)
await self.handle_message(event)
3. Cấu hình cổng (gateway/config.py)
Ba điểm tiếp xúc:
get_connected_platforms()— Thêm kiểm tra thông tin xác thực cần thiết cho nền tảng của bạnload_gateway_config()— Thêm mục nhập bản đồ env mã thông báo:Platform.NEWPLAT: "NEWPLAT_TOKEN"_apply_env_overrides()— Ánh xạ tất cả các biến envNEWPLAT_*vào cấu hình
4. Chạy cổng (gateway/run.py)
Năm điểm tiếp xúc:
_create_adapter()— Thêm nhánhelif platform == Platform.NEWPLAT:- Bản đồ người dùng được phép
_is_user_authoriZed()—Platform.NEWPLAT: "NEWPLAT_ALLOWED_USERS" _is_user_authoriZed()cho phép_tất cả bản đồ —Platform.NEWPLAT: "NEWPLAT_ALLOW_ALL_USERS"- Kiểm tra sớm bộ dữ liệu
_any_allowlist— Thêm"NEWPLAT_ALLOWED_USERS" - Kiểm tra sớm bộ dữ liệu
_allow_all— Thêm"NEWPLAT_ALLOW_ALL_USERS" - Bộ đông lạnh
_UPDATE_ALLOWED_PLATFORMS— ThêmPlatform.NEWPLAT
5. Phân phối đa nền tảng
gateway/platforms/webhook.py— Thêm"newplat"vào bộ dữ liệu loại phân phốicron/scheduler.py— Thêm vào bộ đông lạnh_KNOWN_DELIVERY_PLATFORMSvà bản đồ nền tảng_deliver_result()
6. Tích hợp CLI
Hermes_CLI/config.py— Thêm tất cả các biến thểNEWPLAT_*vào_EXTRA_ENV_KEYSHermes_CLI/gateway.py— Thêm mục vào danh sách_PLATFORMSvới khóa, nhãn, biểu tượng cảm xúc, token_var, setup_instructions và varsHermes_CLI/platforms.py— Thêm mục nhậpPlatformInfocó nhãn và default_toolset (được sử dụng bởiskills_configvàtools_configTUI)Hermes_CLI/setup.py— Thêm chức năng_setup_newplat()(có thể ủy quyền chogateway.py) và thêm bộ dữ liệu vào danh sách nền tảng nhắn tinHermes_CLI/status.py— Thêm mục phát hiện nền tảng:"NewPlat": ("NEWPLAT_TOKEN", "NEWPLAT_HOME_CHANNEL")Hermes_CLI/dump.py— Thêm"newplat": "NEWPLAT_TOKEN"vào lệnh phát hiện nền tảng
7. Công cụ
tools/send_message_tool.py— Thêm"newplat": Platform.NEWPLATvào bản đồ nền tảngtools/cronjob_tools.py— Thêmnewplatvào chuỗi mô tả mục tiêu phân phối
8. Bộ công cụ
toolsets.py— Thêm định nghĩa bộ công cụ"Hermes-newplat"với_Hermes_CORE_TOOLStoolsets.py— Thêm"Hermes-newplat"vào danh sách bao gồm"Hermes-gateway"
9. Tùy chọn: Gợi ý về nền tảng
agent/prompt_builder.py — Nếu nền tảng của bạn có các giới hạn hiển thị cụ thể (không đánh dấu, giới hạn độ dài tin nhắn, v.v.), hãy thêm mục nhập vào lệnh _PLATFORM_HINTS. Thao tác này sẽ đưa hướng dẫn dành riêng cho nền tảng vào lời nhắc của hệ thống:
_PLATFORM_HINTS = {
# ...
"newplat": (
"You are chatting via NewPlat. It supports markdown formatting "
"but has a 4000-character message limit."
),
}
Không phải tất cả các nền tảng đều cần gợi ý — chỉ thêm một gợi ý nếu hành vi của tổng đài viên sẽ khác.
10. Kiểm tra
Tạo tests/gateway/test_newplat.py bao gồm:
- Xây dựng bộ chuyển đổi từ cấu hình
- Xây dựng sự kiện tin nhắn
- Phương thức gửi (giả lập API bên ngoài)
- Các tính năng dành riêng cho nền tảng (mã hóa, định tuyến, v.v.)
11. Tài liệu| Tập tin | Thêm gì |
|------|-------------|
| website/docs/user-guide/messaging/newplat.md | Trang thiết lập nền tảng đầy đủ |
| website/docs/user-guide/messaging/index.md | Bảng so sánh nền tảng, sơ đồ kiến trúc, bảng bộ công cụ, phần bảo mật, liên kết các bước tiếp theo |
| website/docs/reference/environment-variables.md | Tất cả NEWPLAT_* env vars |
| website/docs/reference/toolsets-reference.md | bộ công cụ Hermes-newplat |
| website/docs/integrations/index.md | Liên kết nền tảng |
| website/sidebars.ts | Mục nhập thanh bên cho trang tài liệu |
| website/docs/developer-guide/architecture.md | Số lượng bộ điều hợp + danh sách |
| website/docs/developer-guide/gateway-internals.md | Danh sách tập tin bộ điều hợp |
Kiểm tra tính chẵn lẻ
Trước khi đánh dấu PR nền tảng mới là hoàn chỉnh, hãy chạy kiểm tra tính chẵn lẻ đối với nền tảng đã được thiết lập:
# Find every .py file mentioning the reference platform
search_files "BlueBubbles" output_mode="files_only" file_glob="*.py"
# Find every .py file mentioning the new platform
search_files "newplat" output_mode="files_only" file_glob="*.py"
# Any file in the first set but not the second is a potential gap
Lặp lại cho các tệp .md và .ts. Điều tra từng khoảng trống - đó là bảng liệt kê nền tảng (cần cập nhật) hay tham chiếu dành riêng cho nền tảng (bỏ qua)?
Các mẫu phổ biến
Bộ điều hợp thăm dò ý kiến dài
Nếu bộ điều hợp của bạn sử dụng tính năng bỏ phiếu dài (như Telegram hoặc Weixin), hãy sử dụng tác vụ vòng lặp bỏ phiếu:
async def connect(self):
self._poll_task = asyncio.create_task(self._poll_loop())
self._mark_connected()
async def _poll_loop(self):
while self._running:
messages = await self._fetch_updates()
for msg in messages:
await self.handle_message(self._build_event(msg))
Bộ điều hợp gọi lại/Webhook
Nếu nền tảng đẩy tin nhắn đến điểm cuối của bạn (như Cuộc gọi lại WeCom), hãy chạy máy chủ HTTP:
async def connect(self):
self._app = web.Application()
self._app.router.add_post("/callback", self._handle_callback)
# ... start aiohttp server
self._mark_connected()
async def _handle_callback(self, request):
event = self._build_event(await request.text())
await self._message_queue.put(event)
return web.Response(text="success") # Acknowledge immediately
Đối với các nền tảng có thời hạn phản hồi chặt chẽ (ví dụ: giới hạn 5 giây của WeCom), hãy luôn xác nhận ngay lập tức và chủ động gửi phản hồi của tổng đài viên qua API sau đó. Phiên tổng đài viên kéo dài 3–30 phút — việc trả lời nội tuyến trong cửa sổ phản hồi gọi lại là không khả thi.
Khóa mã thông báo
Nếu bộ điều hợp giữ kết nối liên tục với thông tin xác thực duy nhất, hãy thêm khóa theo phạm vi để ngăn hai hồ sơ sử dụng cùng một thông tin xác thực:
from gateway.status import acquire_scoped_lock, release_scoped_lock
async def connect(self):
if not acquire_scoped_lock("newplat", self._token):
logger.error("Token already in use by another profile")
return False
# ... connect
async def disconnect(self):
release_scoped_lock("newplat", self._token)
Triển khai tham khảo
| Bộ chuyển đổi | Mẫu | Độ phức tạp | Tài liệu tham khảo tốt cho |
|---|---|---|---|
BlueBubbles.py | REST + webhook | Trung bình | Tích hợp API REST đơn giản |
weixin.py | Thăm dò ý kiến dài + CDN | Cao | Xử lý phương tiện, mã hóa |
WeCom_callback.py | Gọi lại/webhook | Trung bình | Máy chủ HTTP, mật mã AES, đa ứng dụng |
Telegram.py | Thăm dò ý kiến dài + API Bot | Cao | Bộ điều hợp đầy đủ tính năng với các nhóm, chủ đề |