feature: enhance alias sandbox performance when running code (#91)

This commit is contained in:
Weirui Kuang
2026-01-07 11:09:44 +08:00
committed by GitHub
parent 1f0cd9b58a
commit fe4b7f53b0
3 changed files with 265 additions and 31 deletions

View File

@@ -2,7 +2,7 @@
import io
import sys
import logging
import subprocess
import asyncio
import traceback
from contextlib import redirect_stderr, redirect_stdout
@@ -44,26 +44,33 @@ async def run_ipython_cell(
stdout_buf = io.StringIO()
stderr_buf = io.StringIO()
with redirect_stdout(stdout_buf), redirect_stderr(stderr_buf):
preprocessing_exc_tuple = None
try:
transformed_cell = ipy.transform_cell(code)
except Exception:
transformed_cell = code
preprocessing_exc_tuple = sys.exc_info()
def thread_target():
with redirect_stdout(stdout_buf), redirect_stderr(stderr_buf):
preprocessing_exc_tuple = None
try:
transformed_cell = ipy.transform_cell(code)
except Exception:
transformed_cell = code
preprocessing_exc_tuple = sys.exc_info()
if transformed_cell is None:
raise HTTPException(
status_code=500,
detail="IPython cell transformation failed: "
"transformed_cell is None.",
if transformed_cell is None:
raise HTTPException(
status_code=500,
detail=(
"IPython cell transformation failed: "
"transformed_cell is None."
),
)
asyncio.run(
ipy.run_cell_async(
code,
transformed_cell=transformed_cell,
preprocessing_exc_tuple=preprocessing_exc_tuple,
),
)
await ipy.run_cell_async(
code,
transformed_cell=transformed_cell,
preprocessing_exc_tuple=preprocessing_exc_tuple,
)
await asyncio.to_thread(thread_target)
stdout_content = stdout_buf.getvalue()
stderr_content = stderr_buf.getvalue()
@@ -128,16 +135,16 @@ async def run_shell_command(
if not command:
raise HTTPException(status_code=400, detail="Command is required.")
result = subprocess.run(
proc = await asyncio.create_subprocess_shell(
command,
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
check=False,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
)
stdout_content = result.stdout
stderr_content = result.stderr
stdout_bytes, stderr_bytes = await proc.communicate()
stdout_content = stdout_bytes.decode()
stderr_content = stderr_bytes.decode()
content_list = []
@@ -161,7 +168,7 @@ async def run_shell_command(
content_list.append(
TextContent(
type="text",
text=str(result.returncode),
text=str(proc.returncode),
description="returncode",
),
)
@@ -173,7 +180,7 @@ async def run_shell_command(
+ "\n"
+ stderr_content
+ "\n"
+ str(result.returncode),
+ str(proc.returncode),
description="output",
),
)

View File

@@ -107,12 +107,31 @@
function getSandboxIdFromPath() {
const pathParts = window.location.pathname.split('/');
if (pathParts.length >= 3 && pathParts[1] === 'desktop') {
return pathParts[2];
// Find 'desktop' anywhere in the path to support arbitrary URL prefixes
// Supports: /desktop/{sandbox_id}/... or /custom/prefix/desktop/{sandbox_id}/...
const desktopIndex = pathParts.indexOf('desktop');
if (desktopIndex !== -1 && pathParts.length > desktopIndex + 1) {
// Return null if sandbox_id is empty (e.g., /desktop/ or /desktop//)
return pathParts[desktopIndex + 1] || null;
}
return null;
}
function getWebSocketPath(sandbox_id) {
// Extract the path prefix up to and including /desktop/{sandbox_id}
// This preserves any custom URL prefix for reverse proxy deployments
const currentPath = window.location.pathname;
// Use non-greedy matching (.*?) to find the FIRST occurrence of /desktop/
// This ensures consistency with getSandboxIdFromPath() which uses indexOf()
const desktopMatch = currentPath.match(/(.*?)\/desktop\/([^\/]+)/);
if (desktopMatch) {
// Use the passed sandbox_id parameter for consistency
return desktopMatch[1] + '/desktop/' + sandbox_id;
}
// Fallback to simple path
return '/desktop/' + sandbox_id;
}
document.getElementById('sendCtrlAltDelButton')
.onclick = sendCtrlAltDel;
@@ -141,7 +160,7 @@
url += ':' + port;
}
url += '/desktop/' + sandbox_id;
url += getWebSocketPath(sandbox_id);
if (path && path !== 'websockify') {
url += '?path=' + encodeURIComponent(path);