diff --git a/docs/tools.rst b/docs/tools.rst index 6add5ef8..a57d630c 100644 --- a/docs/tools.rst +++ b/docs/tools.rst @@ -41,10 +41,10 @@ Python :members: :noindex: -Terminal --------- +Tmux +---- -.. automodule:: gptme.tools.terminal +.. automodule:: gptme.tools.tmux :members: :noindex: diff --git a/gptme/tools/__init__.py b/gptme/tools/__init__.py index 6c4d23db..8581b637 100644 --- a/gptme/tools/__init__.py +++ b/gptme/tools/__init__.py @@ -17,7 +17,7 @@ from .shell import tool as shell_tool from .subagent import tool as subagent_tool from .summarize import summarize -from .terminal import tool as terminal_tool +from .tmux import tool as tmux_tool logger = logging.getLogger(__name__) @@ -44,7 +44,7 @@ python_tool, shell_tool, subagent_tool, - terminal_tool, + tmux_tool, browser_tool, gh_tool, ] diff --git a/gptme/tools/terminal.py b/gptme/tools/tmux.py similarity index 86% rename from gptme/tools/terminal.py rename to gptme/tools/tmux.py index 7fbefca0..0d51f228 100644 --- a/gptme/tools/terminal.py +++ b/gptme/tools/tmux.py @@ -1,10 +1,11 @@ """ -You can use the terminal tool to run long-lived and/or interactive applications in a tmux session. Requires tmux to be installed. +You can use the tmux tool to run long-lived and/or interactive applications in a tmux session. Requires tmux to be installed. This tool is suitable to run long-running commands or interactive applications that require user input. Examples of such commands: ``npm run dev``, ``python3 server.py``, ``python3 train.py``, etc. It allows for inspecting pane contents and sending input. """ + import logging import shutil import subprocess @@ -55,7 +56,20 @@ def new_session(command: str) -> Message: if session.startswith("gptme_"): _max_session_id = max(_max_session_id, int(session.split("_")[1])) session_id = f"gptme_{_max_session_id + 1}" - cmd = ["tmux", "new-session", "-d", "-s", session_id, command] + # cmd = ["tmux", "new-session", "-d", "-s", session_id, command] + cmd = ["tmux", "new-session", "-d", "-s", session_id, "bash"] + print(" ".join(cmd)) + result = subprocess.run( + " ".join(cmd), + check=True, + capture_output=True, + text=True, + shell=True, + ) + assert result.returncode == 0 + print(result.stdout, result.stderr) + + cmd = ["tmux", "send-keys", "-t", session_id, command, "Enter"] print(" ".join(cmd)) result = subprocess.run( " ".join(cmd), @@ -78,7 +92,8 @@ def new_session(command: str) -> Message: def send_keys(pane_id: str, keys: str) -> Message: result = subprocess.run( - ["tmux", "send-keys", "-t", pane_id, *keys.split(" ")], + f"tmux send-keys -t {pane_id} {keys}", + shell=True, capture_output=True, text=True, ) @@ -124,15 +139,15 @@ def list_sessions() -> Message: return Message("system", f"Active tmux sessions: {sessions}") -def execute_terminal( +def execute_tmux( code: str, ask: bool, args: list[str] ) -> Generator[Message, None, None]: - """Executes a terminal command and returns the output.""" + """Executes a command in tmux and returns the output.""" assert not args cmd = code.strip() if ask: - print_preview(f"Terminal command: {cmd}", "sh") + print_preview(f"Command: {cmd}", "bash") confirm = ask_execute() print() if not confirm: @@ -160,7 +175,7 @@ def execute_terminal( instructions = """ -You can use the terminal tool to run long-lived and/or interactive applications in a tmux session. +You can use the tmux tool to run long-lived and/or interactive applications in a tmux session. This tool is suitable to run long-running commands or interactive applications that require user input. Examples of such commands are: `npm run dev`, `npm create vue@latest`, `python3 server.py`, `python3 train.py`, etc. @@ -177,9 +192,9 @@ def execute_terminal( examples = """ #### Managing a dev server User: Start the dev server -Assistant: Certainly! To start the dev server we should use the terminal tool to run it in a tmux session: -```terminal -new_session npm run dev +Assistant: Certainly! To start the dev server we should use tmux: +```tmux +new_session 'npm run dev' ``` System: Running `npm run dev` in session 0 @@ -251,12 +266,12 @@ def execute_terminal( tool = ToolSpec( - name="terminal", + name="tmux", desc="Executes shell commands in a tmux session", instructions=instructions, # we want to skip the last two examples in prompting examples="####".join(examples.split("####")[:-2]), - execute=execute_terminal, - block_types=["terminal"], + execute=execute_tmux, + block_types=["tmux"], available=shutil.which("tmux") is not None, ) diff --git a/tests/test_cli.py b/tests/test_cli.py index 512f17c8..8f15d409 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -258,15 +258,15 @@ def test_stdin(args: list[str], runner: CliRunner): # TODO: move elsewhere @pytest.mark.slow -def test_terminal(args: list[str], runner: CliRunner): +def test_tmux(args: list[str], runner: CliRunner): """ $ gptme '/impersonate lets find out the current load - ```terminal + ```tmux new_session top ```' """ args.append( - f"{CMDFIX}impersonate find out the current load\n```terminal\nnew_session top\n```" + f"{CMDFIX}impersonate lets find out the current load\n```tmux\nnew_session top\n```" ) print(f"running: gptme {' '.join(args)}") result = runner.invoke(gptme.cli.main, args)