Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,26 @@ pnpm dev

Runs on `http://localhost:3000` by default.

## Pre-commit setup

AstrBot uses [pre-commit](https://pre-commit.com/) hooks to automatically format and lint Python code before each commit. The hooks run `ruff check`, `ruff format`, and `pyupgrade` (see [`.pre-commit-config.yaml`](.pre-commit-config.yaml) for details).

To set it up:

```bash
pip install pre-commit
pre-commit install
```

After installation, the hooks will run automatically on `git commit`. You can also run them manually at any time:

```bash
ruff format .
ruff check .
```

> **Note:** If you use VSCode, install the `Ruff` extension for real-time formatting and linting in the editor.

## Dev environment tips

1. When modifying the WebUI, be sure to maintain componentization and clean code. Avoid duplicate code.
Expand Down
20 changes: 19 additions & 1 deletion astrbot/core/astr_agent_tool_exec.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
from astrbot.core.provider.entites import ProviderRequest
from astrbot.core.provider.register import llm_tools
from astrbot.core.tools.computer_tools import (
CuaKeyboardTypeTool,
CuaMouseClickTool,
CuaScreenshotTool,
ExecuteShellTool,
FileDownloadTool,
FileEditTool,
Expand Down Expand Up @@ -186,7 +189,9 @@ def _get_runtime_computer_tools(
cls,
runtime: str,
tool_mgr,
booter: str | None = None,
) -> dict[str, FunctionTool]:
booter = "" if booter is None else str(booter).lower()
if runtime == "sandbox":
shell_tool = tool_mgr.get_builtin_tool(ExecuteShellTool)
python_tool = tool_mgr.get_builtin_tool(PythonTool)
Expand All @@ -196,7 +201,7 @@ def _get_runtime_computer_tools(
write_tool = tool_mgr.get_builtin_tool(FileWriteTool)
edit_tool = tool_mgr.get_builtin_tool(FileEditTool)
grep_tool = tool_mgr.get_builtin_tool(GrepTool)
return {
tools = {
shell_tool.name: shell_tool,
python_tool.name: python_tool,
upload_tool.name: upload_tool,
Expand All @@ -206,6 +211,18 @@ def _get_runtime_computer_tools(
edit_tool.name: edit_tool,
grep_tool.name: grep_tool,
}
if booter == "cua":
screenshot_tool = tool_mgr.get_builtin_tool(CuaScreenshotTool)
mouse_click_tool = tool_mgr.get_builtin_tool(CuaMouseClickTool)
keyboard_type_tool = tool_mgr.get_builtin_tool(CuaKeyboardTypeTool)
tools.update(
{
screenshot_tool.name: screenshot_tool,
mouse_click_tool.name: mouse_click_tool,
keyboard_type_tool.name: keyboard_type_tool,
}
)
return tools
if runtime == "local":
shell_tool = tool_mgr.get_builtin_tool(ExecuteShellTool)
python_tool = tool_mgr.get_builtin_tool(LocalPythonTool)
Expand Down Expand Up @@ -242,6 +259,7 @@ def _build_handoff_toolset(
runtime_computer_tools = cls._get_runtime_computer_tools(
runtime,
tool_mgr,
provider_settings.get("sandbox", {}).get("booter"),
)

# Keep persona semantics aligned with the main agent: tools=None means
Expand Down
19 changes: 19 additions & 0 deletions astrbot/core/astr_main_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@
BrowserExecTool,
CreateSkillCandidateTool,
CreateSkillPayloadTool,
CuaKeyboardTypeTool,
CuaMouseClickTool,
CuaScreenshotTool,
EvaluateSkillCandidateTool,
ExecuteShellTool,
FileDownloadTool,
Expand Down Expand Up @@ -1015,6 +1018,22 @@ def _apply_sandbox_tools(
req.func_tool.add_tool(tool_mgr.get_builtin_tool(RollbackSkillReleaseTool))
req.func_tool.add_tool(tool_mgr.get_builtin_tool(SyncSkillReleaseTool))

if booter == "cua":
req.system_prompt += (
"\n[CUA Desktop Control]\n"
"Use `astrbot_execute_shell` with `background=true` to launch GUI apps. "
'Use Firefox for browser tasks, for example `firefox "https://example.com"`. '
"After each visible step, call `astrbot_cua_screenshot` with "
"`send_to_user=true` and `return_image_to_llm=true` so the user can "
"monitor progress. When typing, inspect the screenshot first and confirm "
"the target field is focused and empty or safe to append to. Use "
"`astrbot_cua_mouse_click` for coordinates and `astrbot_cua_keyboard_type` "
"for text input; use text=`\\n` for Enter.\n"
)
req.func_tool.add_tool(tool_mgr.get_builtin_tool(CuaScreenshotTool))
req.func_tool.add_tool(tool_mgr.get_builtin_tool(CuaMouseClickTool))
req.func_tool.add_tool(tool_mgr.get_builtin_tool(CuaKeyboardTypeTool))

req.system_prompt = f"{req.system_prompt or ''}\n{SANDBOX_MODE_PROMPT}\n"


Expand Down
5 changes: 5 additions & 0 deletions astrbot/core/computer/booters/base.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from ..olayer import (
BrowserComponent,
FileSystemComponent,
GUIComponent,
PythonComponent,
ShellComponent,
)
Expand Down Expand Up @@ -29,6 +30,10 @@ def capabilities(self) -> tuple[str, ...] | None:
def browser(self) -> BrowserComponent | None:
return None

@property
def gui(self) -> GUIComponent | None:
return None

async def boot(self, session_id: str) -> None: ...

async def shutdown(self) -> None: ...
Expand Down
Loading
Loading