| 82 | ) |
| 83 | |
| 84 | async def call( |
| 85 | self, |
| 86 | context: ContextWrapper[AstrAgentContext], |
| 87 | command: str, |
| 88 | background: bool = False, |
| 89 | timeout: int | None = 300, |
| 90 | env: dict[str, Any] | None = None, |
| 91 | ) -> ToolExecResult: |
| 92 | if permission_error := check_admin_permission(context, "Shell execution"): |
| 93 | return permission_error |
| 94 | |
| 95 | sb = await get_booter( |
| 96 | context.context.context, |
| 97 | context.context.event.unified_msg_origin, |
| 98 | ) |
| 99 | try: |
| 100 | cwd: str | None = None |
| 101 | if is_local_runtime(context): |
| 102 | current_workspace_root = workspace_root( |
| 103 | context.context.event.unified_msg_origin |
| 104 | ) |
| 105 | current_workspace_root.mkdir(parents=True, exist_ok=True) |
| 106 | cwd = str(current_workspace_root) |
| 107 | |
| 108 | env = dict(env or {}) |
| 109 | effective_background = background and not _is_self_detached_command(command) |
| 110 | |
| 111 | stdout_file: str | None = None |
| 112 | if effective_background: |
| 113 | local_runtime = is_local_runtime(context) |
| 114 | stdout_file = _build_background_output_path( |
| 115 | local_runtime=local_runtime, |
| 116 | ) |
| 117 | command = _redirect_background_stdout_command( |
| 118 | command, |
| 119 | output_path=stdout_file, |
| 120 | local_runtime=local_runtime, |
| 121 | ) |
| 122 | |
| 123 | result = await sb.shell.exec( |
| 124 | command, |
| 125 | cwd=cwd, |
| 126 | background=effective_background, |
| 127 | env=env, |
| 128 | timeout=timeout or 300, |
| 129 | ) |
| 130 | if stdout_file: |
| 131 | result["stdout"] = ( |
| 132 | f"Command is running in the background. stdout/stderr is being " |
| 133 | f"written to `{stdout_file}`. Use astrbot_file_read_tool to read it." |
| 134 | ) |
| 135 | return json.dumps(result, ensure_ascii=False) |
| 136 | except Exception as e: |
| 137 | detail = str(e) or type(e).__name__ |
| 138 | return f"Error executing command: {detail}" |
| 139 | |
| 140 | |
| 141 | def _is_self_detached_command(command: str) -> bool: |