Align remote exec with code execution timeouts
Send the normal _code_execution timeout group to connected A0 CLI sessions for terminal, Python, Node.js, input, and output remote execution. Size the plugin-side wait budget from the selected timeout group with a small transport grace period and update the tool prompt to steer long-running work toward output polling.
Alessandro committed
Jun 2, 2026 at 11:55 UTC
8a39542dc3bd7518d9da548b9bcb0227e43fd26e
2 files changed
+50
-3
plugins/_a0_connector/prompts/agent.system.tool.code_execution_remote.md
+3
@@ -33,6 +33,9 @@ Runtime-specific fields:
33
- Use `output` to poll a running session and `runtime=reset` for a stuck session.
34
Use `reset: true` on a new command when you need a clean session and want to
35
run the replacement command immediately.
36
+- Execution and output polling timeouts follow the normal `_code_execution`
37
+ plugin settings. For builds, installs, servers, tests, training, and other
38
+ long work, redirect logs and poll with `runtime=output`.
39
- Paths and shell syntax are evaluated on the CLI host, not inside Agent Zero.
40
- When the user gives a relative path like `tmp/file.txt`, keep it relative to
41
the CLI host terminal. Do not prepend or `cd` to `/a0/usr/workdir`; that is the
plugins/_a0_connector/tools/code_execution_remote.py
+47
-3
@@ -9,6 +9,7 @@ from helpers.tool import Response, Tool
9
from helpers.ws import NAMESPACE
10
from helpers.ws_manager import ConnectionNotFoundError, get_shared_ws_manager
11
12
+from plugins._a0_connector.helpers.exec_config import build_exec_config
13
from plugins._a0_connector.helpers.ws_runtime import (
14
clear_pending_exec_op,
15
remote_exec_metadata_for_sid,
@@ -19,8 +20,15 @@ from plugins._a0_connector.helpers.ws_runtime import (
20
)
21
22
22
-EXEC_OP_TIMEOUT = 120.0
23
+EXEC_OP_TRANSPORT_GRACE = 15.0
24
+EXEC_OP_DEFAULT_TIMEOUT = 120.0
25
EXEC_OP_EVENT = "connector_exec_op"
26
+_TIMEOUT_KEYS = (
27
+ "first_output_timeout",
28
+ "between_output_timeout",
29
+ "max_exec_timeout",
30
+ "dialog_timeout",
31
+)
32
33
34
class CodeExecutionRemote(Tool):
@@ -40,6 +48,36 @@ class CodeExecutionRemote(Tool):
48
return value.strip().lower() in {"1", "true", "yes", "on"}
49
return False
50
51
+ @staticmethod
52
+ def _timeout_group_for_runtime(
53
+ runtime: str,
54
+ exec_config: dict[str, Any],
55
+ ) -> dict[str, int] | None:
56
+ if runtime == "output":
57
+ source = exec_config.get("output_timeouts")
58
+ elif runtime in {"terminal", "python", "nodejs", "input"}:
59
+ source = exec_config.get("code_exec_timeouts")
60
+ else:
61
+ return None
62
+
63
+ if not isinstance(source, dict):
64
+ return None
65
+
66
+ timeouts: dict[str, int] = {}
67
+ for key in _TIMEOUT_KEYS:
68
+ try:
69
+ timeouts[key] = max(0, int(source[key]))
70
+ except (KeyError, TypeError, ValueError):
71
+ return None
72
+ return timeouts
73
+
74
+ @staticmethod
75
+ def _wait_timeout_for_runtime(runtime: str, exec_config: dict[str, Any]) -> float:
76
+ timeouts = CodeExecutionRemote._timeout_group_for_runtime(runtime, exec_config)
77
+ if not timeouts:
78
+ return EXEC_OP_DEFAULT_TIMEOUT
79
+ return max(float(value) for value in timeouts.values()) + EXEC_OP_TRANSPORT_GRACE
80
+
81
def get_log_object(self):
82
import uuid
83
@@ -156,6 +194,11 @@ class CodeExecutionRemote(Tool):
194
if reason is not None:
195
payload["reason"] = str(reason)
196
197
+ exec_config = build_exec_config(agent=self.agent)
198
+ if timeouts := self._timeout_group_for_runtime(runtime, exec_config):
199
+ payload["timeouts"] = timeouts
200
+ wait_timeout = self._wait_timeout_for_runtime(runtime, exec_config)
201
+
202
loop = asyncio.get_running_loop()
203
future: asyncio.Future[dict[str, Any]] = loop.create_future()
204
store_pending_exec_op(
@@ -174,7 +217,7 @@ class CodeExecutionRemote(Tool):
217
payload,
218
handler_id=f"{self.__class__.__module__}.{self.__class__.__name__}",
219
)
177
- result = await asyncio.wait_for(future, timeout=EXEC_OP_TIMEOUT)
220
+ result = await asyncio.wait_for(future, timeout=wait_timeout)
221
except ConnectionNotFoundError:
222
clear_pending_exec_op(op_id)
223
return Response(
@@ -189,7 +232,8 @@ class CodeExecutionRemote(Tool):
232
return Response(
233
message=(
234
"code_execution_remote: timed out waiting for CLI to respond "
192
- f"to runtime={runtime!r} in session {session}"
235
+ f"to runtime={runtime!r} in session {session} after "
236
+ f"{wait_timeout:g} seconds"
237
),
238
break_loop=False,
239
)