Skip to content

Commit 78fedd4

Browse files
committed
timeout for interpreter module
1 parent 9e7d404 commit 78fedd4

File tree

5 files changed

+23
-9
lines changed

5 files changed

+23
-9
lines changed

camel/interpreters/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class BaseInterpreter(ABC):
1919
r"""An abstract base class for code interpreters."""
2020

2121
@abstractmethod
22-
def run(self, code: str, code_type: str) -> str:
22+
def run(self, code: str, code_type: str, timeout: int = None) -> str:
2323
r"""Executes the given code based on its type.
2424
2525
Args:

camel/interpreters/docker_interpreter.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,12 @@ def __init__(
7878
require_confirm: bool = True,
7979
print_stdout: bool = False,
8080
print_stderr: bool = True,
81+
default_timeout: int = 60,
8182
) -> None:
8283
self.require_confirm = require_confirm
8384
self.print_stdout = print_stdout
8485
self.print_stderr = print_stderr
85-
86+
self.default_timeout = default_timeout
8687
# lazy initialization of container
8788
self._container: Optional[Container] = None
8889

@@ -152,6 +153,7 @@ def _run_file_in_container(
152153
self,
153154
file: Path,
154155
code_type: str,
156+
timeout: int = None,
155157
) -> str:
156158
code_type = self._check_code_type(code_type)
157159
commands = shlex.split(
@@ -166,6 +168,7 @@ def _run_file_in_container(
166168
stdout, stderr = self._container.exec_run(
167169
commands,
168170
demux=True,
171+
timeout=timeout if timeout is not None else self.default_timeout,
169172
).output
170173

171174
if self.print_stdout and stdout:
@@ -184,6 +187,7 @@ def run(
184187
self,
185188
code: str,
186189
code_type: str,
190+
timeout: int = None,
187191
) -> str:
188192
r"""Executes the given code in the conatiner attached to the
189193
interpreter, and captures the stdout and stderr streams.
@@ -228,7 +232,7 @@ def run(
228232

229233
try:
230234
temp_file_path = self._create_file_in_container(code)
231-
result = self._run_file_in_container(temp_file_path, code_type)
235+
result = self._run_file_in_container(temp_file_path, code_type,timeout=timeout)
232236
except docker.errors.APIError as e:
233237
raise InterpreterError(
234238
f"Execution halted due to docker API error: {e.explanation}. "

camel/interpreters/internal_python_interpreter.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
import importlib
1717
import typing
1818
from typing import Any, ClassVar, Dict, List, Optional
19-
19+
import concurrent.futures
2020
from camel.interpreters.base import BaseInterpreter
2121
from camel.interpreters.interpreter_error import InterpreterError
2222

@@ -87,15 +87,17 @@ def __init__(
8787
import_white_list: Optional[List[str]] = None,
8888
unsafe_mode: bool = False,
8989
raise_error: bool = False,
90+
default_timeout:int = 60
9091
) -> None:
9192
self.action_space = action_space or dict()
9293
self.state = self.action_space.copy()
9394
self.fuzz_state: Dict[str, Any] = dict()
9495
self.import_white_list = import_white_list or list()
9596
self.raise_error = raise_error
9697
self.unsafe_mode = unsafe_mode
98+
self.default_timeout = default_timeout
9799

98-
def run(self, code: str, code_type: str) -> str:
100+
def run(self, code: str, code_type: str, timeout:int =None) -> str:
99101
r"""Executes the given code with specified code type in the
100102
interpreter.
101103
@@ -145,7 +147,13 @@ def run(self, code: str, code_type: str) -> str:
145147

146148
return result
147149
else:
148-
return str(self.execute(code))
150+
try:
151+
with concurrent.futures.ThreadPoolExecutor() as executor:
152+
future = executor.submit(self._execute_ast)
153+
line_result = future.result(timeout=timeout or self.default_timeout)
154+
return str(line_result)
155+
except concurrent.futures.TimeoutError:
156+
raise InterpreterError("Code execution timed out.")
149157

150158
def update_action_space(self, action_space: Dict[str, Any]) -> None:
151159
r"""Updates action space for *python* interpreter."""

camel/interpreters/ipython_interpreter.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,12 @@ def __init__(
4242
require_confirm: bool = True,
4343
print_stdout: bool = False,
4444
print_stderr: bool = True,
45+
default_timeout: int = 60,
4546
) -> None:
4647
self.require_confirm = require_confirm
4748
self.print_stdout = print_stdout
4849
self.print_stderr = print_stderr
49-
50+
self.default_timeout = default_timeout
5051
self.kernel_manager: Optional[KernelManager] = None
5152
self.client: Optional[BlockingKernelClient] = None
5253

@@ -118,7 +119,7 @@ def _execute(self, code: str, timeout: float) -> str:
118119
exec_result = "\n".join(outputs)
119120
return self._clean_ipython_output(exec_result)
120121

121-
def run(self, code: str, code_type: str) -> str:
122+
def run(self, code: str, code_type: str, timeout:int = None) -> str:
122123
r"""Executes the given code in the Jupyter kernel.
123124
124125
Args:
@@ -138,7 +139,7 @@ def run(self, code: str, code_type: str) -> str:
138139
if code_type == "bash":
139140
code = f"%%bash\n({code})"
140141
try:
141-
result = self._execute(code, timeout=TIMEOUT)
142+
result = self._execute(code, timeout=timeout or self.default_timeout)
142143
except Exception as e:
143144
raise InterpreterError(f"Execution failed: {e!s}")
144145

camel/interpreters/subprocess_interpreter.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ def run_file(
8888
self,
8989
file: Path,
9090
code_type: str,
91+
timeout: int = None
9192
) -> str:
9293
r"""Executes a code file in a subprocess and captures its output.
9394

0 commit comments

Comments
 (0)