feat: discovering plugins by manifests

This commit is contained in:
Junyan Qin
2025-04-12 15:37:15 +08:00
parent 2e1fb21ff9
commit 11342e75de
9 changed files with 215 additions and 60 deletions
+14 -13
View File
@@ -9,7 +9,7 @@ from .. import loader, events, context, models
from ...core import entities as core_entities
from ...provider.tools import entities as tools_entities
from ...utils import funcschema
from ...discover import engine as discover_engine
class PluginLoader(loader.PluginLoader):
"""加载 plugins/ 目录下的插件"""
@@ -31,13 +31,6 @@ class PluginLoader(loader.PluginLoader):
async def initialize(self):
"""初始化"""
setattr(models, 'register', self.register)
setattr(models, 'on', self.on)
setattr(models, 'func', self.func)
setattr(context, 'register', self.register)
setattr(context, 'handler', self.handler)
setattr(context, 'llm_func', self.llm_func)
def register(
self,
@@ -49,14 +42,15 @@ class PluginLoader(loader.PluginLoader):
self.ap.logger.debug(f'注册插件 {name} {version} by {author}')
container = context.RuntimeContainer(
plugin_name=name,
plugin_description=description,
plugin_label=discover_engine.I18nString(en_US=name, zh_CN=name),
plugin_description=discover_engine.I18nString(en_US=description, zh_CN=description),
plugin_version=version,
plugin_author=author,
plugin_source='',
plugin_repository='',
pkg_path=self._current_pkg_path,
main_file=self._current_module_path,
event_handlers={},
content_functions=[],
tools=[],
)
self._current_container = container
@@ -126,7 +120,7 @@ class PluginLoader(loader.PluginLoader):
func=handler,
)
self._current_container.content_functions.append(llm_function)
self._current_container.tools.append(llm_function)
return func
@@ -165,7 +159,7 @@ class PluginLoader(loader.PluginLoader):
func=func,
)
self._current_container.content_functions.append(llm_function)
self._current_container.tools.append(llm_function)
return func
@@ -205,4 +199,11 @@ class PluginLoader(loader.PluginLoader):
async def load_plugins(self):
"""加载插件
"""
setattr(models, 'register', self.register)
setattr(models, 'on', self.on)
setattr(models, 'func', self.func)
setattr(context, 'register', self.register)
setattr(context, 'handler', self.handler)
setattr(context, 'llm_func', self.llm_func)
await self._walk_plugin_path(__import__("plugins", fromlist=[""]))
+95
View File
@@ -0,0 +1,95 @@
from __future__ import annotations
import typing
import abc
import os
import traceback
from ...core import app
from .. import context, events, models
from .. import loader
from ...utils import funcschema
from ...provider.tools import entities as tools_entities
class PluginManifestLoader(loader.PluginLoader):
"""通过插件清单发现插件"""
_current_container: context.RuntimeContainer = None
def __init__(self, ap: app.Application):
super().__init__(ap)
def handler(
self,
event: typing.Type[events.BaseEventModel]
) -> typing.Callable[[typing.Callable], typing.Callable]:
"""注册事件处理器"""
self.ap.logger.debug(f'注册事件处理器 {event.__name__}')
def wrapper(func: typing.Callable) -> typing.Callable:
self._current_container.event_handlers[event] = func
return func
return wrapper
def llm_func(
self,
name: str=None,
) -> typing.Callable:
"""注册内容函数"""
self.ap.logger.debug(f'注册内容函数 {name}')
def wrapper(func: typing.Callable) -> typing.Callable:
function_schema = funcschema.get_func_schema(func)
function_name = self._current_container.plugin_name + '-' + (func.__name__ if name is None else name)
llm_function = tools_entities.LLMFunction(
name=function_name,
human_desc='',
description=function_schema['description'],
parameters=function_schema['parameters'],
func=func,
)
self._current_container.tools.append(llm_function)
return func
return wrapper
async def load_plugins(self):
"""加载插件"""
setattr(context, 'handler', self.handler)
setattr(context, 'llm_func', self.llm_func)
plugin_manifests = self.ap.discover.get_components_by_kind('Plugin')
for plugin_manifest in plugin_manifests:
try:
current_plugin_container = context.RuntimeContainer(
plugin_name=plugin_manifest.metadata.name,
plugin_label=plugin_manifest.metadata.label,
plugin_description=plugin_manifest.metadata.description,
plugin_version=plugin_manifest.metadata.version,
plugin_author=plugin_manifest.metadata.author,
plugin_repository=plugin_manifest.metadata.repository,
main_file=os.path.join(plugin_manifest.rel_dir, plugin_manifest.execution.python.path),
pkg_path=plugin_manifest.rel_dir,
event_handlers={},
tools=[],
)
self._current_container = current_plugin_container
# extract the plugin class
# this step will load the plugin module,
# so the event handlers and tools will be registered
plugin_class = plugin_manifest.get_python_component_class()
current_plugin_container.plugin_class = plugin_class
self.plugins.append(current_plugin_container)
except Exception as e:
self.ap.logger.error(f'加载插件 {plugin_manifest.metadata.name} 时发生错误')
traceback.print_exc()