feat(plugin): 引入Prompt组件系统以实现动态Prompt注入

引入了一个新的插件组件类型 `BasePrompt`,允许插件动态地向核心Prompt模板中注入额外的上下文信息。该系统旨在提高Prompt的可扩展性和可定制性,使得开发者可以在不修改核心代码的情况下,通过插件来丰富和调整模型的行为。

主要变更包括:
- **`BasePrompt` 基类**: 定义了Prompt组件的标准接口,包括 `execute` 方法用于生成注入内容,以及 `injection_point` 属性用于指定目标Prompt。
- **`PromptComponentManager`**: 一个新的管理器,负责注册、分类和执行所有 `BasePrompt` 组件。它会在构建核心Prompt时,自动查找并执行相关组件,将其输出拼接到主Prompt内容之前。
- **核心Prompt逻辑更新**: `src.chat.utils.prompt.Prompt` 类现在会调用 `PromptComponentManager` 来获取并注入组件内容。
- **插件系统集成**: `ComponentRegistry` 和 `PluginManager` 已更新,以支持 `BasePrompt` 组件的注册、管理和统计。
- **示例插件更新**: `hello_world_plugin` 中增加了一个 `WeatherPrompt` 示例,演示了如何创建和注册一个新的Prompt组件。
- **代码重构**: 将 `PromptParameters` 类从 `prompt.py` 移动到独立的 `prompt_params.py` 文件中,以改善模块化和解决循环依赖问题。
This commit is contained in:
minecraft1024a
2025-10-19 13:00:18 +08:00
parent 4f2cb56740
commit 50a6c2de58
12 changed files with 428 additions and 85 deletions

View File

@@ -11,6 +11,7 @@ from src.plugin_system.base.base_chatter import BaseChatter
from src.plugin_system.base.base_command import BaseCommand
from src.plugin_system.base.base_events_handler import BaseEventHandler
from src.plugin_system.base.base_interest_calculator import BaseInterestCalculator
from src.plugin_system.base.base_prompt import BasePrompt
from src.plugin_system.base.base_tool import BaseTool
from src.plugin_system.base.component_types import (
ActionInfo,
@@ -22,6 +23,7 @@ from src.plugin_system.base.component_types import (
InterestCalculatorInfo,
PluginInfo,
PlusCommandInfo,
PromptInfo,
ToolInfo,
)
from src.plugin_system.base.plus_command import PlusCommand
@@ -37,6 +39,7 @@ ComponentClassType = (
| type[PlusCommand]
| type[BaseChatter]
| type[BaseInterestCalculator]
| type[BasePrompt]
)
@@ -183,6 +186,10 @@ class ComponentRegistry:
assert isinstance(component_info, InterestCalculatorInfo)
assert issubclass(component_class, BaseInterestCalculator)
ret = self._register_interest_calculator_component(component_info, component_class)
case ComponentType.PROMPT:
assert isinstance(component_info, PromptInfo)
assert issubclass(component_class, BasePrompt)
ret = self._register_prompt_component(component_info, component_class)
case _:
logger.warning(f"未知组件类型: {component_type}")
ret = False
@@ -346,6 +353,31 @@ class ComponentRegistry:
logger.debug(f"已注册InterestCalculator组件: {calculator_name}")
return True
def _register_prompt_component(
self, prompt_info: PromptInfo, prompt_class: "ComponentClassType"
) -> bool:
"""注册Prompt组件到Prompt特定注册表"""
prompt_name = prompt_info.name
if not prompt_name:
logger.error(f"Prompt组件 {prompt_class.__name__} 必须指定名称")
return False
if not hasattr(self, "_prompt_registry"):
self._prompt_registry: dict[str, type[BasePrompt]] = {}
if not hasattr(self, "_enabled_prompt_registry"):
self._enabled_prompt_registry: dict[str, type[BasePrompt]] = {}
_assign_plugin_attrs(
prompt_class, prompt_info.plugin_name, self.get_plugin_config(prompt_info.plugin_name) or {}
)
self._prompt_registry[prompt_name] = prompt_class # type: ignore
if prompt_info.enabled:
self._enabled_prompt_registry[prompt_name] = prompt_class # type: ignore
logger.debug(f"已注册Prompt组件: {prompt_name}")
return True
# === 组件移除相关 ===
async def remove_component(self, component_name: str, component_type: ComponentType, plugin_name: str) -> bool:
@@ -580,7 +612,17 @@ class ComponentRegistry:
component_name: str,
component_type: ComponentType | None = None,
) -> (
type[BaseCommand | BaseAction | BaseEventHandler | BaseTool | PlusCommand | BaseChatter | BaseInterestCalculator] | None
type[
BaseCommand
| BaseAction
| BaseEventHandler
| BaseTool
| PlusCommand
| BaseChatter
| BaseInterestCalculator
| BasePrompt
]
| None
):
"""获取组件类,支持自动命名空间解析
@@ -829,6 +871,7 @@ class ComponentRegistry:
events_handlers: int = 0
plus_command_components: int = 0
chatter_components: int = 0
prompt_components: int = 0
for component in self._components.values():
if component.component_type == ComponentType.ACTION:
action_components += 1
@@ -842,6 +885,8 @@ class ComponentRegistry:
plus_command_components += 1
elif component.component_type == ComponentType.CHATTER:
chatter_components += 1
elif component.component_type == ComponentType.PROMPT:
prompt_components += 1
return {
"action_components": action_components,
"command_components": command_components,
@@ -849,6 +894,7 @@ class ComponentRegistry:
"event_handlers": events_handlers,
"plus_command_components": plus_command_components,
"chatter_components": chatter_components,
"prompt_components": prompt_components,
"total_components": len(self._components),
"total_plugins": len(self._plugins),
"components_by_type": {

View File

@@ -358,13 +358,14 @@ class PluginManager:
event_handler_count = stats.get("event_handlers", 0)
plus_command_count = stats.get("plus_command_components", 0)
chatter_count = stats.get("chatter_components", 0)
prompt_count = stats.get("prompt_components", 0)
total_components = stats.get("total_components", 0)
# 📋 显示插件加载总览
if total_registered > 0:
logger.info("🎉 插件系统加载完成!")
logger.info(
f"📊 总览: {total_registered}个插件, {total_components}个组件 (Action: {action_count}, Command: {command_count}, Tool: {tool_count}, PlusCommand: {plus_command_count}, EventHandler: {event_handler_count}, Chatter: {chatter_count})"
f"📊 总览: {total_registered}个插件, {total_components}个组件 (Action: {action_count}, Command: {command_count}, Tool: {tool_count}, PlusCommand: {plus_command_count}, EventHandler: {event_handler_count}, Chatter: {chatter_count}, Prompt: {prompt_count})"
)
# 显示详细的插件列表
@@ -402,6 +403,9 @@ class PluginManager:
plus_command_components = [
c for c in plugin_info.components if c.component_type == ComponentType.PLUS_COMMAND
]
prompt_components = [
c for c in plugin_info.components if c.component_type == ComponentType.PROMPT
]
if action_components:
action_details = [format_component(c) for c in action_components]
@@ -425,6 +429,9 @@ class PluginManager:
if event_handler_components:
event_handler_details = [format_component(c) for c in event_handler_components]
logger.info(f" 📢 EventHandler组件: {', '.join(event_handler_details)}")
if prompt_components:
prompt_details = [format_component(c) for c in prompt_components]
logger.info(f" 📝 Prompt组件: {', '.join(prompt_details)}")
# 权限节点信息
if plugin_instance := self.loaded_plugins.get(plugin_name):