mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-08-10 21:10:59 +00:00
fix(agent-runner): clean plugin review issues
This commit is contained in:
@@ -12,7 +12,7 @@ class MCPRouterGroup(group.RouterGroup):
|
|||||||
async def initialize(self) -> None:
|
async def initialize(self) -> None:
|
||||||
@self.route('/servers', methods=['GET', 'POST'], auth_type=group.AuthType.USER_TOKEN)
|
@self.route('/servers', methods=['GET', 'POST'], auth_type=group.AuthType.USER_TOKEN)
|
||||||
async def _() -> str:
|
async def _() -> str:
|
||||||
"""获取MCP服务器列表"""
|
"""List MCP servers or create a new MCP server."""
|
||||||
if quart.request.method == 'GET':
|
if quart.request.method == 'GET':
|
||||||
servers = await self.ap.mcp_service.get_mcp_servers(contain_runtime_info=True)
|
servers = await self.ap.mcp_service.get_mcp_servers(contain_runtime_info=True)
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ class MCPRouterGroup(group.RouterGroup):
|
|||||||
|
|
||||||
@self.route('/servers/<server_name>', methods=['GET', 'PUT', 'DELETE'], auth_type=group.AuthType.USER_TOKEN)
|
@self.route('/servers/<server_name>', methods=['GET', 'PUT', 'DELETE'], auth_type=group.AuthType.USER_TOKEN)
|
||||||
async def _(server_name: str) -> str:
|
async def _(server_name: str) -> str:
|
||||||
"""获取、更新或删除MCP服务器配置"""
|
"""Get, update, or delete an MCP server configuration."""
|
||||||
from urllib.parse import unquote
|
from urllib.parse import unquote
|
||||||
|
|
||||||
server_name = unquote(server_name)
|
server_name = unquote(server_name)
|
||||||
@@ -59,7 +59,7 @@ class MCPRouterGroup(group.RouterGroup):
|
|||||||
|
|
||||||
@self.route('/servers/<server_name>/test', methods=['POST'], auth_type=group.AuthType.USER_TOKEN)
|
@self.route('/servers/<server_name>/test', methods=['POST'], auth_type=group.AuthType.USER_TOKEN)
|
||||||
async def _(server_name: str) -> str:
|
async def _(server_name: str) -> str:
|
||||||
"""测试MCP服务器连接"""
|
"""Test an MCP server connection."""
|
||||||
from urllib.parse import unquote
|
from urllib.parse import unquote
|
||||||
|
|
||||||
server_name = unquote(server_name)
|
server_name = unquote(server_name)
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ class MCPService:
|
|||||||
await self.ap.tool_mgr.mcp_tool_loader.remove_mcp_server(server_name)
|
await self.ap.tool_mgr.mcp_tool_loader.remove_mcp_server(server_name)
|
||||||
|
|
||||||
async def test_mcp_server(self, server_name: str, server_data: dict) -> int:
|
async def test_mcp_server(self, server_name: str, server_data: dict) -> int:
|
||||||
"""测试 MCP 服务器连接并返回任务 ID"""
|
"""Test an MCP server connection and return the task ID."""
|
||||||
|
|
||||||
runtime_mcp_session: RuntimeMCPSession | None = None
|
runtime_mcp_session: RuntimeMCPSession | None = None
|
||||||
|
|
||||||
|
|||||||
@@ -211,7 +211,7 @@ class PreProcessor(stage.PipelineStage):
|
|||||||
# time instead of the first message/creation time.
|
# time instead of the first message/creation time.
|
||||||
conversation.update_time = now
|
conversation.update_time = now
|
||||||
|
|
||||||
# 设置query
|
# Attach resolved session state to the query.
|
||||||
query.session = session
|
query.session = session
|
||||||
query.prompt = conversation.prompt.copy()
|
query.prompt = conversation.prompt.copy()
|
||||||
query.messages = await self._resolve_history_messages(runner_id, conversation)
|
query.messages = await self._resolve_history_messages(runner_id, conversation)
|
||||||
@@ -292,7 +292,7 @@ class PreProcessor(stage.PipelineStage):
|
|||||||
if me.base64 is not None:
|
if me.base64 is not None:
|
||||||
content_list.append(provider_message.ContentElement.from_image_base64(me.base64))
|
content_list.append(provider_message.ContentElement.from_image_base64(me.base64))
|
||||||
elif isinstance(me, platform_message.Voice):
|
elif isinstance(me, platform_message.Voice):
|
||||||
# 转成文件链接,让下游 runner 上传到目标模型
|
# Convert voice input into file content for downstream model upload.
|
||||||
if me.base64:
|
if me.base64:
|
||||||
content_list.append(provider_message.ContentElement.from_file_base64(me.base64, 'voice.silk'))
|
content_list.append(provider_message.ContentElement.from_file_base64(me.base64, 'voice.silk'))
|
||||||
elif me.url:
|
elif me.url:
|
||||||
@@ -334,7 +334,7 @@ class PreProcessor(stage.PipelineStage):
|
|||||||
runner_config,
|
runner_config,
|
||||||
)
|
)
|
||||||
|
|
||||||
# =========== 触发事件 PromptPreProcessing
|
# Emit PromptPreProcessing before the runner receives the query.
|
||||||
|
|
||||||
event = events.PromptPreProcessing(
|
event = events.PromptPreProcessing(
|
||||||
session_name=f'{query.session.launcher_type.value}_{query.session.launcher_id}',
|
session_name=f'{query.session.launcher_type.value}_{query.session.launcher_id}',
|
||||||
|
|||||||
@@ -468,7 +468,12 @@ class PluginRuntimeConnector(ManagedRuntimeConnector):
|
|||||||
)
|
)
|
||||||
|
|
||||||
file_bytes = download_resp.content
|
file_bytes = download_resp.content
|
||||||
self._extract_deps_metadata(file_bytes, task_context)
|
plugin_author, plugin_name = self._inspect_plugin_package(
|
||||||
|
file_bytes,
|
||||||
|
task_context,
|
||||||
|
)
|
||||||
|
if task_context is not None and plugin_author and plugin_name:
|
||||||
|
task_context.metadata['plugin_name'] = f'{plugin_author}/{plugin_name}'
|
||||||
file_key = await self.handler.send_file(file_bytes, 'lbpkg')
|
file_key = await self.handler.send_file(file_bytes, 'lbpkg')
|
||||||
install_info['plugin_file_key'] = file_key
|
install_info['plugin_file_key'] = file_key
|
||||||
self.ap.logger.info(f'Transfered file {file_key} to plugin runtime')
|
self.ap.logger.info(f'Transfered file {file_key} to plugin runtime')
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ Legacy Coze API Runner.
|
|||||||
|
|
||||||
DEPRECATED: This runner has been migrated to the AgentRunner plugin format.
|
DEPRECATED: This runner has been migrated to the AgentRunner plugin format.
|
||||||
Use the official `langbot/coze-agent` plugin instead.
|
Use the official `langbot/coze-agent` plugin instead.
|
||||||
|
|
||||||
Migration target: /home/glwuy/langbot-app/langbot-agent-runner/coze-agent/
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ Legacy DashScope (阿里云百炼) API Runner.
|
|||||||
|
|
||||||
DEPRECATED: This runner has been migrated to the AgentRunner plugin format.
|
DEPRECATED: This runner has been migrated to the AgentRunner plugin format.
|
||||||
Use the official `langbot/dashscope-agent` plugin instead.
|
Use the official `langbot/dashscope-agent` plugin instead.
|
||||||
|
|
||||||
Migration target: /home/glwuy/langbot-app/langbot-agent-runner/dashscope-agent/
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ Legacy Dify Service API Runner.
|
|||||||
|
|
||||||
DEPRECATED: This runner has been migrated to the AgentRunner plugin format.
|
DEPRECATED: This runner has been migrated to the AgentRunner plugin format.
|
||||||
Use the official `langbot/dify-agent` plugin instead.
|
Use the official `langbot/dify-agent` plugin instead.
|
||||||
|
|
||||||
Migration target: /home/glwuy/langbot-app/langbot-agent-runner/dify-agent/
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ Legacy Langflow API Runner.
|
|||||||
|
|
||||||
DEPRECATED: This runner has been migrated to the AgentRunner plugin format.
|
DEPRECATED: This runner has been migrated to the AgentRunner plugin format.
|
||||||
Use the official `langbot/langflow-agent` plugin instead.
|
Use the official `langbot/langflow-agent` plugin instead.
|
||||||
|
|
||||||
Migration target: /home/glwuy/langbot-app/langbot-agent-runner/langflow-agent/
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ Legacy Local Agent Runner.
|
|||||||
|
|
||||||
DEPRECATED: This runner has been migrated to the AgentRunner plugin format.
|
DEPRECATED: This runner has been migrated to the AgentRunner plugin format.
|
||||||
Use the official `langbot/local-agent` plugin instead.
|
Use the official `langbot/local-agent` plugin instead.
|
||||||
|
|
||||||
Migration target: /home/glwuy/langbot-app/langbot-local-agent/
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ Legacy n8n Service API Runner.
|
|||||||
|
|
||||||
DEPRECATED: This runner has been migrated to the AgentRunner plugin format.
|
DEPRECATED: This runner has been migrated to the AgentRunner plugin format.
|
||||||
Use the official `langbot/n8n-agent` plugin instead.
|
Use the official `langbot/n8n-agent` plugin instead.
|
||||||
|
|
||||||
Migration target: /home/glwuy/langbot-app/langbot-agent-runner/n8n-agent/
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ Legacy Tbox (蚂蚁百宝箱) API Runner.
|
|||||||
|
|
||||||
DEPRECATED: This runner has been migrated to the AgentRunner plugin format.
|
DEPRECATED: This runner has been migrated to the AgentRunner plugin format.
|
||||||
Use the official `langbot/tbox-agent` plugin instead.
|
Use the official `langbot/tbox-agent` plugin instead.
|
||||||
|
|
||||||
Migration target: /home/glwuy/langbot-app/langbot-agent-runner/tbox-agent/
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
class ToolNotFoundError(ValueError):
|
||||||
|
"""Raised when a requested tool cannot be found in any active loader."""
|
||||||
|
|
||||||
|
def __init__(self, name: str):
|
||||||
|
self.name = name
|
||||||
|
super().__init__(f'Tool not found: {name}')
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
|
async def is_box_backend_available(ap: Any) -> bool:
|
||||||
|
"""Return whether the configured Box backend is ready for tool execution."""
|
||||||
|
box_service = getattr(ap, 'box_service', None)
|
||||||
|
if box_service is None:
|
||||||
|
return False
|
||||||
|
if not getattr(box_service, 'available', False):
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
status = await box_service.get_status()
|
||||||
|
backend_info = status.get('backend', {})
|
||||||
|
return bool(backend_info.get('available', False))
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
@@ -30,7 +30,7 @@ class MCPSessionStatus(enum.Enum):
|
|||||||
|
|
||||||
|
|
||||||
class RuntimeMCPSession:
|
class RuntimeMCPSession:
|
||||||
"""运行时 MCP 会话"""
|
"""Runtime MCP session."""
|
||||||
|
|
||||||
ap: app.Application
|
ap: app.Application
|
||||||
|
|
||||||
@@ -352,12 +352,12 @@ class RuntimeMCPSession:
|
|||||||
return info
|
return info
|
||||||
|
|
||||||
async def shutdown(self):
|
async def shutdown(self):
|
||||||
"""关闭会话并清理资源"""
|
"""Close the session and release resources."""
|
||||||
try:
|
try:
|
||||||
# 设置shutdown事件,通知lifecycle任务退出
|
# Signal the lifecycle task to exit.
|
||||||
self._shutdown_event.set()
|
self._shutdown_event.set()
|
||||||
|
|
||||||
# 等待lifecycle任务完成(带超时)
|
# Wait for the lifecycle task with a bounded timeout.
|
||||||
if self._lifecycle_task and not self._lifecycle_task.done():
|
if self._lifecycle_task and not self._lifecycle_task.done():
|
||||||
try:
|
try:
|
||||||
await asyncio.wait_for(self._lifecycle_task, timeout=5.0)
|
await asyncio.wait_for(self._lifecycle_task, timeout=5.0)
|
||||||
@@ -411,9 +411,9 @@ class RuntimeMCPSession:
|
|||||||
|
|
||||||
# @loader.loader_class('mcp')
|
# @loader.loader_class('mcp')
|
||||||
class MCPLoader(loader.ToolLoader):
|
class MCPLoader(loader.ToolLoader):
|
||||||
"""MCP 工具加载器。
|
"""MCP tool loader.
|
||||||
|
|
||||||
在此加载器中管理所有与 MCP Server 的连接。
|
This loader owns all active MCP server connections.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
sessions: dict[str, RuntimeMCPSession]
|
sessions: dict[str, RuntimeMCPSession]
|
||||||
@@ -468,14 +468,14 @@ class MCPLoader(loader.ToolLoader):
|
|||||||
self.ap.logger.debug(f'Started MCP server {server_config["name"]}({server_config["uuid"]})')
|
self.ap.logger.debug(f'Started MCP server {server_config["name"]}({server_config["uuid"]})')
|
||||||
|
|
||||||
async def load_mcp_server(self, server_config: dict) -> RuntimeMCPSession:
|
async def load_mcp_server(self, server_config: dict) -> RuntimeMCPSession:
|
||||||
"""加载 MCP 服务器到运行时
|
"""Load an MCP server into the runtime.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
server_config: 服务器配置字典,必须包含:
|
server_config: Server config dict. Must include:
|
||||||
- name: 服务器名称
|
- name: Server name.
|
||||||
- mode: 连接模式 (stdio/sse/http)
|
- mode: Connection mode (stdio/sse/http).
|
||||||
- enable: 是否启用
|
- enable: Whether the server is enabled.
|
||||||
- extra_args: 额外的配置参数 (可选)
|
- extra_args: Optional extra config.
|
||||||
"""
|
"""
|
||||||
uuid_ = server_config.get('uuid')
|
uuid_ = server_config.get('uuid')
|
||||||
if not uuid_:
|
if not uuid_:
|
||||||
@@ -518,7 +518,7 @@ class MCPLoader(loader.ToolLoader):
|
|||||||
return all_functions
|
return all_functions
|
||||||
|
|
||||||
async def has_tool(self, name: str) -> bool:
|
async def has_tool(self, name: str) -> bool:
|
||||||
"""检查工具是否存在"""
|
"""Return whether a loaded MCP tool exists."""
|
||||||
for session in self.sessions.values():
|
for session in self.sessions.values():
|
||||||
for function in session.get_tools():
|
for function in session.get_tools():
|
||||||
if function.name == name:
|
if function.name == name:
|
||||||
@@ -541,7 +541,7 @@ class MCPLoader(loader.ToolLoader):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
async def invoke_tool(self, name: str, parameters: dict, query: pipeline_query.Query | None) -> typing.Any:
|
async def invoke_tool(self, name: str, parameters: dict, query: pipeline_query.Query | None) -> typing.Any:
|
||||||
"""执行工具调用"""
|
"""Invoke a loaded MCP tool."""
|
||||||
for session in self.sessions.values():
|
for session in self.sessions.values():
|
||||||
for function in session.get_tools():
|
for function in session.get_tools():
|
||||||
if function.name == name:
|
if function.name == name:
|
||||||
@@ -557,7 +557,7 @@ class MCPLoader(loader.ToolLoader):
|
|||||||
raise ValueError(f'Tool not found: {name}')
|
raise ValueError(f'Tool not found: {name}')
|
||||||
|
|
||||||
async def remove_mcp_server(self, server_name: str):
|
async def remove_mcp_server(self, server_name: str):
|
||||||
"""移除 MCP 服务器"""
|
"""Remove an MCP server from the runtime."""
|
||||||
if server_name not in self.sessions:
|
if server_name not in self.sessions:
|
||||||
self.ap.logger.warning(f'MCP server {server_name} not found in sessions, skipping removal')
|
self.ap.logger.warning(f'MCP server {server_name} not found in sessions, skipping removal')
|
||||||
return
|
return
|
||||||
@@ -567,24 +567,24 @@ class MCPLoader(loader.ToolLoader):
|
|||||||
self.ap.logger.info(f'Removed MCP server: {server_name}')
|
self.ap.logger.info(f'Removed MCP server: {server_name}')
|
||||||
|
|
||||||
def get_session(self, server_name: str) -> RuntimeMCPSession | None:
|
def get_session(self, server_name: str) -> RuntimeMCPSession | None:
|
||||||
"""获取指定名称的 MCP 会话"""
|
"""Get an MCP session by server name."""
|
||||||
return self.sessions.get(server_name)
|
return self.sessions.get(server_name)
|
||||||
|
|
||||||
def has_session(self, server_name: str) -> bool:
|
def has_session(self, server_name: str) -> bool:
|
||||||
"""检查是否存在指定名称的 MCP 会话"""
|
"""Return whether a session exists for the server name."""
|
||||||
return server_name in self.sessions
|
return server_name in self.sessions
|
||||||
|
|
||||||
def get_all_server_names(self) -> list[str]:
|
def get_all_server_names(self) -> list[str]:
|
||||||
"""获取所有已加载的 MCP 服务器名称"""
|
"""Return all loaded MCP server names."""
|
||||||
return list(self.sessions.keys())
|
return list(self.sessions.keys())
|
||||||
|
|
||||||
def get_server_tool_count(self, server_name: str) -> int:
|
def get_server_tool_count(self, server_name: str) -> int:
|
||||||
"""获取指定服务器的工具数量"""
|
"""Return the number of tools exposed by one MCP server."""
|
||||||
session = self.get_session(server_name)
|
session = self.get_session(server_name)
|
||||||
return len(session.get_tools()) if session else 0
|
return len(session.get_tools()) if session else 0
|
||||||
|
|
||||||
def get_all_servers_info(self) -> dict[str, dict]:
|
def get_all_servers_info(self) -> dict[str, dict]:
|
||||||
"""获取所有服务器的信息"""
|
"""Return runtime information for all loaded MCP servers."""
|
||||||
info = {}
|
info = {}
|
||||||
for server_name, session in self.sessions.items():
|
for server_name, session in self.sessions.items():
|
||||||
tools = session.get_tools()
|
tools = session.get_tools()
|
||||||
@@ -598,7 +598,7 @@ class MCPLoader(loader.ToolLoader):
|
|||||||
return info
|
return info
|
||||||
|
|
||||||
async def shutdown(self):
|
async def shutdown(self):
|
||||||
"""关闭所有工具"""
|
"""Shut down all MCP sessions."""
|
||||||
self.ap.logger.info('Shutting down all MCP sessions...')
|
self.ap.logger.info('Shutting down all MCP sessions...')
|
||||||
for server_name, session in list(self.sessions.items()):
|
for server_name, session in list(self.sessions.items()):
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import langbot_plugin.api.entities.builtin.resource.tool as resource_tool
|
|||||||
from langbot_plugin.api.entities.events import pipeline_query
|
from langbot_plugin.api.entities.events import pipeline_query
|
||||||
|
|
||||||
from .. import loader
|
from .. import loader
|
||||||
|
from ..errors import ToolNotFoundError
|
||||||
|
from .availability import is_box_backend_available
|
||||||
from . import skill as skill_loader
|
from . import skill as skill_loader
|
||||||
|
|
||||||
EXEC_TOOL_NAME = 'exec'
|
EXEC_TOOL_NAME = 'exec'
|
||||||
@@ -52,18 +54,7 @@ class NativeToolLoader(loader.ToolLoader):
|
|||||||
|
|
||||||
async def _check_backend_available(self) -> bool:
|
async def _check_backend_available(self) -> bool:
|
||||||
"""Check if the box backend is truly available (not just the runtime)."""
|
"""Check if the box backend is truly available (not just the runtime)."""
|
||||||
box_service = getattr(self.ap, 'box_service', None)
|
return await is_box_backend_available(self.ap)
|
||||||
if box_service is None:
|
|
||||||
return False
|
|
||||||
if not getattr(box_service, 'available', False):
|
|
||||||
return False
|
|
||||||
# Check if backend is truly available via get_status
|
|
||||||
try:
|
|
||||||
status = await box_service.get_status()
|
|
||||||
backend_info = status.get('backend', {})
|
|
||||||
return backend_info.get('available', False)
|
|
||||||
except Exception:
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def get_tools(self, bound_plugins: list[str] | None = None) -> list[resource_tool.LLMTool]:
|
async def get_tools(self, bound_plugins: list[str] | None = None) -> list[resource_tool.LLMTool]:
|
||||||
if not self._is_sandbox_available():
|
if not self._is_sandbox_available():
|
||||||
@@ -100,7 +91,7 @@ class NativeToolLoader(loader.ToolLoader):
|
|||||||
return await self._invoke_glob(parameters, query)
|
return await self._invoke_glob(parameters, query)
|
||||||
if name == GREP_TOOL_NAME:
|
if name == GREP_TOOL_NAME:
|
||||||
return await self._invoke_grep(parameters, query)
|
return await self._invoke_grep(parameters, query)
|
||||||
raise ValueError(f'未找到工具: {name}')
|
raise ToolNotFoundError(name)
|
||||||
|
|
||||||
async def shutdown(self):
|
async def shutdown(self):
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import typing
|
|||||||
import langbot_plugin.api.entities.builtin.resource.tool as resource_tool
|
import langbot_plugin.api.entities.builtin.resource.tool as resource_tool
|
||||||
|
|
||||||
from .. import loader
|
from .. import loader
|
||||||
|
from .availability import is_box_backend_available
|
||||||
|
|
||||||
# Align with Claude Code's Skill tool design:
|
# Align with Claude Code's Skill tool design:
|
||||||
# - activate: Activate a skill via Tool Call, returns SKILL.md content
|
# - activate: Activate a skill via Tool Call, returns SKILL.md content
|
||||||
@@ -45,18 +46,7 @@ class SkillToolLoader(loader.ToolLoader):
|
|||||||
|
|
||||||
async def _check_sandbox_available(self) -> bool:
|
async def _check_sandbox_available(self) -> bool:
|
||||||
"""Check if the box backend is truly available (not just the runtime)."""
|
"""Check if the box backend is truly available (not just the runtime)."""
|
||||||
box_service = getattr(self.ap, 'box_service', None)
|
return await is_box_backend_available(self.ap)
|
||||||
if box_service is None:
|
|
||||||
return False
|
|
||||||
if not getattr(box_service, 'available', False):
|
|
||||||
return False
|
|
||||||
# Check if backend is truly available via get_status
|
|
||||||
try:
|
|
||||||
status = await box_service.get_status()
|
|
||||||
backend_info = status.get('backend', {})
|
|
||||||
return backend_info.get('available', False)
|
|
||||||
except Exception:
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def get_tools(self, bound_plugins: list[str] | None = None) -> list[resource_tool.LLMTool]:
|
async def get_tools(self, bound_plugins: list[str] | None = None) -> list[resource_tool.LLMTool]:
|
||||||
if not self._is_available():
|
if not self._is_available():
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ from typing import TYPE_CHECKING
|
|||||||
import langbot_plugin.api.entities.builtin.resource.tool as resource_tool
|
import langbot_plugin.api.entities.builtin.resource.tool as resource_tool
|
||||||
from langbot_plugin.api.entities.events import pipeline_query
|
from langbot_plugin.api.entities.events import pipeline_query
|
||||||
|
|
||||||
|
from .errors import ToolNotFoundError
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from ...core import app
|
from ...core import app
|
||||||
from langbot.pkg.provider.tools.loaders import (
|
from langbot.pkg.provider.tools.loaders import (
|
||||||
@@ -128,7 +130,7 @@ class ToolManager:
|
|||||||
return tools
|
return tools
|
||||||
|
|
||||||
async def execute_func_call(self, name: str, parameters: dict, query: pipeline_query.Query | None) -> typing.Any:
|
async def execute_func_call(self, name: str, parameters: dict, query: pipeline_query.Query | None) -> typing.Any:
|
||||||
"""执行函数调用"""
|
"""Execute a tool call through the active tool loaders."""
|
||||||
|
|
||||||
if await self.native_tool_loader.has_tool(name):
|
if await self.native_tool_loader.has_tool(name):
|
||||||
return await self.native_tool_loader.invoke_tool(name, parameters, query)
|
return await self.native_tool_loader.invoke_tool(name, parameters, query)
|
||||||
@@ -138,7 +140,7 @@ class ToolManager:
|
|||||||
return await self.mcp_tool_loader.invoke_tool(name, parameters, query)
|
return await self.mcp_tool_loader.invoke_tool(name, parameters, query)
|
||||||
if await self.skill_tool_loader.has_tool(name):
|
if await self.skill_tool_loader.has_tool(name):
|
||||||
return await self.skill_tool_loader.invoke_tool(name, parameters, query)
|
return await self.skill_tool_loader.invoke_tool(name, parameters, query)
|
||||||
raise ValueError(f'未找到工具: {name}')
|
raise ToolNotFoundError(name)
|
||||||
|
|
||||||
async def shutdown(self):
|
async def shutdown(self):
|
||||||
await self.native_tool_loader.shutdown()
|
await self.native_tool_loader.shutdown()
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ import typing
|
|||||||
|
|
||||||
|
|
||||||
def import_modules_in_pkg(pkg: typing.Any) -> None:
|
def import_modules_in_pkg(pkg: typing.Any) -> None:
|
||||||
"""
|
"""Import all Python modules inside a package.
|
||||||
导入一个包内的所有模块
|
|
||||||
Args:
|
Args:
|
||||||
pkg: 要导入的包对象
|
pkg: Package object to import from.
|
||||||
"""
|
"""
|
||||||
pkg_path = os.path.dirname(pkg.__file__)
|
pkg_path = os.path.dirname(pkg.__file__)
|
||||||
import_dir(pkg_path)
|
import_dir(pkg_path)
|
||||||
|
|||||||
Reference in New Issue
Block a user