diff --git a/nanobot/agent/tools/shell.py b/nanobot/agent/tools/shell.py index 02dc3ec3..f6d37f14 100644 --- a/nanobot/agent/tools/shell.py +++ b/nanobot/agent/tools/shell.py @@ -89,7 +89,11 @@ class _PreparedCommand: maximum=600, ), shell=StringSchema( - "Optional shell binary to launch. Unix: sh, bash, zsh. Windows: powershell, pwsh, cmd.", + ( + "Optional shell binary to launch. Windows: powershell, pwsh, cmd." + if _IS_WINDOWS + else "Optional shell binary to launch. Unix: sh, bash, zsh." + ), nullable=True, ), login=BooleanSchema( @@ -227,6 +231,13 @@ class ExecTool(Tool): @property def description(self) -> str: + platform_note = ( + "On Windows, use PowerShell syntax by default; pass shell='cmd' " + "only for cmd-specific commands. " + if _IS_WINDOWS + else "On Unix, commands run through bash by default; pass shell='sh' " + "or shell='zsh' when needed. " + ) return ( "Execute a shell command and return its output. " "Use this for tests, builds, package commands, git commands, and " @@ -234,8 +245,7 @@ class ExecTool(Tool): "inspection and apply_patch/write_file/edit_file for file changes " "instead of cat, shell find/grep, echo, or sed. " "Use -y or --yes flags to avoid interactive prompts. " - "On Windows, use PowerShell syntax by default; pass shell='cmd' " - "only for cmd-specific commands. " + f"{platform_note}" "For long-running or interactive commands, pass yield_time_ms; " "if the command keeps running, exec returns a session_id that can " "be polled or written to with write_stdin. Output is truncated at " diff --git a/tests/tools/test_tool_descriptions.py b/tests/tools/test_tool_descriptions.py index bb7665e4..9ae2fc58 100644 --- a/tests/tools/test_tool_descriptions.py +++ b/tests/tools/test_tool_descriptions.py @@ -1,3 +1,6 @@ +import sys +from unittest.mock import patch + from nanobot.agent.tools.apply_patch import ApplyPatchTool from nanobot.agent.tools.exec_session import ListExecSessionsTool, WriteStdinTool from nanobot.agent.tools.filesystem import EditFileTool, ReadFileTool, WriteFileTool @@ -44,3 +47,26 @@ def test_coding_tool_descriptions_steer_discovery_and_shell_usage() -> None: assert "do not use this to start new commands" in write_stdin assert "wait_for" in write_stdin assert "recover a session_id" in list_sessions + + +def test_exec_tool_shell_guidance_matches_platform() -> None: + with patch("nanobot.agent.tools.shell._IS_WINDOWS", False): + unix_description = ExecTool().description.lower() + assert "on unix" in unix_description + assert "powershell" not in unix_description + assert "cmd-specific" not in unix_description + + with patch("nanobot.agent.tools.shell._IS_WINDOWS", True): + windows_description = ExecTool().description.lower() + assert "powershell syntax" in windows_description + assert "shell='cmd'" in windows_description + + shell_parameter = ExecTool().parameters["properties"]["shell"]["description"].lower() + if sys.platform == "win32": + assert "powershell" in shell_parameter + assert "cmd" in shell_parameter + assert "unix" not in shell_parameter + else: + assert "unix" in shell_parameter + assert "powershell" not in shell_parameter + assert "cmd" not in shell_parameter