feat(sandbox): enhance sandbox management and tool artifact handling

- Introduced SandboxManager.delete_storage method for improved storage management.
- Refactored skill loading and tool artifact handling in DifyCliInitializer and SandboxBashSession.
- Updated LLMNode to extract and compile tool artifacts, enhancing integration with skills.
- Improved attribute management in AttrMap for better error handling and retrieval methods.
This commit is contained in:
Harry
2026-01-22 17:25:58 +08:00
parent e7c3e4cd21
commit 9d80770dfc
13 changed files with 147 additions and 154 deletions

View File

@ -8,7 +8,6 @@ from types import TracebackType
from core.sandbox.sandbox import Sandbox
from core.session.cli_api import CliApiSession, CliApiSessionManager
from core.skill.entities.tool_artifact import ToolArtifact
from core.skill.skill_manager import SkillManager
from core.virtual_environment.__base.helpers import pipeline
from ..bash.dify_cli import DifyCliConfig
@ -19,17 +18,10 @@ logger = logging.getLogger(__name__)
class SandboxBashSession:
def __init__(
self,
*,
sandbox: Sandbox,
node_id: str,
allow_tools: list[tuple[str, str]] | None,
) -> None:
def __init__(self, *, sandbox: Sandbox, node_id: str, tools: ToolArtifact | None) -> None:
self._sandbox = sandbox
self._node_id = node_id
self._allow_tools = allow_tools
self._tools = tools
self._bash_tool: SandboxBashTool | None = None
self._cli_api_session: CliApiSession | None = None
self._tenant_id = sandbox.tenant_id
@ -42,8 +34,8 @@ class SandboxBashSession:
tenant_id=self._tenant_id,
user_id=self._user_id,
)
if self._allow_tools is not None:
tools_path = self._setup_node_tools_directory(self._node_id, self._allow_tools, self._cli_api_session)
if self._tools is not None and not self._tools.is_empty():
tools_path = self._setup_node_tools_directory(self._node_id, self._tools, self._cli_api_session)
else:
tools_path = DifyCli.GLOBAL_TOOLS_PATH
@ -57,24 +49,9 @@ class SandboxBashSession:
def _setup_node_tools_directory(
self,
node_id: str,
allow_tools: list[tuple[str, str]],
tools: ToolArtifact,
cli_api_session: CliApiSession,
) -> str | None:
artifact: ToolArtifact | None = SkillManager.load_tool_artifact(
self._sandbox.tenant_id,
self._app_id,
self._assets_id,
)
if artifact is None or artifact.is_empty():
logger.info("No tools found in artifact for assets_id=%s", self._assets_id)
return None
artifact = artifact.filter(allow_tools)
if artifact.is_empty():
logger.info("No tools found in artifact for assets_id=%s", self._assets_id)
return None
node_tools_path = f"{DifyCli.TOOLS_ROOT}/{node_id}"
vm = self._sandbox.vm
@ -86,7 +63,7 @@ class SandboxBashSession:
)
config_json = json.dumps(
DifyCliConfig.create(session=cli_api_session, tenant_id=self._tenant_id, artifact=artifact).model_dump(
DifyCliConfig.create(session=cli_api_session, tenant_id=self._tenant_id, artifact=tools).model_dump(
mode="json"
),
ensure_ascii=False,
@ -98,7 +75,7 @@ class SandboxBashSession:
).execute(raise_on_error=True)
logger.info(
"Node %s tools initialized, path=%s, tool_count=%d", node_id, node_tools_path, len(artifact.references)
"Node %s tools initialized, path=%s, tool_count=%d", node_id, node_tools_path, len(tools.references)
)
return node_tools_path

View File

@ -60,8 +60,8 @@ class DifyCliInitializer(SandboxInitializer):
logger.info("Dify CLI uploaded to sandbox, path=%s", DifyCli.PATH)
artifact = SkillManager.load_tool_artifact(self._tenant_id, self._app_id, self._assets_id)
if artifact is None or not artifact.references:
artifact = SkillManager.load_artifact(self._tenant_id, self._app_id, self._assets_id)
if artifact is None or not artifact.get_tool_artifact().is_empty:
logger.info("No tools found in artifact for assets_id=%s", self._assets_id)
return
@ -72,7 +72,7 @@ class DifyCliInitializer(SandboxInitializer):
["mkdir", "-p", DifyCli.GLOBAL_TOOLS_PATH], error_message="Failed to create global tools dir"
).execute(raise_on_error=True)
config = DifyCliConfig.create(self._cli_api_session, self._tenant_id, artifact)
config = DifyCliConfig.create(self._cli_api_session, self._tenant_id, artifact.get_tool_artifact())
config_json = json.dumps(config.model_dump(mode="json"), ensure_ascii=False)
config_path = f"{DifyCli.GLOBAL_TOOLS_PATH}/{DifyCli.CONFIG_FILENAME}"
vm.upload_file(config_path, BytesIO(config_json.encode("utf-8")))

View File

@ -9,6 +9,7 @@ from core.sandbox.entities import AppAssets, SandboxType
from core.sandbox.entities.providers import SandboxProviderEntity
from core.sandbox.initializer.app_assets_initializer import AppAssetsInitializer
from core.sandbox.initializer.dify_cli_initializer import DifyCliInitializer
from core.sandbox.initializer.skill_initializer import SkillInitializer
from core.sandbox.sandbox import Sandbox
from core.sandbox.storage.archive_storage import ArchiveSandboxStorage
from core.virtual_environment.__base.virtual_environment import VirtualEnvironment
@ -123,6 +124,7 @@ class SandboxManager:
.app(app_id)
.initializer(AppAssetsInitializer(tenant_id, app_id, assets.id))
.initializer(DifyCliInitializer(tenant_id, user_id, app_id, assets.id))
.initializer(SkillInitializer(tenant_id, user_id, app_id, assets.id))
.storage(storage, assets.id)
.build()
)
@ -130,6 +132,11 @@ class SandboxManager:
logger.info("Sandbox created: id=%s, assets=%s", sandbox.vm.metadata.id, sandbox.assets_id)
return sandbox
@classmethod
def delete_storage(cls, tenant_id: str, user_id: str) -> None:
storage = ArchiveSandboxStorage(tenant_id, SandboxBuilder.draft_id(user_id))
storage.delete()
@classmethod
def create_draft(
cls,
@ -153,6 +160,7 @@ class SandboxManager:
.app(app_id)
.initializer(AppAssetsInitializer(tenant_id, app_id, assets.id))
.initializer(DifyCliInitializer(tenant_id, user_id, app_id, assets.id))
.initializer(SkillInitializer(tenant_id, user_id, app_id, assets.id))
.storage(storage, assets.id)
.build()
)
@ -183,6 +191,7 @@ class SandboxManager:
.app(app_id)
.initializer(AppAssetsInitializer(tenant_id, app_id, assets.id))
.initializer(DifyCliInitializer(tenant_id, user_id, app_id, assets.id))
.initializer(SkillInitializer(tenant_id, user_id, app_id, assets.id))
.storage(storage, assets.id)
.build()
)