Skip to content

Commit

Permalink
Optionally return shell output on incorrect command (langchain-ai#894) (
Browse files Browse the repository at this point in the history
langchain-ai#899)

This allows the LLM to correct its previous command by looking at the
error message output to the shell.

Additionally, this uses subprocess.run because that is now recommended
over subprocess.check_output:

https://docs.python.org/3/library/subprocess.html#using-the-subprocess-module

Co-authored-by: Amos Ng <[email protected]>
  • Loading branch information
2 people authored and zachschillaci27 committed Mar 8, 2023
1 parent 96986a1 commit 07f0e3d
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 2 deletions.
13 changes: 11 additions & 2 deletions langchain/utilities/bash.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,27 @@
class BashProcess:
"""Executes bash commands and returns the output."""

def __init__(self, strip_newlines: bool = False):
def __init__(self, strip_newlines: bool = False, return_err_output: bool = False):
"""Initialize with stripping newlines."""
self.strip_newlines = strip_newlines
self.return_err_output = return_err_output

def run(self, commands: Union[str, List[str]]) -> str:
"""Run commands and return final output."""
if isinstance(commands, str):
commands = [commands]
commands = ";".join(commands)
try:
output = subprocess.check_output(commands, shell=True).decode()
output = subprocess.run(
commands,
shell=True,
check=True,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
).stdout.decode()
except subprocess.CalledProcessError as error:
if self.return_err_output:
return error.stdout.decode()
return str(error)
if self.strip_newlines:
output = output.strip()
Expand Down
7 changes: 7 additions & 0 deletions tests/unit_tests/test_bash.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ def test_incorrect_command() -> None:
assert output == "Command 'invalid_command' returned non-zero exit status 127."


def test_incorrect_command_return_err_output() -> None:
"""Test optional returning of shell output on incorrect command."""
session = BashProcess(return_err_output=True)
output = session.run(["invalid_command"])
assert output == "/bin/sh: 1: invalid_command: not found\n"


def test_create_directory_and_files(tmp_path: Path) -> None:
"""Test creation of a directory and files in a temporary directory."""
session = BashProcess(strip_newlines=True)
Expand Down

0 comments on commit 07f0e3d

Please sign in to comment.