Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 22 additions & 17 deletions app/tool/python_execute.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import asyncio
import multiprocessing
import sys
from io import StringIO
Expand Down Expand Up @@ -36,22 +37,9 @@ def _run_code(self, code: str, result_dict: dict, safe_globals: dict) -> None:
finally:
sys.stdout = original_stdout

async def execute(
self,
code: str,
timeout: int = 5,
) -> Dict:
"""
Executes the provided Python code with a timeout.

Args:
code (str): The Python code to execute.
timeout (int): Execution timeout in seconds.

Returns:
Dict: Contains 'output' with execution output or error message and 'success' status.
"""

def _run_in_process(self, code: str, timeout: int) -> Dict:
"""Run code in a subprocess. This method is blocking and should be
called via run_in_executor to avoid blocking the event loop."""
with multiprocessing.Manager() as manager:
result = manager.dict({"observation": "", "success": False})
if isinstance(__builtins__, dict):
Expand All @@ -64,7 +52,6 @@ async def execute(
proc.start()
proc.join(timeout)

# timeout process
if proc.is_alive():
proc.terminate()
proc.join(1)
Expand All @@ -73,3 +60,21 @@ async def execute(
"success": False,
}
return dict(result)

async def execute(
self,
code: str,
timeout: int = 5,
) -> Dict:
"""
Executes the provided Python code with a timeout.

Args:
code (str): The Python code to execute.
timeout (int): Execution timeout in seconds.

Returns:
Dict: Contains 'observation' with execution output or error message and 'success' status.
"""
loop = asyncio.get_event_loop()
return await loop.run_in_executor(None, self._run_in_process, code, timeout)