Skip to content

fix: run local python in session workspace#8792

Open
zouyonghe wants to merge 1 commit into
AstrBotDevs:masterfrom
zouyonghe:fix/8730-local-python-workspace
Open

fix: run local python in session workspace#8792
zouyonghe wants to merge 1 commit into
AstrBotDevs:masterfrom
zouyonghe:fix/8730-local-python-workspace

Conversation

@zouyonghe

@zouyonghe zouyonghe commented Jun 15, 2026

Copy link
Copy Markdown
Member

Summary

  • run local Python tool code from the same per-session workspace used by local shell commands
  • add optional cwd support to the local Python computer component
  • add a regression test that verifies LocalPythonTool passes the normalized UMO workspace as cwd

Fixes #8730.

Verification

  • uv run pytest tests/unit/test_python_tools.py tests/unit/test_computer.py -q
  • uv run ruff check astrbot/core/computer/olayer/python.py astrbot/core/computer/booters/local.py astrbot/core/tools/computer_tools/python.py tests/unit/test_python_tools.py
  • uv run ruff format --check astrbot/core/computer/olayer/python.py astrbot/core/computer/booters/local.py astrbot/core/tools/computer_tools/python.py tests/unit/test_python_tools.py
  • git diff --check

Summary by Sourcery

Ensure local Python tool execution uses the same per-session workspace as local shell commands and support passing a working directory to the local Python executor.

New Features:

  • Allow specifying an optional working directory (cwd) for local Python execution in the computer component.

Bug Fixes:

  • Align LocalPythonTool execution with the per-session workspace used by local shell commands so Python runs in the correct session-specific directory.

Tests:

  • Add a regression test verifying that LocalPythonTool passes the normalized unified message origin workspace as cwd to the Python executor.

@dosubot dosubot Bot added size:S This PR changes 10-29 lines, ignoring generated files. area:core The bug / feature is about astrbot's core, backend labels Jun 15, 2026

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • The new cwd parameter on astrbot.core.computer.olayer.python.exec is only documented by the signature; consider expanding the docstring to describe its purpose and behavior (e.g., defaulting to the Astrbot root when omitted) to keep the abstraction clear for other callers.
  • In local.py, cwd is normalized with os.path.abspath(cwd) but not validated; if there’s any chance of callers passing a non-existent directory, consider either creating/validating it here or explicitly documenting that the caller must ensure existence to avoid surprising subprocess errors.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The new `cwd` parameter on `astrbot.core.computer.olayer.python.exec` is only documented by the signature; consider expanding the docstring to describe its purpose and behavior (e.g., defaulting to the Astrbot root when omitted) to keep the abstraction clear for other callers.
- In `local.py`, `cwd` is normalized with `os.path.abspath(cwd)` but not validated; if there’s any chance of callers passing a non-existent directory, consider either creating/validating it here or explicitly documenting that the caller must ensure existence to avoid surprising `subprocess` errors.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds support for executing Python code within a specific working directory by introducing a cwd parameter to the Python execution methods and resolving the workspace root in the local Python tool. A unit test was also added to verify this behavior. Feedback was provided on the new unit test, pointing out a potential flakiness issue on platforms with symlinked temporary directories (such as macOS) and suggesting a robust way to resolve the workspace path consistently.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +35 to +70
monkeypatch.setattr(
"astrbot.core.tools.computer_tools.python.get_local_booter",
lambda: SimpleNamespace(python=SimpleNamespace(exec=python_exec)),
)
monkeypatch.setattr(
"astrbot.core.tools.computer_tools.python.workspace_root",
lambda umo: tmp_path / umo.replace(":", "_"),
)

event = SimpleNamespace(
unified_msg_origin="onebot:GroupMessage:12345",
role="admin",
get_platform_name=lambda: "onebot",
)
context = ContextWrapper(
context=SimpleNamespace(
event=event,
context=SimpleNamespace(
get_config=lambda **_kwargs: {
"provider_settings": {"computer_use_require_admin": True}
}
),
),
tool_call_timeout=60,
)

await tool.call(context, code="print('ok')", timeout=30)

workspace = tmp_path / "onebot_GroupMessage_12345"
assert workspace.is_dir()
python_exec.assert_awaited_once_with(
"print('ok')",
timeout=30,
silent=False,
cwd=str(workspace.resolve(strict=False)),
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

On environments where the temporary directory path contains symlinks (such as macOS, where /var is a symlink to /private/var), the unresolved path returned by the mocked workspace_root will not match the resolved path used in the assertion (workspace.resolve(strict=False)). This can cause flaky test failures.

To make the test robust and platform-independent, we can resolve the workspace path once and use it consistently for both the mock and the assertion.

    workspace = (tmp_path / "onebot_GroupMessage_12345").resolve(strict=False)
    monkeypatch.setattr(
        "astrbot.core.tools.computer_tools.python.get_local_booter",
        lambda: SimpleNamespace(python=SimpleNamespace(exec=python_exec)),
    )
    monkeypatch.setattr(
        "astrbot.core.tools.computer_tools.python.workspace_root",
        lambda umo: workspace,
    )

    event = SimpleNamespace(
        unified_msg_origin="onebot:GroupMessage:12345",
        role="admin",
        get_platform_name=lambda: "onebot",
    )
    context = ContextWrapper(
        context=SimpleNamespace(
            event=event,
            context=SimpleNamespace(
                get_config=lambda **_kwargs: {
                    "provider_settings": {"computer_use_require_admin": True}
                }
            ),
        ),
        tool_call_timeout=60,
    )

    await tool.call(context, code="print('ok')", timeout=30)

    assert workspace.is_dir()
    python_exec.assert_awaited_once_with(
        "print('ok')",
        timeout=30,
        silent=False,
        cwd=str(workspace),
    )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:core The bug / feature is about astrbot's core, backend size:S This PR changes 10-29 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

local模式下shell工具和python工具的工作目录不一致的问题

1 participant