refactor: consolidate sandbox management and initialization

- Moved sandbox-related classes and functions into a dedicated module for better organization.
- Updated the sandbox initialization process to streamline asset management and environment setup.
- Removed deprecated constants and refactored related code to utilize new sandbox entities.
- Enhanced the workflow context to support sandbox integration, allowing for improved state management during execution.
- Adjusted various components to utilize the new sandbox structure, ensuring compatibility across the application.
This commit is contained in:
Harry
2026-01-21 20:42:19 +08:00
parent 1fcff5f8d1
commit 9ed83a808a
30 changed files with 449 additions and 545 deletions

View File

@ -6,7 +6,7 @@ from core.virtual_environment.__base.virtual_environment import VirtualEnvironme
from extensions.ext_storage import storage
from extensions.storage.file_presign_storage import FilePresignStorage
from ..constants import APP_ASSETS_PATH, APP_ASSETS_ZIP_PATH
from ..entities import AppAssets
from .base import SandboxInitializer
logger = logging.getLogger(__name__)
@ -26,11 +26,11 @@ class AppAssetsInitializer(SandboxInitializer):
(
pipeline(env)
.add(["wget", "-q", download_url, "-O", APP_ASSETS_ZIP_PATH], error_message="Failed to download assets zip")
.add(["wget", "-q", download_url, "-O", AppAssets.ZIP_PATH], error_message="Failed to download assets zip")
# unzip with silent error and return 1 if the zip is empty
# FIXME(Mairuis): should use a more robust way to check if the zip is empty
.add(
["sh", "-c", f"unzip {APP_ASSETS_ZIP_PATH} -d {APP_ASSETS_PATH} 2>/dev/null || [ $? -eq 1 ]"],
["sh", "-c", f"unzip {AppAssets.ZIP_PATH} -d {AppAssets.PATH} 2>/dev/null || [ $? -eq 1 ]"],
error_message="Failed to unzip assets",
)
.execute(timeout=APP_ASSETS_DOWNLOAD_TIMEOUT, raise_on_error=True)
@ -55,12 +55,12 @@ class DraftAppAssetsInitializer(SandboxInitializer):
(
pipeline(env)
.add(["rm", "-rf", APP_ASSETS_PATH])
.add(["wget", "-q", download_url, "-O", APP_ASSETS_ZIP_PATH], error_message="Failed to download assets zip")
.add(["rm", "-rf", AppAssets.PATH])
.add(["wget", "-q", download_url, "-O", AppAssets.ZIP_PATH], error_message="Failed to download assets zip")
# unzip with silent error and return 1 if the zip is empty
# FIXME(Mairuis): should use a more robust way to check if the zip is empty
.add(
["sh", "-c", f"unzip {APP_ASSETS_ZIP_PATH} -d {APP_ASSETS_PATH} 2>/dev/null || [ $? -eq 1 ]"],
["sh", "-c", f"unzip {AppAssets.ZIP_PATH} -d {AppAssets.PATH} 2>/dev/null || [ $? -eq 1 ]"],
error_message="Failed to unzip assets",
)
.execute(timeout=APP_ASSETS_DOWNLOAD_TIMEOUT, raise_on_error=True)

View File

@ -11,12 +11,7 @@ from core.virtual_environment.__base.helpers import pipeline
from core.virtual_environment.__base.virtual_environment import VirtualEnvironment
from ..bash.dify_cli import DifyCliConfig, DifyCliLocator
from ..constants import (
DIFY_CLI_CONFIG_FILENAME,
DIFY_CLI_GLOBAL_TOOLS_PATH,
DIFY_CLI_PATH,
DIFY_CLI_ROOT,
)
from ..entities import DifyCli
from .base import SandboxInitializer
logger = logging.getLogger(__name__)
@ -44,10 +39,10 @@ class DifyCliInitializer(SandboxInitializer):
binary = self._locator.resolve(env.metadata.os, env.metadata.arch)
pipeline(env).add(
["mkdir", "-p", f"{DIFY_CLI_ROOT}/bin"], error_message="Failed to create dify CLI directory"
["mkdir", "-p", f"{DifyCli.ROOT}/bin"], error_message="Failed to create dify CLI directory"
).execute(raise_on_error=True)
env.upload_file(DIFY_CLI_PATH, BytesIO(binary.path.read_bytes()))
env.upload_file(DifyCli.PATH, BytesIO(binary.path.read_bytes()))
# Use 'cp' with mode preservation workaround: copy file to itself to claim ownership,
# then use 'install' to set executable permission
@ -55,14 +50,14 @@ class DifyCliInitializer(SandboxInitializer):
[
"sh",
"-c",
f"cat '{DIFY_CLI_PATH}' > '{DIFY_CLI_PATH}.tmp' && "
f"mv '{DIFY_CLI_PATH}.tmp' '{DIFY_CLI_PATH}' && "
f"chmod +x '{DIFY_CLI_PATH}'",
f"cat '{DifyCli.PATH}' > '{DifyCli.PATH}.tmp' && "
f"mv '{DifyCli.PATH}.tmp' '{DifyCli.PATH}' && "
f"chmod +x '{DifyCli.PATH}'",
],
error_message="Failed to mark dify CLI as executable",
).execute(raise_on_error=True)
logger.info("Dify CLI uploaded to sandbox, path=%s", DIFY_CLI_PATH)
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:
@ -73,16 +68,16 @@ class DifyCliInitializer(SandboxInitializer):
self._cli_api_session = CliApiSessionManager().create(tenant_id=self._tenant_id, user_id=self._user_id)
pipeline(env).add(
["mkdir", "-p", DIFY_CLI_GLOBAL_TOOLS_PATH], error_message="Failed to create global tools dir"
["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_json = json.dumps(config.model_dump(mode="json"), ensure_ascii=False)
config_path = f"{DIFY_CLI_GLOBAL_TOOLS_PATH}/{DIFY_CLI_CONFIG_FILENAME}"
config_path = f"{DifyCli.GLOBAL_TOOLS_PATH}/{DifyCli.CONFIG_FILENAME}"
env.upload_file(config_path, BytesIO(config_json.encode("utf-8")))
pipeline(env, cwd=DIFY_CLI_GLOBAL_TOOLS_PATH).add(
[DIFY_CLI_PATH, "init"], error_message="Failed to initialize Dify CLI"
pipeline(env, cwd=DifyCli.GLOBAL_TOOLS_PATH).add(
[DifyCli.PATH, "init"], error_message="Failed to initialize Dify CLI"
).execute(raise_on_error=True)
logger.info("Global tools initialized, path=%s, tool_count=%d", DIFY_CLI_GLOBAL_TOOLS_PATH, len(self._tools))
logger.info("Global tools initialized, path=%s, tool_count=%d", DifyCli.GLOBAL_TOOLS_PATH, len(self._tools))