chore: docs

This commit is contained in:
Junyan Qin
2026-03-21 23:48:27 +08:00
parent 1fcdbd472f
commit 9f23f4c572
7 changed files with 3614 additions and 0 deletions
@@ -0,0 +1,479 @@
# 适配器新目录结构
## 1. 设计目标
- **模块化**:每个适配器从单文件拆分到独立目录,各模块职责清晰
- **可维护**:随着事件和 API 的增加,代码量会显著增长,目录结构有助于管理复杂度
- **一致性**:所有适配器遵循相同的目录布局和文件命名约定
- **兼容现有发现机制**:保持 YAML manifest + ComponentDiscoveryEngine 的注册体系
## 2. 新目录布局
### 2.1 整体结构
```
pkg/platform/
├── __init__.py
├── botmgr.py # PlatformManager + RuntimeBot(重构)
├── event_bus.py # EventBus(新增)
├── event_router.py # EventRouter(新增)
├── logger.py # EventLogger(保留)
├── webhook_pusher.py # WebhookPusher(重构为 WebhookHandler
├── adapters/ # 适配器(新目录)
│ ├── __init__.py
│ │
│ ├── telegram/
│ │ ├── __init__.py
│ │ ├── adapter.py # TelegramAdapter 主类
│ │ ├── event_converter.py # 平台事件 → 统一事件
│ │ ├── message_converter.py # MessageChain 互转
│ │ ├── api_impl.py # 通用 API 实现
│ │ ├── platform_api.py # call_platform_api 的动作映射
│ │ ├── types.py # 平台特有类型定义
│ │ └── manifest.yaml # 适配器清单
│ │
│ ├── discord/
│ │ ├── __init__.py
│ │ ├── adapter.py
│ │ ├── event_converter.py
│ │ ├── message_converter.py
│ │ ├── api_impl.py
│ │ ├── platform_api.py
│ │ ├── types.py
│ │ ├── voice.py # Discord 语音连接管理(特有)
│ │ └── manifest.yaml
│ │
│ ├── aiocqhttp/ # OneBot v11 (QQ)
│ │ └── ...
│ ├── qqofficial/
│ │ └── ...
│ ├── lark/ # 飞书
│ │ └── ...
│ ├── dingtalk/
│ │ └── ...
│ ├── slack/
│ │ └── ...
│ ├── wechatpad/
│ │ └── ...
│ ├── officialaccount/ # 微信公众号
│ │ └── ...
│ ├── wecom/ # 企业微信
│ │ └── ...
│ ├── wecombot/
│ │ └── ...
│ ├── wecomcs/
│ │ └── ...
│ ├── kook/
│ │ └── ...
│ ├── line/
│ │ └── ...
│ ├── satori/
│ │ └── ...
│ ├── websocket/ # 内置 WebSocket 适配器
│ │ ├── __init__.py
│ │ ├── adapter.py
│ │ ├── manager.py # WebSocket 连接管理
│ │ └── manifest.yaml
│ │
│ └── legacy/ # 旧版适配器(保留一段时间后移除)
│ ├── gewechat/
│ ├── nakuru/
│ └── qqbotpy/
└── handlers/ # 事件处理器实现(新增)
├── __init__.py
├── base.py # AbstractEventHandler 基类
├── pipeline_handler.py # PipelineHandler
├── agent_handler.py # AgentHandler
├── webhook_handler.py # WebhookHandler
└── plugin_handler.py # PluginHandler
```
### 2.2 适配器目录内各文件职责
以 Telegram 为例:
| 文件 | 职责 | 关键类/函数 |
|------|------|------------|
| `adapter.py` | 主入口,继承 `AbstractPlatformAdapter`,组装其他模块 | `TelegramAdapter` |
| `event_converter.py` | 将 Telegram 原生事件转换为统一事件类型 | `TelegramEventConverter` — 支持 Message/Edit/Delete/Reaction/MemberJoin 等所有事件 |
| `message_converter.py` | `MessageChain` 与 Telegram 消息格式互转 | `TelegramMessageConverter.yiri2target()` / `target2yiri()` |
| `api_impl.py` | 实现通用 API 方法(edit_message, delete_message, get_group_info 等) | 各 API 方法的 Telegram 实现 |
| `platform_api.py` | 实现 `call_platform_api` 的动作分发表 | `PLATFORM_API_MAP = {"pin_message": ..., "unpin_message": ...}` |
| `types.py` | 平台特有的类型定义 | Telegram 特有的枚举、配置结构等 |
| `manifest.yaml` | 适配器清单:名称、配置 schema、支持的事件和 API 列表 | — |
## 3. 新基类设计
### 3.1 AbstractPlatformAdapter
新基类继承自现有 `AbstractMessagePlatformAdapter` 并扩展,位于 `langbot-plugin-sdk` 中:
```python
# langbot_plugin/api/definition/abstract/platform/adapter.py
class AbstractPlatformAdapter(pydantic.BaseModel, metaclass=abc.ABCMeta):
"""平台适配器基类(EBA 版本)
相比旧版 AbstractMessagePlatformAdapter
- 新增通用 API 方法(edit_message, delete_message, get_group_info 等)
- 新增透传 APIcall_platform_api
- 新增能力声明(get_supported_events, get_supported_apis
- 事件监听器支持所有事件类型,不仅限于消息事件
"""
bot_account_id: str = ""
config: dict
logger: AbstractEventLogger = pydantic.Field(exclude=True)
class Config:
arbitrary_types_allowed = True
# ---- 能力声明 ----
def get_supported_events(self) -> list[str]:
"""返回此适配器支持的事件类型列表
默认实现从 manifest.yaml 读取。
适配器也可以 override 此方法动态声明。
"""
return ["message.received"]
def get_supported_apis(self) -> list[str]:
"""返回此适配器支持的 API 列表
默认实现从 manifest.yaml 读取。
"""
return ["send_message", "reply_message"]
# ---- 必需方法(抽象) ----
@abc.abstractmethod
async def send_message(self, target_type, target_id, message) -> MessageResult:
...
@abc.abstractmethod
async def reply_message(self, event, message, quote_origin=False) -> MessageResult:
...
@abc.abstractmethod
async def run_async(self):
...
@abc.abstractmethod
async def kill(self) -> bool:
...
@abc.abstractmethod
def register_listener(self, event_type, callback):
...
@abc.abstractmethod
def unregister_listener(self, event_type, callback):
...
# ---- 可选方法(默认抛 NotSupportedError ----
# edit_message, delete_message, forward_message,
# get_group_info, get_group_member_list, ...
# call_platform_api, ...
# (完整签名见 02-platform-api.md
# ---- 流式输出(保留) ----
async def reply_message_chunk(self, event, bot_message, message,
quote_origin=False, is_final=False):
raise NotSupportedError("reply_message_chunk")
async def is_stream_output_supported(self) -> bool:
return False
# ---- 消息卡片(保留) ----
async def create_message_card(self, message_id, event) -> bool:
return False
async def is_muted(self, group_id) -> bool:
return False
```
### 3.2 AbstractMessagePlatformAdapter 兼容
旧的 `AbstractMessagePlatformAdapter` 保留为 `AbstractPlatformAdapter` 的类型别名:
```python
# 向后兼容
AbstractMessagePlatformAdapter = AbstractPlatformAdapter
```
现有适配器代码中的 `AbstractMessagePlatformAdapter` 引用不需要立即修改。
### 3.3 EventConverter 新设计
现有 `AbstractEventConverter` 只有 `target2yiri``yiri2target` 两个静态方法,且只处理消息事件。
新设计支持多种事件类型:
```python
class AbstractEventConverter:
"""事件转换器基类(EBA 版本)
适配器需要实现此转换器,将平台原生事件转换为统一事件。
"""
@staticmethod
def target2yiri(raw_event: typing.Any) -> typing.Optional[Event]:
"""将平台原生事件转换为统一事件
Args:
raw_event: 平台 SDK 回调传入的原始事件对象
Returns:
统一 Event 对象,如果无法转换或不需要处理则返回 None
"""
raise NotImplementedError
@staticmethod
def yiri2target(event: Event) -> typing.Any:
"""将统一事件转换为平台原生事件(一般不需要)"""
raise NotImplementedError
```
具体适配器的 EventConverter 实现会是一个分发式的结构:
```python
class TelegramEventConverter(AbstractEventConverter):
"""Telegram 事件转换器"""
@staticmethod
def target2yiri(update: telegram.Update) -> typing.Optional[Event]:
# 消息事件
if update.message:
return TelegramEventConverter._convert_message(update)
# 消息编辑
if update.edited_message:
return TelegramEventConverter._convert_edited_message(update)
# 成员变动
if update.chat_member:
return TelegramEventConverter._convert_chat_member(update)
# 回调查询(按钮点击等)
if update.callback_query:
return TelegramEventConverter._convert_callback_query(update)
# 其他 → PlatformSpecificEvent
return TelegramEventConverter._convert_platform_specific(update)
@staticmethod
def _convert_message(update) -> MessageReceivedEvent:
...
@staticmethod
def _convert_edited_message(update) -> MessageEditedEvent:
...
@staticmethod
def _convert_chat_member(update) -> typing.Union[
MemberJoinedEvent, MemberLeftEvent, ...
]:
...
@staticmethod
def _convert_platform_specific(update) -> PlatformSpecificEvent:
...
```
## 4. Manifest 文件格式扩展
现有 manifest.yaml 只声明 `kind`, `metadata`, `spec.config`, `execution`
新增 `spec.supported_events``spec.supported_apis`
```yaml
apiVersion: v1
kind: MessagePlatformAdapter
metadata:
name: telegram
label:
en_US: Telegram
zh_Hans: Telegram
icon: telegram.svg
description:
en_US: Telegram Bot adapter
zh_Hans: Telegram Bot 适配器
spec:
config:
# 现有配置 schema(保持不变)
- key: token
label: { en_US: "Bot Token", zh_Hans: "Bot Token" }
type: string
required: true
sensitive: true
# ...
supported_events:
- message.received
- message.edited
- message.deleted
- message.reaction
- group.member_joined
- group.member_left
- group.member_banned
- group.info_updated
- bot.invited_to_group
- bot.removed_from_group
supported_apis:
required:
- send_message
- reply_message
optional:
- edit_message
- delete_message
- get_group_info
- get_group_member_list
- get_group_member_info
- get_user_info
- upload_file
- get_file_url
- call_platform_api
platform_specific_apis:
- action: pin_message
description: { en_US: "Pin a message", zh_Hans: "置顶消息" }
- action: unpin_message
description: { en_US: "Unpin a message", zh_Hans: "取消置顶" }
- action: get_chat_administrators
description: { en_US: "Get chat admins", zh_Hans: "获取群管理员列表" }
execution:
python:
path: pkg/platform/adapters/telegram/adapter.py
attr: TelegramAdapter
```
## 5. 适配器注册与发现
### 5.1 Blueprint 更新
`templates/components.yaml` 中更新扫描路径:
```yaml
kind: Blueprint
spec:
components:
MessagePlatformAdapter:
fromDirs:
- path: pkg/platform/adapters/ # 新路径
```
`ComponentDiscoveryEngine` 的递归扫描逻辑不变——它会扫描所有子目录中的 `.yaml` 文件。因此每个适配器目录下的 `manifest.yaml` 会被自动发现。
### 5.2 PlatformManager 适配
`PlatformManager.initialize()` 的核心逻辑基本不变:
```python
async def initialize(self):
# 1. 发现适配器组件(自动扫描新目录结构)
self.adapter_components = self.ap.discover.get_components_by_kind('MessagePlatformAdapter')
# 2. 动态导入适配器类
for component in self.adapter_components:
self.adapter_dict[component.metadata.name] = component.get_python_component_class()
# 3. 从数据库加载 Bot 并实例化适配器(不变)
await self.load_bots_from_db()
```
变更点:
- `execution.python.path``pkg/platform/sources/telegram.py` 变为 `pkg/platform/adapters/telegram/adapter.py`
- `get_python_component_class()` 正常工作,因为它按路径动态导入
## 6. RuntimeBot 重构
### 6.1 现有问题
当前 `RuntimeBot.initialize()` 硬编码注册了两个回调:
```python
# 现有代码
self.adapter.register_listener(platform_events.FriendMessage, on_friend_message)
self.adapter.register_listener(platform_events.GroupMessage, on_group_message)
```
### 6.2 新设计
`RuntimeBot` 改为注册一个通用的事件回调:
```python
class RuntimeBot:
async def initialize(self):
# 注册通用事件回调,接收所有事件类型
self.adapter.register_listener(Event, self._on_event)
async def _on_event(
self,
event: Event,
adapter: AbstractPlatformAdapter,
):
"""统一事件入口"""
# 1. 设置事件的 bot_uuid 和 adapter_name
event.bot_uuid = self.bot_entity.uuid
event.adapter_name = self.bot_entity.adapter
# 2. 日志记录
await self._log_event(event)
# 3. 提交给 EventBus
await self.ap.event_bus.emit(event, adapter)
```
适配器侧的 `register_listener` 实现也需调整:
-`event_type``Event`(基类)时,注册为"接收所有事件"的通配回调
- 适配器在收到平台原生事件时,通过 `EventConverter.target2yiri()` 转换后,调用所有匹配的回调
## 7. 从现有单文件适配器迁移
### 7.1 迁移模式
以 Telegram 为例,从 `sources/telegram.py`445 行)拆分:
| 原代码位置 | → 新文件 |
|-----------|----------|
| `TelegramMessageConverter` 类 | `telegram/message_converter.py` |
| `TelegramEventConverter` 类 | `telegram/event_converter.py`(扩展,支持更多事件) |
| `TelegramAdapter.__init__` / `run_async` / `kill` / `register_listener` | `telegram/adapter.py` |
| `TelegramAdapter.send_message` / `reply_message` / `reply_message_chunk` | `telegram/adapter.py`(消息方法保留在主类)+ `telegram/api_impl.py`(新增 API |
| 新增代码 | `telegram/api_impl.py`edit_message, delete_message, get_group_info 等) |
| 新增代码 | `telegram/platform_api.py`pin_message, unpin_message 等的映射) |
| `telegram.yaml` | `telegram/manifest.yaml`(扩展 supported_events/apis |
### 7.2 迁移顺序建议
1. **Telegram** — 功能最完整的适配器之一,适合作为模板
2. **Discord** — 第二个迁移,验证模式的通用性
3. **AioCQHTTP (OneBot)** — 国内最常用,确保兼容
4. **其他适配器** — 按使用频率排序
### 7.3 渐进式迁移
不需要一次性迁移所有适配器。可以采用渐进策略:
1. 先在 `adapters/` 下建立新适配器
2. `Blueprint` 同时扫描 `sources/``adapters/` 两个目录
3. 旧适配器在 `sources/` 中继续工作
4. 逐个迁移到新结构
5. 全部迁移完成后移除 `sources/` 目录
```yaml
# 过渡期的 Blueprint
kind: Blueprint
spec:
components:
MessagePlatformAdapter:
fromDirs:
- path: pkg/platform/sources/ # 旧路径(尚未迁移的适配器)
- path: pkg/platform/adapters/ # 新路径(已迁移的适配器)
```