diff --git a/metagpt/actions/run_code.py b/metagpt/actions/run_code.py index 7fcf20975..74590968c 100644 --- a/metagpt/actions/run_code.py +++ b/metagpt/actions/run_code.py @@ -68,13 +68,55 @@ class RunCode(Action): return namespace.get('result', ""), "" except Exception: # If there is an error in the code, return the error message -<<<<<<< main - return traceback.format_exc() - -======= return "", traceback.format_exc() @classmethod async def run_script(cls, working_directory, additional_python_paths=[], command=[]) -> Tuple[str, str]: working_directory = str(working_directory) additional_python_paths = [str(path) for path in additional_python_paths] + # Copy the current environment variables + env = os.environ.copy() + + # Modify the PYTHONPATH environment variable + additional_python_paths = [working_directory] + additional_python_paths + additional_python_paths = ":".join(additional_python_paths) + env['PYTHONPATH'] = additional_python_paths + ':' + env.get('PYTHONPATH', '') + + # Start the subprocess + process = subprocess.Popen(command, cwd=working_directory, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) + + try: + # Wait for the process to complete, with a timeout + stdout, stderr = process.communicate(timeout=10) + except subprocess.TimeoutExpired: + logger.info("The command did not complete within the given timeout.") + process.kill() # Kill the process if it times out + stdout, stderr = process.communicate() + return stdout.decode('utf-8'), stderr.decode('utf-8') + + async def run( + self, code, mode="script", code_file_name="", test_code="", test_file_name="", command=[], **kwargs + ) -> str: + logger.info(f"Running {' '.join(command)}") + if mode == "script": + outs, errs = await self.run_script(command=command, **kwargs) + elif mode == "text": + outs, errs = await self.run_text(code=code) + + logger.info(f"{outs=}") + logger.info(f"{errs=}") + + context = CONTEXT.format( + code=code, code_file_name=code_file_name, + test_code=test_code, test_file_name=test_file_name, + command=" ".join(command), + outs=outs[:500], # outs might be long but they are not important, truncate them to avoid token overflow + errs=errs[:10000] # truncate errors to avoid token overflow + ) + + prompt = PROMPT_TEMPLATE.format(context=context) + rsp = await self._aask(prompt) + + result = context + rsp + + return result