From f5d60f3c7f79a35150bf5b7116845cd4ea1fe2af Mon Sep 17 00:00:00 2001 From: LIghtJUNction Date: Wed, 29 Apr 2026 02:18:08 +0800 Subject: [PATCH] fix: restore persistent shell session lost in merge, upgrade axios to 1.15.0 --- astrbot/core/astr_agent_tool_exec.py | 9 ++++- astrbot/core/computer/booters/local.py | 43 +++++----------------- astrbot/core/tools/computer_tools/shell.py | 21 +++++++---- dashboard/package.json | 2 +- 4 files changed, 31 insertions(+), 44 deletions(-) diff --git a/astrbot/core/astr_agent_tool_exec.py b/astrbot/core/astr_agent_tool_exec.py index 0fd97bb15..e0c033ab1 100644 --- a/astrbot/core/astr_agent_tool_exec.py +++ b/astrbot/core/astr_agent_tool_exec.py @@ -14,9 +14,14 @@ from astrbot.core.agent.handoff import HandoffTool from astrbot.core.agent.mcp_client import MCPTool from astrbot.core.agent.message import Message from astrbot.core.agent.run_context import ContextWrapper -from astrbot.core.agent.tool import FunctionTool, ToolSchema, ToolSet +from astrbot.core.agent.tool import FunctionTool, ToolSet from astrbot.core.agent.tool_executor import BaseFunctionToolExecutor from astrbot.core.astr_agent_context import AstrAgentContext +from astrbot.core.astr_main_agent_resources import ( + BACKGROUND_TASK_RESULT_WOKE_SYSTEM_PROMPT, + BACKGROUND_TASK_WOKE_USER_PROMPT, + CONVERSATION_HISTORY_INJECT_PREFIX, +) from astrbot.core.cron.events import CronMessageEvent from astrbot.core.message.components import Image from astrbot.core.message.message_event_result import ( @@ -288,7 +293,7 @@ class FunctionToolExecutor(BaseFunctionToolExecutor[AstrAgentContext]): cfg = ctx.get_config(umo=event.unified_msg_origin) provider_settings = cfg.get("provider_settings", {}) runtime = str(provider_settings.get("computer_use_runtime", "local")) - sandbox_cfg = provider_settings.get("sandbox", {}) + tool_mgr = ctx.get_llm_tool_manager() runtime_computer_tools = cls._get_runtime_computer_tools( runtime, tool_mgr, diff --git a/astrbot/core/computer/booters/local.py b/astrbot/core/computer/booters/local.py index f8c8c4fc3..fd6cc9299 100644 --- a/astrbot/core/computer/booters/local.py +++ b/astrbot/core/computer/booters/local.py @@ -108,40 +108,15 @@ class LocalShellComponent(ShellComponent): if not _is_safe_command(command): raise PermissionError("Blocked unsafe shell command.") - def _run() -> dict[str, Any]: - run_env = os.environ.copy() - if env: - run_env.update({str(k): str(v) for k, v in env.items()}) - working_dir = os.path.abspath(cwd) if cwd else get_astrbot_root() - if background: - # `command` is intentionally executed through the current shell so - # local computer-use behavior matches existing tool semantics. - # Safety relies on `_is_safe_command()` and the allowed-root checks. - proc = subprocess.Popen( # noqa: S602 # nosemgrep: python.lang.security.audit.dangerous-subprocess-use-audit - command, - shell=shell, - cwd=working_dir, - env=run_env, - stdout=subprocess.DEVNULL, - stderr=subprocess.DEVNULL, - ) - return {"pid": proc.pid, "stdout": "", "stderr": "", "exit_code": None} - # `command` is intentionally executed through the current shell so - # local computer-use behavior matches existing tool semantics. - # Safety relies on `_is_safe_command()` and the allowed-root checks. - result = subprocess.run( # noqa: S602 # nosemgrep: python.lang.security.audit.dangerous-subprocess-use-audit - command, - shell=shell, - cwd=working_dir, - env=run_env, - timeout=timeout or 300, - capture_output=True, - ) - return { - "stdout": _decode_shell_output(result.stdout), - "stderr": _decode_shell_output(result.stderr), - "exit_code": result.returncode, - } + key = session_id or "default" + session = PersistentShellSession.get_or_create(key) + return await session.exec( + command, + cwd=cwd, + env=env, + timeout=timeout, + background=background, + ) @staticmethod async def shutdown_all() -> None: diff --git a/astrbot/core/tools/computer_tools/shell.py b/astrbot/core/tools/computer_tools/shell.py index 504286f01..38b2ce06f 100644 --- a/astrbot/core/tools/computer_tools/shell.py +++ b/astrbot/core/tools/computer_tools/shell.py @@ -122,13 +122,20 @@ class ExecuteShellTool(FunctionTool): local_runtime=local_runtime, ) - result = await sb.shell.exec( - command, - cwd=cwd, - background=effective_background, - env=env, - timeout=timeout or 300, - ) + exec_kwargs: dict[str, Any] = { + "command": command, + "background": effective_background, + "env": env, + "timeout": timeout or 300, + } + # Don't pass cwd for local runtime — the persistent shell + # session maintains its own working directory across calls. + if is_local_runtime(context): + exec_kwargs["session_id"] = context.context.event.unified_msg_origin + else: + exec_kwargs["cwd"] = cwd + + result = await sb.shell.exec(**exec_kwargs) if stdout_file: result["stdout"] = ( f"Command is running in the background. stdout/stderr is being " diff --git a/dashboard/package.json b/dashboard/package.json index cd6375d97..af7ac8f1f 100644 --- a/dashboard/package.json +++ b/dashboard/package.json @@ -19,7 +19,7 @@ "@tiptap/starter-kit": "3.20.5", "@tiptap/vue-3": "3.20.5", "apexcharts": "5.10.4", - "axios": "1.13.6", + "axios": "1.15.0", "axios-mock-adapter": "^2.1.0", "chance": "1.1.13", "d3": "^7.9.0",