refactor: move private helpers below class and add section comment
linuztx committed
Mar 8, 2026 at 19:39 UTC
2c7ad353c754c7565d9034aba16dacdb4d81d4ce
1 file changed
+110
-106
plugins/code_execution/tools/code_execution_tool.py
+110
-106
@@ -15,111 +15,6 @@ from plugins.code_execution.helpers.shell_local import LocalInteractiveSession
15
from plugins.code_execution.helpers.shell_ssh import SSHInteractiveSession
16
17
18
-def _resolve_ssh_enabled(raw_value) -> bool:
19
- """Resolve ssh_enabled: 'auto' detects based on dockerized state."""
20
- val = str(raw_value).strip().lower()
21
- if val == "auto":
22
- return not runtime.is_dockerized()
23
- return val in ("true", "1", "yes", "on")
24
-
25
-
26
-def _resolve_ssh_addr(cfg_addr: str) -> str:
27
- """Resolve SSH address: fall back to rfc_url from settings when empty."""
28
- if cfg_addr:
29
- return cfg_addr
30
- set = settings.get_settings()
31
- host = set.get("rfc_url", "localhost")
32
- # Strip protocol and port from URL
33
- if "//" in host:
34
- host = host.split("//")[1]
35
- if ":" in host:
36
- host = host.split(":")[0]
37
- if host.endswith("/"):
38
- host = host.rstrip("/")
39
- return host or "localhost"
40
-
41
-
42
-async def _resolve_ssh_pass(cfg_pass: str) -> str:
43
- """Resolve SSH password: fall back to root_password via RFC when empty."""
44
- if cfg_pass:
45
- return cfg_pass
46
- return await rfc_exchange.get_root_password()
47
-
48
-
49
-def _get_config(agent) -> dict:
50
- cfg = plugins.get_plugin_config("code_execution", agent=agent) or {}
51
-
52
- # SSH / TTY switch (supports auto/true/false)
53
- ssh_enabled = _resolve_ssh_enabled(cfg.get("ssh_enabled", "auto"))
54
-
55
- # SSH credentials (with RFC fallbacks)
56
- ssh_addr = _resolve_ssh_addr(str(cfg.get("ssh_addr", "")))
57
- ssh_port = int(cfg.get("ssh_port", 55022))
58
- ssh_user = str(cfg.get("ssh_user", "root"))
59
- ssh_pass = str(cfg.get("ssh_pass", ""))
60
-
61
- # Timeouts for python/nodejs/terminal runtimes
62
- code_exec_timeouts = {
63
- "first_output_timeout": int(cfg.get("code_exec_first_output_timeout", 30)),
64
- "between_output_timeout": int(cfg.get("code_exec_between_output_timeout", 15)),
65
- "max_exec_timeout": int(cfg.get("code_exec_max_exec_timeout", 180)),
66
- "dialog_timeout": int(cfg.get("code_exec_dialog_timeout", 5)),
67
- }
68
-
69
- # Timeouts for "output" runtime
70
- output_timeouts = {
71
- "first_output_timeout": int(cfg.get("output_first_output_timeout", 90)),
72
- "between_output_timeout": int(cfg.get("output_between_output_timeout", 45)),
73
- "max_exec_timeout": int(cfg.get("output_max_exec_timeout", 300)),
74
- "dialog_timeout": int(cfg.get("output_dialog_timeout", 5)),
75
- }
76
-
77
- # Prompt patterns (one regex per line, or a list)
78
- prompt_patterns_raw = cfg.get(
79
- "prompt_patterns",
80
- r"(\(venv\)).+[$#] ?$" + "\n"
81
- + r"root@[^:]+:[^#]+# ?$" + "\n"
82
- + r"[a-zA-Z0-9_.-]+@[^:]+:[^$#]+[$#] ?$" + "\n"
83
- + r"\(?.*\)?\s*PS\s+[^>]+> ?$",
84
- )
85
- if isinstance(prompt_patterns_raw, list):
86
- prompt_lines = [str(p) for p in prompt_patterns_raw]
87
- else:
88
- prompt_lines = str(prompt_patterns_raw).splitlines()
89
- prompt_patterns = [
90
- re.compile(p.strip())
91
- for p in prompt_lines
92
- if p.strip()
93
- ]
94
-
95
- # Dialog patterns (one regex per line, or a list)
96
- dialog_patterns_raw = cfg.get(
97
- "dialog_patterns",
98
- "Y/N\nyes/no\n:\\s*$\n\\?\\s*$",
99
- )
100
- if isinstance(dialog_patterns_raw, list):
101
- dialog_lines = [str(p) for p in dialog_patterns_raw]
102
- else:
103
- dialog_lines = str(dialog_patterns_raw).splitlines()
104
- dialog_patterns = [
105
- re.compile(p.strip(), re.IGNORECASE)
106
- for p in dialog_lines
107
- if p.strip()
108
- ]
109
-
110
- return {
111
- "ssh_enabled": ssh_enabled,
112
- "ssh_addr": ssh_addr,
113
- "ssh_port": ssh_port,
114
- "ssh_user": ssh_user,
115
- "ssh_pass": ssh_pass,
116
- "code_exec_timeouts": code_exec_timeouts,
117
- "output_timeouts": output_timeouts,
118
- "prompt_patterns": prompt_patterns,
119
- "dialog_patterns": dialog_patterns,
120
- }
121
-
122
-
18
@dataclass
19
class ShellWrap:
20
id: int
@@ -477,7 +372,7 @@ class CodeExecution(Tool):
372
truncated_output.splitlines()[-3:] if truncated_output else []
373
)
374
last_lines.reverse()
480
- for idx, line in enumerate(last_lines):
375
+ for _, line in enumerate(last_lines):
376
for pat in prompt_patterns:
377
if pat.search(line.strip()):
378
PrintStyle.info(
@@ -564,6 +459,115 @@ class CodeExecution(Tool):
459
return normalized
460
461
462
+# ------------------------------------------------------------------
463
+# Internal
464
+# ------------------------------------------------------------------
465
+
466
+def _resolve_ssh_enabled(raw_value) -> bool:
467
+ """Resolve ssh_enabled: 'auto' detects based on dockerized state."""
468
+ val = str(raw_value).strip().lower()
469
+ if val == "auto":
470
+ return not runtime.is_dockerized()
471
+ return val in ("true", "1", "yes", "on")
472
+
473
+
474
+def _resolve_ssh_addr(cfg_addr: str) -> str:
475
+ """Resolve SSH address: fall back to rfc_url from settings when empty."""
476
+ if cfg_addr:
477
+ return cfg_addr
478
+ set = settings.get_settings()
479
+ host = set.get("rfc_url", "localhost")
480
+ # Strip protocol and port from URL
481
+ if "//" in host:
482
+ host = host.split("//")[1]
483
+ if ":" in host:
484
+ host = host.split(":")[0]
485
+ if host.endswith("/"):
486
+ host = host.rstrip("/")
487
+ return host or "localhost"
488
+
489
+
490
+async def _resolve_ssh_pass(cfg_pass: str) -> str:
491
+ """Resolve SSH password: fall back to root_password via RFC when empty."""
492
+ if cfg_pass:
493
+ return cfg_pass
494
+ return await rfc_exchange.get_root_password()
495
+
496
+
497
+def _get_config(agent) -> dict:
498
+ cfg = plugins.get_plugin_config("code_execution", agent=agent) or {}
499
+
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
+ }
516
+
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)),
523
+ }
524
+
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
+ ]
557
+
558
+ 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,
568
+ }
569
+
570
+
571
def make_dir(path: str):
572
import os
573
os.makedirs(path, exist_ok=True)