feat: support bwrap/seatbelt-based local sandbox runtime for Computer Use

This commit is contained in:
Soulter
2026-02-27 00:20:01 +08:00
parent 84994b5d98
commit 6948fac7b6
12 changed files with 267 additions and 78 deletions

View File

@@ -13,14 +13,21 @@ from .permissions import check_admin_permission
@dataclass
class ExecuteShellTool(FunctionTool):
name: str = "astrbot_execute_shell"
description: str = "Execute a command in the shell."
description: str = (
"Execute a command in the shell. "
"In local_sandboxed runtime, writes are restricted to ~/.astrbot/workspace/<session>."
)
parameters: dict = field(
default_factory=lambda: {
"type": "object",
"properties": {
"command": {
"type": "string",
"description": "The bash command to execute. Equal to 'cd {working_dir} && {your_command}'.",
"description": "The shell command to execute.",
},
"cwd": {
"type": "string",
"description": "Optional working directory for command execution.",
},
"background": {
"type": "boolean",
@@ -44,21 +51,36 @@ class ExecuteShellTool(FunctionTool):
self,
context: ContextWrapper[AstrAgentContext],
command: str,
cwd: str | None = None,
background: bool = False,
env: dict = {},
) -> ToolExecResult:
if permission_error := check_admin_permission(context, "Shell execution"):
return permission_error
event = context.context.event
cfg = context.context.context.get_config(umo=event.unified_msg_origin)
runtime = str(
cfg.get("provider_settings", {}).get("computer_use_runtime", "local")
)
if self.is_local:
sb = get_local_booter()
sb = get_local_booter(
event.unified_msg_origin,
sandboxed=runtime == "local_sandboxed",
)
else:
sb = await get_booter(
context.context.context,
context.context.event.unified_msg_origin,
event.unified_msg_origin,
)
try:
result = await sb.shell.exec(command, background=background, env=env)
result = await sb.shell.exec(
command,
cwd=cwd,
background=background,
env=env,
)
return json.dumps(result)
except Exception as e:
return f"Error executing command: {str(e)}"