feat: Separate timeouts for code exec and output (#739)

The Master committed Sep 25, 2025 at 14:11 UTC bc980a21a119b69be5528eac0bee04dd03b6f58d
1 file changed +27 -3
python/tools/code_execution_tool.py
+27 -3
@@ -13,6 +13,22 @@ from python.helpers.messages import truncate_text as truncate_text_agent
13 import re
14
15
16 +# Timeouts for python, nodejs, and terminal runtimes.
17 +CODE_EXEC_TIMEOUTS: dict[str, int] = {
18 + "first_output_timeout": 30,
19 + "between_output_timeout": 15,
20 + "max_exec_timeout": 180,
21 + "dialog_timeout": 5,
22 +}
23 +
24 +# Timeouts for output runtime.
25 +OUTPUT_TIMEOUTS: dict[str, int] = {
26 + "first_output_timeout": 90,
27 + "between_output_timeout": 45,
28 + "max_exec_timeout": 300,
29 + "dialog_timeout": 5,
30 +}
31 +
32 @dataclass
33 class State:
34 ssh_enabled: bool
@@ -42,7 +58,7 @@ class CodeExecution(Tool):
58 )
59 elif runtime == "output":
60 response = await self.get_terminal_output(
45 - session=session, first_output_timeout=60, between_output_timeout=5
61 + session=session, timeouts=OUTPUT_TIMEOUTS
62 )
63 elif runtime == "reset":
64 response = await self.reset_terminal(session=session)
@@ -139,7 +155,7 @@ class CodeExecution(Tool):
155 return await self.terminal_session(session, command, reset, prefix)
156
157 async def terminal_session(
142 - self, session: int, command: str, reset: bool = False, prefix: str = ""
158 + self, session: int, command: str, reset: bool = False, prefix: str = "", timeouts: dict | None = None
159 ):
160
161 self.state = await self.prepare_state(reset=reset, session=session)
@@ -164,7 +180,7 @@ class CodeExecution(Tool):
180 PrintStyle(
181 background_color="white", font_color="#1B4F72", bold=True
182 ).print(f"{self.agent.agent_name} code execution output{locl}")
167 - return await self.get_terminal_output(session=session, prefix=prefix)
183 + return await self.get_terminal_output(session=session, prefix=prefix, timeouts=(timeouts or CODE_EXEC_TIMEOUTS))
184
185 except Exception as e:
186 if i == 1:
@@ -196,11 +212,19 @@ class CodeExecution(Tool):
212 max_exec_timeout=180, # hard cap on total runtime
213 sleep_time=0.1,
214 prefix="",
215 + timeouts: dict | None = None,
216 ):
217
218 # if not self.state:
219 self.state = await self.prepare_state(session=session)
220
221 + # Override timeouts if a dict is provided
222 + if timeouts:
223 + first_output_timeout = timeouts.get("first_output_timeout", first_output_timeout)
224 + between_output_timeout = timeouts.get("between_output_timeout", between_output_timeout)
225 + dialog_timeout = timeouts.get("dialog_timeout", dialog_timeout)
226 + max_exec_timeout = timeouts.get("max_exec_timeout", max_exec_timeout)
227 +
228 # Common shell prompt regex patterns (add more as needed)
229 prompt_patterns = [
230 re.compile(r"\(venv\).+[$#] ?$"), # (venv) ...$ or (venv) ...#