From a29f569e0867902e4489788c0a099f8d3f4c2fa5 Mon Sep 17 00:00:00 2001 From: Harry Date: Tue, 27 Jan 2026 14:19:10 +0800 Subject: [PATCH] feat(sandbox): enhance logging with colored output and add AppAssetAttrsInitializer --- .../app_asset_attrs_initializer.py | 24 +++++++++++++++ .../initializer/app_assets_initializer.py | 5 ---- .../draft_app_assets_initializer.py | 7 +---- api/core/workflow/nodes/llm/node.py | 29 ++++++++++++------- api/services/app_asset_package_service.py | 12 ++++---- api/services/sandbox/sandbox_service.py | 4 +++ 6 files changed, 54 insertions(+), 27 deletions(-) create mode 100644 api/core/sandbox/initializer/app_asset_attrs_initializer.py diff --git a/api/core/sandbox/initializer/app_asset_attrs_initializer.py b/api/core/sandbox/initializer/app_asset_attrs_initializer.py new file mode 100644 index 0000000000..d4cb623ec5 --- /dev/null +++ b/api/core/sandbox/initializer/app_asset_attrs_initializer.py @@ -0,0 +1,24 @@ +import logging + +from core.app_assets.constants import AppAssetsAttrs +from core.sandbox.sandbox import Sandbox +from services.app_asset_package_service import AppAssetPackageService + +from .base import SyncSandboxInitializer + +logger = logging.getLogger(__name__) + +APP_ASSETS_DOWNLOAD_TIMEOUT = 60 * 10 + + +class AppAssetAttrsInitializer(SyncSandboxInitializer): + def __init__(self, tenant_id: str, app_id: str, assets_id: str) -> None: + self._tenant_id = tenant_id + self._app_id = app_id + self._assets_id = assets_id + + def initialize(self, sandbox: Sandbox) -> None: + # Load published app assets and unzip the artifact bundle. + app_assets = AppAssetPackageService.get_tenant_app_assets(self._tenant_id, self._assets_id) + sandbox.attrs.set(AppAssetsAttrs.FILE_TREE, app_assets.asset_tree) + sandbox.attrs.set(AppAssetsAttrs.APP_ASSETS_ID, self._assets_id) diff --git a/api/core/sandbox/initializer/app_assets_initializer.py b/api/core/sandbox/initializer/app_assets_initializer.py index 48eb8bf99c..d7bda14aee 100644 --- a/api/core/sandbox/initializer/app_assets_initializer.py +++ b/api/core/sandbox/initializer/app_assets_initializer.py @@ -1,6 +1,5 @@ import logging -from core.app_assets.constants import AppAssetsAttrs from core.app_assets.storage import AssetPath from core.sandbox.sandbox import Sandbox from core.virtual_environment.__base.helpers import pipeline @@ -20,13 +19,9 @@ class AppAssetsInitializer(AsyncSandboxInitializer): self._assets_id = assets_id def initialize(self, sandbox: Sandbox) -> None: - from services.app_asset_package_service import AppAssetPackageService from services.app_asset_service import AppAssetService # Load published app assets and unzip the artifact bundle. - app_assets = AppAssetPackageService.get_tenant_app_assets(self._tenant_id, self._assets_id) - sandbox.attrs.set(AppAssetsAttrs.FILE_TREE, app_assets.asset_tree) - sandbox.attrs.set(AppAssetsAttrs.APP_ASSETS_ID, self._assets_id) vm = sandbox.vm asset_storage = AppAssetService.get_storage() zip_ref = AssetPath.build_zip(self._tenant_id, self._app_id, self._assets_id) diff --git a/api/core/sandbox/initializer/draft_app_assets_initializer.py b/api/core/sandbox/initializer/draft_app_assets_initializer.py index d242f895e4..9e8b646db6 100644 --- a/api/core/sandbox/initializer/draft_app_assets_initializer.py +++ b/api/core/sandbox/initializer/draft_app_assets_initializer.py @@ -7,7 +7,6 @@ from core.sandbox.sandbox import Sandbox from core.sandbox.services import AssetDownloadService from core.sandbox.services.asset_download_service import AssetDownloadItem from core.virtual_environment.__base.helpers import pipeline -from services.app_asset_package_service import AppAssetPackageService from services.app_asset_service import AppAssetService from .base import AsyncSandboxInitializer @@ -26,13 +25,9 @@ class DraftAppAssetsInitializer(AsyncSandboxInitializer): def initialize(self, sandbox: Sandbox) -> None: # Load published app assets and unzip the artifact bundle. - app_assets = AppAssetPackageService.get_tenant_app_assets(self._tenant_id, self._assets_id) - sandbox.attrs.set(AppAssetsAttrs.FILE_TREE, app_assets.asset_tree) - sandbox.attrs.set(AppAssetsAttrs.APP_ASSETS_ID, self._assets_id) - vm = sandbox.vm build_id = self._assets_id - tree = app_assets.asset_tree + tree = sandbox.attrs.get(AppAssetsAttrs.FILE_TREE) asset_storage = AppAssetService.get_storage() nodes = list(tree.walk_files()) if not nodes: diff --git a/api/core/workflow/nodes/llm/node.py b/api/core/workflow/nodes/llm/node.py index f64d1c8ab0..d2d7c8d425 100644 --- a/api/core/workflow/nodes/llm/node.py +++ b/api/core/workflow/nodes/llm/node.py @@ -298,17 +298,18 @@ class LLMNode(Node[LLMNodeData]): structured_output: LLMStructuredOutput | None = None sandbox = self.graph_runtime_state.sandbox - if self.tool_call_enabled: - if sandbox: - tool_dependencies = self._extract_tool_dependencies() - generator = self._invoke_llm_with_sandbox( - sandbox=sandbox, - model_instance=model_instance, - prompt_messages=prompt_messages, - stop=stop, - variable_pool=variable_pool, - tool_dependencies=tool_dependencies, - ) + has_skill_prompt = self._has_skill_prompt() + if sandbox and has_skill_prompt: + tool_dependencies = self._extract_tool_dependencies() + generator = self._invoke_llm_with_sandbox( + sandbox=sandbox, + model_instance=model_instance, + prompt_messages=prompt_messages, + stop=stop, + variable_pool=variable_pool, + tool_dependencies=tool_dependencies, + ) + elif self.tool_call_enabled: generator = self._invoke_llm_with_tools( model_instance=model_instance, prompt_messages=prompt_messages, @@ -1811,6 +1812,12 @@ class LLMNode(Node[LLMNodeData]): generation_data, ) + def _has_skill_prompt(self) -> bool: + for prompt in self.node_data.prompt_template: + if isinstance(prompt, LLMNodeChatModelMessage) and prompt.skill: + return True + return False + def _extract_tool_dependencies(self) -> ToolDependencies | None: """Extract tool artifact from prompt template.""" diff --git a/api/services/app_asset_package_service.py b/api/services/app_asset_package_service.py index 582a42d36a..e671811884 100644 --- a/api/services/app_asset_package_service.py +++ b/api/services/app_asset_package_service.py @@ -78,6 +78,7 @@ class AppAssetPackageService: assets: list[AssetItem], upload_url: str, tenant_id: str, + app_id: str, user_id: str, ) -> None: """Package assets into a ZIP and upload directly to the given URL.""" @@ -97,13 +98,11 @@ class AppAssetPackageService: return asset_storage = AppAssetService.get_storage() - storage_keys = [a.get_storage_key() for a in assets] - download_urls = asset_storage.storage.get_download_urls(storage_keys, 10 * 60) - + asset_paths = [AssetPath.draft(tenant_id, app_id, asset.asset_id) for asset in assets] + download_urls = asset_storage.get_download_urls(asset_paths) download_items = [ - SandboxDownloadItem(url=url, path=a.path) for a, url in zip(assets, download_urls, strict=True) + SandboxDownloadItem(url=url, path=asset.path) for asset, url in zip(assets, download_urls, strict=True) ] - with ZipSandbox(tenant_id=tenant_id, user_id=user_id, app_id="asset-packager") as zs: zs.download_items(download_items) archive = zs.zip() @@ -146,6 +145,7 @@ class AppAssetPackageService: assets=built_assets, upload_url=runtime_upload_url, tenant_id=tenant_id, + app_id=app_id, user_id=account_id, ) @@ -156,6 +156,7 @@ class AppAssetPackageService: assets=source_items, upload_url=source_upload_url, tenant_id=tenant_id, + app_id=app_id, user_id=account_id, ) @@ -181,5 +182,6 @@ class AppAssetPackageService: assets=built_assets, upload_url=upload_url, tenant_id=tenant_id, + app_id=app_id, user_id=user_id, ) diff --git a/api/services/sandbox/sandbox_service.py b/api/services/sandbox/sandbox_service.py index 9bb97f0ed2..f462a239b2 100644 --- a/api/services/sandbox/sandbox_service.py +++ b/api/services/sandbox/sandbox_service.py @@ -3,6 +3,7 @@ import logging from core.sandbox.builder import SandboxBuilder from core.sandbox.entities import AppAssets, SandboxType from core.sandbox.entities.providers import SandboxProviderEntity +from core.sandbox.initializer.app_asset_attrs_initializer import AppAssetAttrsInitializer from core.sandbox.initializer.app_assets_initializer import AppAssetsInitializer from core.sandbox.initializer.dify_cli_initializer import DifyCliInitializer from core.sandbox.initializer.draft_app_assets_initializer import DraftAppAssetsInitializer @@ -35,6 +36,7 @@ class SandboxService: .options(sandbox_provider.config) .user(user_id) .app(app_id) + .initializer(AppAssetAttrsInitializer(tenant_id, app_id, assets.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)) @@ -71,6 +73,7 @@ class SandboxService: .options(sandbox_provider.config) .user(user_id) .app(app_id) + .initializer(AppAssetAttrsInitializer(tenant_id, app_id, assets.id)) .initializer(DraftAppAssetsInitializer(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)) @@ -102,6 +105,7 @@ class SandboxService: .options(sandbox_provider.config) .user(user_id) .app(app_id) + .initializer(AppAssetAttrsInitializer(tenant_id, app_id, assets.id)) .initializer(DraftAppAssetsInitializer(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))