diff --git a/modules/serviceCenter/services/serviceAgent/sandboxExecutor.py b/modules/serviceCenter/services/serviceAgent/sandboxExecutor.py index 1882d7eb..15362e65 100644 --- a/modules/serviceCenter/services/serviceAgent/sandboxExecutor.py +++ b/modules/serviceCenter/services/serviceAgent/sandboxExecutor.py @@ -3,7 +3,6 @@ """Sandboxed code execution for the AI agent executeCode tool.""" import logging -import signal import sys import io import traceback @@ -72,15 +71,12 @@ async def executePython(code: str) -> Dict[str, Any]: sys.stdout = capturedOutput sys.stderr = capturedOutput - if sys.platform != "win32": - signal.signal(signal.SIGALRM, lambda *_: (_ for _ in ()).throw(TimeoutError("Execution timed out"))) - signal.alarm(_MAX_EXECUTION_TIME_S) + # Do not use signal.SIGALRM here: _run executes inside a thread-pool worker + # (asyncio.run_in_executor). signal.signal only works on the main thread. + # Wall-clock limit is enforced by asyncio.wait_for around run_in_executor. exec(compile(code, "", "exec"), restrictedGlobals) - if sys.platform != "win32": - signal.alarm(0) - output = capturedOutput.getvalue() if len(output) > _MAX_OUTPUT_CHARS: output = output[:_MAX_OUTPUT_CHARS] + f"\n... (truncated at {_MAX_OUTPUT_CHARS} chars)" @@ -94,14 +90,12 @@ async def executePython(code: str) -> Dict[str, Any]: finally: sys.stdout = oldStdout sys.stderr = oldStderr - if sys.platform != "win32": - signal.alarm(0) loop = asyncio.get_event_loop() try: result = await asyncio.wait_for( loop.run_in_executor(None, _run), - timeout=_MAX_EXECUTION_TIME_S + 5, + timeout=float(_MAX_EXECUTION_TIME_S) + 5.0, ) return result except asyncio.TimeoutError: