1
+from __future__ import annotations
2
+
3
+from typing import Any
4
+
5
+_TIMEOUT_KEYS = (
6
+ "first_output_timeout",
7
+ "between_output_timeout",
8
+ "max_exec_timeout",
9
+ "dialog_timeout",
10
+)
11
+
12
+_DEFAULT_CODE_EXEC_TIMEOUTS = {
13
+ "first_output_timeout": 30,
14
+ "between_output_timeout": 15,
15
+ "max_exec_timeout": 180,
16
+ "dialog_timeout": 5,
17
+}
18
+_DEFAULT_OUTPUT_TIMEOUTS = {
19
+ "first_output_timeout": 90,
20
+ "between_output_timeout": 45,
21
+ "max_exec_timeout": 300,
22
+ "dialog_timeout": 5,
23
+}
24
+_DEFAULT_PROMPT_PATTERNS = [
25
+ r"(\(venv\)).+[$#] ?$",
26
+ r"root@[^:]+:[^#]+# ?$",
27
+ r"[a-zA-Z0-9_.-]+@[^:]+:[^$#]+[$#] ?$",
28
+ r"\(?.*\)?\s*PS\s+[^>]+> ?$",
29
+]
30
+_DEFAULT_DIALOG_PATTERNS = [
31
+ r"Y/N",
32
+ r"yes/no",
33
+ r":\s*$",
34
+ r"\?\s*$",
35
+]
36
+
37
+
38
+def _coerce_timeout_group(raw: Any, defaults: dict[str, int]) -> dict[str, int]:
39
+ group = raw if isinstance(raw, dict) else {}
40
+ result: dict[str, int] = {}
41
+ for key in _TIMEOUT_KEYS:
42
+ value = group.get(key, defaults[key])
43
+ try:
44
+ result[key] = int(value)
45
+ except (TypeError, ValueError):
46
+ result[key] = defaults[key]
47
+ return result
48
+
49
+
50
+def _pattern_lines(raw: Any, defaults: list[str]) -> list[str]:
51
+ if isinstance(raw, list):
52
+ values = raw
53
+ elif isinstance(raw, str):
54
+ values = raw.splitlines()
55
+ else:
56
+ values = defaults
57
+
58
+ patterns = [str(value).strip() for value in values if str(value).strip()]
59
+ return patterns or list(defaults)
60
+
61
+
62
+def build_exec_config() -> dict[str, Any]:
63
+ from helpers import plugins
64
+
65
+ try:
66
+ config = plugins.get_plugin_config("_code_execution") or {}
67
+ except Exception:
68
+ config = {}
69
+
70
+ return {
71
+ "version": 1,
72
+ "code_exec_timeouts": _coerce_timeout_group(
73
+ config.get("code_exec_timeouts") or {
74
+ key: config.get(f"code_exec_{key}")
75
+ for key in _TIMEOUT_KEYS
76
+ if f"code_exec_{key}" in config
77
+ },
78
+ _DEFAULT_CODE_EXEC_TIMEOUTS,
79
+ ),
80
+ "output_timeouts": _coerce_timeout_group(
81
+ config.get("output_timeouts") or {
82
+ key: config.get(f"output_{key}")
83
+ for key in _TIMEOUT_KEYS
84
+ if f"output_{key}" in config
85
+ },
86
+ _DEFAULT_OUTPUT_TIMEOUTS,
87
+ ),
88
+ "prompt_patterns": _pattern_lines(
89
+ config.get("prompt_patterns"),
90
+ _DEFAULT_PROMPT_PATTERNS,
91
+ ),
92
+ "dialog_patterns": _pattern_lines(
93
+ config.get("dialog_patterns"),
94
+ _DEFAULT_DIALOG_PATTERNS,
95
+ ),
96
+ }