Feat: add local & ssh provider in admin panel (#14995)

### What problem does this PR solve?

This PR improves the connector dashboard task management experience and
adds better visibility into connector execution logs.

### Overview:

<img width="700" alt="image"
src="https://github.com/user-attachments/assets/0e643433-878e-44f7-9b98-5b8217be5e19"
/>

### 1. Support hot switching during agent runs and complete log updates

Supports switching providers during an agent run, for example:

local provider -> self-managed provider -> local provider

<img width="700" alt="image"
src="https://github.com/user-attachments/assets/bc52fc77-e44b-415d-b5c9-0e035f9a2cee"
/>

### 2. Support SSH provider

<img width="700" alt="image"
src="https://github.com/user-attachments/assets/d3039f7a-df71-4e07-9120-5748f36ece64"
/>

### 3. Support local provider

<img width="700" alt="image"
src="https://github.com/user-attachments/assets/d5d1b170-8d45-4da4-afa3-957bb69557b8"
/>

### 4. Expose self-managed deployment defaults

Self-managed deployment defaults are now visible to users and can be
customized in `docker/.env`.

These values are kept as deployment defaults because changes require a
hard restart to take effect.

<img width="700" alt="image"
src="https://github.com/user-attachments/assets/05923610-e083-4f1c-bef9-4db90ad131b8"
/>

### Type of change

- [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
Magicbook1108
2026-05-19 17:36:27 +08:00
committed by GitHub
parent 77834870fc
commit f6537ae4ce
20 changed files with 1835 additions and 408 deletions

View File

@ -361,11 +361,21 @@ class CodeExec(ToolBase, ABC):
# Try using the new sandbox provider system first
try:
from agent.sandbox.client import execute_code as sandbox_execute_code
from agent.sandbox.client import get_provider_info
from agent.sandbox.client import reload_provider
from agent.sandbox.providers.base import SandboxProviderConfigError
if self.check_if_canceled("CodeExec execution"):
return
reload_provider()
provider_info = get_provider_info()
provider_type = provider_info.get("provider_type") or "unknown"
logging.info(
f"[CodeExec]: dispatching execution to sandbox provider '{provider_type}' "
f"(language={language}, timeout={timeout_seconds}s)"
)
# Execute code using the provider system
result = sandbox_execute_code(code=code, language=language, timeout=timeout_seconds, arguments=arguments)
@ -376,7 +386,7 @@ class CodeExec(ToolBase, ABC):
return self._process_execution_result(
result.stdout,
result.stderr,
"Provider system",
f"Provider system ({provider_type})",
artifacts,
execution_metadata=result.metadata,
)
@ -388,10 +398,8 @@ class CodeExec(ToolBase, ABC):
# Provider modules are unavailable, fall back to legacy HTTP sandbox.
logging.info(f"[CodeExec]: Provider system not available, using HTTP fallback: {provider_error}")
except RuntimeError as provider_error:
if not self._should_fallback_to_http(provider_error):
self.set_output("_ERROR", f"Provider system execution failed: {provider_error}")
return self.output()
logging.info(f"[CodeExec]: Provider system not available, using HTTP fallback: {provider_error}")
self.set_output("_ERROR", f"Provider system execution failed: {provider_error}")
return self.output()
# Fallback to direct HTTP request
code_b64 = self._encode_code(code)
@ -502,15 +510,6 @@ class CodeExec(ToolBase, ABC):
return metadata.get("result_value"), False
return self._deserialize_stdout(stdout), True
@staticmethod
def _should_fallback_to_http(provider_error: RuntimeError) -> bool:
message = str(provider_error).lower()
fallback_markers = (
"no sandbox provider configured",
"sandbox provider type not configured",
)
return any(marker in message for marker in fallback_markers)
@classmethod
def _ensure_bucket_lifecycle(cls):
if cls._lifecycle_configured: