mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-07-20 11:26:07 +00:00
feat(toolmgr): enhance tool initialization with backend availability checks
This commit is contained in:
@@ -26,6 +26,34 @@ class NativeToolLoader(loader.ToolLoader):
|
|||||||
def __init__(self, ap):
|
def __init__(self, ap):
|
||||||
super().__init__(ap)
|
super().__init__(ap)
|
||||||
self._tools: list[resource_tool.LLMTool] | None = None
|
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]:
|
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():
|
||||||
@@ -225,8 +253,12 @@ class NativeToolLoader(loader.ToolLoader):
|
|||||||
refresh_skill(selected_skill.get('name', ''))
|
refresh_skill(selected_skill.get('name', ''))
|
||||||
|
|
||||||
def _is_sandbox_available(self) -> bool:
|
def _is_sandbox_available(self) -> bool:
|
||||||
box_service = getattr(self.ap, 'box_service', None)
|
"""Check if sandbox backend is available.
|
||||||
return bool(getattr(box_service, 'available', False))
|
|
||||||
|
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:
|
def _build_exec_tool(self) -> resource_tool.LLMTool:
|
||||||
return resource_tool.LLMTool(
|
return resource_tool.LLMTool(
|
||||||
|
|||||||
@@ -27,20 +27,51 @@ class SkillToolLoader(loader.ToolLoader):
|
|||||||
def __init__(self, ap):
|
def __init__(self, ap):
|
||||||
super().__init__(ap)
|
super().__init__(ap)
|
||||||
self._tools: list[resource_tool.LLMTool] = []
|
self._tools: list[resource_tool.LLMTool] = []
|
||||||
|
self._sandbox_available: bool = False
|
||||||
|
|
||||||
async def initialize(self):
|
async def initialize(self):
|
||||||
self._tools = [
|
# Check if sandbox backend is available (same check as native tools)
|
||||||
self._build_activate_skill_tool(),
|
self._sandbox_available = await self._check_sandbox_available()
|
||||||
self._build_register_skill_tool(),
|
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]:
|
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 []
|
||||||
return list(self._tools)
|
return list(self._tools)
|
||||||
|
|
||||||
async def has_tool(self, name: str) -> bool:
|
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:
|
async def invoke_tool(self, name: str, parameters: dict, query) -> typing.Any:
|
||||||
if name == ACTIVATE_SKILL_TOOL_NAME:
|
if name == ACTIVATE_SKILL_TOOL_NAME:
|
||||||
|
|||||||
@@ -44,16 +44,6 @@ class ToolManager:
|
|||||||
self.native_tool_loader = native_loader.NativeToolLoader(self.ap)
|
self.native_tool_loader = native_loader.NativeToolLoader(self.ap)
|
||||||
await self.native_tool_loader.initialize()
|
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)
|
self.plugin_tool_loader = plugin_loader.PluginToolLoader(self.ap)
|
||||||
await self.plugin_tool_loader.initialize()
|
await self.plugin_tool_loader.initialize()
|
||||||
self.mcp_tool_loader = mcp_loader.MCPLoader(self.ap)
|
self.mcp_tool_loader = mcp_loader.MCPLoader(self.ap)
|
||||||
|
|||||||
Reference in New Issue
Block a user