mofox-plugin-dev-toolkit 0.3.3__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 (46) hide show
  1. mofox_plugin_dev_toolkit-0.3.3.dist-info/METADATA +730 -0
  2. mofox_plugin_dev_toolkit-0.3.3.dist-info/RECORD +46 -0
  3. mofox_plugin_dev_toolkit-0.3.3.dist-info/WHEEL +5 -0
  4. mofox_plugin_dev_toolkit-0.3.3.dist-info/entry_points.txt +2 -0
  5. mofox_plugin_dev_toolkit-0.3.3.dist-info/licenses/LICENSE +674 -0
  6. mofox_plugin_dev_toolkit-0.3.3.dist-info/top_level.txt +1 -0
  7. mpdt/__init__.py +15 -0
  8. mpdt/__main__.py +8 -0
  9. mpdt/cli.py +316 -0
  10. mpdt/commands/__init__.py +9 -0
  11. mpdt/commands/check.py +498 -0
  12. mpdt/commands/dev.py +318 -0
  13. mpdt/commands/generate.py +448 -0
  14. mpdt/commands/init.py +686 -0
  15. mpdt/dev/bridge_plugin/__init__.py +17 -0
  16. mpdt/dev/bridge_plugin/cleanup_handler.py +65 -0
  17. mpdt/dev/bridge_plugin/dev_config.py +24 -0
  18. mpdt/dev/bridge_plugin/file_watcher.py +169 -0
  19. mpdt/dev/bridge_plugin/plugin.py +219 -0
  20. mpdt/templates/__init__.py +165 -0
  21. mpdt/templates/action_template.py +102 -0
  22. mpdt/templates/adapter_template.py +129 -0
  23. mpdt/templates/chatter_template.py +103 -0
  24. mpdt/templates/event_template.py +116 -0
  25. mpdt/templates/plus_command_template.py +150 -0
  26. mpdt/templates/prompt_template.py +92 -0
  27. mpdt/templates/router_template.py +175 -0
  28. mpdt/templates/tool_template.py +98 -0
  29. mpdt/utils/__init__.py +10 -0
  30. mpdt/utils/code_parser.py +401 -0
  31. mpdt/utils/color_printer.py +99 -0
  32. mpdt/utils/config_loader.py +171 -0
  33. mpdt/utils/config_manager.py +297 -0
  34. mpdt/utils/file_ops.py +207 -0
  35. mpdt/utils/license_generator.py +980 -0
  36. mpdt/utils/plugin_parser.py +195 -0
  37. mpdt/utils/template_engine.py +112 -0
  38. mpdt/validators/__init__.py +26 -0
  39. mpdt/validators/auto_fix_validator.py +990 -0
  40. mpdt/validators/base.py +129 -0
  41. mpdt/validators/component_validator.py +842 -0
  42. mpdt/validators/config_validator.py +119 -0
  43. mpdt/validators/metadata_validator.py +107 -0
  44. mpdt/validators/structure_validator.py +72 -0
  45. mpdt/validators/style_validator.py +117 -0
  46. mpdt/validators/type_validator.py +206 -0
@@ -0,0 +1,65 @@
1
+ """
2
+ DevBridge 清理事件处理器
3
+ 在程序停止时清理 DevBridge 插件和目标插件
4
+ """
5
+
6
+ import shutil
7
+ from pathlib import Path
8
+ from typing import ClassVar
9
+
10
+ from src.common.logger import get_logger
11
+ from src.plugin_system.base import BaseEventHandler
12
+ from src.plugin_system.base.component_types import EventType
13
+
14
+ from .dev_config import TARGET_PLUGIN_NAME, TARGET_PLUGIN_PATH
15
+
16
+ logger = get_logger("dev_bridge_cleanup")
17
+
18
+
19
+ class CleanupHandler(BaseEventHandler):
20
+ """清理事件处理器 - 在程序停止时清理插件文件"""
21
+
22
+ handler_name = "dev_bridge_cleanup"
23
+ handler_description = "DevBridge 清理处理器"
24
+ weight = -100 # 负权重,确保最后执行
25
+ init_subscribe: ClassVar[list[EventType | str]] = [EventType.ON_STOP]
26
+
27
+ def __init__(self):
28
+ super().__init__()
29
+ self._target_plugin_name = TARGET_PLUGIN_NAME
30
+ self._target_plugin_path = TARGET_PLUGIN_PATH
31
+
32
+ async def execute(self, kwargs: dict | None) -> tuple[bool, bool, str | None]:
33
+ """程序停止时执行清理(同步删除)"""
34
+ logger.info("🛑 收到停止事件,准备清理 DevBridge...")
35
+
36
+ self._delete_plugins()
37
+
38
+ return True, True, None
39
+
40
+ def _delete_plugins(self):
41
+ """同步删除插件目录"""
42
+ plugin_dir = Path(__file__).parent
43
+ # 目标插件在 plugins 目录中的路径
44
+ plugins_dir = plugin_dir.parent # plugins 目录
45
+ source_path = Path(self._target_plugin_path)
46
+ target_plugin_dir = plugins_dir / self._target_plugin_name if self._target_plugin_name else None
47
+
48
+ # 判断目标插件是否本来就在 plugins 目录下
49
+ is_in_plugins_dir = source_path.parent.resolve() == plugins_dir.resolve()
50
+
51
+ # 删除目标开发插件(仅当它是复制进来的时候)
52
+ if not is_in_plugins_dir and target_plugin_dir and target_plugin_dir.exists():
53
+ try:
54
+ shutil.rmtree(target_plugin_dir)
55
+ logger.info(f"🧹 目标插件已清理: {target_plugin_dir}")
56
+ except Exception as e:
57
+ logger.warning(f"⚠️ 清理目标插件失败: {e}")
58
+
59
+ # 删除 DevBridge 自己
60
+ try:
61
+ if plugin_dir.exists():
62
+ shutil.rmtree(plugin_dir)
63
+ print(f"[DevBridge] 🧹 DevBridge 插件已清理: {plugin_dir}")
64
+ except Exception as e:
65
+ print(f"[DevBridge] ⚠️ 清理 DevBridge 插件失败: {e}")
@@ -0,0 +1,24 @@
1
+ """
2
+ 开发模式配置文件
3
+ 此文件在 mpdt dev 注入时会被修改,用于传递开发插件的配置信息
4
+ """
5
+
6
+ # ==================== 开发目标插件配置 ====================
7
+ # 以下常量会在 mpdt dev 注入时被自动修改
8
+
9
+ # 目标插件的绝对路径
10
+ TARGET_PLUGIN_PATH: str = ""
11
+
12
+ # 目标插件名称
13
+ TARGET_PLUGIN_NAME: str = ""
14
+
15
+ # 是否启用文件监控
16
+ ENABLE_FILE_WATCHER: bool = True
17
+
18
+ # 文件监控防抖延迟(秒)
19
+ DEBOUNCE_DELAY: float = 0.3
20
+
21
+ # ==================== 其他配置 ====================
22
+
23
+ # 发现服务器端口
24
+ DISCOVERY_PORT: int = 12318
@@ -0,0 +1,169 @@
1
+ """
2
+ 文件监控器模块
3
+ 负责监控目标插件的文件变化并触发重载
4
+ """
5
+
6
+ import asyncio
7
+ import time
8
+ from collections.abc import Callable, Coroutine
9
+ from pathlib import Path
10
+ from typing import TYPE_CHECKING, Any
11
+
12
+ from watchdog.events import FileSystemEvent, FileSystemEventHandler
13
+ from watchdog.observers import Observer
14
+
15
+ if TYPE_CHECKING:
16
+ pass
17
+
18
+ try:
19
+ from src.common.logger import get_logger
20
+ logger = get_logger("dev_watcher")
21
+ except ImportError:
22
+ import logging
23
+ logger = logging.getLogger("dev_watcher")
24
+
25
+
26
+ class PluginFileHandler(FileSystemEventHandler):
27
+ """插件文件变化处理器"""
28
+
29
+ def __init__(
30
+ self,
31
+ plugin_path: Path,
32
+ callback: Callable[[str], Coroutine[Any, Any, None] | None],
33
+ debounce_delay: float = 0.3
34
+ ):
35
+ self.plugin_path = plugin_path
36
+ self.callback = callback
37
+ self.debounce_delay = debounce_delay
38
+ self.last_modified: dict[str, float] = {}
39
+ self._loop: asyncio.AbstractEventLoop | None = None
40
+
41
+ def set_event_loop(self, loop: asyncio.AbstractEventLoop):
42
+ """设置事件循环"""
43
+ self._loop = loop
44
+
45
+ def on_modified(self, event: FileSystemEvent):
46
+ if event.is_directory:
47
+ return
48
+ src_path = event.src_path
49
+ if isinstance(src_path, bytes):
50
+ src_path = src_path.decode()
51
+ self._handle_change(str(src_path))
52
+
53
+ def on_created(self, event: FileSystemEvent):
54
+ if event.is_directory:
55
+ return
56
+ src_path = event.src_path
57
+ if isinstance(src_path, bytes):
58
+ src_path = src_path.decode()
59
+ self._handle_change(str(src_path))
60
+
61
+ def _handle_change(self, src_path: str):
62
+ """处理文件变化"""
63
+ # 只监控 Python 文件
64
+ if not src_path.endswith(".py"):
65
+ return
66
+
67
+ # 防抖处理
68
+ now = time.time()
69
+ if src_path in self.last_modified:
70
+ if now - self.last_modified[src_path] < self.debounce_delay:
71
+ return
72
+
73
+ self.last_modified[src_path] = now
74
+
75
+ # 获取相对路径
76
+ try:
77
+ rel_path = Path(src_path).relative_to(self.plugin_path)
78
+ except ValueError:
79
+ rel_path = Path(src_path).name
80
+
81
+ logger.info(f"检测到文件变化: {rel_path}")
82
+
83
+ # 在事件循环中调度回调
84
+ if self._loop and self.callback:
85
+ asyncio.run_coroutine_threadsafe(
86
+ self._async_callback(str(rel_path)),
87
+ self._loop
88
+ )
89
+
90
+ async def _async_callback(self, rel_path: str):
91
+ """异步回调包装"""
92
+ try:
93
+ result = self.callback(rel_path)
94
+ if asyncio.iscoroutine(result):
95
+ await result
96
+ except Exception as e:
97
+ logger.error(f"文件变化回调执行失败: {e}")
98
+
99
+
100
+ class FileWatcher:
101
+ """文件监控器"""
102
+
103
+ def __init__(
104
+ self,
105
+ plugin_path: str | Path,
106
+ on_change_callback: Callable[[str], Coroutine[Any, Any, None] | None],
107
+ debounce_delay: float = 0.3
108
+ ):
109
+ self.plugin_path = Path(plugin_path)
110
+ self.on_change_callback = on_change_callback
111
+ self.debounce_delay = debounce_delay
112
+ self._observer: Any = None
113
+ self._handler: PluginFileHandler | None = None
114
+ self._running = False
115
+
116
+ def start(self, loop: asyncio.AbstractEventLoop | None = None):
117
+ """启动文件监控"""
118
+ if self._running:
119
+ logger.warning("文件监控器已在运行")
120
+ return
121
+
122
+ if not self.plugin_path.exists():
123
+ logger.error(f"插件路径不存在: {self.plugin_path}")
124
+ return
125
+
126
+ # 创建处理器
127
+ self._handler = PluginFileHandler(
128
+ self.plugin_path,
129
+ self.on_change_callback,
130
+ self.debounce_delay
131
+ )
132
+
133
+ # 设置事件循环
134
+ if loop:
135
+ self._handler.set_event_loop(loop)
136
+ else:
137
+ try:
138
+ self._handler.set_event_loop(asyncio.get_running_loop())
139
+ except RuntimeError:
140
+ pass
141
+
142
+ # 创建并启动观察者
143
+ self._observer = Observer()
144
+ self._observer.schedule(
145
+ self._handler,
146
+ str(self.plugin_path),
147
+ recursive=True
148
+ )
149
+ self._observer.start()
150
+ self._running = True
151
+
152
+ logger.info(f"文件监控已启动: {self.plugin_path}")
153
+
154
+ def stop(self):
155
+ """停止文件监控"""
156
+ if not self._running:
157
+ return
158
+
159
+ if self._observer:
160
+ self._observer.stop()
161
+ self._observer.join(timeout=2)
162
+ self._observer = None
163
+
164
+ self._running = False
165
+ logger.info("文件监控已停止")
166
+
167
+ @property
168
+ def is_running(self) -> bool:
169
+ return self._running
@@ -0,0 +1,219 @@
1
+ """
2
+ DevBridge 插件 - 完整的开发模式插件
3
+ 负责文件监控、插件重载等所有开发操作
4
+ 配置通过 dev_config.py 中的常量传递(mpdt dev 注入时动态修改)
5
+ """
6
+
7
+ import asyncio
8
+ from pathlib import Path
9
+ from typing import ClassVar
10
+
11
+ from src.common.logger import get_logger
12
+ from src.plugin_system import (
13
+ BasePlugin,
14
+ register_plugin,
15
+ )
16
+
17
+ # 导入配置(由 mpdt dev 注入时修改)
18
+ from .dev_config import (
19
+ DEBOUNCE_DELAY,
20
+ ENABLE_FILE_WATCHER,
21
+ TARGET_PLUGIN_NAME,
22
+ TARGET_PLUGIN_PATH,
23
+ )
24
+
25
+ logger = get_logger("dev_bridge")
26
+
27
+
28
+ @register_plugin
29
+ class DevBridgePlugin(BasePlugin):
30
+ """开发模式桥接插件
31
+
32
+ 这是一个完整的开发模式插件,负责:
33
+ 1. 监控目标插件的文件变化
34
+ 2. 自动重载目标插件
35
+
36
+ 配置通过 dev_config.py 传递,mpdt dev 在注入时会修改这些常量。
37
+ """
38
+
39
+ plugin_name = "dev_bridge"
40
+ enable_plugin = True
41
+ config_file_name = "config.toml"
42
+ dependencies: ClassVar = []
43
+ python_dependencies: ClassVar = []
44
+
45
+ def __init__(self, *args, **kwargs):
46
+ super().__init__(*args, **kwargs)
47
+ self._file_watcher = None
48
+ self._target_plugin_name = TARGET_PLUGIN_NAME
49
+ self._target_plugin_path = TARGET_PLUGIN_PATH
50
+
51
+ def get_plugin_components(self) -> list:
52
+ """注册清理事件处理器"""
53
+ from .cleanup_handler import CleanupHandler
54
+
55
+ return [(CleanupHandler.get_handler_info(), CleanupHandler)]
56
+
57
+ async def on_plugin_loaded(self):
58
+ """插件加载完成后启动文件监控"""
59
+ from .file_watcher import FileWatcher
60
+
61
+ logger.info("=" * 60)
62
+ logger.info("🚀 DevBridge 开发模式插件已加载")
63
+ logger.info(f"📦 目标插件: {self._target_plugin_name}")
64
+ logger.info(f"📂 目标路径: {self._target_plugin_path}")
65
+ logger.info("=" * 60)
66
+
67
+ # 检查目标插件是否成功加载
68
+ await self._check_target_plugin_loaded()
69
+
70
+ # 启动文件监控
71
+ if ENABLE_FILE_WATCHER and self._target_plugin_path:
72
+ plugin_path = Path(self._target_plugin_path)
73
+ if plugin_path.exists():
74
+ self._file_watcher = FileWatcher(plugin_path, self._on_file_changed, DEBOUNCE_DELAY)
75
+ # 获取当前事件循环并启动监控
76
+ try:
77
+ loop = asyncio.get_running_loop()
78
+ self._file_watcher.start(loop)
79
+ logger.info("👀 文件监控已启动")
80
+ logger.info("📝 修改 Python 文件将自动重载插件")
81
+ except Exception as e:
82
+ logger.error(f"启动文件监控失败: {e}")
83
+ else:
84
+ logger.warning(f"目标插件路径不存在: {plugin_path}")
85
+ else:
86
+ logger.info("文件监控已禁用或未配置目标路径")
87
+
88
+ async def _check_target_plugin_loaded(self):
89
+ """检查目标插件是否成功加载,未加载则报错提示"""
90
+ if not self._target_plugin_name:
91
+ logger.error("❌ 未配置目标插件名称")
92
+ return
93
+
94
+ try:
95
+ from src.plugin_system.apis import plugin_manage_api
96
+
97
+ is_loaded = plugin_manage_api.is_plugin_loaded(self._target_plugin_name)
98
+ is_enabled = plugin_manage_api.is_plugin_enabled(self._target_plugin_name)
99
+
100
+ if not is_loaded:
101
+ logger.error("=" * 60)
102
+ logger.error(f"❌ 目标插件 {self._target_plugin_name} 未加载!")
103
+ logger.error("")
104
+ if not is_enabled:
105
+ logger.error("📋 原因: 插件已被禁用")
106
+ logger.error("")
107
+ logger.error("🔧 解决方案:")
108
+ logger.error(" 1. 检查插件的 config.toml 中 [plugin] enabled = true")
109
+ logger.error(" 2. 或在 plugin.py 中设置 enable_plugin = True")
110
+ logger.error(" 3. 或直接删除 enable_plugin 行(默认启用)")
111
+ else:
112
+ logger.error("📋 原因: 插件加载失败,请检查插件代码是否有错误")
113
+ logger.error("=" * 60)
114
+ else:
115
+ logger.info(f"✅ 目标插件 {self._target_plugin_name} 已成功加载")
116
+
117
+ except ValueError:
118
+ logger.error(f"❌ 目标插件 {self._target_plugin_name} 未注册")
119
+ except Exception as e:
120
+ logger.error(f"❌ 检查目标插件状态时出错: {e}")
121
+
122
+ async def _on_file_changed(self, rel_path: str):
123
+ """文件变化回调 - 同步文件并重载目标插件"""
124
+ if not self._target_plugin_name:
125
+ logger.warning("未配置目标插件名称,跳过重载")
126
+ return
127
+
128
+ logger.info(f"📝 检测到文件变化: {rel_path}")
129
+
130
+ # 先同步文件到 plugins 目录
131
+ try:
132
+ self._sync_plugin_files()
133
+ logger.info("📦 文件已同步到 plugins 目录")
134
+ except Exception as e:
135
+ logger.error(f"❌ 同步文件失败: {e}")
136
+ return
137
+
138
+ try:
139
+ from src.plugin_system.apis import plugin_manage_api
140
+
141
+ plugin_name = self._target_plugin_name
142
+ is_loaded = plugin_manage_api.is_plugin_loaded(plugin_name)
143
+ is_enabled = plugin_manage_api.is_plugin_enabled(plugin_name)
144
+
145
+ if is_loaded:
146
+ # 插件已加载,检查是否被禁用
147
+ if not is_enabled:
148
+ logger.info(f"🔓 插件 {plugin_name} 已禁用,正在启用...")
149
+ await plugin_manage_api.enable_plugin(plugin_name)
150
+
151
+ # 重载插件
152
+ logger.info(f"🔄 正在重载插件: {plugin_name}...")
153
+ success = await plugin_manage_api.reload_plugin(plugin_name)
154
+ if success:
155
+ logger.info(f"✅ 插件 {plugin_name} 重载成功")
156
+ else:
157
+ logger.error(f"❌ 插件 {plugin_name} 重载失败")
158
+ else:
159
+ # 插件未加载,使用 enable_plugin 来加载并启用
160
+ # enable_plugin 会同时处理加载和启用,即使插件之前被禁用
161
+ logger.info(f"📦 插件 {plugin_name} 未加载,正在启用并加载...")
162
+ success = await plugin_manage_api.enable_plugin(plugin_name)
163
+ if success:
164
+ logger.info(f"✅ 插件 {plugin_name} 启用并加载成功")
165
+ else:
166
+ logger.error(f"❌ 插件 {plugin_name} 启用/加载失败")
167
+
168
+ except ValueError as e:
169
+ # 插件未注册,尝试扫描并加载
170
+ logger.warning(f"⚠️ 插件未注册: {e}")
171
+ logger.info("🔍 正在扫描插件目录...")
172
+ try:
173
+ from src.plugin_system.apis import plugin_manage_api
174
+
175
+ plugin_manage_api.rescan_and_register_plugins(load_after_register=True)
176
+ if plugin_manage_api.is_plugin_loaded(self._target_plugin_name):
177
+ logger.info(f"✅ 插件 {self._target_plugin_name} 扫描并加载成功")
178
+ else:
179
+ logger.error(f"❌ 插件 {self._target_plugin_name} 扫描后仍未加载")
180
+ except Exception as scan_e:
181
+ logger.error(f"❌ 扫描插件目录失败: {scan_e}")
182
+ except Exception as e:
183
+ logger.error(f"❌ 操作插件时出错: {e}")
184
+ import traceback
185
+
186
+ traceback.print_exc()
187
+
188
+ def _sync_plugin_files(self):
189
+ """将源插件目录同步到 plugins 目录"""
190
+ import shutil
191
+
192
+ source_path = Path(self._target_plugin_path)
193
+ # plugins 目录是 dev_bridge 所在目录的父目录
194
+ plugins_dir = Path(__file__).parent.parent
195
+ target_path = plugins_dir / self._target_plugin_name
196
+
197
+ # 如果源插件已经在 plugins 目录下,不需要同步
198
+ if source_path.parent.resolve() == plugins_dir.resolve():
199
+ return
200
+
201
+ if not source_path.exists():
202
+ raise FileNotFoundError(f"源插件目录不存在: {source_path}")
203
+
204
+ # 删除旧的目标目录
205
+ if target_path.exists():
206
+ shutil.rmtree(target_path)
207
+
208
+ # 复制新文件
209
+ shutil.copytree(source_path, target_path)
210
+
211
+ async def on_plugin_unload(self):
212
+ """插件卸载时停止文件监控"""
213
+ # 停止文件监控
214
+ if self._file_watcher:
215
+ self._file_watcher.stop()
216
+ self._file_watcher = None
217
+ logger.info("文件监控已停止")
218
+
219
+ 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")