mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-10-20 15:37:27 +08:00
fix(tools): hide register_skill when Cloud sandboxes cannot scan host directories
scan_skill_directory is disabled for Cloud-managed sandboxes, but the register_skill tool was still advertised to the model whenever a backend was available, so every call failed closed without a usable explanation. Advertise register_skill only when the runtime may scan sandbox directories, and keep activate available in both modes.
This commit is contained in:
@@ -35,10 +35,7 @@ class SkillToolLoader(loader.ToolLoader):
|
||||
# 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(),
|
||||
]
|
||||
self._tools = self._build_skill_tools()
|
||||
else:
|
||||
self.ap.logger.info(
|
||||
'Skill tools (activate/register_skill) are NOT available. '
|
||||
@@ -54,14 +51,32 @@ class SkillToolLoader(loader.ToolLoader):
|
||||
if not await self._is_available():
|
||||
return []
|
||||
if not self._tools:
|
||||
self._tools = [
|
||||
self._build_activate_skill_tool(),
|
||||
self._build_register_skill_tool(),
|
||||
]
|
||||
self._tools = self._build_skill_tools()
|
||||
return list(self._tools)
|
||||
|
||||
def _build_skill_tools(self) -> list[resource_tool.LLMTool]:
|
||||
tools = [self._build_activate_skill_tool()]
|
||||
if self._skill_registration_available():
|
||||
tools.append(self._build_register_skill_tool())
|
||||
else:
|
||||
self.ap.logger.info(
|
||||
'register_skill is NOT available: Cloud sandboxes never scan arbitrary '
|
||||
'host skill directories. Install skills through the skill store instead.'
|
||||
)
|
||||
return tools
|
||||
|
||||
def _skill_registration_available(self) -> bool:
|
||||
"""Host skill scanning is disabled for Cloud-managed sandboxes."""
|
||||
|
||||
box_service = getattr(self.ap, 'box_service', None)
|
||||
return not bool(getattr(box_service, 'managed_admission_required', False))
|
||||
|
||||
async def has_tool(self, name: str) -> bool:
|
||||
return await self._is_available() and name in SKILL_TOOL_NAMES
|
||||
if not await self._is_available() or name not in SKILL_TOOL_NAMES:
|
||||
return False
|
||||
if name == REGISTER_SKILL_TOOL_NAME:
|
||||
return self._skill_registration_available()
|
||||
return True
|
||||
|
||||
async def _is_available(self) -> bool:
|
||||
"""Check if skill tools should be available.
|
||||
|
||||
@@ -737,3 +737,23 @@ async def test_native_skill_tools_require_runner_box_binding():
|
||||
with pytest.raises(BoxValidationError, match='Runner must bind a Box'):
|
||||
await loader.invoke_tool('exec', {'command': 'true'}, _make_query())
|
||||
ap.box_service.execute_tool.assert_not_awaited()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_register_skill_hidden_when_cloud_scanning_is_disabled(self):
|
||||
from langbot.pkg.provider.tools.loaders.skill_authoring import SkillToolLoader
|
||||
|
||||
ap = _make_ap()
|
||||
ap.skill_mgr = _make_skill_manager({'demo': _make_skill_data(name='demo')})
|
||||
ap.box_service = SimpleNamespace(
|
||||
available=True,
|
||||
managed_admission_required=True,
|
||||
get_backend_status=AsyncMock(return_value={'backend': {'available': True}}),
|
||||
)
|
||||
|
||||
loader = SkillToolLoader(ap)
|
||||
await loader.initialize()
|
||||
|
||||
assert [tool.name for tool in await loader.get_tools()] == ['activate']
|
||||
assert await loader.has_tool('register_skill') is False
|
||||
assert await loader.has_tool('activate') is True
|
||||
|
||||
Reference in New Issue
Block a user