feat(toolmgr): enhance tool initialization with backend availability checks

This commit is contained in:
huanghuoguoguo
2026-05-14 09:01:20 +08:00
parent fd03b202a8
commit 656dafb07a
3 changed files with 71 additions and 18 deletions

View File

@@ -26,6 +26,34 @@ class NativeToolLoader(loader.ToolLoader):
def __init__(self, ap):
super().__init__(ap)
self._tools: list[resource_tool.LLMTool] | None = None
self._backend_available: bool | None = None
async def initialize(self):
"""Check if backend is truly available at startup."""
self._backend_available = await self._check_backend_available()
if self._backend_available:
self.ap.logger.info('Native sandbox tools (exec/read/write/edit/glob/grep) are available.')
else:
self.ap.logger.warning(
'Native sandbox tools (exec/read/write/edit/glob/grep) are NOT available. '
'No sandbox backend (Docker/nsjail/E2B) is ready. '
'The LLM will not have access to code execution or file operation tools.'
)
async def _check_backend_available(self) -> bool:
"""Check if the box backend is truly available (not just the runtime)."""
box_service = getattr(self.ap, 'box_service', None)
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]:
if not self._is_sandbox_available():
@@ -225,8 +253,12 @@ class NativeToolLoader(loader.ToolLoader):
refresh_skill(selected_skill.get('name', ''))
def _is_sandbox_available(self) -> bool:
box_service = getattr(self.ap, 'box_service', None)
return bool(getattr(box_service, 'available', False))
"""Check if sandbox backend is available.
This checks the cached backend availability from initialization,
not just whether the box_service process is running.
"""
return bool(self._backend_available)
def _build_exec_tool(self) -> resource_tool.LLMTool:
return resource_tool.LLMTool(

View File

@@ -27,20 +27,51 @@ class SkillToolLoader(loader.ToolLoader):
def __init__(self, ap):
super().__init__(ap)
self._tools: list[resource_tool.LLMTool] = []
self._sandbox_available: bool = False
async def initialize(self):
self._tools = [
self._build_activate_skill_tool(),
self._build_register_skill_tool(),
]
# Check if sandbox backend is available (same check as native tools)
self._sandbox_available = await self._check_sandbox_available()
if self._sandbox_available:
self._tools = [
self._build_activate_skill_tool(),
self._build_register_skill_tool(),
]
else:
self.ap.logger.info(
'Skill tools (activate/register_skill) are NOT available. '
'No sandbox backend (Docker/nsjail/E2B) is ready.'
)
async def _check_sandbox_available(self) -> bool:
"""Check if the box backend is truly available (not just the runtime)."""
box_service = getattr(self.ap, 'box_service', None)
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]:
if not self._has_skill_manager():
if not self._is_available():
return []
return list(self._tools)
async def has_tool(self, name: str) -> bool:
return self._has_skill_manager() and name in SKILL_TOOL_NAMES
return self._is_available() and name in SKILL_TOOL_NAMES
def _is_available(self) -> bool:
"""Check if skill tools should be available.
Skill tools require both a skill manager and a sandbox backend.
"""
return self._has_skill_manager() and self._sandbox_available
async def invoke_tool(self, name: str, parameters: dict, query) -> typing.Any:
if name == ACTIVATE_SKILL_TOOL_NAME:

View File

@@ -44,16 +44,6 @@ class ToolManager:
self.native_tool_loader = native_loader.NativeToolLoader(self.ap)
await self.native_tool_loader.initialize()
# Log native (sandbox) tool availability once at startup
box_service = getattr(self.ap, 'box_service', None)
if box_service and getattr(box_service, 'available', False):
self.ap.logger.info('Native sandbox tools (exec/read/write/edit/glob/grep) are available.')
else:
self.ap.logger.warning(
'Native sandbox tools (exec/read/write/edit/glob/grep) are NOT available. '
'Box runtime is not connected — the LLM will not have access to code execution tools.'
)
self.plugin_tool_loader = plugin_loader.PluginToolLoader(self.ap)
await self.plugin_tool_loader.initialize()
self.mcp_tool_loader = mcp_loader.MCPLoader(self.ap)