fix(box): tighten sandbox exposure and restore box integration coverage

This commit is contained in:
youhuanghe
2026-03-24 04:01:16 +00:00
committed by WangCham
parent 63d22b1f8e
commit 2911220054
11 changed files with 127 additions and 48 deletions

View File

@@ -279,11 +279,6 @@ class BoxService:
default_host_workspace = os.path.join(self.shared_host_root, 'default')
return os.path.realpath(os.path.abspath(default_host_workspace))
def get_managed_skills_root(self) -> str | None:
if self.shared_host_root is None:
return None
return os.path.join(self.shared_host_root, 'skills')
def _ensure_default_host_workspace(self):
if self.default_host_workspace is None:
return

View File

@@ -2,8 +2,12 @@ from __future__ import annotations
import abc
import typing
from typing import TYPE_CHECKING
from ..core import app
if TYPE_CHECKING:
from ..core import app
import langbot_plugin.api.entities.builtin.pipeline.query as pipeline_query
import langbot_plugin.api.entities.builtin.provider.message as provider_message
preregistered_runners: list[typing.Type[RequestRunner]] = []
@@ -25,17 +29,17 @@ class RequestRunner(abc.ABC):
name: str = None
ap: app.Application
ap: 'app.Application'
pipeline_config: dict
def __init__(self, ap: app.Application, pipeline_config: dict):
def __init__(self, ap: 'app.Application', pipeline_config: dict):
self.ap = ap
self.pipeline_config = pipeline_config
@abc.abstractmethod
async def run(
self, query: core_entities.Query
) -> typing.AsyncGenerator[llm_entities.Message | llm_entities.MessageChunk, None]:
self, query: 'pipeline_query.Query'
) -> typing.AsyncGenerator['provider_message.Message | provider_message.MessageChunk', None]:
"""运行请求"""
pass

View File

@@ -2,12 +2,14 @@ from __future__ import annotations
import abc
import typing
from typing import TYPE_CHECKING
from langbot_plugin.api.entities.events import pipeline_query
from ...core import app
import langbot_plugin.api.entities.builtin.resource.tool as resource_tool
if TYPE_CHECKING:
from ...core import app
preregistered_loaders: list[typing.Type[ToolLoader]] = []
@@ -28,9 +30,9 @@ class ToolLoader(abc.ABC):
name: str = None
ap: app.Application
ap: 'app.Application'
def __init__(self, ap: app.Application):
def __init__(self, ap: 'app.Application'):
self.ap = ap
async def initialize(self):

View File

@@ -147,7 +147,6 @@ class RuntimeMCPSession:
try:
await box_service.create_session(
session_payload,
skip_host_mount_validation=True,
)
except Exception:
self.error_phase = MCPSessionErrorPhase.SESSION_CREATE
@@ -164,9 +163,7 @@ class RuntimeMCPSession:
exec_payload['cmd'] = install_cmd
exec_payload['timeout_sec'] = self.box_config.startup_timeout_sec or 120
try:
result = await box_service.client.execute(
box_service.build_spec(exec_payload, skip_host_mount_validation=True)
)
result = await box_service.client.execute(box_service.build_spec(exec_payload))
except Exception:
self.error_phase = MCPSessionErrorPhase.DEP_INSTALL
raise

View File

@@ -17,12 +17,14 @@ class NativeToolLoader(loader.ToolLoader):
self._sandbox_exec_tool: resource_tool.LLMTool | None = None
async def get_tools(self, bound_plugins: list[str] | None = None) -> list[resource_tool.LLMTool]:
if not self._is_sandbox_available():
return []
if self._sandbox_exec_tool is None:
self._sandbox_exec_tool = self._build_sandbox_exec_tool()
return [self._sandbox_exec_tool]
async def has_tool(self, name: str) -> bool:
return name == SANDBOX_EXEC_TOOL_NAME
return name == SANDBOX_EXEC_TOOL_NAME and self._is_sandbox_available()
async def invoke_tool(self, name: str, parameters: dict, query: pipeline_query.Query):
if name != SANDBOX_EXEC_TOOL_NAME:
@@ -37,6 +39,10 @@ class NativeToolLoader(loader.ToolLoader):
async def shutdown(self):
pass
def _is_sandbox_available(self) -> bool:
box_service = getattr(self.ap, 'box_service', None)
return bool(getattr(box_service, 'available', False))
def _build_sandbox_exec_tool(self) -> resource_tool.LLMTool:
return resource_tool.LLMTool(
name=SANDBOX_EXEC_TOOL_NAME,

View File

@@ -1,27 +1,30 @@
from __future__ import annotations
import typing
from typing import TYPE_CHECKING
from ...core import app
from langbot.pkg.utils import importutil
from langbot.pkg.provider.tools import loaders
from langbot.pkg.provider.tools.loaders import mcp as mcp_loader, native as native_loader, plugin as plugin_loader
import langbot_plugin.api.entities.builtin.resource.tool as resource_tool
from langbot_plugin.api.entities.events import pipeline_query
if TYPE_CHECKING:
from ...core import app
importutil.import_modules_in_pkg(loaders)
class ToolManager:
"""LLM工具管理器"""
ap: app.Application
ap: 'app.Application'
native_tool_loader: native_loader.NativeToolLoader
plugin_tool_loader: plugin_loader.PluginToolLoader
mcp_tool_loader: mcp_loader.MCPLoader
def __init__(self, ap: app.Application):
def __init__(self, ap: 'app.Application'):
self.ap = ap
async def initialize(self):