Chuyển tới nội dung chính

Nội bộ cổng

Cổng nhắn tin là một quy trình dài hạn kết nối Hermes với hơn 14 nền tảng nhắn tin bên ngoài thông qua một kiến trúc thống nhất.

Tệp chính

Tập tinMục đích
gateway/run.pyGatewayRunner — vòng lặp chính, lệnh gạch chéo, gửi tin nhắn (~7.500 dòng)
gateway/session.pySessionStore — tính bền vững của cuộc trò chuyện và xây dựng khóa phiên
gateway/delivery.pyGửi tin nhắn đi tới các nền tảng/kênh mục tiêu
gateway/pairing.pyLuồng ghép nối DM để ủy quyền người dùng
gateway/channel_directory.pyÁnh xạ ID trò chuyện thành tên mà con người có thể đọc được để phân phối định kỳ
gateway/hooks.pyKhám phá móc, tải và gửi sự kiện trong vòng đời
gateway/mirror.pyPhản chiếu tin nhắn giữa các phiên cho send_message
gateway/status.pyQuản lý khóa mã thông báo cho các phiên bản cổng có phạm vi hồ sơ
gateway/builtin_hooks/Các hook luôn được đăng ký (ví dụ: hook nhắc hệ thống BOOT.md)
gateway/platforms/Bộ điều hợp nền tảng (một bộ điều hợp cho mỗi nền tảng nhắn tin)

Tổng quan về kiến trúc

┌─────────────────────────────────────────────────┐
│ GatewayRunner │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Telegram │ │ Discord │ │ Slack │ ... │
│ │ Adapter │ │ Adapter │ │ Adapter │ │
│ └─────┬─────┘ └─────┬────┘ └─────┬────┘ │
│ │ │ │ │
│ └──────────────┼──────────────┘ │
│ ▼ │
│ _handle_message() │
│ │ │
│ ┌────────────┼────────────┐ │
│ ▼ ▼ ▼ │
│ Slash command AIAgent Queue/BG │
│ dispatch creation sessions │
│ │ │
│ ▼ │
│ SessionStore │
│ (SQLite persistence) │
└─────────────────────────────────────────────────┘

Luồng tin nhắn

Khi có tin nhắn đến từ bất kỳ nền tảng nào:

  1. Bộ điều hợp nền tảng nhận sự kiện thô, chuẩn hóa nó thành MessageEvent
  2. Bộ điều hợp cơ sở kiểm tra bảo vệ phiên hoạt động:
    • Nếu tác nhân đang chạy trong phiên này → thông báo xếp hàng, hãy đặt sự kiện ngắt
    • Nếu /approve , /deny , /stop → bỏ qua bảo vệ (gửi nội tuyến)
  3. GatewayRunner._handle_message() nhận được sự kiện:
    • Giải quyết khóa phiên thông qua _session_key_for_source() (định dạng: agent:main:{platform}:{chat_type}:{chat_id} )
    • Kiểm tra ủy quyền (xem Ủy quyền bên dưới)
    • Kiểm tra xem đó có phải là lệnh gạch chéo không → gửi đến trình xử lý lệnh
    • Kiểm tra xem tác nhân đã chạy chưa → chặn các lệnh như /stop , /status
    • Ngược lại → tạo phiên bản AIAgent và chạy cuộc trò chuyện
  4. Phản hồi được gửi lại thông qua bộ chuyển đổi nền tảng

Định dạng khóa phiên

Khóa phiên mã hóa bối cảnh định tuyến đầy đủ:

agent:main:{platform}:{chat_type}:{chat_id}

Ví dụ: agent:main:telegram:private:123456789

Các nền tảng nhận biết luồng (chủ đề diễn đàn Telegram, luồng Discord, luồng Slack) có thể bao gồm ID luồng trong phần chat_id. Không bao giờ tạo khóa phiên theo cách thủ công — luôn sử dụng build_session_key() từ gateway/session.py .

Bảo vệ tin nhắn hai cấp

Khi một tác nhân đang hoạt động tích cực, các tin nhắn đến sẽ đi qua hai bộ bảo vệ tuần tự:

  1. Cấp 1 — Bộ điều hợp cơ sở ( gateway/platforms/base.py ): Kiểm tra _active_sessions . Nếu phiên đang hoạt động, hãy xếp hàng tin nhắn vào _pending_messages và đặt sự kiện gián đoạn. Điều này sẽ bắt các tin nhắn trước khi chúng đến được người chạy cổng.

  2. Cấp 2 — Người chạy cổng ( gateway/run.py ): Kiểm tra _running_agents . Chặn các lệnh cụ thể ( /stop , /new , /queue , /status , /approve , /deny ) và định tuyến chúng một cách thích hợp. Mọi thứ khác đều kích hoạt running_agent.interrupt() .

Các lệnh phải đến được với người chạy trong khi tác nhân bị chặn (như /approve ) được gửi nội tuyến thông qua await self._message_handler(event) — chúng bỏ qua hệ thống tác vụ nền để tránh các điều kiện chạy đua.

Ủy quyềnCổng sử dụng kiểm tra ủy quyền nhiều lớp, được đánh giá theo thứ tự:

  1. Cờ cho phép tất cả trên mỗi nền tảng (ví dụ: TELEGRAM_ALLOW_ALL_USERS ) — nếu được đặt, tất cả người dùng trên nền tảng đó đều được ủy quyền
  2. Danh sách cho phép nền tảng (ví dụ: TELEGRAM_ALLOWED_USERS ) — ID người dùng được phân tách bằng dấu phẩy
  3. Ghép nối DM — người dùng đã xác thực có thể ghép nối người dùng mới thông qua mã ghép nối
  4. Cho phép tất cả toàn cầu ( GATEWAY_ALLOW_ALL_USERS ) — nếu được đặt, tất cả người dùng trên tất cả các nền tảng đều được ủy quyền
  5. Mặc định: từ chối — người dùng trái phép sẽ bị từ chối

Luồng ghép nối DM

Admin: /pair
Gateway: "Pairing code: ABC123. Share with the user."
New user: ABC123
Gateway: "Paired! You're now authorized."

Trạng thái ghép nối được duy trì trong gateway/pairing.py và vẫn tiếp tục khởi động lại.

Gửi lệnh gạch chéo

Tất cả các lệnh gạch chéo trong cổng đều đi qua cùng một đường dẫn phân giải:

  1. resolve_command() từ hermes_cli/commands.py ánh xạ đầu vào thành tên chuẩn (xử lý bí danh, khớp tiền tố)
  2. Tên chuẩn được kiểm tra theo GATEWAY_KNOWN_COMMANDS
  3. Trình xử lý trong công văn _handle_message() dựa trên tên chuẩn
  4. Một số lệnh được kiểm soát trên cấu hình ( gateway_config_gate trên CommandDef )

Người bảo vệ đặc vụ đang chạy

Các lệnh KHÔNG được thực thi trong khi tác nhân đang xử lý sẽ bị từ chối sớm:

if _quick_key in self._running_agents:
if canonical == "model":
return "⏳ Agent is running — wait for it to finish or /stop first."

Các lệnh bỏ qua ( /stop , /new , /approve , /deny , /queue , /status ) có cách xử lý đặc biệt.

Nguồn cấu hình

Cổng đọc cấu hình từ nhiều nguồn:

NguồnNó cung cấp những gì
~/.hermes/.envKhóa API, mã thông báo bot, thông tin xác thực nền tảng
~/.hermes/config.yamlCài đặt mô hình, cấu hình công cụ, tùy chọn hiển thị
Biến môi trườngGhi đè bất kỳ mục nào ở trên

Không giống như CLI (sử dụng load_cli_config() với giá trị mặc định được mã hóa cứng), cổng đọc config.yaml trực tiếp qua trình tải YAML. Điều này có nghĩa là các khóa cấu hình tồn tại trong lệnh mặc định của CLI nhưng không có trong tệp cấu hình của người dùng có thể hoạt động khác nhau giữa CLI và cổng.

Bộ điều hợp nền tảng

Mỗi nền tảng nhắn tin đều có bộ điều hợp trong gateway/platforms/ :

gateway/platforms/
├── base.py

# BaseAdapter — shared logic for all platforms
├── telegram.py

# Telegram Bot API (long polling or webhook)
├── discord.py

# Discord bot via discord.py
├── slack.py

# Slack Socket Mode
├── whatsapp.py

# WhatsApp Business Cloud API
├── signal.py

# Signal via signal-cli REST API
├── matrix.py

# Matrix via matrix-nio (optional E2EE)
├── mattermost.py

# Mattermost WebSocket API
├── email.py

# Email via IMAP/SMTP
├── sms.py

# SMS via Twilio
├── dingtalk.py

# DingTalk WebSocket
├── feishu.py

# Feishu/Lark WebSocket or webhook
├── wecom.py

# WeCom (WeChat Work) callback
├── webhook.py

# Inbound/outbound webhook adapter
├── api_server.py

# REST API server adapter
└── homeassistant.py

# Home Assistant conversation integration

Bộ điều hợp thực hiện một giao diện chung:

  • connect() / disconnect() — quản lý vòng đời
  • send_message() — gửi tin nhắn đi
  • on_message() — chuẩn hóa tin nhắn gửi đến → MessageEvent

Khóa mã thông báo

Bộ điều hợp kết nối bằng thông tin xác thực duy nhất gọi acquire_scoped_lock() trong connect()release_scoped_lock() trong disconnect() . Điều này ngăn hai hồ sơ sử dụng cùng một mã thông báo bot.

Đường dẫn giao hàng

Việc giao hàng đi ( gateway/delivery.py ) xử lý:

  • Trả lời trực tiếp — gửi phản hồi trở lại cuộc trò chuyện ban đầu
  • Phân phối kênh gia đình — định tuyến kết quả công việc định kỳ và kết quả nền tới kênh chính đã được định cấu hình
  • Phân phối mục tiêu rõ ràng — công cụ send_message chỉ định telegram:-1001234567890
  • Phân phối đa nền tảng — phân phối tới một nền tảng khác với tin nhắn ban đầu

Việc phân phối công việc định kỳ KHÔNG được phản ánh vào lịch sử phiên cổng - chúng chỉ tồn tại trong phiên định kỳ của riêng chúng. Đây là sự lựa chọn thiết kế có chủ ý để tránh vi phạm việc luân phiên thông báo.

MócMóc cổng là các mô-đun Python phản hồi các sự kiện trong vòng đời:

Sự kiện móc cổng

Sự kiệnKhi bị sa thải
gateway:startupQuá trình cổng bắt đầu
session:startPhiên trò chuyện mới bắt đầu
session:endPhiên hoàn thành hoặc hết thời gian
session:resetNgười dùng đặt lại phiên bằng /new
agent:startĐại lý bắt đầu xử lý tin nhắn
agent:stepĐại lý hoàn thành một lần lặp gọi công cụ
agent:endĐại lý kết thúc và trả lời phản hồi
command:*Bất kỳ lệnh gạch chéo nào đều được thực thi

Móc được phát hiện từ gateway/builtin_hooks/ (luôn hoạt động) và ~/.hermes/hooks/ (do người dùng cài đặt). Mỗi hook là một thư mục có tệp kê khai HOOK.yamlhandler.py .

Tích hợp nhà cung cấp bộ nhớ

Khi plugin nhà cung cấp bộ nhớ (ví dụ: Honcho) được bật:

  1. Cổng tạo AIAgent cho mỗi tin nhắn có ID phiên
  2. MemoryManager khởi tạo nhà cung cấp với ngữ cảnh phiên
  3. Các công cụ của nhà cung cấp (ví dụ: honcho_profile , viking_search ) được định tuyến thông qua:
AIAgent._invoke_tool()
→ self._memory_manager.handle_tool_call(name, args)
→ provider.handle_tool_call(name, args)

  1. Khi kết thúc/đặt lại phiên, on_session_end() kích hoạt để dọn dẹp và xóa dữ liệu cuối cùng

Vòng đời xóa bộ nhớ

Khi một phiên được đặt lại, tiếp tục hoặc hết hạn:

  1. Bộ nhớ tích hợp được xóa vào đĩa
  2. Lỗi hook on_session_end() của nhà cung cấp bộ nhớ
  3. AIAgent tạm thời chạy lượt hội thoại chỉ trong bộ nhớ
  4. Ngữ cảnh sau đó sẽ bị loại bỏ hoặc lưu trữ

Bảo trì nền

Cổng này chạy bảo trì định kỳ cùng với việc xử lý tin nhắn:

  • Cron tích tắc — kiểm tra lịch trình công việc và sa thải công việc đến hạn
  • Phiên hết hạn — dọn sạch các phiên bị bỏ rơi sau khi hết thời gian chờ
  • Xóa bộ nhớ — chủ động xóa bộ nhớ trước khi hết phiên
  • Làm mới bộ đệm — làm mới danh sách mô hình và trạng thái nhà cung cấp

Quản lý quy trình

Cổng hoạt động như một quy trình lâu dài, được quản lý thông qua:

  • hermes gateway start / hermes gateway stop — điều khiển thủ công
  • systemctl (Linux) hoặc launchctl (macOS) — quản lý dịch vụ
  • Tệp PID tại ~/.hermes/gateway.pid — theo dõi quy trình trong phạm vi hồ sơ

Trong phạm vi hồ sơ so với toàn cầu: start_gateway() sử dụng tệp PID trong phạm vi hồ sơ. hermes gateway stop chỉ dừng cổng của cấu hình hiện tại. hermes gateway stop --all sử dụng chức năng quét toàn cầu ps aux để loại bỏ tất cả các quy trình cổng (được sử dụng trong quá trình cập nhật).

Tài liệu liên quan