diff --git a/pkg/api/http/controller/groups/system.py b/pkg/api/http/controller/groups/system.py index 979d60b2..2db910b9 100644 --- a/pkg/api/http/controller/groups/system.py +++ b/pkg/api/http/controller/groups/system.py @@ -56,3 +56,24 @@ class SystemRouterGroup(group.RouterGroup): return self.success( data=await self.ap.tool_mgr.execute_func_call(data['tool_name'], data['tool_parameters']) ) + + @self.route('/debug/plugin/action', methods=['POST'], auth_type=group.AuthType.USER_TOKEN) + async def _() -> str: + if not constants.debug_mode: + return self.http_status(403, 403, 'Forbidden') + + data = await quart.request.json + + class AnoymousAction: + value = 'anonymous_action' + + def __init__(self, value: str): + self.value = value + + resp = await self.ap.plugin_connector.handler.call_action( + AnoymousAction(data['action']), + data['data'], + timeout=data.get('timeout', 10), + ) + + return self.success(data=resp) diff --git a/pkg/command/cmdmgr.py b/pkg/command/cmdmgr.py index b9dae7c8..133e6a80 100644 --- a/pkg/command/cmdmgr.py +++ b/pkg/command/cmdmgr.py @@ -16,13 +16,11 @@ importutil.import_modules_in_pkg(operators) class CommandManager: - """命令管理器""" - ap: app.Application cmd_list: list[operator.CommandOperator] """ - 运行时命令列表,扁平存储,各个对象包含对应的子节点引用 + Runtime command list, flat storage, each object contains a reference to the corresponding child node """ def __init__(self, ap: app.Application): @@ -64,30 +62,15 @@ class CommandManager: ) -> typing.AsyncGenerator[command_context.CommandReturn, None]: """执行命令""" - found = False - if len(context.crt_params) > 0: # 查找下一个参数是否对应此节点的某个子节点名 - for oper in operator_list: - if (context.crt_params[0] == oper.name or context.crt_params[0] in oper.alias) and ( - oper.parent_class is None or oper.parent_class == operator.__class__ - ): - found = True + command_list = await self.ap.plugin_connector.list_commands() - context.crt_command = context.crt_params[0] - context.crt_params = context.crt_params[1:] - - async for ret in self._execute(context, oper.children, oper): - yield ret - break - - if not found: # 如果下一个参数未在此节点的子节点中找到,则执行此节点或者报错 - if operator is None: - yield command_context.CommandReturn(error=command_errors.CommandNotFoundError(context.crt_params[0])) - else: - if operator.lowest_privilege > context.privilege: - yield command_context.CommandReturn(error=command_errors.CommandPrivilegeError(operator.name)) - else: - async for ret in operator.execute(context): - yield ret + for command in command_list: + if command.metadata.name == context.command: + async for ret in self.ap.plugin_connector.execute_command(context): + yield ret + break + else: + yield command_context.CommandReturn(error=command_errors.CommandNotFoundError(context.command)) async def execute( self, @@ -103,7 +86,6 @@ class CommandManager: privilege = 2 ctx = command_context.ExecuteContext( - query=query, session=session, command_text=command_text, command='', @@ -113,5 +95,9 @@ class CommandManager: privilege=privilege, ) + ctx.command = ctx.params[0] + + ctx.shift() + async for ret in self._execute(ctx, self.cmd_list): yield ret diff --git a/pkg/plugin/connector.py b/pkg/plugin/connector.py index c7496e70..8969d35d 100644 --- a/pkg/plugin/connector.py +++ b/pkg/plugin/connector.py @@ -16,6 +16,7 @@ from langbot_plugin.api.entities import events from langbot_plugin.api.entities import context import langbot_plugin.runtime.io.connection as base_connection from langbot_plugin.api.definition.components.manifest import ComponentManifest +from langbot_plugin.api.entities.builtin.command import context as command_context class PluginRuntimeConnector: @@ -118,3 +119,18 @@ class PluginRuntimeConnector: async def call_tool(self, tool_name: str, parameters: dict[str, Any]) -> dict[str, Any]: return await self.handler.call_tool(tool_name, parameters) + + async def list_commands(self) -> list[ComponentManifest]: + list_commands_data = await self.handler.list_commands() + + return [ComponentManifest.model_validate(command) for command in list_commands_data] + + async def execute_command( + self, command_ctx: command_context.ExecuteContext + ) -> typing.AsyncGenerator[command_context.CommandReturn, None]: + gen = self.handler.execute_command(command_ctx.model_dump(serialize_as_any=True)) + + async for ret in gen: + cmd_ret = command_context.CommandReturn.model_validate(ret) + + yield cmd_ret diff --git a/pkg/plugin/handler.py b/pkg/plugin/handler.py index 16c95770..9e9449cc 100644 --- a/pkg/plugin/handler.py +++ b/pkg/plugin/handler.py @@ -117,3 +117,25 @@ class RuntimeConnectionHandler(handler.Handler): ) return result['tool_response'] + + async def list_commands(self) -> list[dict[str, Any]]: + """List commands""" + result = await self.call_action( + LangBotToRuntimeAction.LIST_COMMANDS, + {}, + timeout=10, + ) + return result['commands'] + + async def execute_command(self, command_context: dict[str, Any]) -> typing.AsyncGenerator[dict[str, Any], None]: + """Execute command""" + gen = self.call_action_generator( + LangBotToRuntimeAction.EXECUTE_COMMAND, + { + 'command_context': command_context, + }, + timeout=10, + ) + + async for ret in gen: + yield ret