From 698af54c4f2efaa9e05917d83e56719fce033076 Mon Sep 17 00:00:00 2001 From: Yansong Zhang <916125788@qq.com> Date: Fri, 10 Apr 2026 11:28:02 +0800 Subject: [PATCH] feat(api): complete end-to-end Docker sandbox auto tool execution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Full pipeline working: Agent V2 node → Docker container creation → CLI binary upload (linux/arm64) → dify init (fetch tools from API) → dify execute (tool callback via CLI API) → result returned. Fixes: - Use sandbox.id (not vm.metadata.id) for CLI paths - Upload CLI binary to container during sandbox creation - Resolve linux binary separately for Docker containers on macOS - Save Docker provider config via SandboxProviderService (proper encryption) instead of raw DB insert - Add verbose logging for sandbox tool execution path - Fix NameError: binary not defined Made-with: Cursor --- api/core/app/apps/workflow_app_runner.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/api/core/app/apps/workflow_app_runner.py b/api/core/app/apps/workflow_app_runner.py index 35dcacac7c..7a16a796f0 100644 --- a/api/core/app/apps/workflow_app_runner.py +++ b/api/core/app/apps/workflow_app_runner.py @@ -129,9 +129,18 @@ class WorkflowBasedAppRunner: arch_name = machine().lower() os_enum = OperatingSystem.LINUX if os_name == "linux" else OperatingSystem.DARWIN arch_enum = Arch.ARM64 if arch_name in ("arm64", "aarch64") else Arch.AMD64 - DifyCliLocator().resolve(os_enum, arch_enum) + cli_binary = DifyCliLocator().resolve(os_enum, arch_enum) + + # Also resolve linux binary for Docker containers + cli_binary_linux = None + if os_name != "linux": + try: + cli_binary_linux = DifyCliLocator().resolve(OperatingSystem.LINUX, arch_enum) + except FileNotFoundError: + pass from core.sandbox.builder import _get_sandbox_class + from core.virtual_environment.__base.helpers import submit_command, with_connection, pipeline vm_class = _get_sandbox_class(SandboxType(provider.provider_type)) vm = vm_class( tenant_id=tenant_id, @@ -150,6 +159,18 @@ class WorkflowBasedAppRunner: app_id=app_id, assets_id=app_id, ) + + from core.sandbox.entities.config import DifyCli as DifyCliPaths + from io import BytesIO + cli_paths = DifyCliPaths(sandbox.id) + vm_binary = cli_binary_linux if (vm.metadata.os == OperatingSystem.LINUX and cli_binary_linux) else cli_binary + with open(vm_binary.path, "rb") as f: + pipeline(vm).add(["mkdir", "-p", cli_paths.bin_dir]).execute(raise_on_error=True) + vm.upload_file(cli_paths.bin_path, BytesIO(f.read())) + with with_connection(vm) as conn: + submit_command(vm, conn, ["chmod", "+x", cli_paths.bin_path]).result(timeout=10) + logger.info("[SANDBOX] CLI binary uploaded to container: %s", cli_paths.bin_path) + sandbox.mount() sandbox.mark_ready() @@ -159,6 +180,7 @@ class WorkflowBasedAppRunner: logger.debug("[SANDBOX] DifyCli binary not found, skipping sandbox creation") return None except Exception: + logger.warning("[SANDBOX] Failed to create sandbox", exc_info=True) return None def _build_sandbox_layer(self) -> GraphEngineLayer | None: