mofox-plugin-dev-toolkit 0.2.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. mofox_plugin_dev_toolkit-0.2.1.dist-info/METADATA +409 -0
  2. mofox_plugin_dev_toolkit-0.2.1.dist-info/RECORD +43 -0
  3. mofox_plugin_dev_toolkit-0.2.1.dist-info/WHEEL +5 -0
  4. mofox_plugin_dev_toolkit-0.2.1.dist-info/entry_points.txt +2 -0
  5. mofox_plugin_dev_toolkit-0.2.1.dist-info/licenses/LICENSE +674 -0
  6. mofox_plugin_dev_toolkit-0.2.1.dist-info/top_level.txt +1 -0
  7. mpdt/__init__.py +15 -0
  8. mpdt/__main__.py +8 -0
  9. mpdt/cli.py +314 -0
  10. mpdt/commands/__init__.py +9 -0
  11. mpdt/commands/check.py +316 -0
  12. mpdt/commands/dev.py +550 -0
  13. mpdt/commands/generate.py +366 -0
  14. mpdt/commands/init.py +487 -0
  15. mpdt/dev/bridge_plugin/__init__.py +17 -0
  16. mpdt/dev/bridge_plugin/discovery_server.py +126 -0
  17. mpdt/dev/bridge_plugin/plugin.py +258 -0
  18. mpdt/templates/__init__.py +165 -0
  19. mpdt/templates/action_template.py +102 -0
  20. mpdt/templates/adapter_template.py +129 -0
  21. mpdt/templates/chatter_template.py +103 -0
  22. mpdt/templates/event_template.py +116 -0
  23. mpdt/templates/plus_command_template.py +150 -0
  24. mpdt/templates/prompt_template.py +92 -0
  25. mpdt/templates/router_template.py +175 -0
  26. mpdt/templates/tool_template.py +98 -0
  27. mpdt/utils/__init__.py +10 -0
  28. mpdt/utils/color_printer.py +99 -0
  29. mpdt/utils/config_loader.py +171 -0
  30. mpdt/utils/config_manager.py +297 -0
  31. mpdt/utils/file_ops.py +203 -0
  32. mpdt/utils/license_generator.py +980 -0
  33. mpdt/utils/plugin_parser.py +196 -0
  34. mpdt/utils/template_engine.py +112 -0
  35. mpdt/validators/__init__.py +26 -0
  36. mpdt/validators/auto_fix_validator.py +182 -0
  37. mpdt/validators/base.py +121 -0
  38. mpdt/validators/component_validator.py +415 -0
  39. mpdt/validators/config_validator.py +173 -0
  40. mpdt/validators/metadata_validator.py +125 -0
  41. mpdt/validators/structure_validator.py +70 -0
  42. mpdt/validators/style_validator.py +125 -0
  43. mpdt/validators/type_validator.py +223 -0
@@ -0,0 +1,258 @@
1
+ """
2
+ DevBridge 插件 - 为 mpdt dev 提供 WebSocket 桥接
3
+ 临时注入到主程序,提供插件重载接口
4
+ """
5
+
6
+ import asyncio
7
+ from typing import ClassVar, Set
8
+
9
+ from fastapi import WebSocket, WebSocketDisconnect
10
+ from src.common.logger import get_logger
11
+ from src.common.security import VerifiedDep
12
+ from src.common.server import get_global_server
13
+ from src.plugin_system import (
14
+ BasePlugin,
15
+ register_plugin,
16
+ )
17
+ from src.plugin_system.apis.plugin_info_api import list_plugins
18
+ from src.plugin_system.base.base_http_component import BaseRouterComponent
19
+ from src.plugin_system.base.component_types import ComponentInfo
20
+
21
+ logger = get_logger("dev_bridge")
22
+
23
+
24
+ class DevBridgeRouter(BaseRouterComponent):
25
+ """开发模式 WebSocket 路由组件"""
26
+
27
+ component_name = "dev_bridge_router"
28
+ component_description = "开发模式 WebSocket 桥接,提供插件重载接口"
29
+ component_version = "1.0.0"
30
+
31
+ def __init__(self, plugin_config: dict | None = None):
32
+ """初始化路由组件"""
33
+ self.active_connections: Set[WebSocket] = set()
34
+ super().__init__(plugin_config)
35
+
36
+ def register_endpoints(self) -> None:
37
+ """注册 HTTP 端点"""
38
+
39
+ @self.router.websocket("/ws")
40
+ async def websocket_endpoint(websocket: WebSocket):
41
+ """WebSocket 端点 - 与 mpdt dev 通信
42
+
43
+ 完整路径: ws://{host}:{port}/plugin-api/dev_bridge/dev_bridge_router/ws
44
+
45
+ 消息格式:
46
+ 客户端 → 服务器:
47
+ {"command": "reload", "plugin_name": "xxx"}
48
+ {"command": "status"}
49
+ {"command": "ping"}
50
+ {"command": "get_loaded_plugins"}
51
+
52
+ 服务器 → 客户端:
53
+ {"type": "reload_result", "success": true, "message": "..."}
54
+ {"type": "status", "loaded_plugins": [...], "failed_plugins": [...]}
55
+ {"type": "pong"}
56
+ {"type": "plugins_loaded", "loaded": [...], "failed": [...]}
57
+ """
58
+ await websocket.accept()
59
+ self.active_connections.add(websocket)
60
+ logger.info("开发模式客户端已连接")
61
+
62
+ # 立即发送插件加载状态
63
+ try:
64
+ status = self._get_plugin_status()
65
+ await websocket.send_json({
66
+ "type": "plugins_loaded",
67
+ "loaded": status["loaded_plugins"],
68
+ "failed": status["failed_plugins"]
69
+ })
70
+ logger.info(f"已发送插件状态: {len(status['loaded_plugins'])} 个已加载")
71
+ except Exception as e:
72
+ logger.error(f"发送插件状态失败: {e}")
73
+
74
+ try:
75
+ while True:
76
+ data = await websocket.receive_json()
77
+ command = data.get("command")
78
+
79
+ if command == "reload":
80
+ plugin_name = data.get("plugin_name")
81
+ if not plugin_name:
82
+ await websocket.send_json({"type": "error", "message": "缺少 plugin_name 参数"})
83
+ continue
84
+
85
+ # 执行插件重载
86
+ success, message = await self._reload_plugin(plugin_name)
87
+ await websocket.send_json(
88
+ {
89
+ "type": "reload_result",
90
+ "success": success,
91
+ "plugin_name": plugin_name,
92
+ "message": message,
93
+ }
94
+ )
95
+
96
+ elif command == "status":
97
+ # 返回插件状态
98
+ logger.info("返回插件状态")
99
+ status = self._get_plugin_status()
100
+ await websocket.send_json({"type": "status", **status})
101
+
102
+ elif command == "ping":
103
+ await websocket.send_json({"type": "pong"})
104
+
105
+ elif command == "get_loaded_plugins":
106
+ status = self._get_plugin_status()
107
+ await websocket.send_json(
108
+ {
109
+ "type": "loaded_plugins",
110
+ "loaded": status["loaded_plugins"],
111
+ "failed": status["failed_plugins"],
112
+ }
113
+ )
114
+
115
+ else:
116
+ await websocket.send_json({"type": "error", "message": f"未知命令: {command}"})
117
+
118
+ except WebSocketDisconnect:
119
+ logger.info("开发模式客户端已断开")
120
+ except Exception as e:
121
+ logger.error(f"WebSocket 通信错误: {e}")
122
+ finally:
123
+ self.active_connections.discard(websocket)
124
+
125
+ @self.router.get("/status")
126
+ async def get_status():
127
+ """HTTP 状态查询端点
128
+
129
+ 完整路径: http://{host}:{port}/plugin-api/dev_bridge/dev_bridge_router/status
130
+ """
131
+ return self._get_plugin_status()
132
+
133
+ @self.router.post("/reload/{plugin_name}")
134
+ async def reload_plugin(plugin_name: str):
135
+ """HTTP 重载端点
136
+
137
+ 完整路径: http://{host}:{port}/plugin-api/dev_bridge/dev_bridge_router/reload/{plugin_name}
138
+ """
139
+ success, message = await self._reload_plugin(plugin_name)
140
+ return {"success": success, "plugin_name": plugin_name, "message": message}
141
+
142
+ async def _reload_plugin(self, plugin_name: str) -> tuple[bool, str]:
143
+ """重载插件
144
+
145
+ Args:
146
+ plugin_name: 插件名称(不是目录名)
147
+
148
+ Returns:
149
+ (成功, 消息)
150
+ """
151
+ from src.plugin_system.apis import (
152
+ plugin_manage_api,
153
+ )
154
+
155
+ try:
156
+ logger.info(f"开始重载插件: {plugin_name}")
157
+ success = await plugin_manage_api.reload_plugin(plugin_name)
158
+
159
+ # 广播重载成功消息
160
+ await self._broadcast({"type": "plugin_reloaded", "plugin_name": plugin_name, "success": success})
161
+
162
+ return True, f"插件 {plugin_name} 重载成功"
163
+ except Exception as e:
164
+ error_msg = f"插件重载失败: {e}"
165
+ logger.error(error_msg)
166
+
167
+ # 广播重载失败消息
168
+ await self._broadcast(
169
+ {"type": "plugin_reloaded", "plugin_name": plugin_name, "success": False, "error": str(e)}
170
+ )
171
+
172
+ return False, error_msg
173
+
174
+ def _get_plugin_status(self) -> dict:
175
+ """获取插件状态"""
176
+ # 使用 plugin_info_api 获取插件列表
177
+ from src.plugin_system.apis import (
178
+ plugin_info_api,
179
+ )
180
+
181
+ loaded_plugins = plugin_info_api.list_plugins("loaded")
182
+ failed_plugins = plugin_info_api.list_plugins("failed")
183
+
184
+ return {"loaded_plugins": loaded_plugins, "failed_plugins": failed_plugins}
185
+
186
+ async def _broadcast(self, message: dict) -> None:
187
+ """向所有连接的客户端广播消息"""
188
+ if not self.active_connections:
189
+ return
190
+
191
+ disconnected = set()
192
+ for connection in self.active_connections:
193
+ try:
194
+ await connection.send_json(message)
195
+ except Exception as e:
196
+ logger.warning(f"广播消息失败: {e}")
197
+ disconnected.add(connection)
198
+
199
+ # 清理断开的连接
200
+ self.active_connections -= disconnected
201
+
202
+
203
+ @register_plugin
204
+ class DevBridgePlugin(BasePlugin):
205
+ """开发模式桥接插件
206
+
207
+ 这是一个特殊的插件,在开发模式下临时注入到主程序。
208
+ 通过 WebSocket 与 mpdt dev 通信,提供插件重载等功能。
209
+ """
210
+
211
+ plugin_name = "dev_bridge"
212
+ enable_plugin = True
213
+ config_file_name = "config.toml"
214
+ dependencies: ClassVar = []
215
+ python_dependencies: ClassVar = []
216
+
217
+ def __init__(self, *args, **kwargs):
218
+ super().__init__(*args, **kwargs)
219
+ self._router_component: DevBridgeRouter | None = None
220
+ self._discovery_task: asyncio.Task | None = None
221
+
222
+ def get_plugin_components(self) -> list[tuple[ComponentInfo, type]]:
223
+ """注册路由组件"""
224
+ return [(DevBridgeRouter.get_router_info(), DevBridgeRouter)]
225
+
226
+ async def on_plugin_loaded(self):
227
+ """插件加载完成后启动发现服务器"""
228
+ from .discovery_server import start_discovery_server
229
+
230
+ # 获取主程序的 host 和 port
231
+ # 从 app_state 或配置中获取
232
+ try:
233
+ server = get_global_server()
234
+ main_host = server.host
235
+ main_port = server.port
236
+ except Exception:
237
+ main_host = "127.0.0.1"
238
+ main_port = 8000
239
+
240
+ # 启动发现服务器
241
+ self._discovery_task = asyncio.create_task(start_discovery_server(main_host, main_port))
242
+
243
+ logger.info(f"DevBridge 插件已加载,发现服务器: http://127.0.0.1:12318")
244
+ logger.info(f"WebSocket 端点: ws://{main_host}:{main_port}/plugin-api/dev_bridge/dev_bridge_router/ws")
245
+
246
+ async def on_plugin_unload(self):
247
+ """插件卸载时停止发现服务器"""
248
+ from .discovery_server import stop_discovery_server
249
+
250
+ if self._discovery_task:
251
+ self._discovery_task.cancel()
252
+ try:
253
+ await self._discovery_task
254
+ except asyncio.CancelledError:
255
+ pass
256
+
257
+ await stop_discovery_server()
258
+ logger.info("DevBridge 插件已卸载")
@@ -0,0 +1,165 @@
1
+ """
2
+ 组件模板索引
3
+
4
+ 此模块导出所有组件模板的获取函数。
5
+ """
6
+
7
+ from datetime import datetime
8
+
9
+ from mpdt.templates.action_template import get_action_template
10
+ from mpdt.templates.adapter_template import get_adapter_template
11
+ from mpdt.templates.chatter_template import get_chatter_template
12
+ from mpdt.templates.event_template import get_event_handler_template
13
+ from mpdt.templates.plus_command_template import get_plus_command_template
14
+ from mpdt.templates.prompt_template import get_prompt_template
15
+ from mpdt.templates.router_template import get_router_template
16
+ from mpdt.templates.tool_template import get_tool_template
17
+
18
+ # 导出所有模板获取函数
19
+ __all__ = [
20
+ "get_action_template",
21
+ "get_tool_template",
22
+ "get_event_handler_template",
23
+ "get_adapter_template",
24
+ "get_prompt_template",
25
+ "get_plus_command_template",
26
+ "get_chatter_template",
27
+ "get_router_template",
28
+ "get_component_template",
29
+ "prepare_component_context",
30
+ ]
31
+
32
+
33
+ def get_component_template(component_type: str) -> str:
34
+ """
35
+ 根据组件类型获取对应的模板
36
+
37
+ Args:
38
+ component_type: 组件类型 (action, tool, event, adapter, prompt, plus_command, chatter, router)
39
+
40
+ Returns:
41
+ 模板字符串
42
+
43
+ Raises:
44
+ ValueError: 不支持的组件类型
45
+ """
46
+ template_map = {
47
+ "action": get_action_template,
48
+ "tool": get_tool_template,
49
+ "event": get_event_handler_template,
50
+ "adapter": get_adapter_template,
51
+ "prompt": get_prompt_template,
52
+ "plus_command": get_plus_command_template,
53
+ "chatter": get_chatter_template,
54
+ "router": get_router_template,
55
+ }
56
+
57
+ if component_type not in template_map:
58
+ raise ValueError(
59
+ f"不支持的组件类型: {component_type}. "
60
+ f"支持的类型: {', '.join(template_map.keys())}"
61
+ )
62
+
63
+ return template_map[component_type]()
64
+
65
+
66
+ def prepare_component_context(
67
+ component_type: str,
68
+ component_name: str,
69
+ plugin_name: str,
70
+ author: str = "",
71
+ description: str = "",
72
+ is_async: bool = False,
73
+ ) -> dict[str, str]:
74
+ """
75
+ 准备组件模板上下文
76
+
77
+ Args:
78
+ component_type: 组件类型 (action, tool, event, adapter, prompt, plus_command,router,chatter)
79
+ component_name: 组件名称 (snake_case)
80
+ plugin_name: 插件名称
81
+ author: 作者
82
+ description: 描述
83
+ is_async: 是否异步
84
+
85
+ Returns:
86
+ 模板上下文字典
87
+ """
88
+ from mpdt.utils.file_ops import to_pascal_case
89
+
90
+ # 转换为 PascalCase 并添加类型后缀
91
+ class_name = to_pascal_case(component_name)
92
+
93
+ # 根据组件类型添加合适的后缀
94
+ suffix_map = {
95
+ "action": "Action",
96
+ "tool": "Tool",
97
+ "event": "EventHandler",
98
+ "adapter": "Adapter",
99
+ "prompt": "Prompt",
100
+ "plus_command": "PlusCommand",
101
+ "chatter": "Chatter",
102
+ "router": "Router",
103
+ }
104
+
105
+ suffix = suffix_map.get(component_type, "")
106
+ if suffix and not class_name.endswith(suffix):
107
+ class_name = f"{class_name}{suffix}"
108
+
109
+ date = datetime.now().strftime("%Y-%m-%d")
110
+
111
+ # 基础上下文
112
+ context = {
113
+ "component_name": component_name,
114
+ "class_name": class_name,
115
+ "plugin_name": plugin_name,
116
+ "author": author,
117
+ "description": description or f"{class_name} 组件",
118
+ "date": date,
119
+ "async_keyword": "async " if is_async else "",
120
+ "await_keyword": "await " if is_async else "",
121
+ "component_type": component_type + "s", # actions, tools, etc.
122
+ "module_name": component_name,
123
+ "method_name": _get_method_name(component_type),
124
+ }
125
+
126
+ # 特定组件类型的额外字段
127
+ if component_type == "plus_command":
128
+ context["command_name"] = component_name
129
+ elif component_type == "tool":
130
+ context["tool_name"] = component_name
131
+ elif component_type == "event":
132
+ context["event_type"] = component_name.replace("_handler", "").replace("_event", "")
133
+ elif component_type == "adapter":
134
+ context["adapter_name"] = component_name
135
+ elif component_type == "prompt":
136
+ context["prompt_name"] = component_name
137
+ elif component_type == "chatter":
138
+ context["chatter_name"] = component_name
139
+ elif component_type == "router":
140
+ context["router_name"] = component_name
141
+
142
+ return context
143
+
144
+
145
+ def _get_method_name(component_type: str) -> str:
146
+ """
147
+ 根据组件类型获取主要方法名
148
+
149
+ Args:
150
+ component_type: 组件类型
151
+
152
+ Returns:
153
+ 方法名
154
+ """
155
+ method_map = {
156
+ "action": "execute",
157
+ "plus_command": "execute",
158
+ "tool": "run",
159
+ "event": "handle",
160
+ "adapter": "connect",
161
+ "prompt": "build",
162
+ "chatter": "chat",
163
+ "router": "route",
164
+ }
165
+ return method_map.get(component_type, "execute")
@@ -0,0 +1,102 @@
1
+ """
2
+ Action 组件模板
3
+ """
4
+
5
+ ACTION_TEMPLATE = '''"""
6
+ {description}
7
+
8
+ Created by: {author}
9
+ Created at: {date}
10
+ """
11
+
12
+ from src.common.logger import get_logger
13
+ from src.plugin_system import BaseAction, ActionActivationType, ChatMode
14
+
15
+ logger = get_logger(__name__)
16
+
17
+
18
+ class {class_name}(BaseAction):
19
+ """
20
+ {description}
21
+
22
+ Action 组件用于执行聊天中的具体动作任务。
23
+ """
24
+
25
+ # Action 元数据
26
+ action_name: str = "{component_name}"
27
+ action_description: str = "{description}"
28
+
29
+ # 激活配置
30
+ mode_enable: list[ChatMode] = [ChatMode.FOCUS, ChatMode.NORMAL] # 支持的聊天模式
31
+ parallel_action: bool = False # 是否允许与其他 Action 并行执行
32
+
33
+ # 专注模式激活配置
34
+ focus_activation_type: ActionActivationType = ActionActivationType.KEYWORD
35
+ # 普通模式激活配置
36
+ normal_activation_type: ActionActivationType = ActionActivationType.LLM_JUDGE
37
+
38
+ # 激活条件
39
+ activation_keywords: list[str] = ["关键词1", "关键词2"] # 关键词激活时使用
40
+ keyword_case_sensitive: bool = False # 关键词是否区分大小写
41
+
42
+ # LLM 判断激活的提示词
43
+ llm_judge_prompt: str = """
44
+ 判断用户是否需要执行某个特定操作。
45
+ 如果需要,返回 true,否则返回 false。
46
+ """
47
+
48
+ async def go_activate(self, llm_judge_model=None) -> bool:
49
+ """
50
+ 自定义激活逻辑(推荐方式)
51
+
52
+ 可以组合使用以下工具函数:
53
+ - await self._keyword_match(["关键词"]) # 关键词匹配
54
+ - await self._random_activation(0.3) # 随机激活(30%概率)
55
+ - await self._llm_judge_activation(prompt, llm_judge_model) # LLM判断
56
+
57
+ Returns:
58
+ 是否激活此 Action
59
+ """
60
+ # 示例:关键词匹配
61
+ return await self._keyword_match(self.activation_keywords, self.keyword_case_sensitive)
62
+
63
+ async def execute(self) -> tuple[bool, str]:
64
+ """
65
+ 执行 Action 的主要逻辑
66
+
67
+ 可以使用以下方法:
68
+ - await self.send_text("文本内容") # 发送文本消息
69
+ - await self.send_image(image_base64) # 发送图片
70
+ - await self.send_command("command_name", args) # 调用命令
71
+ - await self.call_action("action_name", data) # 调用其他 Action
72
+ - await self.wait_for_new_message(timeout) # 等待用户回复
73
+
74
+ Returns:
75
+ (是否成功, 结果消息)
76
+ """
77
+ try:
78
+ logger.info(f"执行 Action: {{self.action_name}}")
79
+
80
+ # TODO: 实现 Action 的核心逻辑
81
+
82
+ # 示例:发送消息
83
+ await self.send_text("Action 执行成功!")
84
+
85
+ # 存储 Action 信息到上下文
86
+ await self.store_action_info(
87
+ action_build_into_prompt=True,
88
+ action_prompt_display=f"执行了 {{self.action_name}}",
89
+ action_done=True
90
+ )
91
+
92
+ return True, "执行成功"
93
+
94
+ except Exception as e:
95
+ logger.error(f"Action 执行失败: {{e}}")
96
+ return False, f"执行失败: {{e}}"
97
+ '''
98
+
99
+
100
+ def get_action_template() -> str:
101
+ """获取 Action 组件模板"""
102
+ return ACTION_TEMPLATE
@@ -0,0 +1,129 @@
1
+ """
2
+ Adapter 组件模板
3
+ """
4
+
5
+ ADAPTER_TEMPLATE = '''"""
6
+ {description}
7
+
8
+ Created by: {author}
9
+ Created at: {date}
10
+ """
11
+
12
+ from typing import Any
13
+
14
+ from mofox_wire import MessageEnvelope
15
+ from src.common.logger import get_logger
16
+ from src.plugin_system import BaseAdapter
17
+
18
+ logger = get_logger(__name__)
19
+
20
+
21
+ class {class_name}(BaseAdapter):
22
+ """
23
+ {description}
24
+
25
+ Adapter 组件用于连接不同的平台或服务。
26
+
27
+ 支持的场景:
28
+ - QQ/微信等聊天平台
29
+ - Discord/Telegram 等国际平台
30
+ - 自定义 API 服务
31
+ - WebSocket/HTTP 协议适配
32
+ """
33
+
34
+ # Adapter 元数据
35
+ adapter_name: str = "{adapter_name}"
36
+ adapter_version: str = "1.0.0"
37
+ adapter_author: str = "{author}"
38
+ adapter_description: str = "{description}"
39
+
40
+ # 是否在子进程中运行
41
+ run_in_subprocess: bool = False
42
+ # 子进程启动脚本路径(相对于插件目录)
43
+ subprocess_entry: str | None = None
44
+
45
+ async def from_platform_message(self, raw: Any) -> MessageEnvelope:
46
+ """
47
+ 将平台原始消息转换为标准 MessageEnvelope 格式
48
+
49
+ Args:
50
+ raw: 平台原始消息对象
51
+
52
+ Returns:
53
+ MessageEnvelope: 标准消息信封
54
+ """
55
+ try:
56
+ logger.debug(f"转换平台消息: {{raw}}")
57
+
58
+ # TODO: 解析平台消息并转换为 MessageEnvelope
59
+ # 示例:
60
+ # message_id = raw.get("message_id")
61
+ # user_id = raw.get("user_id")
62
+ # content = raw.get("content")
63
+ # timestamp = raw.get("timestamp")
64
+ #
65
+ # return MessageEnvelope(
66
+ # message_id=message_id,
67
+ # user_id=user_id,
68
+ # content=content,
69
+ # timestamp=timestamp,
70
+ # platform="your_platform"
71
+ # )
72
+
73
+ raise NotImplementedError("需要实现 from_platform_message 方法")
74
+
75
+ except Exception as e:
76
+ logger.error(f"转换消息失败: {{e}}")
77
+ raise
78
+
79
+ async def _send_platform_message(self, envelope: MessageEnvelope) -> None:
80
+ """
81
+ 发送消息到平台
82
+
83
+ Args:
84
+ envelope: 要发送的消息信封
85
+ """
86
+ try:
87
+ logger.info(f"发送消息: {{envelope.message_id}}")
88
+
89
+ # TODO: 实现发送消息逻辑
90
+ # 将 MessageEnvelope 转换为平台格式并发送
91
+ # 示例:
92
+ # platform_message = {{
93
+ # "target_id": envelope.target_id,
94
+ # "content": envelope.content,
95
+ # "message_type": envelope.message_type
96
+ # }}
97
+ # await self.platform_api.send(platform_message)
98
+
99
+ raise NotImplementedError("需要实现 _send_platform_message 方法")
100
+
101
+ except Exception as e:
102
+ logger.error(f"发送消息失败: {{e}}")
103
+ raise
104
+
105
+ async def on_adapter_loaded(self) -> None:
106
+ """
107
+ 适配器加载时的钩子
108
+ 可以在这里执行初始化逻辑
109
+ """
110
+ logger.info(f"{{self.adapter_name}} 适配器加载完成")
111
+
112
+ # TODO: 初始化逻辑
113
+ # 例如:建立连接、加载配置、启动后台任务等
114
+
115
+ async def on_adapter_unloaded(self) -> None:
116
+ """
117
+ 适配器卸载时的钩子
118
+ 可以在这里执行清理逻辑
119
+ """
120
+ logger.info(f"{{self.adapter_name}} 适配器卸载")
121
+
122
+ # TODO: 清理逻辑
123
+ # 例如:关闭连接、保存状态、停止后台任务等
124
+ '''
125
+
126
+
127
+ def get_adapter_template() -> str:
128
+ """获取 Adapter 组件模板"""
129
+ return ADAPTER_TEMPLATE