feat(shell): implement background command execution with detached shell command support

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
Soulter
2026-04-27 22:27:18 +08:00
parent ffa7508a8b
commit 44e31bd49c
4 changed files with 23 additions and 8 deletions

View File

@@ -0,0 +1,18 @@
import shlex
_BACKGROUND_SPAWN_SCRIPT = (
"import subprocess, sys; "
"p = subprocess.Popen("
"['bash', '-lc', sys.argv[1]], "
"stdin=subprocess.DEVNULL, "
"stdout=subprocess.DEVNULL, "
"stderr=subprocess.DEVNULL, "
"start_new_session=True, "
"close_fds=True"
"); "
"print(p.pid)"
)
def build_detached_shell_command(command: str) -> str:
return f"python3 -c {shlex.quote(_BACKGROUND_SPAWN_SCRIPT)} {shlex.quote(command)}"

View File

@@ -10,6 +10,7 @@ from astrbot.api import logger
from ..olayer import FileSystemComponent, PythonComponent, ShellComponent
from .base import ComputerBooter
from .shell_background import build_detached_shell_command
from .shipyard_search_file_util import search_files_via_shell
@@ -52,9 +53,7 @@ class ShipyardShellWrapper:
run_command = f"{env_prefix} {run_command}"
if background:
run_command = (
f"nohup sh -lc {shlex.quote(run_command)} >/dev/null 2>&1 & echo $!"
)
run_command = build_detached_shell_command(run_command)
result = await self._shell.exec(
run_command,

View File

@@ -13,6 +13,7 @@ from ..olayer import (
ShellComponent,
)
from .base import ComputerBooter
from .shell_background import build_detached_shell_command
from .shipyard_search_file_util import search_files_via_shell
try:
@@ -116,9 +117,7 @@ class NeoShellComponent(ShellComponent):
run_command = f"{env_prefix} {run_command}"
if background:
run_command = (
f"nohup sh -lc {shlex.quote(run_command)} >/dev/null 2>&1 & echo $!"
)
run_command = build_detached_shell_command(run_command)
result = await self._sandbox.shell.exec(
run_command,

View File

@@ -60,7 +60,7 @@ class ExecuteShellTool(FunctionTool):
},
"background": {
"type": "boolean",
"description": "Run the command in the background. Use the file read tool to read the output later.",
"description": "Run the command in the background. Use the file read tool to read the output later. For long running commands, using this option.",
"default": False,
},
"timeout": {
@@ -123,7 +123,6 @@ class ExecuteShellTool(FunctionTool):
timeout=timeout or 300,
)
if stdout_file:
result["stdout_file"] = stdout_file
result["stdout"] = (
f"Command is running in the background. stdout/stderr is being "
f"written to `{stdout_file}`. Use astrbot_file_read_tool to read it."