refactor: resolve config once per execution and deduplicate helpers
linuztx committed
Mar 8, 2026 at 20:15 UTC
f6acef23c29052664a2bff3a3ebe1b4c96560917
1 file changed
+47
-96
plugins/code_execution/tools/code_execution_tool.py
+47
-96
@@ -39,25 +39,26 @@ class CodeExecution(Tool):
39
self.allow_running = bool(self.args.get("allow_running", False))
40
reset = bool(self.args.get("reset", False) or runtime_arg == "reset")
41
42
+ cfg = _get_config(self.agent)
43
+
44
if runtime_arg == "python":
45
response = await self.execute_python_code(
44
- code=self.args["code"], session=session, reset=reset
46
+ cfg, code=self.args["code"], session=session, reset=reset
47
)
48
elif runtime_arg == "nodejs":
49
response = await self.execute_nodejs_code(
48
- code=self.args["code"], session=session, reset=reset
50
+ cfg, code=self.args["code"], session=session, reset=reset
51
)
52
elif runtime_arg == "terminal":
53
response = await self.execute_terminal_command(
52
- command=self.args["code"], session=session, reset=reset
54
+ cfg, command=self.args["code"], session=session, reset=reset
55
)
56
elif runtime_arg == "output":
55
- cfg = _get_config(self.agent)
57
response = await self.get_terminal_output(
57
- session=session, timeouts=cfg["output_timeouts"]
58
+ cfg, session=session, timeouts=cfg["output_timeouts"]
59
)
60
elif runtime_arg == "reset":
60
- response = await self.reset_terminal(session=session)
61
+ response = await self.reset_terminal(cfg, session=session)
62
else:
63
response = self.agent.read_prompt(
64
"fw.code.runtime_wrong.md", runtime=runtime_arg
@@ -87,9 +88,8 @@ class CodeExecution(Tool):
88
async def after_execution(self, response, **kwargs):
89
self.agent.hist_add_tool_result(self.name, response.message, **(response.additional or {}))
90
90
- async def prepare_state(self, reset=False, session: int | None = None):
91
+ async def prepare_state(self, cfg: dict, reset=False, session: int | None = None):
92
self.state: State | None = self.agent.get_data("_cet_state")
92
- cfg = _get_config(self.agent)
93
ssh_enabled = cfg["ssh_enabled"]
94
95
# always reset state when ssh_enabled changes
@@ -131,43 +131,40 @@ class CodeExecution(Tool):
131
self.agent.set_data("_cet_state", self.state)
132
return self.state
133
134
- async def execute_python_code(self, session: int, code: str, reset: bool = False):
134
+ async def execute_python_code(self, cfg: dict, session: int, code: str, reset: bool = False):
135
escaped_code = shlex.quote(code)
136
command = f"ipython -c {escaped_code}"
137
prefix = "python> " + self.format_command_for_output(code) + "\n\n"
138
- return await self.terminal_session(session, command, reset, prefix)
138
+ return await self.terminal_session(cfg, session, command, reset, prefix)
139
140
- async def execute_nodejs_code(self, session: int, code: str, reset: bool = False):
140
+ async def execute_nodejs_code(self, cfg: dict, session: int, code: str, reset: bool = False):
141
escaped_code = shlex.quote(code)
142
command = f"node /exe/node_eval.js {escaped_code}"
143
prefix = "node> " + self.format_command_for_output(code) + "\n\n"
144
- return await self.terminal_session(session, command, reset, prefix)
144
+ return await self.terminal_session(cfg, session, command, reset, prefix)
145
146
async def execute_terminal_command(
147
- self, session: int, command: str, reset: bool = False
147
+ self, cfg: dict, session: int, command: str, reset: bool = False
148
):
149
- cfg = _get_config(self.agent)
149
prefix = (
150
("bash>" if not runtime.is_windows() or cfg["ssh_enabled"] else "PS>")
151
+ self.format_command_for_output(command)
152
+ "\n\n"
153
)
155
- return await self.terminal_session(session, command, reset, prefix)
154
+ return await self.terminal_session(cfg, session, command, reset, prefix)
155
156
async def terminal_session(
158
- self, session: int, command: str, reset: bool = False, prefix: str = "", timeouts: dict | None = None
157
+ self, cfg: dict, session: int, command: str, reset: bool = False, prefix: str = "", timeouts: dict | None = None
158
):
160
- self.state = await self.prepare_state(reset=reset, session=session)
159
+ self.state = await self.prepare_state(cfg, reset=reset, session=session)
160
161
await self.agent.handle_intervention() # wait for intervention and handle it, if paused
162
163
# Check if session is running and handle it
164
if not self.allow_running:
166
- if response := await self.handle_running_session(session):
165
+ if response := await self.handle_running_session(cfg, session):
166
return response
167
169
- cfg = _get_config(self.agent)
170
-
168
# try again on lost connection
169
for i in range(2):
170
try:
@@ -188,6 +185,7 @@ class CodeExecution(Tool):
185
background_color="white", font_color="#1B4F72", bold=True
186
).print(f"{self.agent.agent_name} code execution output{locl}")
187
return await self.get_terminal_output(
188
+ cfg,
189
session=session,
190
prefix=prefix,
191
timeouts=(timeouts or cfg["code_exec_timeouts"]),
@@ -196,7 +194,7 @@ class CodeExecution(Tool):
194
except Exception as e:
195
if i == 1:
196
PrintStyle.error(str(e))
199
- await self.prepare_state(reset=True, session=session)
197
+ await self.prepare_state(cfg, reset=True, session=session)
198
continue
199
else:
200
raise e
@@ -209,6 +207,7 @@ class CodeExecution(Tool):
207
208
async def get_terminal_output(
209
self,
210
+ cfg: dict,
211
session=0,
212
reset_full_output=True,
213
first_output_timeout=30,
@@ -219,7 +218,7 @@ class CodeExecution(Tool):
218
prefix="",
219
timeouts: dict | None = None,
220
):
222
- self.state = await self.prepare_state(session=session)
221
+ self.state = await self.prepare_state(cfg, session=session)
222
223
# Override timeouts if a dict is provided
224
if timeouts:
@@ -228,7 +227,6 @@ class CodeExecution(Tool):
227
dialog_timeout = timeouts.get("dialog_timeout", dialog_timeout)
228
max_exec_timeout = timeouts.get("max_exec_timeout", max_exec_timeout)
229
231
- cfg = _get_config(self.agent)
230
prompt_patterns = cfg["prompt_patterns"]
231
dialog_patterns = cfg["dialog_patterns"]
232
@@ -348,6 +346,7 @@ class CodeExecution(Tool):
346
347
async def handle_running_session(
348
self,
349
+ cfg: dict,
350
session=0,
351
reset_full_output=True,
352
prefix=""
@@ -357,7 +356,6 @@ class CodeExecution(Tool):
356
if not self.state.shells[session].running:
357
return None
358
360
- cfg = _get_config(self.agent)
359
prompt_patterns = cfg["prompt_patterns"]
360
dialog_patterns = cfg["dialog_patterns"]
361
@@ -372,7 +370,7 @@ class CodeExecution(Tool):
370
truncated_output.splitlines()[-3:] if truncated_output else []
371
)
372
last_lines.reverse()
375
- for _, line in enumerate(last_lines):
373
+ for line in last_lines:
374
for pat in prompt_patterns:
375
if pat.search(line.strip()):
376
PrintStyle.info(
@@ -406,7 +404,7 @@ class CodeExecution(Tool):
404
if self.state and session in self.state.shells:
405
self.state.shells[session].running = False
406
409
- async def reset_terminal(self, session=0, reason: str | None = None):
407
+ async def reset_terminal(self, cfg: dict, session=0, reason: str | None = None):
408
if reason:
409
PrintStyle(font_color="#FFA500", bold=True).print(
410
f"Resetting terminal session {session}... Reason: {reason}"
@@ -416,7 +414,7 @@ class CodeExecution(Tool):
414
f"Resetting terminal session {session}..."
415
)
416
419
- await self.prepare_state(reset=True, session=session)
417
+ await self.prepare_state(cfg, reset=True, session=session)
418
response = self.agent.read_prompt(
419
"fw.code.info.md", info=self.agent.read_prompt("fw.code.reset.md")
420
)
@@ -464,7 +462,6 @@ class CodeExecution(Tool):
462
# ------------------------------------------------------------------
463
464
def _resolve_ssh_enabled(raw_value) -> bool:
467
- """Resolve ssh_enabled: 'auto' detects based on dockerized state."""
465
val = str(raw_value).strip().lower()
466
if val == "auto":
467
return not runtime.is_dockerized()
@@ -472,12 +469,10 @@ def _resolve_ssh_enabled(raw_value) -> bool:
469
470
471
def _resolve_ssh_addr(cfg_addr: str) -> str:
475
- """Resolve SSH address: fall back to rfc_url from settings when empty."""
472
if cfg_addr:
473
return cfg_addr
474
set = settings.get_settings()
475
host = set.get("rfc_url", "localhost")
480
- # Strip protocol and port from URL
476
if "//" in host:
477
host = host.split("//")[1]
478
if ":" in host:
@@ -488,83 +483,39 @@ def _resolve_ssh_addr(cfg_addr: str) -> str:
483
484
485
async def _resolve_ssh_pass(cfg_pass: str) -> str:
491
- """Resolve SSH password: fall back to root_password via RFC when empty."""
486
if cfg_pass:
487
return cfg_pass
488
return await rfc_exchange.get_root_password()
489
490
497
-def _get_config(agent) -> dict:
498
- cfg = plugins.get_plugin_config("code_execution", agent=agent) or {}
491
+def _parse_patterns(raw, flags=0) -> list[re.Pattern]:
492
+ lines = [str(p) for p in raw] if isinstance(raw, list) else str(raw).splitlines()
493
+ return [re.compile(p.strip(), flags) for p in lines if p.strip()]
494
+
495
+
496
+_TIMEOUT_KEYS = ("first_output_timeout", "between_output_timeout", "max_exec_timeout", "dialog_timeout")
497
500
- # SSH / TTY switch (supports auto/true/false)
501
- ssh_enabled = _resolve_ssh_enabled(cfg.get("ssh_enabled", "auto"))
502
-
503
- # SSH credentials (with RFC fallbacks)
504
- ssh_addr = _resolve_ssh_addr(str(cfg.get("ssh_addr", "")))
505
- ssh_port = int(cfg.get("ssh_port", 55022))
506
- ssh_user = str(cfg.get("ssh_user", "root"))
507
- ssh_pass = str(cfg.get("ssh_pass", ""))
508
-
509
- # Timeouts for python/nodejs/terminal runtimes
510
- code_exec_timeouts = {
511
- "first_output_timeout": int(cfg.get("code_exec_first_output_timeout", 30)),
512
- "between_output_timeout": int(cfg.get("code_exec_between_output_timeout", 15)),
513
- "max_exec_timeout": int(cfg.get("code_exec_max_exec_timeout", 180)),
514
- "dialog_timeout": int(cfg.get("code_exec_dialog_timeout", 5)),
515
- }
498
517
- # Timeouts for "output" runtime
518
- output_timeouts = {
519
- "first_output_timeout": int(cfg.get("output_first_output_timeout", 90)),
520
- "between_output_timeout": int(cfg.get("output_between_output_timeout", 45)),
521
- "max_exec_timeout": int(cfg.get("output_max_exec_timeout", 300)),
522
- "dialog_timeout": int(cfg.get("output_dialog_timeout", 5)),
499
+def _parse_timeouts(cfg: dict, prefix: str, defaults: tuple[int, ...]) -> dict:
500
+ return {
501
+ key: int(cfg.get(f"{prefix}_{key}", default))
502
+ for key, default in zip(_TIMEOUT_KEYS, defaults)
503
}
504
525
- # Prompt patterns (one regex per line, or a list)
526
- prompt_patterns_raw = cfg.get(
527
- "prompt_patterns",
528
- r"(\(venv\)).+[$#] ?$" + "\n"
529
- + r"root@[^:]+:[^#]+# ?$" + "\n"
530
- + r"[a-zA-Z0-9_.-]+@[^:]+:[^$#]+[$#] ?$" + "\n"
531
- + r"\(?.*\)?\s*PS\s+[^>]+> ?$",
532
- )
533
- if isinstance(prompt_patterns_raw, list):
534
- prompt_lines = [str(p) for p in prompt_patterns_raw]
535
- else:
536
- prompt_lines = str(prompt_patterns_raw).splitlines()
537
- prompt_patterns = [
538
- re.compile(p.strip())
539
- for p in prompt_lines
540
- if p.strip()
541
- ]
542
-
543
- # Dialog patterns (one regex per line, or a list)
544
- dialog_patterns_raw = cfg.get(
545
- "dialog_patterns",
546
- "Y/N\nyes/no\n:\\s*$\n\\?\\s*$",
547
- )
548
- if isinstance(dialog_patterns_raw, list):
549
- dialog_lines = [str(p) for p in dialog_patterns_raw]
550
- else:
551
- dialog_lines = str(dialog_patterns_raw).splitlines()
552
- dialog_patterns = [
553
- re.compile(p.strip(), re.IGNORECASE)
554
- for p in dialog_lines
555
- if p.strip()
556
- ]
505
+
506
+def _get_config(agent) -> dict:
507
+ cfg = plugins.get_plugin_config("code_execution", agent=agent) or {}
508
509
return {
559
- "ssh_enabled": ssh_enabled,
560
- "ssh_addr": ssh_addr,
561
- "ssh_port": ssh_port,
562
- "ssh_user": ssh_user,
563
- "ssh_pass": ssh_pass,
564
- "code_exec_timeouts": code_exec_timeouts,
565
- "output_timeouts": output_timeouts,
566
- "prompt_patterns": prompt_patterns,
567
- "dialog_patterns": dialog_patterns,
510
+ "ssh_enabled": _resolve_ssh_enabled(cfg.get("ssh_enabled", "auto")),
511
+ "ssh_addr": _resolve_ssh_addr(str(cfg.get("ssh_addr", ""))),
512
+ "ssh_port": int(cfg.get("ssh_port", 55022)),
513
+ "ssh_user": str(cfg.get("ssh_user", "root")),
514
+ "ssh_pass": str(cfg.get("ssh_pass", "")),
515
+ "code_exec_timeouts": _parse_timeouts(cfg, "code_exec", (30, 15, 180, 5)),
516
+ "output_timeouts": _parse_timeouts(cfg, "output", (90, 45, 300, 5)),
517
+ "prompt_patterns": _parse_patterns(cfg.get("prompt_patterns", "")),
518
+ "dialog_patterns": _parse_patterns(cfg.get("dialog_patterns", ""), re.IGNORECASE),
519
}
520
521