Open devstein opened 1 year ago
To fix the issue with the recursive function in PythonREPL, we need to update the run
method to ensure that the function is defined in the correct scope. We can do this by updating the exec
call to include the self.locals
dictionary in the self.globals
dictionary. This will ensure that the function is defined in the correct scope and can be called recursively.
Here's the updated run
method:
def run(self, command: str) -> str:
"""Run command with own globals/locals and returns anything printed."""
old_stdout = sys.stdout
sys.stdout = mystdout = StringIO()
try:
# Update the exec call to include self.locals in self.globals
exec(command, {**self.globals, **self.locals}, self.locals)
sys.stdout = old_stdout
output = mystdout.getvalue()
except Exception as e:
sys.stdout = old_stdout
output = repr(e)
return output
With this change, the PythonREPL should now work correctly with recursive functions.
System Info
MacOS, Python 3.11.2, langchain 0.0.174
Who can help?
N/A
Information
Related Components
Reproduction
I hit a strange error when using PythonREPL in an agent. It happens with this recursive Python function. It was written by gpt-3.5-turbo and is valid Python:
Note that everything works as expected for non-recursive functions.
Using this function as string input, I reduced the issue to this minimal example:
When executed with exec(cmd), it runs as expected. I found that PythonREPL runs the command with exec(command, self.globals, self.locals).
Setting globals & locals in this python_repl instance makes the fragment work as expected:
This hack solves it only in the context of this simple example, but not if python_repl added as a tool to an AgentExecutor.
At the core, the issue seems to be caused by Python scopes, but my knowledge of this is not profound enough to fully understand what's happening.
Expected behavior
I would have expected PythonREPL to accept recursive functions.